world leader in high performance signal processing
Trace: » link

Linker Scripts

Linker Scripts are used by the Linker for mapping application code and data objects. Unlike Linux applications, the memory locations of application image must be specified during link-time (or rather hardcoded) for bare metal applications. You may supply your own linker script by using the -T command line option. When you do this, your linker script will replace the default linker script.

A simple Linker Script is given below. Only basic level explanations are provided for getting started with the concept. Please consult gnu web pages for detailed information.

A simple Linker Script

MEMORY
{
  MEM_L1_CODE       : ORIGIN = 0xFFA00000, LENGTH = 0x10000
  MEM_L1_CODE_CACHE : ORIGIN = 0xFFA10000, LENGTH = 0x4000
  MEM_L1_SCRATCH    : ORIGIN = 0xFFB00000, LENGTH = 0x1000
  MEM_L1_DATA_B     : ORIGIN = 0xFF900000, LENGTH = 0x8000
  MEM_L1_DATA_A     : ORIGIN = 0xFF800000, LENGTH = 0x8000
  MEM_SDRAM         : ORIGIN = 0x00000000, LENGTH = 64 * 1024 * 1024
  MEM_L2            : ORIGIN = 0xFEB00000, LENGTH = 0x0
}
 
/* The default linker script, for single core blackfin standalone executables */
OUTPUT_FORMAT("elf32-bfin", "elf32-bfin", "elf32-bfin") 
OUTPUT_ARCH(bfin) 
ENTRY(__start)
 
SECTIONS
{
  /* Read-only sections, merged into text segment: */
  PROVIDE (__executable_start = 0x0); . = 0x0;
 
  .sdram.data :
  {
  	. = 0x10000;
	*(.sdram.data)
  } >MEM_SDRAM =0
 
  .l2             :
  {
    *(.l2 .l2.*)
  } >MEM_L2 =0
 
  .text           :
  {
    *(.text .text.* .l1.text .l1.text.*)
    KEEP (*(.text.*personality*))
    /* .gnu.warning sections are handled specially by elf32.em.  */
    *(.gnu.warning)
  } >MEM_L1_CODE =0
 
  .init           :
  {
    KEEP (*(.init))
  } >MEM_L1_CODE =0
 
  .fini           :
  {
    KEEP (*(.fini))
  } >MEM_L1_CODE =0
 
  .rodata         : 
  { 
    *(.rodata .rodata.*) 
  } >MEM_L1_DATA_A

  .data           :
  {
    *(.data .data.* .l1.data .l1.data.*)
    KEEP (*(.*personality*))
  } >MEM_L1_DATA_A
 
  .bss            :
  {
   __bss_start = .;
    *(.bss .bss.*)
    *(COMMON)
    __bss_end = .;
  } >MEM_L1_DATA_A
 
  . = ALIGN(32 / 8);
  . = ALIGN(32 / 8);
 
  __end = .; PROVIDE (_end = .);
  __stack_start = ORIGIN(MEM_L1_SCRATCH);
  __stack_end   = ORIGIN(MEM_L1_SCRATCH) + 0x200;
 
  /DISCARD/ : { *(.note.GNU-stack) }
}

MEMORY Command

This command includes the absolute memory blocks on the target (on chip and off chip memories) that will be used for mapping objects. This part is self explanatory if one is aware of the memory architecture of Blackfin. User can modify the block according to his requirement, although the reserved memory regions should not be touched. An ORIGIN and its LENGTH must be provided for each block / segment.

MEMORY
{
  MEM_L1_CODE       : ORIGIN = 0xFFA00000, LENGTH = 0x10000
  MEM_L1_CODE_CACHE : ORIGIN = 0xFFA10000, LENGTH = 0x4000
  MEM_L1_SCRATCH    : ORIGIN = 0xFFB00000, LENGTH = 0x1000
  MEM_L1_DATA_B     : ORIGIN = 0xFF900000, LENGTH = 0x8000
  MEM_L1_DATA_A     : ORIGIN = 0xFF800000, LENGTH = 0x8000
  MEM_SDRAM         : ORIGIN = 0x00000000, LENGTH = 64 * 1024 * 1024
  MEM_L2            : ORIGIN = 0xFEB00000, LENGTH = 0x0
}

SECTIONS Command

.l2             :   <-------------//output section
{
    *(.l2 .l2.*)    <-------------//input section
} >MEM_L2 =0        <-------------//memory block

The input sections specify the layout of the program across the target memory. It tells the Linker how to map the various object files to various memory blocks. The input sections are connected to memory blocks through the output sections - whose names are usually same as that of input sections.

Important generic sections and their associated code:

Section Example code Description
.text void function(){} code
.rodata const int const_global_data = 0x3333; constant data
.data int global_data = 0x1234; initialized global data
.bss int global_data_uninit; uninitialized global data
.init This section holds executable instructions that contribute to the process initialization code. That is, when a program starts to run the system arranges to execute the code in this section before the main program entry point (called main in C programs).
.fini This section holds executable instructions that contribute to the process termination code. That is, when a program exits normally, the system arranges to execute the code in this section.
*(COMMON) Specify where in your output file to place uninitialized data with this notation. *(COMMON) by itself refers to all uninitialized data from all input files (so far as it is not yet allocated);

Search patterns for sections

The linker script language permits shell patterns. The string ”.text” will only match a section named ”.text”. The string ”.text.*” will match any section whose name begins with ”.text.”, such as ”.text.fn”.

*(.text .text.*) 

Special symbol ”.”

This is a location counter. In the above case, the succeeding input section will be arranged with the new location -which is 0x10000 in SDRAM.

. = 0x10000;

Stack Symbols

The stack_start and stack_end are symbols that specify the valid stack region. Stack cannot be changed dynamically in bare metal systems.

  __stack_start = ORIGIN(MEM_L1_SCRATCH);
  __stack_end   = ORIGIN(MEM_L1_SCRATCH) + 0x200;

Data initialization Symbols

Startup code can initialize memory run-time (from bss_start to bss_end) when these symbols are defined in the script.

.bss            :
  {
   __bss_start = .;
    *(.bss .bss.*)
    *(COMMON)
    __bss_end = .;
  } >MEM_L1_DATA_A

Default Linker script does not include workaround for anomalies “05000189 - False Protection Exceptions when Speculative Fetch Is Cancelled” or “05000310 - False Hardware Errors Caused by Fetches at the Boundary of Reserved Memory (although this is included in VDSP LDFs). Modify Linker scripts for appropriate workaround. Refer to Anomalies for more information.

Dual Core Linker Script

When -mmulticore is used, Linker pulls in the appropriate scripts for dual core programming. Default script is given below (note that when -mcorea or -mcoreb is used, only the blocks related to the appropriate Core is pulled in - the blocks of other core will be then Zero - refer to bf561a.ld and bf561b.ld in the toolchain):

MEMORY
{
  MEM_L1_CODE : ORIGIN = 0xFFA00000, LENGTH = 0x4000
  MEM_L1_CODE_CACHE : ORIGIN = 0xFFA10000, LENGTH = 0x4000
  MEM_L1_SCRATCH : ORIGIN = 0xFFB00000, LENGTH = 0x1000
  MEM_L1_DATA_B : ORIGIN = 0xFF900000, LENGTH = 0x8000
  MEM_L1_DATA_A : ORIGIN = 0xFF800000, LENGTH = 0x8000

  B_MEM_L1_CODE : ORIGIN = 0xFF600000, LENGTH = 0x4000
  B_MEM_L1_CODE_CACHE : ORIGIN = 0xFF610000, LENGTH = 0x4000
  B_MEM_L1_SCRATCH : ORIGIN = 0xFF700000, LENGTH = 0x1000
  B_MEM_L1_DATA_B : ORIGIN = 0xFF500000, LENGTH = 0x8000
  B_MEM_L1_DATA_A : ORIGIN = 0xFF400000, LENGTH = 0x8000

  MEM_L2 : ORIGIN = 0xFEB00000, LENGTH = 0x20000
  MEM_L2_SHARED : ORIGIN = 0xFEB20000, LENGTH = 0x0
}

Default Linker Script

Default Linker Files are not easy to understand if you are new to the concept - this is because a standard linker script is often used as a common file across multiple toolchains.

Dynamic linking sections

A lot of information pertains to that of Dynamic Linking in Linux. Therefore, it is common to find sections such as a below in standard scripts. These can be ignored for bare metal applications.

  .rel.init       : { *(.rel.init) }
  .rela.init      : { *(.rela.init) }
  .rel.text       : { *(.rel.text .rel.text.* .rel.gnu.linkonce.t.*) }
  .rela.text      : { *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) }
  .rel.fini       : { *(.rel.fini) }
  .rela.fini      : { *(.rela.fini) }
  .rel.rodata     : { *(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*) }
.....................................................................

C++ Exception Handling

There are sections meant for Exception handling on C++ codes. A quick explanation is available from this thread: Use of exception handling sections (also refer to the nice articles written Ian Taylor on each of these sections).

.eh_frame_hdr       : { *(.eh_frame_hdr) } >MEM_L1_DATA_A
 
.eh_frame           : ONLY_IF_RO { KEEP (*(.eh_frame)) } >MEM_L1_DATA_A  
.gcc_except_table   : ONLY_IF_RO { *(.gcc_except_table .gcc_except_table.*) } >MEM_L1_DATA_A
 
/* Adjust the address for the data segment.  We want to adjust up to the same address within the page on the next page up.  */. = ALIGN(0x1000) + (. & (0x1000 - 1));
 
/* Exception handling  */
.eh_frame           : ONLY_IF_RW { KEEP (*(.eh_frame)) } >MEM_L1_DATA_A
.gcc_except_table   : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) } >MEM_L1_DATA_A    

The below text about -fexceptions also explains how GCC controls this feature Code Gen options:-

Enable exception handling. Generates extra code needed to propagate exceptions. For some targets, this implies GCC will generate frame unwind information for all functions, which can produce significant data size overhead, although it does not affect execution. If you do not specify this option, GCC will enable it by default for languages like C++ which normally require exception handling, and disable it for languages like C that do not normally require it. However, you may need to enable this option when compiling C code that needs to interoperate properly with exception handlers written in C++. You may also wish to disable this option if you are compiling older C++ programs that don't use exception handling.

The default CRT code seem to include just the following for a C program:

STATIC EH_FRAME_SECTION_CONST int32 __FRAME_END__[]       
__attribute__ ((unused, section(EH_FRAME_SECTION_NAME), aligned(sizeof(int32))))      = { 0 };

Which compiles to a small array of data: “_FRAME_END_: 0x0000 0x0000”.

Debug with DWARF

Below is taken from - Debugging with DWARF

DWARF (Debug With Arbitrary Record Format) is a format for debugging information for ELF files. While DWARF is defined in a way that allows it to be used with any object file format, it's most often used with ELF. Each of the different kinds of DWARF data are stored in their own section. The names of these sections all start with ”.debug_”. For more information, refer to DWARF Standard

  • .debug_abbrev Abbreviations used in the .debug_info section
  • .debug_aranges A mapping between memory address and compilation
  • .debug_frame Call Frame Information
  • .debug_info The core DWARF data containing DIEs
  • .debug_line Line Number Program
  • .debug_loc Macro descriptions
  • .debug_macinfo A lookup table for global objects and functions
  • .debug_pubnames A lookup table for global objects and functions
  • .debug_pubtypes A lookup table for global types
  • .debug_ranges Address ranges referenced by DIEs
  • .debug_str String table used by .debug_info

The default Linker file shows how the debug sections are included.

  /* DWARF debug sections.
     Symbols in the DWARF debugging sections are relative to the beginning
     of the section so we begin them at 0.  */
  /* DWARF 1 */
  .debug          0 : { *(.debug) }
  .line           0 : { *(.line) }
  /* GNU DWARF 1 extensions */
  .debug_srcinfo  0 : { *(.debug_srcinfo) }
  .debug_sfnames  0 : { *(.debug_sfnames) }
  /* DWARF 1.1 and DWARF 2 */
  .debug_aranges  0 : { *(.debug_aranges) }
  .debug_pubnames 0 : { *(.debug_pubnames) }
  /* DWARF 2 */
  .debug_info     0 : { *(.debug_info .gnu.linkonce.wi.*) }
  .debug_abbrev   0 : { *(.debug_abbrev) }
  .debug_line     0 : { *(.debug_line) }
  .debug_frame    0 : { *(.debug_frame) }
  .debug_str      0 : { *(.debug_str) }
  .debug_loc      0 : { *(.debug_loc) }
  .debug_macinfo  0 : { *(.debug_macinfo) }
  /* SGI/MIPS DWARF 2 extensions */
  .debug_weaknames 0 : { *(.debug_weaknames) }
  .debug_funcnames 0 : { *(.debug_funcnames) }
  .debug_typenames 0 : { *(.debug_typenames) }
  .debug_varnames  0 : { *(.debug_varnames) }

Linker Map file

The Linker can be asked to generate a Map file for user. It will include descriptive details of how the program code and data is arranged in the memory through the provided Linker Script.

-Wl,-Map=Linker.map

Important parts of the Map file:

Memory Configuration - should match the Memory Command in Script.

Memory Configuration
Name             Origin             Length             Attributes
MEM_L1_CODE      0xffa00000         0x00010000
MEM_L1_CODE_CACHE 0xffa10000         0x00004000
MEM_L1_SCRATCH   0xffb00000         0x00001000
MEM_L1_DATA_B    0xff900000         0x00008000
MEM_L1_DATA_A    0xff800000         0x00008000
MEM_L2           0xfeb00000         0x00000000
*default*        0x00000000         0xffffffff

List of all object files and library files Linked in to

LOAD c:/program files/analog devices/gnu toolchain/svn-20101128/elf/bin/../lib/gcc/bfin-elf/4.3.5/../../../../bfin-elf/lib/basiccrt.o
LOAD c:/program files/analog devices/gnu toolchain/svn-20101128/elf/bin/../lib/gcc/bfin-elf/4.3.5/crti.o
LOAD c:/program files/analog devices/gnu toolchain/svn-20101128/elf/bin/../lib/gcc/bfin-elf/4.3.5/crtbegin.o
LOAD c:/program files/analog devices/gnu toolchain/svn-20101128/elf/bin/../lib/gcc/bfin-elf/4.3.5/crtlibid.o
LOAD ./src/test_gcc_options.o
LOAD c:/program files/analog devices/gnu toolchain/svn-20101128/elf/bin/../lib/gcc/bfin-elf/4.3.5\libgcc.a
START GROUP
LOAD c:/program files/analog devices/gnu toolchain/svn-20101128/elf/bin/../lib/gcc/bfin-elf/4.3.5/../../../../bfin-elf/lib\libc.a
LOAD c:/program files/analog devices/gnu toolchain/svn-20101128/elf/bin/../lib/gcc/bfin-elf/4.3.5/../../../../bfin-elf/lib\libnosys.a
END GROUP

Information on every function Linked in to (example - start address of main() followed by the size)

 .text          0xffa00270       0x10 ./src/test_gcc_options.o
                0xffa00270                main

objdump

Object dumping is a powerful yet easy to use tool for extracting information from an object file. In GCC ELF toolchain this is called 'bfin-elf-objdump'. This tool can parse the *.o files and present output in a readable format to the user. For more information, refer to objdump. The options supported by tool is listed below:

C:\Program Files\Analog Devices\GNU Toolchain\2010R1\elf\bin>bfin-elf-objdump.exe
Usage: bfin-elf-objdump.exe <option(s)> <file(s)> Display information from object <file(s)>.
 At least one of the following switches must be given:
  -a, --archive-headers    Display archive header information
  -f, --file-headers       Display the contents of the overall file header
  -p, --private-headers    Display object format specific file header contents
  -h, --[section-]headers  Display the contents of the section headers
  -x, --all-headers        Display the contents of all headers
  -d, --disassemble        Display assembler contents of executable sections
  -D, --disassemble-all    Display assembler contents of all sections
  -S, --source             Intermix source code with disassembly
  -s, --full-contents      Display the full contents of all sections requested
  -g, --debugging          Display debug information in object file
  -e, --debugging-tags     Display debug information using ctags style
  -G, --stabs              Display (in raw form) any STABS info in the file
  -W, --dwarf              Display DWARF info in the file
  -t, --syms               Display the contents of the symbol table(s)
  -T, --dynamic-syms       Display the contents of the dynamic symbol table
  -r, --reloc              Display the relocation entries in the file
  -R, --dynamic-reloc      Display the dynamic relocation entries in the file
  @<file>                  Read options from <file>
  -v, --version            Display this program's version number
  -i, --info               List object formats and architectures supported
  -H, --help               Display this information

Sample command outputs:

bfin-elf-objdump -d gdb_debugging

gdb_debugging:     file format elf32-bfin

Disassembly of section .text:

ffa00000 <__start>:
ffa00000:       81 61           R1 = 0x30 (X);          /*              R1=0x30( 48) */
ffa00002:       11 3e           SYSCFG = R1;
ffa00004:       21 e1 00 04     R1 = 0x400 (X);         /*              R1=0x400(1024) */
ffa00008:       08 e1 00 05     P0.L = 0x500;           /* (1280)       P0=0x500 */
.........................................................

bfin-elf-objdump -h gdb_debugging

gdb_debugging:     file format elf32-bfin

Sections:
Idx Name          Size      VMA       LMA       File off  Algn
  0 .text         00000510  ffa00000  ffa00000  00002000  22
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
  1 .init         00000012  ffa00510  ffa00510  00002510  20
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
  2 .fini         0000000e  ffa00522  ffa00522  00002522  2**0
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
........................................................