我是汇编代码的新手,我正在使用gdb进行代码处理:
=> 0x080485ee <+132>: cmp %eax,0x80498d4(,%ebx,4)
0x080485f5 <+139>: je 0x80485fc <main+146>
0x080485f7 <+141>: call 0x8048540 <bomb>
我在那一行用断点停止了它并输入了这些gdb命令:
(gdb) print $eax
$10 = 134519000
(gdb) print 0x80498d8
$11 = 134519000
(gdb) print $ebx
$12 = 1
据我所知,cmp指令应该比较%eax和0x80498d4 +(%ebx * 4)的值,它们是相等的,所以代码应该设置零标志并触发je跳转到main + 146 on下一行。但是,当我单步执行代码时,它不会跳转:
(gdb) stepi 2
0x080485ee <+132>: cmp %eax,0x80498d4(,%ebx,4)
0x080485f5 <+139>: je 0x80485fc <main+146>
=> 0x080485f7 <+141>: call 0x8048540 <bomb>
有人可以帮助我理解为什么没有设置零旗并且我没有跳到主+ 146?
答案 0 :(得分:1)
您没有将内存访问转换为正确的C表达式,以便在GDB中进行评估。它应该是*(int*)(0x80498d4 + $ebx*4)
。
说明问题是cmp %eax,0x80498d4(,%ebx,4)
,让我们分解将0x80498d4(,%ebx,4)
部分翻译成C的步骤:
为位移创建一个GDB便利变量以保存一些输入:
set variable $d = 0x80498d4
将置换+索引*比例寻址模式转换为地址:
set variable $addr = $d + $ebx*4
取消引用地址。这就是你所缺少的:
set variable $v = *(int*)$addr
上述三个步骤相当于:set variable $v = *(int*)($d + $ebx*4)
。因此:
将内存中的值与EAX进行比较:
p $eax == $v
将 EAX 设置为内存中的值以使跳转发生:
set variable $eax = $v
答案 1 :(得分:0)
如果我反编译这个汇编代码,它会引导我转到这样的C代码:
if (p!=q[i])
bomb();
其中p是EAX中保存的值,q似乎是一个数组的基址,其元素各有4个字节,这个基址是0x80498d4,而i是EBX中保存的值,它作为索引表示阵列。
但是你期望上面的表达式表现得像这样:
if (p != &q[i]) /* or (p != q+i)
bomb();
对我来说哪一点更有意义:EAX中的值显然是一个地址(一个指针),因此应该再次进行另一个指针的比较,它恰好是q [i]的地址(实际上,q [ 1]因为EBX = 1)具有相同的值,所以要么q是指针数组,要么原始C代码应该像我写的第二个那样读。
无论哪种方式,您编写的汇编代码都会将寄存器与内存值进行比较。事实上,唯一的汇编指令是LEA指令,它返回在表达式中计算的值(常量+寄存器*标度)而不访问存储器。所有其他人使用这些表达式将有效地址计算为LEA,然后使用该地址访问内存。