Useful Compiler Options to Optimize your Code

How can we optimize our programs? One way is to use compiler options that help our compiler do some optimization when it converts your code into assembly and then binary.

We’ll examine the following options:
  1. -g # enable debugging information
  2. -O0 # do not optimize (Capital letter is the option name, zero is the value)
  3. -fno-builtin # do not use builtin function optimizations
Consider this simple C program:



To compile the program with
  • -g Debugging information
  • -o
    • A specifically named executable file (so that it’s not a.out - a stands for assembler)
    • In the example below, the file name we’re providing is hello
Type:



And then use the command objdump to look at the executable file. In here you will find the assembly code version of the C program we just wrote.



Since we’ve piped the command to a more command, you will see the file output to the screen one page at a time. When you look through this file, you’ll notice that most of the assembly code is not based on the code you wrote. These are the standard libraries added to every C program, and there are also functions that you may have specifically called from an outside library. To find your code, type:



Here’s what you would see:

The main code




-static Don’t use a Link Table

With this options, a number of things happened to the executable file:
  1. The file size grew by 1000 times.
    This is because static tells the compiler to load in all of the assembly for all of the libraries that this code is related to. So if you only need one function from the library, the whole thing will be loaded in. This is actually faster in terms of processing because it does not have to first visit a link table and then the code.
  2. The difference in the main code is two lines:

  3. Extra headers were added as well, indicated under Disassembly of section .plt:. This is where the library files have been assembled.

When using a link table:

  • there's an extra step to get to the function that you need in another library
  • but all your programs can share the same libraries instead of having a thousand copies of each library (1 for each of your programs running)



When compiling statically:

  • the code is all there, available just with one step
  • your program bloats a lot (gets bigger in size)




-fno-builtin, No Built-in Function Optimization

Asks the compiler to not do any optimization for built in functions. In our case,
  • leaving this option in caused the assembler to call printf instead of putc!
  • The optimized version of the executable (compiled without -fno-builtin) was slightly smaller


-g, Debugging Info

. Here are the changes seen with this flag:
  • The file is 20% larger (because it also contains debugging tools)
  • The disassembly output contains line number statements so that when the compiler finds an error, it can tell you what line it is on.
  • There are new section headers added
The new Section Headers
  1. .debug_info section:
    describes the program’s debug info for ensuring simple data types, variables and function are being used correctly.
  2. .debug_types
    ensuring complex data types, like containers (arrays, lists, vectors...) are being used correctly.
  3. debug_str section:
    contains strings that are used more than once in the .debug_info and .debug_types sections. This way, duplicates are removed.

Adding more Arguments to Printf

. The printf() that we coded in the C program was replaced with puts() in the assembly code. This was because a 1 argument printf() is the same as a puts(). But what if we add more arguments to printf()? What would happen?
With:
  • 1 Argument: uses puts
  • 2 or more Arguments: an extra register is added for each argument. Printf is called instead
  • 6 or more Arguments: instead of using the mov command to put each argument into a register, it creates a stack and pushes each new argument onto it


-O How Much to Optimize

-O0 : Don’t optimize at all
-O1 : Only do some optimization
-O2 : Do all safe optimizations
-O3 : Do even risky optimizations

Eg.


Calling a Function from another Function, and using -O3

. In this example, we have only looked at calling a function from main. But what if our code is a little more complex?

A new section called can be seen in the object dump file. This hasn’t bought us anything.



In fact, if we also add the flag -O3, the compiler will just add the puts back to main instead of calling output(). Although, for some reason the assembly code still keeps a reference to the output code as well.



There are a lot of compiler options that you can choose from, and it can be pretty overwhelming! But going through some main ones first will help prepare you to learn more and more. Happy compiling!

References

Basic GCC Compiler Options https://wiki.cdot.senecacollege.ca/wiki/SPO600_Compiled_C_Lab

Comments

Popular Posts