0

I am very new to assembly, so I just want to make sure I am understanding whats happening in this code:

  400610:   83 ff 1d                cmp    $0x1d,%edi
  400613:   7f 0c                   jg     400621 <f1+0x11>
  400615:   89 f8                   mov    %edi,%eax
  400617:   c1 e0 04                shl    $0x4,%eax
  40061a:   8d 04 f8                lea    (%rax,%rdi,8),%eax
  40061d:   8d 04 78                lea    (%rax,%rdi,2),%eax
  400620:   c3                      retq   
  400621:   c1 ff 02                sar    $0x2,%edi
  400624:   8d 47 11                lea    0x11(%rdi),%eax
  400627:   c3                      retq   

From what I can see, there is a jump to 400621 but I am not sure what f1+0x11 signifies.

If it does not jump, it continues and shifts %eax to the left 4 (multiplies by 16), then performs eax = rax + rdi * 8, then eax = rax + rdi * 2? I am not sure what the purpose of doing that twice is.

If it does jump, it shifts %eax to the right 2 (divides by 4) and then I am not sure what (lea 0x11(%rdi),%eax) does.

Help would be appreciated, thank you!

Jester
  • 56,577
  • 4
  • 81
  • 125
Andrew Zaw
  • 754
  • 1
  • 9
  • 16
  • 1
    The reason for two `lea` instructions is that the effective addressing is limited so you can't achieve that with a single one. If you understand those ones, what problem do you have with `lea 0x11(%rdi),%eax`? That just does `eax=edi+0x11`. – Jester Nov 21 '18 at 00:06
  • Ah, yes, the maximum number it can be is 8, I know that. So for lea, when a number is outside of the parentheses, it just adds it? If I had `lea 0x11(%rdi,%rsi,4),%eax` it would do `eax = rsi * 4 + rdi + 0x11`? Also for `jg 400621 `, 400621 signifies the address, but what does the second part signify? – Andrew Zaw Nov 21 '18 at 00:08
  • 1
    1) Yes. Not specific to`lea` of course, that's just the general form of an address. 2) The same thing. It's just a friendly service of your disassembler showing it as an offset from the previous symbol. `f1` is presumably the name of this function so `f1+0x11=0x400610+0x11=0x400621` – Jester Nov 21 '18 at 00:21
  • Ah, that makes sense, thank you very much! – Andrew Zaw Nov 21 '18 at 00:51
  • *"the maximum number it can be is 8"* - the address scale in 64b mode can be only 1, 2, 4 or 8. ... it's not about "min/max" value, but only these powers of two are available, "5" is invalid too ( `(,%edi,5)` = error ). (but you can still use `lea` to do multiplication by 5 like `lea (%eax, %eax, 4), %eax` => `eax = eax + eax*4 = eax*5`) – Ped7g Nov 21 '18 at 13:08
  • @Ped7g: easiest way to explain it is that it's a 2-bit shift count. That's literally how it's encoded into the SIB byte in machine code. – Peter Cordes Nov 21 '18 at 20:11
  • Partial duplicate of [Referencing the contents of a memory location. (x86 addressing modes)](https://stackoverflow.com/a/34058400), which explains addressing mode limitations. Also related: [How to multiply a register by 37 using only 2 consecutive leal instructions in x86?](https://stackoverflow.com/q/46480579). And BTW, 4 uops (mov + shl + 2x LEA) is probably not worth it vs. `imul $something, %edi, %eax`. I didn't work out what the actual multiplier is here, but I think the shifts and adds boil down to a multiply by a constant. – Peter Cordes Nov 21 '18 at 20:15

0 Answers0