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:
To compile the program with
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:
With:
-O1 : Only do some optimization
-O2 : Do all safe optimizations
-O3 : Do even risky optimizations
Eg.
A new section called
We’ll examine the following options:
- -g # enable debugging information
- -O0 # do not optimize (Capital letter is the option name, zero is the value)
- -fno-builtin # do not use builtin function optimizations
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
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:- 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. - The difference in the main code is two lines:
- 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
- .debug_info section:
describes the program’s debug info for ensuring simple data types, variables and function are being used correctly. - .debug_types
ensuring complex data types, like containers (arrays, lists, vectors...) are being used correctly. - 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
Comments
Post a Comment