我正在编写一个简单的程序来显示用户提供的名称。 结果是我应该可以input命令并获得预期的结果。
命令
./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
好的,因为你从来没有使用调试器,我会告诉你如何。 首先用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),你能解释一下吗?
编辑
好的,我知道了。 你误会了教程的内容。 实际上, $
表示它的当前位置:
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不是我的汇编程序。 🙂