user5556391
user5556391

Reputation: 11

Understanding subtraction and multiplication in assembly code

Can someone explain what these steps in the disassembled code would do. I have a general idea but I'm still confused. I know that the first two instructions set up the stack and that eax will be a returned value but that's about it.

What I'm looking for is the purpose of the steps below:

push %ebp - base stack frame pointer
mov %esp, %ebp - stack pointer
sub $0x10, %esp - subtracts 16 from ?
mov 0x8(%ebp), %eax - ?
imul 0xc(%ebp), %eax - multiply 12 and ?
mov %eax, -0x4(%ebp) - ?
mov -0x4(%ebp), %eax - puts -0x4(%ebp) not sure what that would be , into eax making it the return value?
leave
ret

Upvotes: 0

Views: 5053

Answers (1)

Matteo Italia
Matteo Italia

Reputation: 126827

; Standard prolog: stack frame setup
push ebp               ; save the old frame pointer
mov ebp, esp           ; set the frame pointer to the current top of the stack
sub esp, 0x10          ; make space for 16 bytes of local variables
; Do the stuff
mov eax, [ebp+8]       ; copy the first parameter in eax
imul eax, [ebp+0xc]    ; multiply eax with the second parameter
mov [ebp-4], eax       ; move the result to the first local variable
mov eax, [ebp-4]       ; move it back to eax (?) => set it as return value
; Standard cdecl epilog - clean up locals & return
leave                  ; restore the old frame pointer
                       ; same as: mov esp, ebp
                       ;          pop ebp
ret                    ; return

(sorry for changing it to Intel notation, but AT&T syntax looks like an unreadable mess to me, especially the hideous notation for dereferencing and offsets1)

To understand this keep around this handy diagram of how the stack normally looks like in a cdecl function call on x86 just after the function prolog:

x86 stack frame scheme

and remember that expressions in brackets are pointer dereferencing operations.

Essentially, this is a (quite naive) translation of

int multiply(int a, int b) {
    //           \      \ &b == ebp+12
    //            \ &a == ebp+8
    int c = a*b;
    //   \    \ multiplication performed in eax
    //    \ &c == ebp-4
    return c;
    //   \ return value left in eax
}

(using the cdecl calling convention, where it's the caller's responsibility to clean up the parameters from the stack)

Probably this was generated by a compiler with optimizations disabled. A more compact version would be:

mov eax, [esp+4]
imul eax, [esp+8]
ret

(since everything can be done in without local variables, there's not even need for setting up a stack frame)


Edit

Just checked, your code matches exactly what gcc produces at -O0, while mine is almost identical to what is generated at -O3.


Notes

  1. For the record: when you see

    displacement(%register, %offset_register, multiplier)
    

    (each component besides %register is optional) in AT&T syntax it actually means

    [register + displacement + offset_register*multiplier]
    

    where the brackets mean "take the value stored here".

    Also, almost all parameters are swapped in AT&T syntax (in Intel syntax the destination operand is on the left, i.e. a mov reads like an assignment - mov ebp, esp => ebp = esp).

Upvotes: 5

Related Questions