我必须使用x86进行家庭作业。我一直在接受这个段落故障,但是我不确定它为什么会发生。这是代码:
addl $4, %eax
movl (%eax), %eax
movl %eax, (%esp)
call atoi
在“call atoi”之前的$ eax等于“11”。为了证明这一点,这就是我在调用之前在gdb中获得的内容。
x/s $eax
0xffffd658: "11"
我想我的一个大问题是在“call atoi”之前注册$ eax应该保留什么,以及$ eax必须为该程序保留什么才能在“call atoi”中进行段错误?
编辑:有人要求登记。 (gdb) x/s $eax
0xffffd658: "11"
(gdb) n
Program received signal SIGSEGV, Segmentation fault.
0x2aaaaaa3 in ?? ()
(gdb) inf r
eax 0x0 0
ecx 0x2aaaaaab 715827883
edx 0x0 0
ebx 0x2c3ff4 2899956
esp 0xffffd458 0xffffd458
ebp 0x80484ef 0x80484ef
esi 0x0 0
edi 0x0 0
eip 0x2aaaaaa3 0x2aaaaaa3
eflags 0x10287 [ CF PF SF IF RF ]
cs 0x23 35
ss 0x2b 43
ds 0x2b 43
es 0x2b 43
fs 0x0 0
gs 0x63 99
(gdb)
答案 0 :(得分:2)
这取决于您的atoi
函数是否需要%eax
或堆栈中的指针。鉴于代码段,您似乎对此犹豫不决:
movl %eax, (%esp)
call atoi
如果那应该是将地址推送到堆栈,你需要真正 push
它(它正确地修改堆栈指针)或自己修改堆栈指针(如与sub %esp, 4
或其他内容一样。
x86堆栈指针指向最后推送的条目,以便push
首先递减堆栈指针,然后将值存储在新指针处。这意味着movl %eax (%esp)
将损坏堆栈中最后一个被推送的条目,而不是在堆栈上放置一个新值。
大多数人让CPU处理数据堆叠而不是手动执行,所以你可能正在寻找:
push %eax
但是,如果相反atoi
期望其%eax
中的参数而不是堆栈,为什么会将其写入堆栈?那仍然会破坏那里的一切。
所以,我要做的第一件事就是选择(推送值):
addl $4, %eax
movl (%eax), %eax
push %eax
call atoi
或(对于使用%eax
),只需:
addl $4, %eax
movl (%eax), %eax
call atoi