From Helix Community
Function Level Linking
- Author: David Hedbor
- Modified By: Rishi Mathew
- Created: 3/18/2005
- Last modified: 2005-03-21 15:30:31
- Description of Function-Level Linking
- How does "rlink" achieve function-level linking?
- Technical Details about "rlink"
- How is "rlink" used in Helix?
- Example of savings with function-level linking
On certain platforms, function level linking is provided by the platform. The gcc linker doesn't provide this feature however. This leads to bloated image-size for dynamic libraries and executables. To rectify this problem, we created a tool called "rlink" which achieves function-level linking on platforms which use gcc for compiling and linking. This tool is a python script and is run prior to the actual linking. It works by removing unused sections from all object files (including those embedded in archives).
2 Description of Function-Level Linking
GCC does *unit* level linking and this can result in larger DLLs than a function level linker. For example, if you have an "a.cpp" file that has 2 fucntions in it:
You will have foo, bar, foo2 and bar2 in it even though you only call foo and foo2. This is because GCC can't break anything down past the *unit* level (.obj). A function level linker would strip out the unused bar and bar2.
3 How does "rlink" achieve function-level linking?
"rlink" works by running "objdump" on all object files used for the linking, including those embedded in archives. From the "objdump" output, information about relocations, symbols and sections is extracted and used to build a section dependancy tree to find out which sections aren't needed. It then proceeds to use "objcopy" to remove the unneeded sections. After this step, any archive files are reassembled and the linking is performed with the modified object files.
Note- When using rlink, the linking stage will take a significantly longer period of time. A lot of work is done to accomplish the function level linking. Don't be alarmed if your build takes a lot longer, as this is expected.
4 Technical Details about "rlink"
The use of "rlink" for function level linking is not limited to Helix. You can also use this with other projects. You need to first make sure that any linking step for a dynamic library or application is prefixed with the rlink call like this:
rlink.py gcc -shared linkscript.exp -o library.so library.o framework.a
rlink will modify and clean out unneeded sections and will then modify the link line to use the newly created objects, followed by an execution of the linker.
4.1. Linker scripts
The "linkscript.exp" file is used to specify functions that need to be exported from the DLL. If you do not provide this file when creating a DLL, none of the functionality will be retained. The syntax of this file is very simple:
"rlink" only cares about the methods specified in the global section. Each and every function that should be accessible from the dll should be listed in this file.
When linking a application binary file, you might need a linker script if your application has a plugin framework, where the plugins depend on symbols defined in the main binary. If no manual plugin loading is performed (i.e via dlopen()) or if each plugin is self-contained and have no dependencies on methods defined in the application binary, a linker script will not be needed.
4.2. Required Command line options
For "rlink" to function correctly you will need to add the following options to your compilation command:
These will ensure that each function and data object will be in their own section. Since "rlink" depends on removing unneeded sections, these options are essential in making it function correctly.
Any object file and archive used for linking must be compiled with these options to get the full effect from "rlink". Without these flags, you can't expect savings above 1-2% most likely.
4.3. Efficiency details
Although function-level linking saves about 25-30% space on Helix projects, this is often not the case when used with other software. It's important to understand when and how "rlink" will assist the most with image size reduction.
In general, "rlink" will work best on source code with larger source code file, where much of the functionality isn't used. Typically you would get this scenario when linking with a larger framework (such as the Helix code base). If an appliction uses a majority of the code it links in, the savings won't be very noticeable. Also when linking to an archive (ar file), the linker will already remove unused object files. That means if you have a framework with a hash map class and this class isn't directly or indirectly referenced by the application, the linker will remove the entire object file from the linking.
Another common architecture for a plugin based application is that the main binary includes all the shared code needed by the modules. In this case also, function-level linking will not help very much. The individual modules will not have a lot of shared code, which they only use a fraction of, since this code is included as a whole in the main application. Even in the worst case scenario "rlink" might be able to save you 5-10%, which for many embedded applications is noteworthy.
Note- Another benefit with "rlink" is that you don't need to use archive files for optimal image size. For gcc to remove an object file from the final linking, it has to be included in an archive file. With "rlink", this step isn't necessary although doing it does in no way negatively affect "rlink".
4.4. Options and debugging
There is only one command line option for rlink, which is used when you use it in a cross compile environment.
-x [cross platform prefix]
The cross platform prefix would typically be something like arm-linux-(note the ending dash) for a system where commands are named arm-linux-gcc. This prefix is prepended to all applicable commands such as objdump, objcopy and ranlib.
There are two environment variables that can be used to control rlink's behavior:
RLINK_DEBUG: if this is set, rlink will print a lot of debug information. It is advisable that when you use this option you redirect the output to a file.
RLINK_DISABLE: if this is set, rlink will do nothing
5 How is "rlink" used in Helix?
Rlink, or rlink.py, is part of the Ribosome project on the Helix community. For more information, see the project website at https://ribosome.helixcommunity.org/
The application, which is a python script, is located in build/bin/rlink.py. This script gets called by the Ribosome build system when function-level linking is enabled.
Function level linking via "rlink" is currently available for Symbian and Linux. On Symbian this is always peformed, while on Linux you might have to enable it. This is done by adding the define HELIX_CONFIG_USE_RLINK in your configuration (cf) file . Please note that on Linux, rlink is only used when building in release mode.
6 Example of savings with function-level linking
As an example of how much space you can save with "rlink", this is the result for a Linux RealPlayer build. Below are the number for some specific plugins. All sizes are in kilobytes.