NASM Длина аргумента - PullRequest
3 голосов
/ 22 апреля 2011

Я пишу простую программу для отображения имени, предоставленного пользователем. В результате я смогу ввести команду и получить ожидаемый результат.

Команда

./hello John

Результат

Hello, John.


Тем не менее, когда программа подходит к отображению имени, это не так. Я считаю, что это как-то связано с вычислением длины аргумента. Ребята, не могли бы вы взглянуть на мой код и сказать, что вы думаете?

; 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

1 Ответ

5 голосов
/ 23 апреля 2011

Хорошо, так как вы никогда не использовали отладчик, я покажу вам, как. Сначала скомпилируйте с nasm -f elf -g hello.asm. Переключатель -g помогает отладчику, поэтому вы можете устанавливать точки останова и т. Д. Теперь запустите его, набрав gdb ./hello -q и набрав break 34. Это говорит gdb остановиться на строке 34. Запустите программу (введите run emi (emi - мое имя: P)). Вы должны увидеть что-то вроде этого:

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) 

Хорошо, давайте посмотрим, что такое ecx, набрав display (char *) $ecx:

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

Вы можете использовать step для продолжения одной инструкцией:

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

Хорошо, вот и мы. ecx указывает на мое имя, поэтому проблема не в этом. Теперь нам не нужно больше смотреть ecx, поэтому использование undisplay gdb больше не покажет. Но нам нужно проверить 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

Ммм, думаю, ты этого не ожидал, верно? :) Проблема, кажется, здесь: mov edx, $. Я не понимаю, что $ (никогда не использовал NASM), не могли бы вы объяснить?

EDIT
Хорошо понял. Вы не поняли, что сказал учебник. $ представляет текущее его местоположение, фактически:

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

сейчас edx содержит адрес инструкции mov edx, $. длиной 5 байтов (код операции (1 байт) + адрес (4 байта)), поэтому eip - edx = 5.
Чтобы получить длину аргумента, вы можете использовать что-то вроде strlen(), но я не могу вам здесь помочь, NASM не мой ассемблер. :)

...