Like I mentioned in the previous post there is something more sophisticated to organize the memory for our program, the linker scripts allows us to do that. lets go back to the most simple example, again…

unsigned long var1;
unsigned long var2 = 34;

int main( void )
{
    return 0;
}

As you remember the previous code will be organized by the compiler in three different sections .text for the code, .data for initialized global variables & .bss for non initialized global variables, just like this

$ arm-none-eabi-gcc -c main.c -o main.o -mcpu=cortex-m0plus
$ arm-none-eabi-objdump -h main.o

main.o:     file format elf32-littlearm

Sections:
Idx Name          Size      VMA       LMA       File off  Algn
  0 .text         0000000c  00000000  00000000  00000034  2**1
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
  1 .data         00000004  00000000  00000000  00000040  2**2
                  CONTENTS, ALLOC, LOAD, DATA
  2 .bss          00000004  00000000  00000000  00000044  2**2
                  ALLOC
  3 .comment      0000001f  00000000  00000000  00000044  2**0
                  CONTENTS, READONLY
  4 .ARM.attributes 0000002c  00000000  00000000  00000063  2**0
                  CONTENTS, READONLY

Now is time for a little experiment. Enter the linker script. Create a file and named linker.ld with the following content. What you are seeing is a declaration of a output sections we called code, inside this we put all the information belong to object file main.o.

SECTIONS
{
    code : { main.o }
}

link it… but, this time using the linker file we just created using the flag -T<name of the file.ld>.

$ arm-none-eabi-gcc main.o -o main.elf -nostdlib -e main -mcpu=cortex-m0plus -Tlinker.ld
$ arm-none-eabi-objdump -h main.elf

main.elf:     file format elf32-littlearm

Sections:
Idx Name          Size      VMA       LMA       File off  Algn
  0 code          0000005e  00000000  00000000  00010000  2**2
                  CONTENTS, ALLOC, LOAD, CODE

Wait!!!!, where all the sections went??, what happened is that we create an output section named code and we put all the contents from object file main.o inside ( just like a previously said ), it is easy to verify, just pay attention to column Size, add all the sections and you will see the result is 0x5e. But there is a more effective way to verify what I’m saying. Generating a Map file.

 $ arm-none-eabi-gcc main.o -o main.elf -nostdlib -e main -mcpu=cortex-m0plus -Tlinker.ld -Wl,-Map=main.map

Open the new generated file main.map, its content should look like down below. What a wonderful piece of information we have. Focus your attention from line 9 to line 24. We can see all the input sections from the main.o file inside the output section code we just declare in linker.ld, in the second column we can found the starting address and notice are one after the other no overlapping. Next column shows the section Size and finally we can observe the symbols ( functions and variables ) stored in each input section. Look at this!!, we can finally verify var2 is in .data and var1 is in .bss . Go ahead and declare more variables and functions and you will see what happens.


Memory Configuration

Name             Origin             Length             Attributes
*default*        0x0000000000000000 0xffffffffffffffff

Linker script and memory map

LOAD main.o

code            0x0000000000000000       0x5e
 main.o()
 .text          0x0000000000000000        0xc main.o
                0x0000000000000000                main
 .data          0x000000000000000c        0x4 main.o
                0x000000000000000c                var2
 .bss           0x0000000000000010        0x4 main.o
                0x0000000000000010                var1
 .comment       0x0000000000000014       0x1e main.o
                                         0x1f (size before relaxing)
 .ARM.attributes
                0x0000000000000032       0x2c main.o
OUTPUT(main.elf elf32-littlearm)
LOAD linker stubs

.glue_7         0x0000000000000060        0x0
 .glue_7        0x0000000000000060        0x0 linker stubs

.glue_7t        0x0000000000000060        0x0
 .glue_7t       0x0000000000000060        0x0 linker stubs

.vfp11_veneer   0x0000000000000060        0x0
 .vfp11_veneer  0x0000000000000060        0x0 linker stubs

.v4_bx          0x0000000000000060        0x0
 .v4_bx         0x0000000000000060        0x0 linker stubs

But this is not exactly what we want, we need somehow be able to set the different sections into specific addresses, we need more control, more granularity. OK lets do it in an orderly fashion, this time put only the actual code ( the .text section ) from main.o inside the section code we declare, just like this

SECTIONS
{
    code : { main.o (.text) }
}

Take a look at the header information, now we can see the rest of the sections but not the .text because it is inside output section code

$ arm-none-eabi-gcc main.o -o main.elf -nostdlib -e main -mcpu=cortex-m0plus -Tlinker.ld -Wl,-Map=main.map
$ arm-none-eabi-objdump -h main.elf

main.elf:     file format elf32-littlearm

Sections:
Idx Name          Size      VMA       LMA       File off  Algn
  0 code          0000000c  00000000  00000000  00010000  2**1
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
  1 .data         00000004  0000000c  0000000c  0001000c  2**2
                  CONTENTS, ALLOC, LOAD, DATA
  2 .bss          00000004  00000010  00000010  00010010  2**2
                  ALLOC
  3 .comment      0000001e  00000000  00000000  00010010  2**0
                  CONTENTS, READONLY
  4 .ARM.attributes 0000002c  00000000  00000000  0001002e  2**0
                  CONTENTS, READONLY

Open the main.map file, do not pay attention to the weird sections ( .glue7, etc.. ) focus your attention on the sections .data, .text and .bss. Only .text is inside the output code section ( line 10 to 13 )

Memory Configuration

Name             Origin             Length             Attributes
*default*        0x0000000000000000 0xffffffffffffffff

Linker script and memory map

LOAD main.o

code            0x0000000000000000        0xc
 main.o(.text)
 .text          0x0000000000000000        0xc main.o
                0x0000000000000000                main
OUTPUT(main.elf elf32-littlearm)
LOAD linker stubs

.data           0x000000000000000c        0x4
 .data          0x000000000000000c        0x4 main.o
                0x000000000000000c                var2

.glue_7         0x0000000000000010        0x0
 .glue_7        0x0000000000000010        0x0 linker stubs

.glue_7t        0x0000000000000010        0x0
 .glue_7t       0x0000000000000010        0x0 linker stubs

.vfp11_veneer   0x0000000000000010        0x0
 .vfp11_veneer  0x0000000000000010        0x0 linker stubs

.v4_bx          0x0000000000000010        0x0
 .v4_bx         0x0000000000000010        0x0 linker stubs

.bss            0x0000000000000010        0x4
 .bss           0x0000000000000010        0x4 main.o
                0x0000000000000010                var1

.comment        0x0000000000000000       0x1e
 .comment       0x0000000000000000       0x1e main.o
                                         0x1f (size before relaxing)

.ARM.attributes
                0x0000000000000000       0x2c
 .ARM.attributes
                0x0000000000000000       0x2c main.o

One more time in your linker script lets declare more output sections one per input section from the main.o file and specify the starting address for each of them

SECTIONS
{
    code 0x1000 : { main.o (.text) }
    dato 0x2000 : { main.o (.data) }
    vars 0x3000 : { main.o (.bss) }
}

The header looks like this: ( pay attention to VMA addresses )

arm-none-eabi-objdump -h main.elf

main.elf:     file format elf32-littlearm

Sections:
Idx Name          Size      VMA       LMA       File off  Algn
  0 code          0000000c  00001000  00001000  00001000  2**1
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
  1 dato          00000004  00002000  00002000  00002000  2**2
                  CONTENTS, ALLOC, LOAD, DATA
  2 vars          00000004  00003000  00003000  00002004  2**2
                  ALLOC
  3 .comment      0000001e  00000000  00000000  00002004  2**0
                  CONTENTS, READONLY
  4 .ARM.attributes 0000002c  00000000  00000000  00002022  2**0
                  CONTENTS, READONLY

And the map file like this: ( again, pay attention to starting address column )

NOTE: We decided to remove the unnecessary information to make things more easy to explain

Memory Configuration

Name             Origin             Length             Attributes
*default*        0x0000000000000000 0xffffffffffffffff

Linker script and memory map

LOAD main.o

code            0x0000000000001000        0xc
 main.o(.text)
 .text          0x0000000000001000        0xc main.o
                0x0000000000001000                main
    :
    :

dato            0x0000000000002000        0x4
 main.o(.data)
 .data          0x0000000000002000        0x4 main.o
                0x0000000000002000                var2

vars            0x0000000000003000        0x4
 main.o(.bss)
 .bss           0x0000000000003000        0x4 main.o
                0x0000000000003000                var1
OUTPUT(main.elf elf32-littlearm)
LOAD linker stubs
    :
    :

This is actually the way we can place the compiled code in the microcontroller memory space, just think about it, you can take the variables and group them into one section and placed right where the RAM memory start, well it is not so straight forward but you are basically getting the idea.