user672118
user672118

Reputation:

NASM Length of an Argument

I am writing a simple program to display a name supplied by the user. The result is that I should be able to enter the command and get the expected result.

Command

./hello John

Result

Hello, John.


Yet when the program gets around to displaying the name, it doesn't. I believe it has something to do with calculating the length of the argument. May you guys please take a look at my code and tell me what you think?

; hello.asm
;
; Assemble: nasm -f elf hello.asm
; Link:     ld -o hello hello.o
; Run:      ./hello <name>

section .data
    period:      db  ".", 10
    periodLen:   equ $-period

    helloMsg:    db  "Hello, "
    helloMsgLen: equ $-helloMsg

    usageMsg:    db  "Usage: hello <name>", 10
    usageMsgLen: equ $-usageMsg

section .text
    global _start

_start:
    pop eax                     ; Get number of arguments
    cmp eax, 2                  ; If one argument
    jne _help                   ; Not equal, show help + exit

    mov eax, 4                  ; System call to write
    mov ebx, 1                  ; Write to console
    mov ecx, helloMsg           ; Display "Hello, "
    mov edx, helloMsgLen        ; Length of hello message
    int 80h

    mov eax, 4                  ; System call to write
    mov ebx, 1                  ; Write to console
    pop ecx                     ; Get program name
    pop ecx                     ; Get name
    mov edx, $                  ; Beginning of line
    sub edx, ecx                ; Get length of name
    int 80h

    mov eax, 4                  ; System call to write
    mov ebx, 1                  ; Write to console
    mov ecx, period             ; Display a period
    mov edx, periodLen          ; Length of period
    int 80h

    mov eax, 1                  ; System call to exit
    mov ebx, 0                  ; No errors
    int 80h

_help:
    mov eax, 4                  ; System call to write
    mov ebx, 1                  ; Write to console
    mov ecx, usageMsg           ; Display usage message
    mov edx, usageMsgLen        ; Length of usage message
    int 80h

    mov eax, 1                  ; System call to exit
    mov ebx, 0                  ; No errors
    int 80h

Upvotes: 3

Views: 2773

Answers (1)

BlackBear
BlackBear

Reputation: 22979

Ok, since you never used a debugger, I'll show you how. First, compile with nasm -f elf -g hello.asm. The -g switch helps the debugger, this way you can set breakpoints etc. Now start it typing gdb ./hello -q and type break 34. This tells gdb to stop at line 34. Run the program (type run emi (emi is my name :P)). You should see something like this:

blackbear@blackbear-laptop:~$ gdb ./hello -q
Reading symbols from /home/blackbear/hello...done.
(gdb) break 34
Breakpoint 1 at 0x80480a9: file hello.asm, line 34.
(gdb) run emi
Starting program: /home/blackbear/hello emi
Hello, 
Breakpoint 1, _start () at hello.asm:34
34      pop ecx                     ; Get name
(gdb) 

Ok, let's see what ecx is, typing display (char *) $ecx:

(gdb) display (char *) $ecx
1: (char *) $ecx = 0xbffff63e "/home/blackbear/hello"

You can use step to continue by one instruction:

(gdb) step
35      mov edx, $                  ; Beginning of line
1: (char *) $ecx = 0xbffff654 "emi"

Ok, here we are. ecx points to my name, so the problem isn't here. Now we don't need to watch ecx anymore, so using undisplay gdb won't show it anymore. But we need to check edx:

(gdb) undisplay
Delete all auto-display expressions? (y or n) y
(gdb) display $edx
2: $edx = 7
(gdb) step
36      sub edx, ecx                ; Get length of name
2: $edx = 134512810
(gdb) step
37      int 80h
2: $edx = 1208257110

Mmh, guess you didn't expect this, right? :) The problem seems to be here: mov edx, $. I don't get that $ (never used NASM), could you please explain?

EDIT
Ok got it. You misunderstood what the tutorial said. The $ represents the current location of it, in fact:

36      sub edx, ecx                ; Get length of name
11: $edx = 134512810
(gdb) display (void *) $edx
12: (void *) $edx = (void *) 0x80480aa
(gdb) display (void *) $eip
13: (void *) $eip = (void *) 0x80480af

now edx contains the address of the instruction mov edx, $. which is 5 bytes long (opcode (1 byte) + address (4 bytes)), that's why eip - edx = 5.
In order to get the length of the argument your only way is to use something like strlen(), but I can't help you here, NASM isn't my assembler. :)

Upvotes: 5

Related Questions