SPO600 – Lab 2

Analyzing Binary Files x86_64
In this lab for spo600 we are compiling a c hello world program, with a few different compiler options, and analyzing the binaries with “objdump”. Using the program objdump, and a couple of it’s options we will disassemble and view information on these files, and learn to read what they are doing in a assembly style format. The lab material can be found here.

The first step I took in performing this lab was to make the necessary c files and a Makefile for performing all the compilations.

hello.c

#include 

int main() {
    printf("Hello World!\n");
}

hello-args.c

#include 

int main() {
    printf("Hello World!\n", 1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
}

hello-function.c

#include 

int main() {
        dothis();    
}

dothis() {
        printf("Hello World!\n");
}

Makefile

BINARIES=hello hello-1 hello-2 hello-3 hello-4 hello-5 hello-6

all:    ${BINARIES}

hello:          hello.c
        gcc     -g      -O0     -fno-builtin    -o hello        hello.c

hello-1:        hello.c
        gcc     -static -g      -O0     -fno-builtin    -o hello-1      hello.c

hello-2:        hello.c
        gcc     -g      -O0     -o hello-2      hello.c

hello-3:        hello.c
        gcc     -O0     -fno-builtin    -o hello-3      hello.c

hello-4:        hello-args.c
        gcc     -g      -O0     -fno-builtin    -o hello-4      hello-args.c

hello-5:        hello-function.c
        gcc     -g      -O0     -fno-builtin    -o hello-5      hello-function.c

hello-6:        hello.c
        gcc     -g      -O3     -fno-builtin    -o hello-6      hello.c

clean:
        rm      -f ${BINARIES}  *.o

Using the Makefile I simply run the “make” command and it will compile all parts for the lab. Using Makefiles really helps to keep everything organized and really clean. They save tons of time not having to rewrite all the compiling options and it confirms that each binary is the most recent version. It becomes even more useful when assembling files because you then have to link the file afterwards, which is just one more command to write. Now to begin analyzing the binary files! I will be using the following command to disassemble and view each of the binary file’s information:

objdump --source ./binary_file_here | less

Change (1)

Add the compiler option -static. Note and explain the change in size, section headers, and the function call.

gcc     -static -g      -O0     -fno-builtin    -o hello-1      hello.c

After adding -static to the gcc options, the size of the file jumped in size by almost 100 times. With this new option, dynamic linking with shared libraries is prevented and static linking is enabled. This means the binary will require the libraries it’s using directly inside the binary, hence the massive increase in size.

Change (2)

Remove the compiler option -fno-builtin. Note and explain the change in the function call.

gcc     -g      -O0     -o hello-2      hello.c

After removing -fno-builtin from the gcc options, the function in the main changed. It became smaller and started using the function “puts” instead of “printf”. After a little research, it seems that running a “puts” is much faster then running “printf” while “printf” has no arguments. This is possibly because of the way printf must scan and format the string, checking each character. This is a possible optimization that was added during compilation.

Change (3)

Remove the compiler option -g. Note and explain the change in size, section headers, and disassembly output.

gcc     -O0     -fno-builtin    -o hello-3      hello.c

After removing -g from the gcc options, the file became about 10% smaller. It also no longer has any of the source code inside it when I use “objdump –source”. The “-g” option in gcc adds extra debugging information, such as the source code and additional information when used with the “gdb” debugger.

Change (4)

Add additional arguments to the printf() function in your program. Note which register each argument is placed in.

gcc     -g      -O0     -fno-builtin    -o hello-4      hello-args.c

Using additional arguments in the printf shows each argument in the disassembled code in movl and mov opcode. It looks like in the mov opcode, the arguments are being saved into registers, while the movl commands, the arguments are being saved into memory. This makes me wonder why only the first 5 arguments are being used in registers, maybe that is the max amount of registers that printf can use for arguments so it uses all of them first for performance reasons, before turning to memory. The remaining arguments show up in memory incrementing the memory address.

Change (5)

Move the printf() call to a separate function, and call that function from main(). Explain the changes in the object code.

gcc     -g      -O0     -fno-builtin    -o hello-5      hello-function.c

Using a separate function that calls printf in the c code changes the way the object code looks when viewed with objdump. Originally there was a printf call being run in the main, now however, there is the custom function that was created. There is a address beside the new function in main, if you follow this address to it’s location, you find the custom functions actual code. This code shows the printf call that would normally be inside main.

Change (6)

Remove -O0 and add -O3 to the gcc options. Note and explain the difference in the compiled code.

gcc     -g      -O3     -fno-builtin    -o hello-6      hello.c

At first glance it looks like the file grew a little larger in size(about 10% again), this is due to a trade off of file size and optimization of the program compiled. By using the option “-O3” with gcc you are getting faster performance at the cost of larger file size and longer compilation times. One of the optimizations that is noticed when using “objdump”, is in the main function the push and pop from the stack is no longer there, since it doesn’t need to be, making unnoticeable performance gains for a hello world program. Some notes about “-O3”: “-O3” may mess up some of the debugging data, “-O2” is very similar to it except it tries not to increase file size, and lacks a few optimizations, “-O0” on the other hand reduces compiling time and allows for the debugging to show properly.

Advertisements

About oatleywillisa

Computer Networking Student
This entry was posted in SBR600 and tagged , , , , , , , , , , , , . Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s