Reputation: 1013
I am working on converting a ARMv7 project.
The tools are Code Compose Studio, and GNU 7.3.1 compiler. These cannot change.
The program entry point is 0x8000 0000 and cannot change.
The entry point is in an assembler files named init.s and the label is "Entry"
There will be hundreds of files in this project.
I have hit a road bump trying to get the assembler label set to the correct address. I have been manipulating this dozens of ways, and here are some examples: I can't promise that I didn't get a few of these attempts mixed up. But nothing is working.
First, the conventional linker script:
{
.text :
{
*(.text*)
} > DDR0
(This is the first entry in the section, location counter hasn't been touched, and DDR0 is defined as 0x80000000 so the location counter should be set to that)
Ok, so everything that in .text is included. I notice the Entry is not where I need it, it is not at the starting address of 0x80000000:
*(.text*)
.text 0x80000000 0x190 ./CAThread.o
0x80000000 CAThread::~CAThread()
0x80000000 CAThread::~CAThread()
0x80000004 CAThread::CAThread()
0x80000004 CAThread::CAThread()
0x80000084 CAThread::Run()
0x80000174 CAThread::StartThread(void*)
.text 0x80000190 0xb4 ./init.o
0x80000190 Entry <----- WRONG LOCATION
.text 0x80000244 0x194 ./main.o
The IDE is placing the object files in sorted order (and also recursive through sub directories). And I can't control that.
I tried a dedicated section, but that failed
{
.entryPoint : {
*(.Entry)
} > DDR0
.text :
{
*(.text*)
} > DDR0
The new section is in the map file, but does NOT have any address, nor any size
*(.Entry)
.text 0x80000000 0x9484
*(.text*)
.text 0x80000000 0x190 ./CAThread.o
0x80000000 CAThread::~CAThread()
0x80000000 CAThread::~CAThread()
0x80000004 CAThread::CAThread()
0x80000004 CAThread::CAThread()
0x80000084 CAThread::Run()
0x80000174 CAThread::StartThread(void*)
.text 0x80000190 0xb4 ./init.o
0x80000190 Entry
.text 0x80000244 0x194 ./main.o
I tried the documented method of setting an absolute address, but that is failing on all accounts. Apparently this version does not understand the syntax, and is ignoring it.
SECTIONS
{
.entryPoint 0x80000000 : {
KEEP(*(.Entry))
}
.text 0x80000000 :
{
*(.text*)
}
I get an error about missing sections. So that I go back to using the trailing > DDR0 syntax.
Next up, I try placing a section name in the assembler file:
@**************************** Code Seection ***********************************
.text
.entryPoint @ ADDED THIS
@ This code is assembled for ARM instructions
.code 32
Entry:
LDR r0, =_stack @ Read the stack address
MSR cpsr_c, #MODE_UND|I_F_BIT @ switch to undef mode
Now I can see in the object dump that the label is in the section name I want it in, and is no longer .text
00000000 l d .debug_aranges 00000000 .debug_aranges
00000000 l d .ARM.attributes 00000000 .ARM.attributes
00000000 g entryPoint 00000000 Entry
00000000 *UND* 00000000 _stack
Still... No change. The section is not there, and now the "init.o : Entry" is gone from the location in the map file. I did find it in the map file, at address 0, with a correct length. So it's there, but not where it's told to be.
So now I get aggressive, and try to tell the linker script EXACTLY what I want and where.
{
KEEP(*(.Entry))
init.o(entryPoint.Entry)
} > DDR0
.text :
{
*(.text*)
} > DDR0 ```
And the result is now an error that says:
```(entryPoint+0x0): multiple definition of `Entry'
./init.o:(entryPoint+0x0): first defined here
Where "here" is the same location. I have to assume that the cryptic statement *(.text*)
is telling it to just drag in every piece of text into the output. So 'Entry' is getting added twice (I haven't found any doc that explains how all the wildcards in *(text*)
are interpreted, nor what those are parenthesis around some of these mean ).
When I tried to explicitly set the location counter to the start address:
{
. = 0x80000000;
KEEP(*(.Entry))
init.o(entryPoint.Entry)
} > DDR0
I received the error:
cannot move location counter backwards (from 80000000 to 00000000)
Unless my math is wrong, moving from an initial location counter of 0 to 0x80000000 is actually moving forward...
Because there will be hundreds of files, and the project evolves, I cannot expect to be manually adding all the individual object files to the linker script. I haven't even tries that at this point, because it's already not worth the effort due to its size. It would be nice if I could tell it to leave out the "init.s" file from the .text section of the linker script, so it could be in it's own .entryPoint section.
But it would be nicer if the linker script actually behaved according to the doc. But it's refusing to place this one single label in it's own section, at the specific address I am trying to use.
Any ideas or suggestions how to accomplish this?
Is it somehow related to the assembler file "init.S" (because it's not a C file)?
EDIT: More Info. This is getting more insane...
I added a section to the assembler file. Apparently it needs a leading dot:
@**************************** Code Section ***********************************
.text
.section .entry
.code 32
Entry:
LDR r0, =_stack
So my linker script is this:
SECTIONS
{
.entry :
{
KEEP(*(.entry)) /* Keep entry here. */
} > DDR0
.text :
{
*(.text*)
KEEP(*(.init))
KEEP(*(.fini))
/* .ctors */
*crtbegin.o(.ctors)
*crtbegin?.o(.ctors)
/* *(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors) */
*(SORT(.ctors.*))
*(.ctors)
/* .dtors */
*crtbegin.o(.dtors)
*crtbegin?.o(.dtors)
/* *(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors)*/
*(SORT(.dtors.*))
*(.dtors)
*(.rodata*)
KEEP(*(.eh_frame*))
} > DDR0
.ARM.extab :
{
*(.ARM.extab* .gnu.linkonce.armextab.*)
} > DDR0
One would think, according to all all the doc I can find, that now the .entry section would be first, and the .text section would be at address after it.
And yet... This is the map file generated:
.entry 0x80000000 0xb4
*(.entry)
.entry 0x80000000 0xb4 ./init.o
0x80000000 Entry
.text 0x80000000 0x9554
*(.text*)
.text 0x80000000 0x190 ./CAThread.o
0x80000000 CAThread::~CAThread()
0x80000000 CAThread::~CAThread()
0x80000004 CAThread::CAThread()
0x80000004 CAThread::CAThread()
0x80000084 CAThread::Run()
0x80000174 CAThread::StartThread(void*)
.text 0x80000190 0x180 ./main.o
0x80000190 ConsoleTask(void*)
0x800001c8 main
It correctly placed the .entry section at address 0x80000000, then proceeded to OVERWRITE THAT SECTION with the object code from .text
And yet... It is correctly placing those .ctors and .dtors after the .text And the There are other sections AFTER this which are correctly placed after the .text.
What is causing it to think that the section .entry can be overwritten?
Upvotes: 2
Views: 2365
Reputation: 1013
After digging more I have found there are attributes necessary to the section command in the assembler file. (assembler is still a learning exercise)
It is necessary to append flags to the section telling it the purpose.
@**************************** Code Section ***********************************
.text
.section .entry, "ax" @ Attributes of the section
.func Entry
https://ftp.gnu.org/old-gnu/Manuals/gas-2.9.1/html_chapter/as_7.html
These define the section as allocatable and executable. I did a object dump for no flags, a only, and ax. These are the reports:
Without attribtes: CONTENTS, RELOC, READONLY
Allocatable : CONTENTS, ALLOC, LOAD, RELOC, READONLY, DATA
Alloc + Exec : CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE
Adding the 'a' only was enough to properly allocate the section, although including 'x' wisely marks the memory as code. The map file output:
.entry 0x80000000 0xb4
.entry 0x80000000 0xb4 ./init.o
0x80000000 Entry
.text 0x800000b4 0x9554
*(.text*)
.text 0x800000b4 0x190 ./CAThread.o
0x800000b4 CAThread::~CAThread()
0x800000b4 CAThread::~CAThread()
0x800000b8 CAThread::CAThread()
0x800000b8 CAThread::CAThread()
0x80000138 CAThread::Run()
0x80000228 CAThread::StartThread(void*)
.text 0x80000244 0x180 ./main.o
(For CAThread, the destructor is just empty)
At this point the actual entry point is correctly set, and the program is loading and executing properly on the target MCU.
If someone else runs into this issue, I hope it helps them. It was certainly an education.
Upvotes: 2