Overriding and redirecting library modules without rebuilding the entire library
It is quite common that some library modules or functions need to be customized for a specific embedded application, and there are several options to do this.
The first option is to rebuild the library with small customizations. Rebuilding a library is a complex process. If we consider the C/C++ standard library then it is much more complicated due to the available prebuild options with different formatters, file descriptors, low level interfaces, and support for multi-byte and float/double.
The linker in IAR Embedded Workbench makes it possible to override modules or routines without the need of rebuilding the entire library. The concept is really simple since the linker will give higher priority for your own modules than for the library modules. Another solution is to redirect the function call.
The linker is a powerful, flexible tool for use in the development of embedded applications. The linker combines one or more relocatable object files produced by the compiler or assembler with selected parts of one or more object libraries to produce an executable image. The linker will automatically load only those library modules, user libraries and Standard C or C++ library variants that are actually needed by the application.
The linker in IAR Embedded Workbench is able to generate a MAP file with all symbols used on the final executable. This option is available under the linker options. This makes it easy to identify the modules that need to be customized. It also helps to find out the library where the module belongs to:
For example, if we want to override the function __write in order to redirect the printf from the default Terminal I/O to the UART or even to a LCD you can find out through the MAP file that the function __write is part of the module write.o:
You can find the source code for the Standard C or C++ library in the arm\src\lib directory of the IDE installation:
Once you have the source code, you only need to add the file into your project like a template and all customizations can be done in the module. With a few different lines, we can notice that the function __write increased in size from 0x10 to 0x3C bytes after the rebuild procedure.
Another solution is to create a function, based on the prototype:
__ATTRIBUTES size_t __write(int, const unsigned char *, size_t);
This means that the linker will give higher priority for your function. All the other functions of the module will not be affected.
The last approach would be changing the reference from one symbol to another symbol. This feature is enabled in the linker through the command line --redirect. This is also useful, for example, to redirect a reference from a non-implemented function to a stub function, or to choose one of several different implementations of a certain function.
For example, if we want to redirect the __write to our own function __write_own that is quite similar to the original function but has small customizations, the command line will be --redirect __write=__write_own . The command needs to be added in the extra options of the linker. After the build we can see that the __write_own function is now called instead of the original __write function.
This concept of overriding and redirecting modules without rebuilding the entire library can also be used for your own libraries and third-party libraries. It is a straightforward way to add the necessary customizations for your system without rebuilding a library that has been tested over the years or has been provided by a third-party product.