I'm having trouble understanding the (erroneous) output of the following assembly code I've generated through a compiler I'm writing.
This is the pseudo-code of what I'm compiling:
int sidefx ( ) {
a = a + 1;
printf("side effect: a is %d\n", a);
return a;
}
void threeargs ( int one, int two, int three ) {
printf("three arguments. one: %d, two: %d, three: %d\n", one, two, three);
}
void main ( ) {
a = 0;
threeargs(sidefx(), sidefx(), sidefx());
}
Here's the assembly code I've generated:
.section .rodata
.comm global_a, 8, 8
.string0:
.string "a is %d\n"
.string1:
.string "one: %d, two: %d, three: %d\n"
.globl main
sidefx: /* Function sidefx() */
enter $(8*0),$0 /* Enter a new stack frame */
movq global_a, %r10 /* Store the value in .global_a in %r10 */
movq $1, %r11 /* Store immediate 1 into %r11 */
addq %r10,%r11 /* Add %r10 and %r11 */
movq %r11, global_a /* Store the result in .global_a */
movq global_a, %rsi /* Put the value of .global_a into second paramater register */
movq $.string0, %rdi /* Move .string0 to first parameter register */
movq $0, %rax
call printf /* Call printf */
movq global_a, %rax /* Return the new value of .global_a */
leave /* Restore old %rsp, %rbp values */
ret /* Pop the return address */
threeargs: /* Function threeargs() */
enter $(8*0),$0 /* Enter a new stack frame */
movq %rdx, %rcx /* Move 3rd parameter register value into 4th parameter register */
movq %rsi, %rdx /* move 2nd parameter register value into 3th parameter register */
movq %rdi, %rsi /* Move 1st parameter register value into 2nd parameter register */
movq $.string1, %rdi /* Move .string1 to 1st parameter register */
movq $0, %rax
call printf /* call printf */
leave /* Restore old %rsp, %rbp values */
ret /* Pop the return address */
main:
enter $(8*0),$0 /* Enter a new stack frame */
movq $0, global_a /* Set .global_a to 0 */
movq $0, %rax
call sidefx /* Call sidefx() */
movq %rax,%rdi /* Store value in %rdi, our first parameter register */
movq $0, %rax
call sidefx /* Call sidefx() */
movq %rax,%rsi /* Store value in %rsi, our second parameter register */
movq $0, %rax
call sidefx /* Call sidefx() */
movq %rax,%rdx /* Store value in %rdx, our third parameter register */
movq $0, %rax
call threeargs /* Call threeargs() */
main_return:
leave
ret
Now here's what I don't understand. The output to the program when compiled (gcc file.s -o code && ./code
) is the following :
dmlittle$ gcc file.s -o code && ./code
a is 1
a is 2
a is 3
one: 1, two: 2147483641, three: 3
The problem with the assembly code is that I'm storing the values of the sidefx()
call that will eventually be parameters to threeargs()
into the function registers, but the 2 succeeding calls to sidefx()
will overwrite the values of %rdi
and %rsi
in order to call printf
. In order to fix this problem I need to store the return values either somewhere in the stack or maybe in callee-saved registers.
Why is the final printf
returning one: 1, two: 2147483641, three: 3
? Shouldn't the first number printed also be mangled like what happened to the second number due to the succeeding sidefx
calls?