I am trying to understand the assembly of this simple C program.
#include<stdio.h>
#include<unistd.h>
#include<fcntl.h>
#include<string.h>
void foobar(char *a){
char c = a[0];
}
int main(){
int fd = open("file.txt", O_RDONLY);
char buf1[100]="\0";
char buf[100];
int aa=0,b=1,c=2,d=3,f=2,g=3;
read(fd,buf1,104);
if(strlen(buf1) > 100){
}else{
strcpy(buf,buf1);
}
//strcpy(buf,buf1);
foobar(buf1);
}
The disassembly of the executable using gdb which i got was foobar disassembly.
0x000000000040067d <+0>: push rbp
0x000000000040067e <+1>: mov rbp,rsp
0x0000000000400681 <+4>: mov QWORD PTR [rbp-0x18],rdi
0x0000000000400685 <+8>: mov rax,QWORD PTR [rbp-0x18]
0x0000000000400689 <+12>: movzx eax,BYTE PTR [rax]
0x000000000040068c <+15>: mov BYTE PTR [rbp-0x1],al
0x000000000040068f <+18>: pop rbp
main disassembly just before foobar
0x0000000000400784 <+243>: lea rax,[rbp-0xf0]
0x000000000040078b <+250>: mov rdi,rax
0x000000000040078e <+253>: call 0x40067d <foobar>
0x0000000000400793 <+258>: mov rbx,QWORD PTR [rbp-0x18]
0x0000000000400797 <+262>: xor rbx,QWORD PTR fs:0x28
0x00000000004007a0 <+271>: je 0x4007a7 <main+278>
0x0000000000400690 <+19>: ret
Now, i have a question regarding the disassembly of foobar
0x0000000000400681 <+4>: mov QWORD PTR [rbp-0x18],rdi
0x0000000000400685 <+8>: mov rax,QWORD PTR [rbp-0x18]
Wouldn't the instruction
mov rax, rdi
would do the work required by the above two instruction. Why using extra memory location rbp - 0x18
for rdi ?
Is it related to pass by reference?
Edit:
Another question which i want to ask is why the foobar function is accessing something(rbp - 0x18)
which is not in the frame of foobar.?
My gcc version is gcc (Ubuntu 4.8.2-19ubuntu1) 4.8.2
Edit: After using -O1 -O2 and -O3 optimization flag while compiling, the foobar assembly changes to
0x0000000000400670 <+0>: repz ret
and while using -O3 flag some of the disassembly of main is
0x0000000000400551 <+81>: rep stos QWORD PTR es:[rdi],rax
0x0000000000400554 <+84>: mov DWORD PTR [rdi],0x0
0x000000000040055a <+90>: mov cl,0x64
0x000000000040055c <+92>: mov edi,r8d
0x000000000040055f <+95>: call 0x4004b0 <__read_chk@plt>
0x0000000000400564 <+100>: mov rdx,QWORD PTR [rsp+0x68]
0x0000000000400569 <+105>: xor rdx,QWORD PTR fs:0x28
0x0000000000400572 <+114>: jne 0x400579 <main+121>
0x0000000000400574 <+116>: add rsp,0x78
0x0000000000400578 <+120>: ret
0x0000000000400579 <+121>: call 0x4004c0 <__stack_chk_fail@plt>
I can't find any call to foobar in main .
As several people commented, you should compile with some optimizations, e.g. at least with
gcc -O1
(and preferablygcc -O2
).If compiling with GCC specifically, I suggest to pass also
-fverbose-asm
since this emit helpful generated comments in the produced assembler file.Here is the relevant listing, compiled using GCC 5.1 on Debian/Sid/amd64, using
gcc-5 -O2 -fverbose-asm -S go.c
then look into the producedgo.s
assembler file with a pager :The compiler inlined to call to
foobar
and optimized its body to empty (since your source code has no observable side-effect forfoobar
). Then it removed any call tofoobar
since it is useless.You might try to compile with
-fdump-tree-all
. You'll get hundreds of dump files, corresponding to the many GCC optimization passes producing them.You could also customize your
gcc
with MELT (a Lisp-like domain specific language to extend GCC), and you could even search some Gimple or Tree patterns using MELT's findgimple mode (a sort-ofgrep
on the Gimple representations internal to GCC).