3

I have to place array at specific address in memory. I'm using GCC.

I declare variable like this:

uint8_t __attribute__((section (".mySection"))) buffer[1234];

And in linker script I've got:

MEMORY
{
FLASH (rx)      : ORIGIN = 0x08000000, LENGTH = 1024K
RAM (xrw)       : ORIGIN = 0x20000000, LENGTH = 145K
MYSEC (x)       : ORIGIN = 0x20025000, LENGTH = 155K
}

and later:

.mySection :
{
  *(.mySection);
} > MYSEC 

It's of course code for embedded system (ARM). Normally my program takes 22 KB, with this modification it takes 384 MB (!).

I don't understand why. If I remove __attribute__ it takes 22 KB again. What am I missing?


Code used:

#inculde (...)

uint8_t __attribute__((section (".mySection"))) buffer = 5;

int main(void){
  buffer = 10;
}

Full linker script (default, not written by me, parts are shortened:

/* Entry Point */
ENTRY(Reset_Handler)

/* Highest address of the user mode stack */
_estack = 0x20050000;    /* end of RAM */
/* Generate a link error if heap and stack don't fit into RAM */
_Min_Heap_Size = 0x200;      /* required amount of heap  */
_Min_Stack_Size = 0x400; /* required amount of stack */

/* Specify the memory areas */
MEMORY
{
FLASH (rx)      : ORIGIN = 0x08000000, LENGTH = 1024K
RAM (xrw)       : ORIGIN = 0x20000000, LENGTH = 145K
MYSEC (x)       : ORIGIN = 0x20025000, LENGTH = 155K
}

/* Define output sections */
SECTIONS
{
  /* The startup code goes first into FLASH */
  .isr_vector :
  {
    (...)
  } >FLASH

  /* The program code and other data goes into FLASH */
  .text :
  {
    (...)
  } >FLASH

  /* Constant data goes into FLASH */
  .rodata :
  {
    (...)
  } >FLASH

  .ARM.extab   : { *(.ARM.extab* .gnu.linkonce.armextab.*) } >FLASH
  .ARM : {
    (...)
  } >FLASH

  .preinit_array     :
  {
    (...)
  } >FLASH
  .init_array :
  {
    (...)
  } >FLASH
  .fini_array :
  {
    (...)
  } >FLASH

  /* used by the startup to initialize data */
  _sidata = LOADADDR(.data);

  /* Initialized data sections goes into RAM, load LMA copy after code */
  .data : 
  {
    (...)
  } >RAM AT> FLASH



  .mySection :
  {
    *(.mySection);
  } > MYSEC 


  /* Uninitialized data section */
  . = ALIGN(4);
  .bss :
  {
    (...)
  } >RAM

  /* User_heap_stack section, used to check that there is enough RAM left */
  ._user_heap_stack :
  {
    (...)
  } >RAM

  /* Remove information from the standard libraries */
  /DISCARD/ :
  {
    (...)
  }

  .ARM.attributes 0 : { *(.ARM.attributes) }
}
zupazt3
  • 966
  • 9
  • 30
  • 4
    Your 384M is pretty close to the size of the region from the from the lowest address in the memory layout in your linker script to the highest address. I'd be inclined to guess, therefore, that the linker is outputting an image that includes that whole space. At least when there's anything assigned to both the topmost and the bottom-most sections. – John Bollinger Jan 07 '16 at 23:16
  • Does `MYSEC` contain any initialized data? – user3386109 Jan 07 '16 at 23:28
  • @user3386109 Yes. There are some assignment operations on "buffer" so MYSEC has initialized variable (buffer). – zupazt3 Jan 07 '16 at 23:35
  • check this article http://mcuoneclipse.com/2012/11/01/defining-variables-at-absolute-addresses-with-gcc . Can you provide the map file? It should give you some hints why the image grows. – Ivan Angelov Jan 08 '16 at 00:59
  • amongst other problems in the `memory` definition, the RAM area is defined as starting at 0x20000000 and has a length of 145*1024 bytes in length. which yields a end address of However, 557019392 decimal. the MYSEC is started at: 0x20025000 (537022464 decimal) so the memory overlaps. The memory areas overlapping is an error. from that point onward, all bets on what is actually being produced are 'off'. suggest fixing the memory definitions so they do not overlap – user3629249 Jan 08 '16 at 02:26
  • the MYSEC only contains a single item and that item is only a bit over 1k in size, so why is the memory definition for 155k? – user3629249 Jan 08 '16 at 02:29
  • Initialisation is not the same as an assignment. @user3386109 asked about the initialisation, not an assignment. So: do you initialise the data? – too honest for this site Jan 08 '16 at 08:06
  • @user3629249 No, the memory areas don't overlap. End address of RAM memory is 537 019 392, I think. Not 557 019 392 as you said. Are you sure your calculations are ok? And section contains only 1k, because it's just an example, there will be something bigger. But no matter what size is the variable, the *.bin file is still large. – zupazt3 Jan 08 '16 at 08:35
  • @Olaf Ok, so I did initialization and it doesn't change anything. I've changed array to normal variable and initialized it: `uint8_t __attribute__((section (".mySection"))) buffer = 5;` *.bin file is still 384. Maybe there are some setting in compiler or linker that has to be set? – zupazt3 Jan 08 '16 at 08:43
  • @Olaf There you go. I don't what more does it says... but I've edited my question and it has now a C code and linker script. – zupazt3 Jan 08 '16 at 09:01
  • Hmm, Try making all uninitialised sections `NOLOAD`. And it is quite strange `MYSEC` is `x`-only. That is RAM, so how do you initialise it? (You wrote you actually do - did you really understand what I wrote about the difference betwee assignment and initialisation?). Where are the labels for your startup code to init that section? I assume that is a Cortex-M; if you have an MPU use that to protect the area lateron against `rw` (the linker settings will not work anyway). – too honest for this site Jan 08 '16 at 09:11
  • @Olaf which sections are "uninitialised" to make them NOLOAD? I only added this one. And it doesn't change anything if there is (x) or (xrw) or (rw) etc. Still large bin file. And by "initialisation" I understand that after declaration I put `= 5`, as you can see in my code. And I don't know about any label for my statup code to init this section.. Can you elaborate a bit? Should I do something more than the code I posted in my answer? – zupazt3 Jan 08 '16 at 09:20
  • @zupazt3: At least `.bss` definitively is. For others it is up to you. Generally, for initialised sections you need some code in your startup code which copies initialisation data from Flash to RAM. Others, like `.bss` are just zeroed. You should RTFM (ld, toolchain, startup code). – too honest for this site Jan 08 '16 at 09:27
  • http://port70.net/~nsz/c/c11/n1570.html#6.7.9 – too honest for this site Jan 08 '16 at 09:34
  • Simply put: `.data` (same for similar sections, but `.data` is one of the standard sections) is in RAM. but RAM contains unspecified values after reset. So where do you think the initial values are stored and how they go into RAM on a bare-metal system without OS and program loader? (Rethorical question, please answer that yourself, SO is not a tutorial site) – too honest for this site Jan 08 '16 at 09:37
  • please reference: , scroll down to the `section` and examine the syntax . then correct the posted C code. – user3629249 Jan 08 '16 at 10:04
  • Maybe [this questions](http://stackoverflow.com/questions/16508946/how-to-write-this-ld-script) is helpful; there are others. You need to use the `AT` syntax in a linker script. The gnu ld concepts are 'lma' (load memory address) and 'vma' (virtual memory address). You should mention you are generating a flat binary. Section attributes are also important (such a allocate, execute, etc). – artless noise Jan 08 '16 at 14:36

1 Answers1

1

I assume your output file is a pure binary format, not an ELF so you don't have ELF bootloader. In that case, placing initialized data at high address obviously will create a big output file. This is because in the binary format you don't have any mechanism to provide specific address, so the file is mapped 1:1 into memory. It means the whole address space up to your custom initialized variable needs to be included in the output file. This is the same situation as with .data section and this is why the .data section is explicitly copied from Flash into RAM area at the startup.

p.s. You can find my article helpful (this issue is described there).

mkmk88
  • 271
  • 1
  • 4