by Travis Goodspeed <travis at utk.edu>
In this article, I describe the use and modification of GCC linker scripts. In particular, I emphasize their use within MSPGCC to add support for an additional target chip, the MSP430F2274. This technique allows the generation of executables for chips which are presently unsupported by MSPGCC, as well as the creation of executables that are intended to work with a custom bootloader.
Until recently, I had been using IAR's compiler for development of the BSL Password Cracker, which was the subject of my Black Hat USA talk. IAR makes a great compiler, but the proprietary UBROF object format prevented me from exporting debugging symbols to GDB. My requests to the company for a copy of the specification have thus-far yielded nothing.
In switching to MSPGCC, I found myself unable to compile executables for the MSP430F2274 around which I had already based the second major revision of my board. In this article, I will describe a simple method for extending the MSPGCC linker to support a new chip by modifying the definition of one that's presently supported. The same technique is also handy for building an image to be compatible with a custom bootloader, as I'll describe in the next installment of my series on reprogramming the TI EZ430U with custom firmware.
Under the hood, a compiler is built of many separate applications. The first stage is a preprocessor which evaluates macros such as the #include directive. After that, the compiler stage translates preprocessed C into assembly language. A third stage, the assembler, converts assembly language into object files, which are complete except for labels that have been left empty for later insertion. A fourth stage, the linker, combines one or more object files into an executable firmware image. In the case of the MSP430, this image is a complete kernel, which does not rely upon a surrounding kernel or dynamic libraries.
As objects enter the linker, they are not quite complete machine code. This is because, prior to linking, it is impossible to know the entry address of any function. They are quite likely to be re-arranged, with unused functions stripped out entirely.
Also unknown prior to linking is the location of various system boundaries, such as the range of memory which is mapped to Flash ROM, that range which is mapped to RAM, and various ranges of lesser importance. Embedded compilers use linking scripts to specify these regions.
IAR's linker, xlink, scripts in the config/ subdirectory of each target, /opt/iar430/config on my machine but more likely C:/Program Files/IAR Systems/Embedded Workbench 5.0/430/config in Windows. Observe the code memory region of lnk430F2274.xcl as an example:
The regions themselves are helpfully described in English comments at the top of the file, giving those too lazy to read the datasheets a helping hand. It's also rather nice that these are standard command-line arguments to xlink.
GCC's linker, ld, uses a different format. Regions are described not as beginning and ending absolute addresses, but rather as an absolute beginning address and a length. The corresponding line in my 2274 script is
text (rx) : ORIGIN = 0x8000, LENGTH = 0x7fe0
The first step in retargetting the linker is to adjust the rest of the lines in the MEMORY stanza to values that work. That is nearly all the work that you must do, but converting memory regions is not quite all that you'll have to contend with. In using an MSP430F1612 script as a starting point, I initially overlooked the following line.
PROVIDE (__stack = 0x2500) ;
That line initializes the stack pointer (r1) to be 0x2500. Nothing is mapped to this address, and the entire region reads each byte as 0x5321. As GCC places globals at the bottom of memory, setting this value to the top of memory, which is to say 0x5fe, results in a functional stack.
You can find my first attempt at an MSP430F2274 linker script here. It works for me, but it comes with the usual warranty, by which I mean none. Place it in the working directory and add -T foo.x to your linking gcc line.
In the near future, I intend to add a linker-script importer for msp430static to give context to different regions of memory. Support will exist for GCC and IAR formats, and a standalone mode will allow translation between formats.