Page 1 of 1

NASM - Linux Getting command line parameters

#1 GunnerInc  Icon User is online

  • "Hurry up and wait"
  • member icon




Reputation: 858
  • View blog
  • Posts: 2,288
  • Joined: 28-March 11

Post icon  Posted 11 July 2012 - 08:29 PM

Now for something different. We will dive into Linux Assembly using NASM.

When you start your program from a terminal, Linux gives you TONS of information on the stack that you can use even if you don't pass any parameters to your program.

This is what the stack looks like when you start your program:
Attached Image

Argument Count
This will ALWAYS be at least 1, even without passing any parameters to your program. Why? Linux will always give you the path to your app.

My code for this tut is in ~/asm/projects/reverse so when I run reverse, the path will be: ./reverse.
gunner@LinuxDevel ~/asm/projects/reverse $ ./reverse hello
./reverse

Lets go back to the asm directory and run from there:
gunner@LinuxDevel ~/asm/projects/reverse $ cd ../../
gunner@LinuxDevel ~/asm $ ./projects/reverse/reverse hello
./projects/reverse/reverse



Don't mind the hello arg, since the code exits if there are no args, I just used that so it will be satisfied.

Aguments Block
After the pointer to the path comes pointers to each passed argument, followed by a NULL pointer. This marks the end of passed arguments.

Environment Block
After the arguments and NULL pointer, Linux will give us pointers to MANY Environment Variables followed again by a NULL pointer to mark the end of the variables. This list can contain well up to 200 items depending on your system.

Command line parameters can be used as input to your program or as switches to tell your program what to do. We will learn how to parse the parameters and for fun, reverse them "in place" and display them.

MAXARGS     equ     5 ; 1 = program path 2 = 1st arg  3 = 2nd arg etc... 
sys_exit    equ     1
sys_read    equ     3
sys_write   equ     4
stdin       equ     0
stdout      equ     1
stderr      equ     3

SECTION     .data
;szErrMsg    db      "Too many arguments.  The max number of args is 4", 10
;ERRLEN      equ     $-szErrMsg
szLineFeed  db      10


SECTION     .text
global      _start
    
_start:
    nop

    push    ebp
    mov     ebp, esp
    
    cmp     dword [ebp + 4], 1
    je      NoArgs                           ; no args entered
    
    ; uncomment the following 2 lines to limit args entered
    ; and set MAXARGS to Total args wanted + 1
    ; cmp     dword [ebp + 4], MAXARGS        ; check total args entered
    ; ja      TooManyArgs                     ; if total is greater than MAXARGS, show error and quit

    mov     ebx, 3
    
DoNextArg:   
    mov     edi, dword [ebp + 4 * ebx]
    test    edi, edi
    jz      Exit
    
    call    GetStrlen
    push    edx                             ; save string length for reverse
    
    mov     ecx, dword [ebp + 4 * ebx]
    call    DisplayNorm                     ; display arg text normally
    
    pop     edi                             ; move string length into edi
    mov     esi, dword [ebp + 4 * ebx]
    call    ReverseIt                       ; now display in reverse
    inc     ebx                             ; step arg array index
    jmp     DoNextArg
    
ReverseIt:
    push    ebx

    add     esi, edi
Next:
    mov     eax, sys_write
    mov     ebx, stdout
    mov     ecx, esi
    mov     edx, 1
    int     80H    
    dec     esi
    dec     edi 
    jns     Next

    mov     ecx, szLineFeed
    mov     edx, 1
    mov     eax, sys_write
    mov     ebx, stdout
    int     80H
    
    pop     ebx
    ret
    
NoArgs:
   ; No args entered,
   ; start program without args here
    jmp     Exit

DisplayNorm:
    push    ebx
    mov     eax, sys_write
    mov     ebx, stdout
    int     80H  
    pop     ebx
    ret
    
GetStrlen:
    push    ebx
    xor     ecx, ecx
    not     ecx
    xor     eax, eax
    cld
    repne   scasb
    mov     byte [edi - 1], 10
    not     ecx
    pop     ebx
    lea     edx, [ecx - 1]
    ret
    
; TooManyArgs:
;     mov     eax, sys_write
;     mov     ebx, stdout
;     mov     ecx, szErrMsg
;     mov     edx, ERRLEN
;     int     80H
    
Exit:
    mov     esp, ebp
    pop     ebp
    
    mov     eax, sys_exit
    xor     ebx, ebx
    int     80H



When run this will be the output:

Attached Image

Ok, lets go though the code:
MAXARGS     equ     5 ; 1 = program path 2 = 1st arg  3 = 2nd arg etc... 
sys_exit    equ     1
sys_read    equ     3
sys_write   equ     4
stdin       equ     0
stdout      equ     1
stderr      equ     3

I don't like using hard coded numbers (or others that do), it just makes the code less readable. So I define some equates to use instead.

    push    ebp
    mov     ebp, esp
    
    cmp     dword [ebp + 4], 1
    je      NoArgs                           ; no args entered
    
    ; uncomment the following 2 lines to limit args entered
    ; and set MAXARGS to Total args wanted + 1
    ; cmp     dword [ebp + 4], MAXARGS        ; check total args entered
    ; ja      TooManyArgs                     ; if total is greater than MAXARGS, show error and quit


We will save esp and use ebp as our base pointer to the stack. So now, instead of the arg count being at [esp], it is now at [ebp + 4]
We check to see if this value is 1 (No args entered) if it is, we start the program anyway you want. This code I just exit.

Next we can check to see if there are too many arguments entered and display a message if wanted. Uncomment the relevant code to see it work.

Now lets loop through the arg pointers:
    mov     ebx, 3    
DoNextArg:   
    mov     edi, dword [ebp + 4 * ebx]
    test    edi, edi
    jz      Exit
    
    call    GetStrlen
    push    edx                             ; save string length for reverse
    
    mov     ecx, dword [ebp + 4 * ebx]
    call    DisplayNorm                     ; display arg text normally
    
    pop     edi                             ; move string length into edi
    mov     esi, dword [ebp + 4 * ebx]
    call    ReverseIt                       ; now display in reverse
    inc     ebx                             ; step arg array index
    jmp     DoNextArg

Here we will use ebx as the index into the argument array. Why start at 3? Since we pushed ebp, the args now start at [ebp + 12], 4 * 3 = 12, so we just increment ebx to get the next array pointer.

First thing we do is check to see if we have a NULL pointer, and if we do we are at the end of the argument array.

Have a valid pointer? Good, now we will get the length of the string, display it normally and display it reversed. Increment ebx for the next array element and loop back to the beginning and get next arg (if there is one). Instead of displaying and reversing the arg text, this is where you would check for switches that tell your program what to do.

GetStrlen:
    push    ebx
    xor     ecx, ecx
    not     ecx
    xor     eax, eax
    cld
    repne   scasb
    mov     byte [edi - 1], 10
    not     ecx
    pop     ebx
    lea     edx, [ecx - 1]
    ret

Here we will use scasb to scan the string for a NULL terminator. We could use scasb in a loop of our own, but we will let the CPU do the loop with repne (repeat while not equal)
scasb looks for the byte that is in eax, we want to find a NULL (0) so we zero out eax. ecx will contain -1 (4,294,967,295), and edi is a pointer to the string to search.

scasb will scan a byte in the string, and if the one we are looking for is not found, it will increment the pointer in edi and decrement ecx and keep repeating until it finds our character. It exits its loop when the character is found, or when ecx equals 0. Once 0 is found, we replace it with the linefeed character (10), and move the string length into edx.

That is about as simple as it gets. Here is a little assignment for you:
Taking the code above, and from what I explained; modify the code to show all the system variables INSTEAD of any command line params.

Attached File(s)



Is This A Good Question/Topic? 3
  • +

Replies To: NASM - Linux Getting command line parameters

#2 RCR  Icon User is offline

  • New D.I.C Head
  • member icon

Reputation: 7
  • View blog
  • Posts: 33
  • Joined: 04-July 12

Posted 14 July 2012 - 01:58 PM

Great lesson, will really help the people that read my tutorial.

- RCR
Was This Post Helpful? 0
  • +
  • -

#3 danzar  Icon User is offline

  • D.I.C Head
  • member icon

Reputation: 8
  • View blog
  • Posts: 108
  • Joined: 10-December 08

Posted 15 July 2012 - 10:15 PM

Thank you, very good read. Hope to see more on the subject of Nasm.


Danzar
Was This Post Helpful? 0
  • +
  • -

Page 1 of 1