3.1 Basic Linker Script Concepts
We need to define some basic concepts and vocabulary in order to describe the linker script language.
The linker combines input files into a single output file. The output file and each input file are in a special data format known as an object file format. Each file is called anobject file. The output file is often called an executable, but for our purposes we will also call it an object file. Each object file has, among other things, a list ofsections. We sometimes refer to a section in an input file as an input section; similarly, a section in the output file is an output section.
Each section in an object file has a name and a size. Most sections also have an associated block of data, known as the section contents. A section may be marked as loadable, which mean that the contents should be loaded into memory when the output file is run. A section with no contents may be allocatable, which means that an area in memory should be set aside, but nothing in particular should be loaded there (in some cases this memory must be zeroed out). A section which is neither loadable nor allocatable typically contains some sort of debugging information.
Every loadable or allocatable output section has two addresses. The first is the VMA, or virtual memory address. This is the address the section will have when the output file is run. The second is the LMA, or load memory address. This is the address at which the section will be loaded. In most cases the two addresses will be the same. An example of when they might be different is when a data section is loaded into ROM, and then copied into RAM when the program starts up (this technique is often used to initialize global variables in a ROM based system). In this case the ROM address would be the LMA, and the RAM address would be the VMA.
You can see the sections in an object file by using the objdump
program with the -h option.
Every object file also has a list of symbols, known as the symbol table. A symbol may be defined or undefined. Each symbol has a name, and each defined symbol has an address, among other information. If you compile a C or C++ program into an object file, you will get a defined symbol for every defined function and global or static variable. Every undefined function or global variable which is referenced in the input file will become an undefined symbol.
You can see the symbols in an object file by using the nm
program, or by using the objdump
program with the -t option.
Hello.c
#include <stdio.h>
int a = 0;
int main ()
{
return 0;
}
gcc hello.c
nm a.out输出如下:
08049f20 d _DYNAMIC
08049ff4 d _GLOBAL_OFFSET_TABLE_
0804847c R _IO_stdin_used
w _Jv_RegisterClasses
08049f10 d __CTOR_END__
08049f0c d __CTOR_LIST__
08049f18 D __DTOR_END__
08049f14 d __DTOR_LIST__
08048480 r __FRAME_END__
08049f1c d __JCR_END__
08049f1c d __JCR_LIST__
0804a010 A __bss_start
0804a008 D __data_start
08048430 t __do_global_ctors_aux
08048330 t __do_global_dtors_aux
0804a00c D __dso_handle
w __gmon_start__
0804842a T __i686.get_pc_thunk.bx
08049f0c d __init_array_end
08049f0c d __init_array_start
080483c0 T __libc_csu_fini
080483d0 T __libc_csu_init
U __libc_start_main@@GLIBC_2.0
0804a010 A _edata
0804a01c A _end
0804845c T _fini
08048478 R _fp_hw
08048298 T _init
08048300 T _start
0804a018 B a
0804a010 b completed.6990
0804a008 W data_start
0804a014 b dtor_idx.6992
08048390 t frame_dummy
080483b4 T main
3.2 Linker Script Format
Linker scripts are text files.
You write a linker script as a series of commands. Each command is either a keyword, possibly followed by arguments, or an assignment to a symbol. You may separate commands using semicolons. Whitespace is generally ignored.
Strings such as file or format names can normally be entered directly. If the file name contains a character such as a comma which would otherwise serve to separate file names, you may put the file name in double quotes. There is no way to use a double quote character in a file name.
You may include comments in linker scripts just as in C, delimited by /* and */. As in C, comments are syntactically equivalent to whitespace.
3.3 Simple Linker Script Example
Many linker scripts are fairly simple.
The simplest possible linker script has just one command: SECTIONS. You use the SECTIONS command to describe the memory layout of the output file.
The SECTIONS command is a powerful command. Here we will describe a simple use of it. Let's assume your program consists only of code, initialized data, and uninitialized data. These will be in the .text, .data, and .bss sections, respectively. Let's assume further that these are the only sections which appear in your input files.
For this example, let's say that the code should be loaded at address 0x10000, and that the data should start at address 0x8000000. Here is a linker script which will do that:
SECTIONS
{
. = 0x10000;
.text : { *(.text) }
. = 0x8000000;
.data : { *(.data) }
.bss : { *(.bss) }
}
You write the SECTIONS command as the keyword SECTIONS, followed by a series of symbol assignments and output section descriptions enclosed in curly braces.
The first line inside the SECTIONS command of the above example sets the value of the special symbol ., which is the location counter. If you do not specify the address of an output section in some other way (other ways are described later), the address is set from the current value of the location counter. The location counter is then incremented by the size of the output section. At the start of the SECTIONS command, the location counter has the value 0.
The second line defines an output section, .text. The colon is required syntax which may be ignored for now. Within the curly braces after the output section name, you list the names of the input sections which should be placed into this output section. The * is a wildcard which matches any file name. The expression *(.text) means all .text input sections in all input files.
Since the location counter is 0x10000 when the output section .text is defined, the linker will set the address of the .text section in the output file to be 0x10000.
The remaining lines define the .data and .bss sections in the output file. The linker will place the .data output section at address 0x8000000. After the linker places the.data output section, the value of the location counter will be 0x8000000 plus the size of the .data output section. The effect is that the linker will place the .bss output section immediately after the .data output section in memory.
The linker will ensure that each output section has the required alignment, by increasing the location counter if necessary. In this example, the specified addresses for the.text and .data sections will probably satisfy any alignment constraints, but the linker may have to create a small gap between the .data and .bss sections.
That's it! That's a simple and complete linker script.