I would like to specify that certain data be located in Flash at a
particular address. For functions, I see that I can use the
_attribute_ capabilities to do this. It doesn't work for constants.
I have been trying to accomplish this primarily using the linker, but
the linker needs to see my data items in a distinct section (so far as I
can tell).
I started with the atmel-rom.ld file available in the lwIP demos, as my
application is based on them. I changed the top of the file to:
MEMORY
{
flash : ORIGIN = 0x00100000, LENGTH = 0x3F000
fixed : ORIGIN = 0x0013F000, LENGTH = 0x1000
ram : ORIGIN = 0x00200000, LENGTH = 64K
}
However, in order to make this work, I have to tell the linker which
modules go into the "fixed" section.
A standard declaration such as
const unsigned char ieee_mac[6] = {
0x00, 0x30, 0x86, // Our IEEE OUI number
OUI_MINE, // This product's code
0xFF, 0xFF}; // Assigned by chip burner
is always going into .rodata, even though I may put an asm (" .section
fixed") before it.
I realize I could accomplish this brute-force using the same method as
the declarations found in at91sam7x256.h (i.e, #define AT91C_PIOB_MDER
((AT91_REG *) 0xFFFFF650) ) but I would prefer something slightly
more elegant.
Any ideas?
Thanks.
Andy
A solution came to mind on the way to work. It takes several steps to explain, but in summary what I did was use inline assembly code for the particular constant instead of using just C. First, I added a line to my compiler flags to cause them to generate the assembly .lst file: -Wa,-adhlns=$(subst $(suffix $<),.lst,$<) \ (tacked onto the CFLAGS definition). Next, I did a make. This created .lst files for everything. The ones I needed I kept, the others I deleted. I edited those lst files to produce true ASM code. I could have put these into the makefile as assembly source, but I chose instead to embed them into the appropriate .C files. For instance, the declaration above > const unsigned char ieee_mac[6] = { > 0x00, 0x30, 0x86, // Our IEEE OUI number > OUI_MINE, // This product's code > 0xFF, 0xFF}; // Assigned by chip burner is now commented out, and the comparable assembly is inserted as a series of C asm() statements as shown below: // const unsigned char ieee_mac[6] = { // 0x00, 0x30, 0x86, // Our IEEE OUI number // OUI_MINE, // This product's code // 0xFF, 0xFF}; // Assigned by chip burner asm (" .global ieee_mac"); asm (" .section .fixed"); asm ("ieee_mac:"); asm (" .byte 0"); asm (" .byte 48"); asm (" .byte -122"); asm (" .byte 16"); asm (" .byte -1"); asm (" .byte -1"); Next, I had to update the linker file. I did it by inserting the .fixed section as the first one, then allowing it to work its regular stuff from there. MEMORY { flash : ORIGIN = 0x00100000, LENGTH = 0x3F000 fixed : ORIGIN = 0x0013F000, LENGTH = 0x1000 ram : ORIGIN = 0x00200000, LENGTH = 64K } _stack_end_ = 0x00200000 + 64K - 4; SECTIONS { . = 0x0013F000; .fixed : { _fixed_beg_ = .; *(.fixed) _fixed_end_ = .; } >fixed . = 0; startup : { *(.startup)} >flash ... I hope this helps others. Andy
Just an additional suggestion: Did you check the gcc variable-attribute
section (see gcc-manual)? The (inline-)assembler-code can be avoided by
assigning a inititialized constant C-structure/array to a
"linker"-section using the section-attribute.
I have just done some AVR-code with avr-gcc which uses this method. I
have not tried the method on an ARM with arm-elf-gcc so far but it
should work with every "GNU-toolchain".
The basic idea:
unsigned char data_table_fixed[] _attribute_ ((section
(".fixed_table"))) =
{ 0xaa, 0x55, 0xff, 0x00 };
For AVR I have used the default linker-scripts (provided by the
toolchain/avr-libc) and just passed the section-address as parameter to
the linker:
LDFLAGS += -Wl,--section-start=.fixed_table=0x2000
But of cause you could use a "DIY" linker-script the way you have
already implemented it.
I checked the locations and contents in a disassembly created with this
target in the makefile:
%.lss: %.elf
[TAB] $(OBJDUMP) -D -h -S -C $< > $@
Remark on your linker-script: If you declare an extra MEMORY area for
"fixed" the line . = 0x0013F000; should not be needed. Did you try to
link without this line in the linker-script?
Martin Thomas
Thanks for the reply, Martin. > Just an additional suggestion: Did you check the gcc variable-attribute > section (see gcc-manual)? The (inline-)assembler-code can be avoided by At the time I did this, I had not found the attributes for variables section yet. Use of the attribute on the variable would have been much more elegant. > Remark on your linker-script: If you declare an extra MEMORY area for > "fixed" the line . = 0x0013F000; should not be needed. Did you try to > link without this line in the linker-script? The reason for the separate section is because we will be putting a bootloader into the same area eventually. I do not want the possibility of application code being in the same region - I would prefer to have the linker tell me I ran out of memory first. I appreciate all you've done with this work. Your examples have been very helpful in understanding how to approach solutions to problems in several areas. Andy
Martin, I just implemented the code according to your example and it works fine. The extra MEMORY line is to force a specific load address for the data. It will be in a protected portion of memory shared with the bootloader. I didn't see another way to force it to the exact address I wanted. Thanks. Andy
Please log in before posting. Registration is free and takes only a minute.
Existing account
Do you have a Google/GoogleMail account? No registration required!
Log in with Google account
Log in with Google account
No account? Register here.