# What's wrong with this Linker script?

**URL:** <https://forum.sierrawireless.com/t/whats-wrong-with-this-linker-script/4598>\
**Category:** Development tools\
**Created:** [August 3, 2010, 6:55pm UTC](https://forum.sierrawireless.com/t/whats-wrong-with-this-linker-script/4598 "2010-08-03T18:55:56Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![awneil](https://avatars.discourse-cdn.com/v4/letter/a/49beb7/32.png) [@awneil](https://forum.sierrawireless.com/u/awneil)\
**Post date:** [August 3, 2010, 6:55pm UTC](https://forum.sierrawireless.com/t/whats-wrong-with-this-linker-script/4598/1 "2010-08-03T18:55:56Z")

</div>

Trying to get Persistent RAM to work with an SDK before v2.10 and/or firmware before R7.2  
See: [Persistent RAM - ADL\_MEM\_UNINIT](https://forum.sierrawireless.com/t/persistent-ram-adl-mem-uninit/3836/1)  
And: [How to customise gcc.lkopt ?](https://forum.sierrawireless.com/t/how-to-customise-gcc-lkopt/4578/1)

This is the standard gcc.lkopt script used by M2MStudio:

> [@](#):
>
> /\* The linker command script \*/
> 
> /\* Set the memory mapping \*/  
> MEMORY  
> {  
> ROM\_MAP (rx) : ORIGIN = 0x00210000, LENGTH = 8192k  
> RAM\_MAP (!rx) : ORIGIN = 0x180C0000, LENGTH = 8192k  
> }  
> PHDRS  
> {  
> appli PT\_LOAD ;  
> }
> 
> SECTIONS  
> {  
> .oat\_header :  
> {  
> opec\_header.o ( .rodata\* )  
> } \> ROM\_MAP :appli
> 
> .text :  
> {  
> /\* RO and ER\_RO symbols are provided for legacy OS support _/  
> /_ define the value of the begin of code section \*/  
> PROVIDE(Image$$APP\_RO$$Base = .);  
> PROVIDE(Image$$RO$$Base = .);  
> \*( .text )  
> . = ALIGN(4);  
> \*( .glue\_7t )  
> . = ALIGN(4);  
> \*( .glue\_7 )  
> . = ALIGN(4);  
> \*( .ctors )  
> . = ALIGN(4);  
> \*( .dtors )  
> . = ALIGN(4);  
> _( .gnu.linkonce.t._ )  
> _( .gnu.linkonce.r._ )  
> . = ALIGN(4);  
> _( .gcc\_except\_table )  
> . = ALIGN(4);  
> ( .rodata )  
> /_ define the value of the end of code section _/  
> PROVIDE(Image$$APP\_RO$$Limit = .);  
> PROVIDE(Image$$RO$$Limit = .);  
> /_ define the length of the code section \*/  
> PROVIDE(Image$$APP\_RO$$Length = SIZEOF(.text));  
> PROVIDE(Image$$ER\_RO$$Length = SIZEOF(.text));  
> \_etext = .;  
> } \> ROM\_MAP :appli
> 
> .data : AT (\_etext)  
> {  
> /\* RW and ER\_RW symbols are provided for legacy OS support _/  
> /_ define the value of the begin of data initialized section \*/  
> PROVIDE(Image$$APP\_DATA$$Base = .);  
> PROVIDE(Image$$RW$$Base = .);  
> _( .data )  
> ( .gnu.linkonce.d. )  
> /_ define the value of the end of data initialized section _/  
> PROVIDE(Image$$APP\_DATA$$Limit = .);  
> PROVIDE(Image$$RW$$Limit = .);  
> /_ define the length of the data initialized section \*/  
> PROVIDE(Image$$APP\_DATA$$Length = SIZEOF(.data));  
> PROVIDE(Image$$ER\_RW$$Length = SIZEOF(.data));  
> } \> RAM\_MAP :appli
> 
> .bss :  
> {  
> /\* ZI symbol is provided for legacy OS support _/  
> /_ define the value of the begin of data zero initialized section \*/  
> PROVIDE(Image$$APP\_BSS$$Base = .);  
> PROVIDE(Image$$ZI$$Base = .);  
> \*( .bss )  
> _( COMMON )  
> ( .gnu.linkonce.b. )  
> /_ define the value of the end of data zero initialized section _/  
> PROVIDE(Image$$APP\_BSS$$Limit = .);  
> PROVIDE(Image$$ZI$$Limit = .);  
> /_ define the length of the data zero initialized section \*/  
> PROVIDE(Image$$APP\_BSS$$ZI$$Length = SIZEOF(.bss));  
> PROVIDE(Image$$ER\_ZI$$ZI$$Length = SIZEOF(.bss));  
> } \> RAM\_MAP :appli
> 
> .uninit (NOLOAD) :  
> {  
> /\* define the value of the begin of uninitialized section _/  
> PROVIDE(Image$$APP\_UNINIT$$Base = .);  
> \* (UNINIT)  
> /_ define the value of the end of uninitialized section _/  
> PROVIDE(Image$$APP\_UNINIT$$Limit = .);  
> PROVIDE(end = .);  
> /_ define the length of the uninitialized section \*/  
> PROVIDE(Image$$APP\_UNINIT$$ZI$$Length = SIZEOF(.uninit));  
> } \> RAM\_MAP :appli
> 
> . = ALIGN(4);  
> }

The bits to do with the “Persistent RAM” are, I think, all the red stuff.

This doesn’t work with v6.63 Firmware - stuff gets corrupted & the app crashes - presumably because the firmware thinks that everything past Image$$ZI$$Limit is Free RAM and, hence, uses it for the Heap, etc?

Moving the definition of Image$$ZI$$Limit stops the corruption/crashing, but the UNINIT data gets cleared at startup - presumably because the firmware uses Image$$ZI$$Limit when it clears RAM?

Moving the whole .uninit section definition before the .bss section definition has similar results (data does not “persist”).

If I move the .uninit section definition before the .data section like this:

> [@](#):
>
> /\* The linker command script \*/
> 
> /\* Set the memory mapping \*/  
> MEMORY  
> {  
> ROM\_MAP (rx) : ORIGIN = 0x00210000, LENGTH = 8192k  
> RAM\_MAP (!rx) : ORIGIN = 0x180C0000, LENGTH = 8192k  
> }  
> PHDRS  
> {  
> appli PT\_LOAD ;  
> }
> 
> SECTIONS  
> {  
> .oat\_header :  
> {  
> opec\_header.o ( .rodata\* )  
> } \> ROM\_MAP :appli
> 
> .text :  
> {  
> /\* RO and ER\_RO symbols are provided for legacy OS support _/  
> /_ define the value of the begin of code section \*/  
> PROVIDE(Image$$APP\_RO$$Base = .);  
> PROVIDE(Image$$RO$$Base = .);  
> \*( .text )  
> . = ALIGN(4);  
> \*( .glue\_7t )  
> . = ALIGN(4);  
> \*( .glue\_7 )  
> . = ALIGN(4);  
> \*( .ctors )  
> . = ALIGN(4);  
> \*( .dtors )  
> . = ALIGN(4);  
> _( .gnu.linkonce.t._ )  
> _( .gnu.linkonce.r._ )  
> . = ALIGN(4);  
> _( .gcc\_except\_table )  
> . = ALIGN(4);  
> ( .rodata )  
> /_ define the value of the end of code section _/  
> PROVIDE(Image$$APP\_RO$$Limit = .);  
> PROVIDE(Image$$RO$$Limit = .);  
> /_ define the length of the code section \*/  
> PROVIDE(Image$$APP\_RO$$Length = SIZEOF(.text));  
> PROVIDE(Image$$ER\_RO$$Length = SIZEOF(.text));  
> \_etext = .;  
> } \> ROM\_MAP :appli
> 
> .uninit (NOLOAD) : AT (\_etext)  
> {  
> /\* define the value of the begin of uninitialized section _/  
> PROVIDE(Image$$APP\_UNINIT$$Base = .);  
> \* (UNINIT)  
> /_ define the value of the end of uninitialized section _/  
> PROVIDE(Image$$APP\_UNINIT$$Limit = .);  
> PROVIDE(end = .);  
> /_ define the length of the uninitialized section \*/  
> PROVIDE(Image$$APP\_UNINIT$$ZI$$Length = SIZEOF(.uninit));  
> } \> RAM\_MAP :appli
> 
> .data :  
> {  
> /\* RW and ER\_RW symbols are provided for legacy OS support _/  
> /_ define the value of the begin of data initialized section \*/  
> PROVIDE(Image$$APP\_DATA$$Base = .);  
> PROVIDE(Image$$RW$$Base = .);  
> _( .data )  
> ( .gnu.linkonce.d. )  
> /_ define the value of the end of data initialized section _/  
> PROVIDE(Image$$APP\_DATA$$Limit = .);  
> PROVIDE(Image$$RW$$Limit = .);  
> /_ define the length of the data initialized section \*/  
> PROVIDE(Image$$APP\_DATA$$Length = SIZEOF(.data));  
> PROVIDE(Image$$ER\_RW$$Length = SIZEOF(.data));  
> } \> RAM\_MAP :appli
> 
> .bss :  
> {  
> /\* ZI symbol is provided for legacy OS support _/  
> /_ define the value of the begin of data zero initialized section \*/  
> PROVIDE(Image$$APP\_BSS$$Base = .);  
> PROVIDE(Image$$ZI$$Base = .);  
> \*( .bss )  
> _( COMMON )  
> ( .gnu.linkonce.b. )  
> /_ define the value of the end of data zero initialized section _/  
> PROVIDE(Image$$APP\_BSS$$Limit = .);  
> PROVIDE(Image$$ZI$$Limit = .);  
> /_ define the length of the data zero initialized section \*/  
> PROVIDE(Image$$APP\_BSS$$ZI$$Length = SIZEOF(.bss));  
> PROVIDE(Image$$ER\_ZI$$ZI$$Length = SIZEOF(.bss));  
> } \> RAM\_MAP :appli
> 
> . = ALIGN(4);  
> }

then the size of the .axf file balloons from under 10MB to over 400MB!! 😮

The resulting .bin file balloons from under 300KB to nearly 400MB;  
the .dwl file goes from under 190KB to nearly 600KB - and fails to load (AT+wDWL gives MEMORY ALLOCATION ERROR)

SO the question is: why does this cause such ballooning of the .axf file size ❓

If I modify the script to explicitly set the start of the .data section, like this:

> [@](#):
>
> :  
> :
> 
> .uninit (NOLOAD) : AT (\_etext)  
> {  
> /\* define the value of the begin of uninitialized section _/  
> PROVIDE(Image$$APP\_UNINIT$$Base = .);  
> \* (UNINIT)  
> /_ define the value of the end of uninitialized section _/  
> PROVIDE(Image$$APP\_UNINIT$$Limit = .);  
> PROVIDE(end = .);  
> /_ define the length of the uninitialized section \*/  
> PROVIDE(Image$$APP\_UNINIT$$ZI$$Length = SIZEOF(.uninit));  
> } \> RAM\_MAP :appli
> 
> .data : AT (\_etext + SIZEOF(.uninit))  
> {  
> :  
> :

then the size of the .axf file returns to under 10MB 🙂  
But the .bin file remains at nearly 400MB, and the .dwl at nearly 600KB - and still fails to load (AT+wDWL gives MEMORY ALLOCATION ERROR)

So, again, the question is: What is causing this ballooning of the .bin and .dwl file sizes - even though the .axf file size is back to “normal”❓

---

<div class="post-metadata">

**Author:** ![awneil](https://avatars.discourse-cdn.com/v4/letter/a/49beb7/32.png) [@awneil](https://forum.sierrawireless.com/u/awneil)\
**Post date:** [August 4, 2010, 8:58am UTC](https://forum.sierrawireless.com/t/whats-wrong-with-this-linker-script/4598/2 "2010-08-04T08:58:39Z")

</div>

> [@awneil first](#):
>
> why does this cause such ballooning of the .axf file size ❓

> [@awneil then](#):
>
> What is causing this ballooning of the .bin and .dwl file sizes - even though the .axf file size is back to “normal”❓

OK - I’ve been using objdump -p -h to see the sections in the .axf file.

For the “standard” M2MStudio linker script (giving ~10MB .axf file and ~300KB .bin), it shows:

```auto
cbox_424.axf: file format elf32-littlearm

Program Header:
    LOAD off 0x00000054 vaddr 0x00210000 paddr 0x00210000 align 2**2
         filesz 0x0004798c memsz 0x00052568 flags rwx
private flags = 206: [interworking enabled] [APCS-32] [FPA float format] [software FP] [has entry point]

Sections:
Idx Name Size VMA LMA File off Algn
  0 .oat_header 0000003c 00210000 00210000 00000054 2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  1 .text 00046ddc 0021003c 0021003c 00000090 2**2
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
  2 .data 00000b74 180c0000 00256e18 00046e6c 2**2
                  CONTENTS, ALLOC, LOAD, DATA
  3 .bss 0000abdc 180c0b74 180c0b74 000479e0 2**2
                  ALLOC
  4 .uninit 00000000 180cb750 180cb750 000479e0 2**0
                  CONTENTS
  5 .debug_abbrev 00018e3f 00000000 00000000 000479e0 2**0
                  CONTENTS, READONLY, DEBUGGING
  6 .debug_info 0008dfde 00000000 00000000 0006081f 2**0
                  CONTENTS, READONLY, DEBUGGING
  7 .debug_line 0005a06d 00000000 00000000 000ee7fd 2**0
                  CONTENTS, READONLY, DEBUGGING
  8 .debug_macinfo 0072b309 00000000 00000000 0014886a 2**0
                  CONTENTS, READONLY, DEBUGGING
  9 .debug_pubnames 000066b2 00000000 00000000 00873b73 2**0
                  CONTENTS, READONLY, DEBUGGING
 10 .debug_str 00014fd7 00000000 00000000 0087a225 2**0
                  CONTENTS, READONLY, DEBUGGING
 11 .comment 0000142e 00000000 00000000 0088f1fc 2**0
                  CONTENTS, READONLY
 12 .debug_frame 000097cc 00000000 00000000 0089062c 2**2
                  CONTENTS, READONLY, DEBUGGING
 13 .debug_loc 0003ba19 00000000 00000000 00899df8 2**0
                  CONTENTS, READONLY, DEBUGGING
 14 .debug_aranges 00002360 00000000 00000000 008d5818 2**3
                  CONTENTS, READONLY, DEBUGGING
 15 .debug_ranges 00002c60 00000000 00000000 008d7b78 2**0
                  CONTENTS, READONLY, DEBUGGING
```

Note the “filesz 0x0004798c memsz 0x00052568” (ie, 293260 and 337256).

With the script modified to move the .uninit section definition before the .data section (giving ~400MB .axf file and ~400MB .bin), it shows:

```auto
cbox_424.axf: file format elf32-littlearm

Program Header:
    LOAD off 0x00000054 vaddr 0x00210000 paddr 0x00210000 align 2**2
         filesz 0x17eb0b80 memsz 0x17ebb768 flags rwx
private flags = 206: [interworking enabled] [APCS-32] [FPA float format] [software FP] [has entry point]

Sections:
Idx Name Size VMA LMA File off Algn
  0 .oat_header 0000003c 00210000 00210000 00000054 2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  1 .text 00046ee8 0021003c 0021003c 00000090 2**2
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
  2 .uninit 0000000c 180c0000 180c0000 00046f78 2**2
                  ALLOC
  3 .data 00000b74 180c000c 180c000c 17eb006c 2**2
                  CONTENTS, ALLOC, LOAD, DATA
  4 .bss 0000abdc 180c0b80 180c0b80 17eb0be0 2**2
                  ALLOC
  5 .debug_abbrev 00018e3f 00000000 00000000 17eb0be0 2**0
                  CONTENTS, READONLY, DEBUGGING
  6 .debug_info 0008dff2 00000000 00000000 17ec9a1f 2**0
                  CONTENTS, READONLY, DEBUGGING
  7 .debug_line 0005a09f 00000000 00000000 17f57a11 2**0
                  CONTENTS, READONLY, DEBUGGING
  8 .debug_macinfo 0072b58f 00000000 00000000 17fb1ab0 2**0
                  CONTENTS, READONLY, DEBUGGING
  9 .debug_pubnames 000066c4 00000000 00000000 186dd03f 2**0
                  CONTENTS, READONLY, DEBUGGING
 10 .debug_str 00014fe5 00000000 00000000 186e3703 2**0
                  CONTENTS, READONLY, DEBUGGING
 11 .comment 0000142e 00000000 00000000 186f86e8 2**0
                  CONTENTS, READONLY
 12 .debug_frame 000097e8 00000000 00000000 186f9b18 2**2
                  CONTENTS, READONLY, DEBUGGING
 13 .debug_loc 0003ba19 00000000 00000000 18703300 2**0
                  CONTENTS, READONLY, DEBUGGING
 14 .debug_aranges 00002360 00000000 00000000 1873ed20 2**3
                  CONTENTS, READONLY, DEBUGGING
 15 .debug_ranges 00002c60 00000000 00000000 18741080 2**0
                  CONTENTS, READONLY, DEBUGGING
```

Note the “filesz 0x17eb0b80 memsz 0x17ebb768” (ie, 401279872 and 401323880)

With the script modified to explicitly set the start of the .data section (back to ~10MB .axf file, but still ~400MB .bin), it shows:

```auto
cbox_424.axf: file format elf32-littlearm

Program Header:
    LOAD off 0x00000054 vaddr 0x00210000 paddr 0x00210000 align 2**2
         filesz 0x00047aa4 memsz 0x0005268c flags rwx
private flags = 206: [interworking enabled] [APCS-32] [FPA float format] [software FP] [has entry point]

Sections:
Idx Name Size VMA LMA File off Algn
  0 .oat_header 0000003c 00210000 00210000 00000054 2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  1 .text 00046ee8 0021003c 0021003c 00000090 2**2
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
  2 .uninit 0000000c 180c0000 180c0000 00046f78 2**2
                  ALLOC
  3 .data 00000b74 180c000c 180c000c 00046f90 2**2
                  CONTENTS, ALLOC, LOAD, DATA
  4 .bss 0000abdc 180c0b80 180c0b80 00047b04 2**2
                  ALLOC
  5 .debug_abbrev 00018e3f 00000000 00000000 00047b04 2**0
                  CONTENTS, READONLY, DEBUGGING
  6 .debug_info 0008dff2 00000000 00000000 00060943 2**0
                  CONTENTS, READONLY, DEBUGGING
  7 .debug_line 0005a09f 00000000 00000000 000ee935 2**0
                  CONTENTS, READONLY, DEBUGGING
  8 .debug_macinfo 0072b58f 00000000 00000000 001489d4 2**0
                  CONTENTS, READONLY, DEBUGGING
  9 .debug_pubnames 000066c4 00000000 00000000 00873f63 2**0
                  CONTENTS, READONLY, DEBUGGING
 10 .debug_str 00014fe5 00000000 00000000 0087a627 2**0
                  CONTENTS, READONLY, DEBUGGING
 11 .comment 0000142e 00000000 00000000 0088f60c 2**0
                  CONTENTS, READONLY
 12 .debug_frame 000097e8 00000000 00000000 00890a3c 2**2
                  CONTENTS, READONLY, DEBUGGING
 13 .debug_loc 0003ba19 00000000 00000000 0089a224 2**0
                  CONTENTS, READONLY, DEBUGGING
 14 .debug_aranges 00002360 00000000 00000000 008d5c40 2**3
                  CONTENTS, READONLY, DEBUGGING
 15 .debug_ranges 00002c60 00000000 00000000 008d7fa0 2**0
                  CONTENTS, READONLY, DEBUGGING
```

Note the “filesz 0x00047aa4 memsz 0x0005268c” (ie, 293540 and 337548).  
This is now about the same as the original - so why is the .bin file still bloated ❓

Do I need to change the options to objcopy (which creates the .bin from the .axf) ❓  
If so, how ❓

---

<div class="post-metadata">

**Author:** ![awneil](https://avatars.discourse-cdn.com/v4/letter/a/49beb7/32.png) [@awneil](https://forum.sierrawireless.com/u/awneil)\
**Post date:** [August 4, 2010, 9:00am UTC](https://forum.sierrawireless.com/t/whats-wrong-with-this-linker-script/4598/3 "2010-08-04T09:00:09Z")

</div>

> [@awneil](#):
>
> why is the .bin file still bloated ❓

It looks like some (unnecessary?) padding is being inserted - but where? and why? and how to stop it?!

---

<div class="post-metadata">

**Author:** ![awneil](https://avatars.discourse-cdn.com/v4/letter/a/49beb7/32.png) [@awneil](https://forum.sierrawireless.com/u/awneil)\
**Post date:** [August 4, 2010, 10:37pm UTC](https://forum.sierrawireless.com/t/whats-wrong-with-this-linker-script/4598/4 "2010-08-04T22:37:05Z")

</div>

Here’s a useful article on GCC Linker Scripts: [warmi.net/docs/gnupro/5\_ut/b … ripts.html](http://www.warmi.net/docs/gnupro/5_ut/b_Usingld/ldLinker_scripts.html)

The secret is in:

> [@](#):
>
> .data : AT (\_etext)

The “AT” specifies the location for the section in the ROM Image (the LMA) - not in the runtime memory (VMA).  
(the ROM image contains the initialisation values which are copied into the runtim RAM location at startup).

So my script should have looked something like:

```auto
.text :
   {
      :
      :
      _etext = .;
   } > ROM_MAP :appli

   .uninit (NOLOAD) :
   {
      :
      :
   } > RAM_MAP :appli

  .data : AT (_etext)
   {
      :
      :
   } > RAM_MAP :appli

   .bss :
   {
      :
      :
   } > RAM_MAP :appli
```

With that, I get sensible sizes for both the .axf file and binary files. 🙂

The code loads OK with AT+WDWL, but the application doesn’t start.

AT+WOPEN=7 gives +WOPEN: 7,8 - which means, “Link Issue. The application global variables area initialisation is impossible”

SO it does look like this is impossible with this firmware. 😢

Unless someone can think of a way to tell the firmware not to use the top of RAM…?

---

<div class="post-metadata">

**Author:** ![daav](https://sea1.discourse-cdn.com/flex025/user_avatar/forum.sierrawireless.com/daav/32/2767_2.png) [@daav](https://forum.sierrawireless.com/u/daav)\
**Post date:** [August 6, 2010, 12:05pm UTC](https://forum.sierrawireless.com/t/whats-wrong-with-this-linker-script/4598/5 "2010-08-06T12:05:02Z")

</div>

Wow… a deep investigation 😉  
… to get the final result I was afraid of…

BTW, please note that if you move to Devleoper Studio 1.1.2, you’ll see that the default linker script has been modified a bit, to make it compatible with both current ARM ELF GCC 4.0.1, and new ARM EABI GCC 4.4.1 now shiped with the studio.  
Unfortunately, it shouldn’t help you, in this case, it’s just for information.  
It’s true that GCC linker seems to easily run away on generating huge output files when wrong linker script syntax. We had headackes for several days when trying to tune the new script; and the trickiest part is to understand why the linker script is wrong…
