Tuesday, January 31, 2017

SPO600 - Lab 4 - Compiled C Code

Within this lab, we looked at how various flags provided to the GNU C Compiler can affect the compiled binary, along with how changes in our code can affect the compiled binary.

The -static Flag

The -static flag tells GCC to not generate a link table, instead it embeds all called functions into the compiled binary itself. In turn that makes the binary grow exponentially, as the compiler doesn't know what functions the library function calls, so the whole library gets loaded into the binary as well.

The -fno-builtin Flag

As the title implies here, this tells GCC to not optimize calls to the built-in functions. In class this was shown using printf. Without the flag the compiler replaces calls to printf (that only have one parameter) with putc. putc doesn't check the string for any patterns, so the code should run much faster that it would when printf is called.

The -g Flag

The -g flag tells the GCC to insert debugging sections into the binary, and in turn that makes the binary much larger. It adds a few more sections into the binary, namely the .debug_info, the .debug_types, and .debug_str sections. The binary also contains a line number table, to allow debuggers to map the compiled operations to their C code counterparts, along with other info containing variable names, and their types, effectively allowing debuggers to reconstruct source code from the assembly code.

printf(), With Many Arguments

In this section, we didn't actually change any flag provided to GCC, instead we simply kept adding more parameters to printf to see what happens. It turns out that after 7 arguments, the compiler starts pushing them onto the stack instead. This is because there are only so many registers in the processor itself, and functions with that many arguments tend to be rare, so it would be wasteful to reserve more registers for parameters.

Calling A Simple Function, With The -O0 Flag

Here we had to compare a binary where printf() was called directly and another one where it was called in another function, and we just called that function. When the code was compiled, in main printf() doesn't exist, instead it called output(), and output() contained the printf() call instead.

Calling A Simple Function, With The -O3 Flag

Here we did the exact same as above, but instead of compiling with no optimizations, we compiled with some. This time main() doesn't have a call to output() at all, instead it has the printf() call. Interestingly, the compiled binary still contains the original output() functions. I assume that is  in case your code is a library of some sorts, and you need to keep all functions in case some external binary needs them.

No comments:

Post a Comment