装配 - CMP未按预期工作

时间:2015-03-03 22:47:26

标签: assembly x86 gdb att

我是汇编代码的新手,我正在使用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?

2 个答案:

答案 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,然后使用该地址访问内存。