[GCC] - Options for moving __flash (or PROGMEM)

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

Freaks,

 

I am >>certain<< that this must have been addressed before, but darned if I can find it.

 

I've got an application that uses -nostartfiles, with my own CRT in .init0.  I'd like to use either __flash or PROGMEM to avoid both SRAM usage and the linking of __do_copy_data.  Of course, when I have any __flash or PROGMEM entities in the source code, that gets linked at the beginning of the binary, before even .init0 where I have placed my own mini CRT, which means the data there will run as code after a reset.  Bad.

 

I know I can use -section-start= to explicitly locate a section to an absolute address, but what I want to do is just move __flash or PROGMEM to somewhere other than start of the binary, and let the linker decide the exact address that should be.  A good place in my view would be anywhere after .fini0, either before .data or after it, but it really doesn't matter much to me other than that.

 

I know that this would be possible by tickling my own custom linker script, but I currently know only enough linker-script-eese to get my face slapped at a party.  Is there another way?  If not, can anyone suggest a reasonable/correct approach for a custom linker script to achieve this?

 

Thanks.

 

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

Last Edited: Sat. Feb 29, 2020 - 06:31 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Just put a JMP in .init0 to jump over .progmem
.
Google "Github wrightflyer sdbootloader" to see how I did this.

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

clawson wrote:
Just put a JMP in .init0 to jump over .progmem

joeymorin wrote:
that gets linked at the beginning of the binary, before even .init0

 

I think you mean in .vectors?:

/*
** The following routine locates to the reset jump at the very start of the bootloader
** so is the first opcode executed at power on. The .vectors ensures (via the linker
** script) that it be positioned first. It is done like this (with an RJMP to "main")
** to ensure that any .progmem data (PSTR() debug strings) can be placed by the linker
** immediately after the reset jump.
**
** (this is all because -nostartfiles is being used to ensure no space is wasted with a
** C Run Time (CRT) including a full size vector table)
*/
__attribute__((naked,section(".vectors"))) void start(void) {
    asm("rjmp main");
}	

Thanks Cliff, that will do.

 

However I still wonder if there's a way of either specifying command-line options during the build, or using a custom linker script, to accomplish my goal without the need for a 2-byte rjmp.  Before anyone points out that 2 bytes is not much, I agree.  I'm not at the point of whinging about those two bytes (yet).

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

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

Sorry Joey, didn't realise it was you. So the only thing I can think of is a custom linker script and hence -Wl,-T

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

main can go in .vectors:

#include <avr/io.h>

const __flash char msg[] = "Hi";

__attribute(( used, section(".vectors") ))
void main(){
    char c;
    const __flash char * s = msg;
    while(c = *s++) PORTB = c;
}

I built with avr-gcc 5.4.0:

avr-gcc --std=gnu11 -nostartfiles -mmcu=attiny13 -DF_CPU=9600000 -Os -ffunction-sections -Wl,--gc-sections -flto -Wl,-flto   nocrt.c   -o nocrt

And here's what I get:

Disassembly of section .text:

00000000 <main>:
   0:   e0 e1           ldi     r30, 0x10       ; 16
   2:   f0 e0           ldi     r31, 0x00       ; 0
   4:   85 91           lpm     r24, Z+
   6:   88 23           and     r24, r24
   8:   11 f0           breq    .+4             ; 0xe <__zero_reg__+0xd>
   a:   88 bb           out     0x18, r24       ; 24
   c:   fb cf           rjmp    .-10            ; 0x4 <__zero_reg__+0x3>
   e:   08 95           ret

00000010 <__trampolines_end>:
  10:   48 69           ori     r20, 0x98       ; 152

 

I have no special talents.  I am only passionately curious. - Albert Einstein

 

Last Edited: Sat. Feb 29, 2020 - 09:38 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

ralphd wrote:
main can go in .vectors:
That looked promising, but I have my own CRT separate from main.  Previously, I had my CRT in .init0, and main in .init9.

 

Placing my CRT at .vectors doesn't save me anything because I would need an rjmp to get around .progmem, whereas .init0 falls through to init9.  I could look into integrating my CRT into main, but for the moment I want to keep them separate.

 

I tried to put both my CRT and main into .vectors, but the results were less than impressive.  The binary grew by 82 bytes.  I haven't sorted out why yet.

 

clawson wrote:
So the only thing I can think of is a custom linker script and hence -Wl,-T
This is where I risk getting my face slapped.

 

I haven't yet spent the time to learn the linker script syntax.  I'd hoped I'd be able to take a shortcut and just move the lines which place .progmem after .vectors to some other place.  I stumbled into it:

--- /home/joeymorin/Software/AVR_toolchain/avr8-gnu-toolchain-linux_x86_64.3.6.2/avr/lib/ldscripts/avr5.x	2018-07-25 05:07:59.000000000 -0400
+++ avr5.x	2020-02-29 19:07:03.114581599 -0500
@@ -86,21 +86,13 @@ SECTIONS
   {
     *(.vectors)
     KEEP(*(.vectors))
-    /* For data that needs to reside in the lower 64k of progmem.  */
-     *(.progmem.gcc*)
     /* PR 13812: Placing the trampolines here gives a better chance
        that they will be in range of the code that uses them.  */
-    . = ALIGN(2);
      __trampolines_start = . ;
     /* The jump trampolines for the 16-bit limited relocs will reside here.  */
     *(.trampolines)
      *(.trampolines*)
      __trampolines_end = . ;
-    /* avr-libc expects these data to reside in lower 64K. */
-     *libprintf_flt.a:*(.progmem.data)
-     *libc.a:*(.progmem.data)
-     *(.progmem*)
-    . = ALIGN(2);
     /* For future tablejump instruction arrays for 3 byte pc devices.
        We don't relax jump/call instructions within these sections.  */
     *(.jumptables)
@@ -162,6 +154,10 @@ SECTIONS
     KEEP (*(.fini1))
     *(.fini0)  /* Infinite loop after program termination.  */
     KEEP (*(.fini0))
+     *(.progmem.gcc*) . = ALIGN(2);
+     *libprintf_flt.a:*(.progmem.data)
+     *libc.a:*(.progmem.data)
+     *(.progmem*) . = ALIGN(2);
      _etext = . ;
   }  > text
   .data          :

I'm sure that this is a kludge, that I've introduced any number of issues by doing this, and that it only works 'by accident', but it's a start.

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

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

Well, that was all for naught.  I moved all of the static const storage into __flash, and linked correctly with my custom script, but the binary ends up being 4 bytes larger than with everything in SRAM.  Looks like the difference is up to the fact that, for one of the entities, I used memcpy but now must use memcpy_P.  The former was handled by the compiler, the former latter linked in from a library and slightly larger than __do_copy_data.  That, and some slightly inflated code involving lpm instead of SRAM.

 

Ah well.  When I need to at least now I know how achieve this for future projects.

 

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

Last Edited: Tue. Mar 3, 2020 - 01:01 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

How much space are you trying to save and from how big a total?

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

I'm not sure I follow. Why can't your own CRT go in .vectors? Ultimately it will CALL main which will jump over the .progmem. that's what you want isn't it?

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

clawson wrote:

Previously, I had my CRT in .init0, and main in .init9.

 

Joey said, " Previously, I had my CRT in .init0, and main in .init9. "

So CRT would fall through to main without any call.

 

I have no special talents.  I am only passionately curious. - Albert Einstein

 

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

Yeah but it's kind of traditional to put main() in .text ;-)

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

andrewm1973 wrote:

How much space are you trying to save and from how big a total?

I wanted to know how to manipulate link order, specifically for moving PROGMEM somewhere else, as it seemed a more elegant way to overcome the issues introduced by -nostartfiles.

 

I did wonder how much space I could save by moving some entities from SRAM into __flash, but this is exploratory at the moment.  So far, it turns out that the flash savings are negative.  The only benefit is reduced SRAM usage.

 

In any event, my primary question has been answered, I now know enough about linker scripts to cause trouble ;-)

 

I won't mark this as solved, though, as further discussion is welcome.

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

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

clawson wrote:

Yeah but it's kind of traditional to put main() in .text ;-)

It's also tradition to have a vector table and a CRT ;-)

 

Besides, >>you're<< one to talk:

__attribute__((section(".init3"))) int main(void) {

;-)

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

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

I think what is wanted can be accomplished without resorting to a custom linker script.

If you are using PROGMEM, and no library function is using data in flash,

you can probably just redefine PROGMEM to use .fini9 .

If you are using __flash or otherwise lack control over the section used,

avr-objcopy might be of use.

Link with -r .

That will prevent assigning of number to symbols.

Use avr-objcopy to rename .progmem* sections to .fini9 .

Link the result without -r .

Iluvatar is the better part of Valar.

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

skeeve wrote:

If you are using PROGMEM, and no library function is using data in flash,

you can probably just redefine PROGMEM to use .fini9 .

Wouldn't that require editing avr/progmem.h, or at least making a local copy?  That seems less desirable than a custom linker script.

 

skeeve wrote:

If you are using __flash or otherwise lack control over the section used,

avr-objcopy might be of use.

Link with -r .

That will prevent assigning of number to symbols.

Use avr-objcopy to rename .progmem* sections to .fini9 .

Link the result without -r .

Likewise, this seems more convoluted than a custom linker script.

 

However, I may have misunderstood you...

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

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

What is desirable depends partly on how much one likes or dislikes a custom linker script.

So far as PROGMEM is concerned, you don't need to #include <avr/progmem.h>/

Use "progmemcustom.h" instead.

#define it in a local header file.

With the right gcc options, one could make gcc find a local

copy of <avr/progmem.h> without changing the source code.

 

I generally try to avoid custom linker scripts.

I won't claim the reasons are entirely rational.

Linker scripts have an aura of magic about them,

at least partly because we rarely see them.

Changing a linker script known to work might not inspire confidence.

The steps in three-step linking are fairly clear.

Iluvatar is the better part of Valar.

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

 

joeymorin wrote:

clawson wrote:

 

Yeah but it's kind of traditional to put main() in .text ;-)

 

It's also tradition to have a vector table and a CRT ;-)

 

 

Besides, >>you're<< one to talk: ...

 

 

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

skeeve wrote:

I generally try to avoid custom linker scripts.

I won't claim the reasons are entirely rational.

Linker scripts have an aura of magic about them,

at least partly because we rarely see them.

Changing a linker script known to work might not inspire confidence.

Quite precisely captures my own concerns.
skeeve wrote:
The steps in three-step linking are fairly clear.

Not to me ;-) ... At least, not at the moment. I've bookmarked this thread for the the next time I feel I need to move PROGMEM.

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

Last Edited: Mon. Mar 2, 2020 - 03:21 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

joeymorin wrote:
Not to me ;-) ... At least, not at the moment. I've bookmarked this thread for the the next time I feel I need to move PROGMEM.
By clear, I meant ease of reading, not necessarily writing.

For example, a needed option on avr-objcopy is --rename-section .

The linker option -r is the same as --relocatable , which should probably be used instead of -r .

Hard to write is not the same as hard to read.

All that said, sometimes the answer is whatever makes one the least nervous.

Iluvatar is the better part of Valar.