我正在编写以下令人讨厌的(NASM)代码,将鼠标指针设置为位置100,100:
section .text
global _start:
_start:
mov eax, 4
mov ecx, 100
mov edx, 100
int 33h
mov eax, 1
int 0x80
我使用以下make文件编译它:
DEPS = Mouse.asm
Mouse: $(DEPS)
nasm -f elf $(DEPS)
ld -m elf_i386 -s -o Mouse Mouse.o
然后我使用$ sudo gdb Mouse在GDB中打开它。然后我输入“break _start”并按“r”运行。当我这样做时,我得到以下输出:
“启动程序:/ home / tyler / ASM / Mouse / Mouse
编程接收信号SIGSEGV,分段故障。 0x0804806f在? () “
在我看来,它甚至都没有在_start打破断点,所以我不知道我做错了什么。我该如何调试呢?
答案 0 :(得分:2)
为了回答您提出的问题(而不是您实际遇到的问题),请使用@ Ped7g建议"滥用" GDB的错误处理是为了让它在第一条指令之前停止而不知道正确的地址:
b *0
在地址零处设置断点(这是不可能的)。r
运行程序,此时GDB尝试实际设置断点。它失败,在执行任何指令之前停止。d 1
删除无效断点si
(或stepi
)将从此处单步执行。这是调试没有符号的程序的有用技巧,即使它是使用ASLR(gcc -pie
)动态链接的,因此您无法获得真正的ELF入口点地址使用readelf -a
。
你做了什么:
然后我输入" break _start"并按" r"跑。
当我使用您使用的相同命令构建后,我得到
Reading symbols from ./Mouse...(no debugging symbols found)...done.
(gdb) b _start
No symbol table is loaded. Use the "file" command.
Make breakpoint pending on future shared library load? (y or [n]) y
Breakpoint 1 (_start) pending.
我必须输入y
或n
才能输入r
来运行程序。
所以我在asm源中标记为_start:
的指令实际上没有断点。我只有一个挂起断点,如果我给GDB一个符号表,它将被设置在某处。 (可以将调试符号剥离到一个单独的文件中,因此这种gdb行为是有道理的。但不幸的是,在这种情况下你很困惑。:/)
您的二进制文件已被删除,因为您使用ld -s
构建了二进制文件。这与您想要调试的内容相反。使用nasm -g -Fdwarf
使用现代dwarf
调试信息格式代替STABS,以获得更好的符号信息。
(gdb) r
Starting program: /home/peter/src/SO/Mouse
Program received signal SIGSEGV, Segmentation fault.
0x0804806f in ?? ()
0x0804806f
处的说明是您的int 33h
。
在_start
之前它没有分段,它只是没有停止,因为你从来没有实际设置一个断点。在静态链接的二进制文件中,在用户空间中运行的第一条指令是ELF入口点处的指令。 (在动态链接的二进制文件中,ELF解释器首先运行并最终跳转到您的_start
或任何您称为入口点的位置。)
使用layout reg
显示寄存器和反汇编。使用set disassembly-flavor intel
获取GNU的类似MASM的语法,当你知道它应该是什么时,该语法足够接近NASM。将它们放在~/.gdbinit
中。另请参阅x86代码wiki的底部,了解有关gdb
和strace
的更多调试提示。
正如评论者指出的那样,你的程序无法在Linux下本地运行。 Linux本身不支持BIOS int 33h
ABI,只支持自己的系统调用ABI。 What are the calling conventions for UNIX & Linux system calls on i386 and x86-64。这就是int 33h
段错误的原因。
如果你想编写MS-DOS或PC-BIOS代码,请使用像BOCHS这样的仿真器(它有一个内置调试器,可以让你单步执行任何操作,甚至是引导程序)。