1
#include <stdio.h>

int f(int x) {
    return x * FACTOR;
}
int main() {
    int x=1;
    printf("%d\n", f(x));
    return 0;
}

For the above program, if I compile it with clang -g -S -DFACTOR=2. I got the following output.

It seems that the following two instructions are related to the multiplication x * 2. But I don't understand how they can compute the multiplication. Could anybody help explain? Thanks.

    leal    (%rdi,%rdi), %eax
...
    movl    $2, %esi
...
Ltmp0:
    ##DEBUG_VALUE: f:x <- $edi
    .loc    1 6 11 prologue_end     ## main.c:6:11
    leal    (%rdi,%rdi), %eax
    .loc    1 6 2 is_stmt 0         ## main.c:6:2
    popq    %rbp
    retq
...
Ltmp2:
    ##DEBUG_VALUE: main:x <- 1
    .loc    1 10 2 prologue_end     ## main.c:10:2
    leaq    L_.str(%rip), %rdi
    movl    $2, %esi
    xorl    %eax, %eax
    callq   _printf
    .loc    1 11 2                  ## main.c:11:2
    xorl    %eax, %eax
    popq    %rbp
    retq
user1424739
  • 11,937
  • 17
  • 63
  • 152
  • 1
    eax = x+x; which is the same thing as `x*2`. using LEA to copy-and-add. – Peter Cordes Mar 06 '19 at 05:45
  • Could you help explain leal in this context in more details? Thanks. – user1424739 Mar 06 '19 at 05:46
  • I linked this question as a duplicate of one where I answered in a lot of detail about what LEA is and why you'd use it for integer math on non-pointers. – Peter Cordes Mar 06 '19 at 05:47
  • What is the difference between leal and leaq? – user1424739 Mar 06 '19 at 05:48
  • `l` is 32-bit operand size, `q` is 64-bit operand-size, same as any other instruction. (AT&T operand-size override suffixes). It's redundant when the destination is a register, that already implies the operand-size. (And LEA only works with a register destination.) Notice that in your question, the C type is `int`, while in the duplicate it's `long`. – Peter Cordes Mar 06 '19 at 05:49
  • The instructions shown the duplicate question is not the same as mine. And I don’t follow the discussion there. It just had too much irrelevant information there. Could you provide an answer for my specific question without inundating with irrelevant stuffs? – user1424739 Mar 06 '19 at 05:53
  • 1
    I already did that in my first comment. Read how LEA works with that summary in mind. Or search on SO for any of the other LEA Q&As; there are a zillion explanations and this specific use-case isn't more interesting or different enough to justify having its own answer. – Peter Cordes Mar 06 '19 at 05:59
  • What the compiler use leal instead of add the number to itself? It is not clear to me that the answers discussed this point. – user1424739 Mar 06 '19 at 06:01
  • 2
    LEA has many more variants, and can do an add without affecting flags. `lea eax, rdi + rdi]` is simpler than `mov eax, edi; shl eax, 1` [What's the purpose of the LEA instruction?](https://stackoverflow.com/q/1658294/995714) – phuclv Mar 06 '19 at 06:43
  • @user1424739: It's *using* LEA to add the number to itself. It needs the result in EAX because of the calling convention, so `add %edi, %edi` or `add %eax, %eax` would require a `mov %edi, %eax` after or before. – Peter Cordes Mar 06 '19 at 06:53
  • 1
    @user1424739: learning by example will only get you so far but not much further. Get a good book or good online tutotial on x86 assembler, learn the basics and then learn about some of the tricks used, e.g. using LEA to add values.Also read about the difference between Gnu assembly and Intel assembly syntax and what the suffixes mean that Gnu uses. – Rudy Velthuis Mar 06 '19 at 07:50

0 Answers0