Author Topic: A specific Q on GCC linker script syntax  (Read 750 times)

0 Members and 1 Guest are viewing this topic.

Offline peter-hTopic starter

  • Super Contributor
  • ***
  • Posts: 4268
  • Country: gb
  • Doing electronics since the 1960s...
A specific Q on GCC linker script syntax
« on: July 28, 2024, 08:19:06 pm »
I have a project (STM ARM32 GCC V11) and I want to locate initialised data (DATA) starting with DATA from main.c and then followed by all the other modules in the project. Is this the correct syntax for that? The align 4 is important to maintain.

Code: [Select]

/* Initialized data sections for non boot block code. These go into RAM. LMA copy is loaded after code. */
/* This stuff is copied from FLASH to RAM by C code in the main stub */
/* This is stuff like int fred = 1; which is copied flash -> ram (not const) */

. = ALIGN(4);

/* main.c DATA */
  .main_data :
  {
    . = ALIGN(4);
    _s_data = .;        /* create a global symbol at data start */
    *main.o (.data .data*)      /* .data sections */
    . = ALIGN(4);
  } >RAM  AT >FLASH_APP

/* Remaining DATA */
._other_data :
  {
    . = ALIGN(4);
    *(.data .data*)      /* .data sections */
      . = ALIGN(4);
    _e_data = .;        /* define a global symbol at data end */
  } >RAM  AT >FLASH_APP

  /* used by the main stub C code to initialize data */
  _si_nonboot_data = LOADADDR(.main_data);


AIUI, the above should first collect DATA objects from main.o and then collect all other DATA objects.

I have seen suggestions that the KEEP directive should be used but not sure about it.

Thank you for any comments.
Z80 Z180 Z280 Z8 S8 8031 8051 H8/300 H8/500 80x86 90S1200 32F417
 

Offline SiliconWizard

  • Super Contributor
  • ***
  • Posts: 15607
  • Country: fr
Re: A specific Q on GCC linker script syntax
« Reply #1 on: July 28, 2024, 10:23:21 pm »
The one point to care about is to make sure you properly copy data from flash to RAM in your startup code, for both sections. But I guess you already figured that.

AFAIK, KEEP is only used to make sure the linker won't prune a given section even if no actual data is inside of it. I don't know what other purpose it may have - if it does, someone else may tell us.
 

Offline ejeffrey

  • Super Contributor
  • ***
  • Posts: 3984
  • Country: us
Re: A specific Q on GCC linker script syntax
« Reply #2 on: July 28, 2024, 11:50:25 pm »
KEEP avoids pruning symbols/sections that have no incoming references.  It's normally used for the entry point and things like interrupt vector tables that are directly accessed by the hardware/platform and not necessarily referenced by code visible to the linker. 

In my experience people overuse KEEP.  A common example is to have a bug where e.g., main is accidentally empty.  This can result in the linker discarding your entire program.  People see that, get pissed at the linker and add KEEP directives to prevent that.  But of course the linker is correct in discarding that code, the bug is that main is empty and it won't call the dead code even if you use KEEP to force it to be present.
 

Offline peter-hTopic starter

  • Super Contributor
  • ***
  • Posts: 4268
  • Country: gb
  • Doing electronics since the 1960s...
Re: A specific Q on GCC linker script syntax
« Reply #3 on: July 29, 2024, 06:24:54 am »
Quote
But I guess you already figured that.

Hopefully - it is done with this

Code: [Select]
extern char _s_data;
extern char _e_data;
extern char _si_data;
memcpy(&_s_data, &_si_nonboot_data, &_e_data - &_s_data);

I found this has exactly the same effect, except that there is a missing align 4 after the main.c DATA stuff (which should make no difference; this CPU supports unaligned data). I think all those align 4 statements are fossils from other ST sample code.

Code: [Select]

. = ALIGN(4);

/* main.c DATA */
  .main_data :
  {
    . = ALIGN(4);
    _s_data = .;        /* create a global symbol at data start */
    *main.o (.data .data*)      /* main.c .data sections */
        *(.data .data*)      /* all other .data sections */
    . = ALIGN(4);
    _e_data = .;        /* define a global symbol at data end */
  } >RAM  AT >FLASH_APP

  _si_nonboot_data = LOADADDR(.main_data);
« Last Edit: July 29, 2024, 11:03:37 am by peter-h »
Z80 Z180 Z280 Z8 S8 8031 8051 H8/300 H8/500 80x86 90S1200 32F417
 

Offline ejeffrey

  • Super Contributor
  • ***
  • Posts: 3984
  • Country: us
Re: A specific Q on GCC linker script syntax
« Reply #4 on: July 29, 2024, 03:19:47 pm »
The align 4 statement right before edata is only to make the memcpy an aligned length.  It only matters for performance of you use C memcpy but if you write your startup code in assembly you might prefer to do exclusively 4 byte accesses.

You want the data segments aligned even when the architecture supports unaligned access.  The compiler will align objects relative to the section beginning so if the linker places the section at an unaligned location *every* integer in the data segment will be unaligned and incur a performance penalty.

In addition, unaligned accesses are not atomic with respect to other cores or DMA which may or may not be a problem for you.

Normally input sections have their own alignment specifier based on their contents so you actually have to work at it to create an unaligned binary.  The ALIGN directives here should be mostly documentation and a bit of insurance.  However you can use linker level ALIGN directives to force a section or subsection to have greater alignment than required by the data.  For instance you might want the output sections to be page aligned on a system with virtual memory, or erase block aligned on a system with flash.
« Last Edit: July 29, 2024, 03:27:42 pm by ejeffrey »
 

Offline peter-hTopic starter

  • Super Contributor
  • ***
  • Posts: 4268
  • Country: gb
  • Doing electronics since the 1960s...
Re: A specific Q on GCC linker script syntax
« Reply #5 on: July 29, 2024, 04:08:04 pm »
Thanks - every day is a school day :)

I've spent a number of days on this problem
https://www.eevblog.com/forum/microcontrollers/looking-for-help-to-debug-32f4-ethernet/msg5587775/#msg5587775

and I am pretty sure that the approach involving two (or more) linkfile sections as in my 1st post above, is problematic for DATA because it creates a mismatch between the FLASH based version and where it is expected to end up in RAM. Took me bloody ages to discover the data (stuff like initialisation values for various peripheral registers) was being copied across with gaps in it.

Fairly obviously, align directives within source code work fine, including those silently added by the compiler. But there seems to be a gotcha with DATA used in conjunction with aligns in the linkfile.
Z80 Z180 Z280 Z8 S8 8031 8051 H8/300 H8/500 80x86 90S1200 32F417
 

Offline ejeffrey

  • Super Contributor
  • ***
  • Posts: 3984
  • Country: us
Re: A specific Q on GCC linker script syntax
« Reply #6 on: July 29, 2024, 05:46:19 pm »
So you are saying that the section alignment is being handled differently for the flash address and the RAM address, so the memcpy that attempts to copy both data sections is doing the wrong thing?  essentially LOADADDR(.main_data) - .main_data != LOADADDR(._other_data) - .other_data?  Have you actually confirmed that by looking at the object dump of the resulting elf file?
 

Offline peter-hTopic starter

  • Super Contributor
  • ***
  • Posts: 4268
  • Country: gb
  • Doing electronics since the 1960s...
Re: A specific Q on GCC linker script syntax
« Reply #7 on: July 29, 2024, 06:45:20 pm »
Yes.

I think it is the use of multiple  >RAM  AT >FLASH_APP statements which produces a discontinuity between the flash block and the ram block. I did a hex dump of src and dest of the ~1500 byte block and found a gap of a few bytes. I think it was the align directive between the two blocks that was the cause, because I could make it work by packing in 1 byte of DATA at a time until the gap closed.

I can well believe nobody has found this before.
 
Z80 Z180 Z280 Z8 S8 8031 8051 H8/300 H8/500 80x86 90S1200 32F417
 

Offline ejeffrey

  • Super Contributor
  • ***
  • Posts: 3984
  • Country: us
Re: A specific Q on GCC linker script syntax
« Reply #8 on: July 29, 2024, 08:14:01 pm »
Not looking for gaps, having gaps should be fine.  I mean looking for the flash vs. sram addresses not agreeing.  Look at `objdump -h <myfile.elf>`and see how the sections are laid out in the VMA vs LMA.
 

Offline peter-hTopic starter

  • Super Contributor
  • ***
  • Posts: 4268
  • Country: gb
  • Doing electronics since the 1960s...
Re: A specific Q on GCC linker script syntax
« Reply #9 on: July 30, 2024, 08:02:28 pm »
I didn't go back to test the objdump stuff (I didn't know you could list it like that until I saw your post) but I think the issue is with using memcpy or similar to set up initialised data in one move, when you have more than one DATA section defined.

I would expect them to concatenate correctly if there are no align directives between the sections but that was exactly what I did have.

There is a lot of really weird stuff in the way these linkfiles work. For example, ST's Cube IDE examples have this at the very end

Code: [Select]
    .code_constants_etc :
  {
    . = ALIGN(4);
    *(.text)           /* .text sections (code) */
    *(.text*)          /* .text* sections (code) */
    *(.rodata)         /* .rodata sections (constants, strings, etc.) */
    *(.rodata*)        /* .rodata* sections (constants, strings, etc.) */
    *(.glue_7)         /* glue arm to thumb code */
    *(.glue_7t)        /* glue thumb to arm code */
*(.eh_frame)

    KEEP (*(.init))
    KEEP (*(.fini))
   
    . = ALIGN(4);
    _e_code_constants_etc = .;        /* define a global symbol at end of code */
} >FLASH

It is after collecting DATA, BSS, etc. But there is no reason why one should be collecting the above (into FLASH) after DATA or BSS. But if you put the above before, strange stuff happens. I spent days narrowing this down, and clearly somebody at ST went down the same path, without documenting why. Text and Rodata are clear enough but the rest is quite subtle. Putting *(.eh_frame) into google produces enough reading for days.
« Last Edit: July 30, 2024, 10:04:24 pm by peter-h »
Z80 Z180 Z280 Z8 S8 8031 8051 H8/300 H8/500 80x86 90S1200 32F417
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf