Overriding specs file not really working

Go To Last Post
12 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I was reordering memory layout and I wanted layout which places my custom section as the first data section, then .data section immediately after that.

 

I learned after many hours wasted that no matter what I do, start address of .data section is *hardcoded*, no matter what I do in my linker file. Ugh. Okay, so I've figured that the file which defines this is specs-<mcu_name>, so for atmega32u4, the file contains, among other things, this:

 

*link_data_start:
	-Tdata 0x800100

Why the value in linker file is overwritten with this is beyond me. Nevertheless, I've figured there might be a way to override the inclusion of this spec file with my own which doesn't define start address of .data. Looking at the avr-gcc --help I've seen this:

-specs=<file>            Override built-in specs with the contents of <file>

Yay! Immediately, I've copied the specs file to my project dir, removed the link_data_start and compiled with avr-gcc <flags> -specs=<path/to/my/specs/file>

 

Looking at the generated .map file, I see that the .data address is again the same. Removing the link_data_start in the original file results in correct .data address, which suggests that:

 

1)overriding is broken

*or*

2) user-specified specs file doesn't override original one so this is a documentation issue.

 

I've tried to delete the original file, but then avr-gcc doesn't want to run at all:

 

laptop:src testing$ avr-gcc -mmcu=atmega32u4 -specs=board/avr/variants/atmega32u4/specs-atmega32u4 -v
Using built-in specs.
Reading specs from board/avr/variants/atmega32u4/specs-atmega32u4
Reading specs from device-specs/specs-atmega32u4
avr-gcc: error: device-specs/specs-atmega32u4: No such file or directory

It's frustrating that the avr-gcc is so insistent on this "magic".

 

Before others suggest that I simply pass -T flag with my .data start address: I do not know which address it will be - it depends on the size of the first section in data region. It's linkers job to determine that, not mine.

 

I've temporarily "fixed" this issue by renaming .data section in linker file with ".mydata" which works. The issue with this is that avr-size doesn't report correct RAM usage in this case since it only counts .data, .bss and .noinit.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Can't you put, your stuff right at the beginning of .data? Otherwise the CRT will not init your objects.
.
The specs-device is introduced by gcc's self specs, dunno if you could bypass that. Maybe just use a small spec file to augment, that overrides the spec in question.
.
The ld scripts are emulation granularity, not per device. Hence data start must come from somewhere else.

avrfreaks does not support Opera. Profile inactive.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Just grab a copy of the linker script, add a few lines, add the linker script to your project and specify it as the one to use.

 

Add two lines to .data section in linker script-

 

     PROVIDE (__data_start = .) ;
    *(.mydata)
    *(.mydata.*)

 

add option to linker-

-Xlinker -script=avr5.xn

or whatever is needed

 

#include <avr/io.h>

__attribute((section(".mydata"))) char mydataArray[16];
char dataArray[16]={1};

int main(void) {
    mydataArray[0]=dataArray[0];
    for(;;){};
}

 

result from map file-

 

.data           0x0000000000800100       0x20 load address 0x00000000000000e8
                0x0000000000800100                PROVIDE (__data_start, .)
 *(.mydata)
 .mydata        0x0000000000800100       0x10 build/default/production/newmain.o
                0x0000000000800100                mydataArray
 *(.mydata.*)
 *(.data)
 *(.data*)
 .data.dataArray
                0x0000000000800110       0x10 build/default/production/newmain.o
                0x0000000000800110                dataArray

 

and the hex file (0xe8 = .data section lma address)

 

:1000E8000000000000000000000000000000000008
:1000F80001000000000000000000000000000000F7

 

Now if you didn't want 'mydata' initialized for some reason, then just put the added section names before the __data_start (mydata will still end up in flash, though).

Last Edited: Fri. Dec 13, 2019 - 08:28 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

curtvm wrote:

Just grab a copy of the linker script, add a few lines, add the linker script to your project and specify it as the one to use.

 

I thought I made it clear I'm using my own, custom linker script.

 

curtvm wrote:

Now if you didn't want 'mydata' initialized for some reason, then just put the added section names before the __data_start (mydata will still end up in flash, though).

 

Yeah, well, that's the entire issue. I don't want it to be in flash, and due to specs file overriding start of .data, this is impossible to achieve without resorting to dirty tricks, like renaming .data to something else.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Maybe I'm not seeing what you want to do or I don't get all the nuances.

 

Say my main.c is this:

char abc = 1;
char buf[64] __attribute__((section(".abcd")));

int main() { 
  while (1);
}

Then I copy the appropriate ldscript into my working directory as "custom.xn" and edit the .data section to add my custom "abcd" section:

 .data          :
  {
     PROVIDE (__data_start = .) ;
    *(.abcd)   /* <= added section */
    *(.data)

Now I compile, with and without the appropriate flags to show that my "buf" data is moved to the front.  I use the "-Wl" flag to specify the custom ldscript.  (The "-B" flag is to compile w/ device packs.)

$ make zz3.elf
avr-gcc -mmcu=atmega328p -DF_CPU=16000000UL -Os -I.. -I../../ -B/opt/local/avr/packs/mega-2.0.12 -o zz3.elf zz3.c
$ avr-nm zz3.elf | grep ' D '
00800102 D __data_end
00800100 D __data_start
00800102 D _edata
00800100 D abc
00800102 D buf

$ vi Makefile ; rm zz3.elf

$ make zz3.elf
avr-gcc -mmcu=atmega328p -DF_CPU=16000000UL -Os -I.. -I../../ -B/opt/local/avr/packs/mega-2.0.12 -Wl,-T,custom.xn -o zz3.elf zz3.c
$ avr-nm zz3.elf | grep ' D '
00800142 D __data_end
00800100 D __data_start
00800142 D _edata
00800140 D abc
00800100 D buf

Did I miss something?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I don't do refunds, but will give more free advice instead.

 

add __DATA_REGION_ORIGIN__ to linker script which is a weak symbol provided in the crt file
  data   (rw!x) : ORIGIN = __DATA_REGION_ORIGIN__, LENGTH = __DATA_REGION_LENGTH__

 

now there is no need for the specs file provided data region address, so remove/comment out in specs file (the one that is used, in its original location)-

#*link_data_start:
#    -Tdata 0x800100

 

now you are in a little more control as that Tdata option seems to be applied at some point where the linker provided origin may have already been used, is seems.

 

The above two changes, I suspect are supposed to be the norm now, but think its just something that was/is overlooked. From some other thread I get the impression the linker script origin thing is a known item on someone's todo list, but in the meantime its easy enough to correct if wanted.

 

add your special data section in linker script before .data section-
.mydata (NOLOAD): {
    *(.mydata)
    *(.mydata*)
} > data

.data    :
...

 

create a test program to verify-

__attribute((section(".mydata"))) char mydataArray[0x100]={1,2,3};
char dataArray[0x10]={4,5,6};

int main(void) {
    mydataArray[0] = dataArray[0];
    for(;;){};
}

 

and can see .mydata is used at start of data region, with .data section to follow-
Sections:
Idx Name          Size      VMA       LMA       File off  Algn
  0 .text         000000e8  00000000  00000000  00000094  2**1
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
  1 .mydata       00000100  00800100  00800100  0000018c  2**0
                  ALLOC
  2 .data         00000010  00800200  000000e8  0000017c  2**0

 

and the startup code looks right, as it starts from 0x0200 loading 0x10 bytes of data from flash (0x00E8 -> 0x200-0x209)-
000000b8 <__do_copy_data>:
  b8:    12 e0           ldi    r17, 0x02    ; 2
  ba:    a0 e0           ldi    r26, 0x00    ; 0
  bc:    b2 e0           ldi    r27, 0x02    ; 2
  be:    e8 ee           ldi    r30, 0xE8    ; 232
  c0:    f0 e0           ldi    r31, 0x00    ; 0
  c2:    02 c0           rjmp    .+4          ; 0xc8 <__do_copy_data+0x10>
  c4:    05 90           lpm    r0, Z+
  c6:    0d 92           st    X+, r0
  c8:    a0 31           cpi    r26, 0x10    ; 16
  ca:    b1 07           cpc    r27, r17

...

  

and .mydata is not getting into flash because of NOLOAD (would otherwise show up as VMA data in hex starting at address 0x800100)-
:0800E0000001FFCFF894FFCFEF
:1000E80004050600000000000000000000000000F9
:00000001FF

 

 

All sales are final.

 

I have no idea what the intention is, and don't really care that much, but I would suspect there is a better plan B. Sometimes there is not, and you just have muck around a bit in these areas like linker scripts.

Last Edited: Sun. Dec 15, 2019 - 01:28 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

curtvm wrote:

I don't do refunds, but will give more free advice instead.

 

Yeah, bingo. However, that's what I've done initially - commented out/removed Tdata from the original specs file - then the linker respected my data origin. Apparently, some other people had similar issues:

 

https://electronics.stackexchange.com/questions/408115/how-does-avr-gcc-linker-know-to-put-the-datasection-at-0x800100-rather-than/408283

 

The reason I don't want to do this (modifying toolchain file) is because my software is open-source, and I don't want to tell people to comment stuff out from the toolchain directory. I will conclude that 1) the only way to achieve what I want without touching toolchain files is to do what I've already done - rename .data to something else in my custom linker script and 2) specs overriding is broken. Silly, but what can you do. I remember doing this exact same thing on some other ARM microcontrollers via linker script and it just worked without any magical overriding of my values in linker file via some other mechanism.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You can use a custom specs file as follows:

 

*link:
  %(link_arch) %(link_data_start) %(link_text_start) %(link_relax) %(link_pmem_wrap) %{shared:%eshared is not supported}

and then use it with -specs=myspecs. As -v tells you, this specs are used after the built-in ones, but before device-specs/specs-<device>.  It overrides the link spec to what the avr backend sets it, i.e. the line above will have the same effect as if you didn't add a custom specs file.

 

However, you can define link spec to anything you want, in particular you can ditch the reference to link_data_start (which in turn IS defined by device-specs) but device-specs DO NOT define link spec itself, hence won't override it.

 

For the avr backend specs, cf.

 

https://gcc.gnu.org/viewcvs/gcc/...

 

 

avrfreaks does not support Opera. Profile inactive.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Learn something new every day. Some days are skipped, though.

 

That should wrap it up.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Shantea wrote:
It's frustrating that the avr-gcc is so insistent on this "magic".

GCC, eh?  Isn't the rant more appropriate on a support forum for that toolchain rather than the "general" forum?

 

 

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Shantea wrote:

I will conclude that 1) the only way to achieve what I want without touching toolchain files is to do what I've already done - rename .data to something else in my custom linker script

As pointed out in https://www.avrfreaks.net/commen... there are better solutions using a custom spec file.

 

Shantea wrote:

and 2) specs overriding is broken. Silly, but what can you do.

It's not broken, it works like with any other gcc incarnation.  It's just that the driver adds -specs no matter what, and because specs overriding *is* working, it will override specs from the command line :-)

 

Shantea wrote:

I remember doing this exact same thing on some other ARM microcontrollers via linker script and it just worked without any magical overriding of my values in linker file via some other mechanism.

The point is that arm-gcc does not come with support for (almost) each and every ARM device out there.  You can achieve the same level of convenience in avr-gcc by removing all specs-<device> files, all lib<device>.a files, all crt<device>.o files, all io*.h files, and start from there.  avr-gcc will still insist on injecting -specs=... though.

 

avrfreaks does not support Opera. Profile inactive.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

SprinterSB wrote:

avr-gcc will still insist on injecting -specs=... though.

Added -nodevicespecs option that works similar to -nodevicelib, but for -specs=device-specs/specs-<device>: It omits adding -specs to the driver's options which turns avr-gcc into a dumb program that knows mostly nothing about sub-processes like compiler proper, assembler, linker.

avrfreaks does not support Opera. Profile inactive.