I have a simple c program that multiplies and adds three variables and returns the results. I have compiled the code into assembly language (ATT format) on a 32 bit machine. I am trying to learn assembly code, and while I can understand some of the lines, I need help understanding why for example leal (%edx, %edx, 2), %edx
, would be done in the following code, like what would be the result to that, what would it accomplish?
Assembly code
.file "calc.c"
.text
.globl calc
.type calc, @function
calc:
pushl %ebp #prolog
movl %esp, %ebp #prolog
movl 8(%ebp), %edx #move %ebp +8 into %edx
movl 16(%ebp), %ecx #move %ebp +16 into %ecx
leal (%edx,%edx,2), %edx
movl 12(%ebp), %eax
leal (%edx,%eax,2), %eax
movl %ecx, %edx
sall $4, %edx
subl %ecx, %edx
addl %edx, %eax
popl %ebp
ret
.size calc, .-calc
.ident "GCC: (Ubuntu 4.3.3-5ubuntu4) 4.3.3"
.section .note.GNU-stack,"",@progbits
C program
#include <stdio.h>
int calc(int x, int y, int z){
return 3*x + 2*y + 15*z;
}
int main(void) {
int x = 2;
int y = 6;
int z = 11;
int result = calc(x,y,z);
printf("x=%d, y=%d, z=%d, result=%d\n", x,y,z,result);
return 0;
}
Could someone help me trace the problem starting from the prolog.
Maybe it can be best explained with the C function code in mind:
int calc(int x, int y, int z){
return 3*x + 2*y + 15*z;
}
Look at parameter x. It is multiplied by 3 so it is easily recognizable in the assembly code:
movl 8(%ebp), %edx
....
leal (%edx,%edx,2), %edx
movl 12(%ebp), %eax
leal (%edx,%eax,2), %eax
It moves the value of argument x into edx. The address of argument x in the stack frame is ebp+8. Then later on with leal it adds edx to 2*edx and stores the value in edx. That equals 3*x.
Then loads argument y into eax, wich you can recognize easily because y is a 32bit int so it is 4 bytes past the start address of x.
Next leal adds edx (i.e. 3*x) with 2*eax (i.e. 2*y) and stores the result in eax, thus in eax you have 3*x + 2*y.
And so on...