venugopal reddy venugopal reddy - 5 months ago 29
Linux Question

C Program translation to Assembly (x86_64) on Linux

I'm a newbie to assembly programming (especially x86_64).I have translated the following c program to assembly.

I understood most of the code but I'm not able to interpret the 2 Instructions I've commented out .

* Isn't the stmnt 1 corrupting contents of rax register by copying 42 to its lower word ?



note: as per the logic stmnt 1 should increment 42 in location whose address is stored in rax

addl $1,(%rax)


could some one explain those 2 instructions .




temp.c



#include<stdio.h>

int main()
{
int a=42,*ptr;

ptr = &a;
(*ptr)++;

return 0;
}


temp.s



.file "temp.c"
.text
.globl main
.type main, @function
main:
.LFB0:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
subq $32, %rsp
movq %fs:40, %rax
movq %rax, -8(%rbp)
xorl %eax, %eax
movl $42, -20(%rbp)
leaq -20(%rbp), %rax
movq %rax, -16(%rbp)
movq -16(%rbp), %rax
movl (%rax), %eax ; stmt 1
leal 1(%rax), %edx ; stmt 2
movq -16(%rbp), %rax
movl %edx, (%rax)
movl $0, %eax
movq -8(%rbp), %rcx
xorq %fs:40, %rcx
je .L3
call __stack_chk_fail
.L3:
leave
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE0:
.size main, .-main
.ident "GCC: (Ubuntu 5.3.1-14ubuntu2.1) 5.3.1 20160413"
.section .note.GNU-stack,"",@progbits

Answer

Yes, stmt1 is overwriting rax, but that is not a problem. stmt2 is then doing edx = eax + 1 in a tricky way using lea. The incremented value in edx is written back into memory at movl %edx, (%rax). This means the (*ptr)++; has been split into multiple steps like this:

rax = ptr;     /* load pointer */
eax = *rax;    /* fetch current value */
edx = eax + 1; /* calculate new value */
rax = ptr;     /* load pointer again */
*rax = edx;    /* write new value */

Yes, addl $1,(%rax) could have been used. You probably don't have optimization enabled which is why you see inefficient code.

With optimization enabled, the following code:

void foo(int* ptr)
{
    (*ptr)++;
}

produces this assembly:

    addl    $1, (%rdi)
    ret

And this:

void foo(int* ptr)
{
    *ptr = 42;
    (*ptr)++;
}

gives:

    movl    $43, (%rdi)
    ret
Comments