简体   繁体   中英

Assembly - CMP not working as expected

I'm new to assembly code and I'm working on code with gdb that has this:

=> 0x080485ee <+132>:   cmp    %eax,0x80498d4(,%ebx,4)
   0x080485f5 <+139>:   je     0x80485fc <main+146>
   0x080485f7 <+141>:   call   0x8048540 <bomb>

I stopped it with a breakpoint at that line and entered these gdb commands:

(gdb) print $eax
$10 = 134519000
(gdb) print 0x80498d8
$11 = 134519000
(gdb) print $ebx
$12 = 1

From what I understand, the cmp instruction should compare the values of %eax and 0x80498d4 + (%ebx * 4), which are equal, so the code should set the zero flag and trigger je to jump to main+146 on the next line. But when I step through the code it doesn't jump:

(gdb) stepi 2
   0x080485ee <+132>:   cmp    %eax,0x80498d4(,%ebx,4)
   0x080485f5 <+139>:   je     0x80485fc <main+146>
=> 0x080485f7 <+141>:   call   0x8048540 <bomb>

Could someone please help me understand why the zero flag wasn't set and je didn't jump to main+146?

Summary

You're not translating the memory access into the correct C expression to evaluate in GDB. It should be *(int*)(0x80498d4 + $ebx*4) .

Explanation

The instruction is question is cmp %eax,0x80498d4(,%ebx,4) , let's break down the steps of translating the 0x80498d4(,%ebx,4) part into C:

Create a GDB convenience variable for the displacement to save some typing:

set variable $d = 0x80498d4

Translate the Displacement + Index*Scale addressing mode into an address:

set variable $addr = $d + $ebx*4

Dereference the address. This is what you were missing:

set variable $v = *(int*)$addr

The three steps above is equivalent to: set variable $v = *(int*)($d + $ebx*4) . Thus:

to compare the value in memory with EAX:

p $eax == $v

to set EAX to value in memory to make the jump happen:

set variable $eax = $v

If I decompile this assembly code, it leads me to a C code like this:

if (p!=q[i])
  bomb();

Where p is the value held in EAX, q seems to be the base address of an array whose elements have 4 bytes each, being this base address 0x80498d4, and i is the value held in EBX, which serves as index to said array.

But you were expecting the above expression to behave like this:

if (p != &q[i])  /* or (p != q+i)
  bomb();

Which kinda make more sense to me: the value in EAX is clearly an address (a pointer) so the comparison should be made agains another pointer and it happens to be that the address of q[i] (actually, q[1] as EBX=1) has the same value, so either q is an array of pointers, or the original C code should read like the second one I've written.

Either way, the assembly code you have written compares a register against a memory value. In fact, the only assembly instruction that returns the value calculated in an expression like that (constant + register * scale) without accessing memory is the LEA instruction. All the others use these expressions to compute the effective address as LEA, and then, access memory using that address.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM