I'd say I'm decent in C++, however I'm very new to linker scripts and I'm not quite sure what I'm doing wrong. First off all, this is my linker script:
ENTRY(ISR_Reset)
MEMORY {
FLASH (rx) : ORIGIN = 0x80000, LENGTH = 128K
RAM (rwx) : ORIGIN = 0x20000000 LENGTH = 36K
}
SECTIONS {
.text : {
*(.vector_table)
*(.text.startup)
*(.text)
*(.rodata)
} > FLASH
__data_flash_source__ = ALIGN(4);
.data : AT(__data_flash_source__) {
__data_section_start__ = .;
*(.data)
*(.init_array)
__data_section_end__ = .;
__ram_end__ = ORIGIN(RAM) + LENGTH(RAM);
} > RAM
.bss : {
*(.bss)
} > RAM
}
I copy the data from FLASH to RAM between __data_section_start__
and __data_section_end__
, then I zero out the rest of the RAM.
I'm using the following command to compile my code:
arm-none-eabi-g++.exe .\src\start.s .\src\main.cpp -o .\bin\main -nostdlib -ffreestanding -fno-exceptions -nostartfiles -T .\src\sam3u2e.ld -mthumb -pedantic -Wall -std=c++17 -ggdb -Ofast
If I remove the -Ofast
flag, and don't use any optimisation I get the following linker error:
section .text._ZN4_PMCC2Ev LMA [0008019c,000801bf] overlaps section .data LMA [0008019c,0008019f]
However if I do include it it compiles just fine, but when I try to initialise structs like so:
struct Example {
unsigned int const ID;
unsigned int volatile & some_register;
Example(unsigned int const id, unsigned int const register_address) : ID(id),
some_register(*((unsigned int volatile *)register_address)) {}
} instance(0x12345678, 0xDEADBEEF);
I notice in the disassembly that the address of instance.some_register
is stored in FLASH, right after the main()
function, but it doesn't seem to get referenced by any code even when writing to it like so:
instance.some_register = 1234;
The instance.ID
, however, is being loaded from RAM, but from a higher address than the size of .data
, which means it never gets copied from FLASH to RAM. But if I change the location of .bss
from > RAM
to > FLASH
it tries to load the instance.ID
from FLASH, which I don't understand, because the ID should be in .rodata
anyway.
Furthermore I notice that even if I don't reference the struct at all in the code other than defining it that the address is still located in FLASH, I wonder if it'd be possible to tell the linker to not include code for initialised structs that aren't referenced anywhere?
EDIT: Linker sections:
as you can see the .data section (that gets copied into RAM) is only 4 bytes in size.
However the assembly tries to load instance.ID
and the address of instance.some_register
from RAM ---that's higher than 0x20000004, which confuses me, because those values should be read-only anyways and therefore stored in flash?
EDIT 2: I probably wasn't clear enough in what I want the code to do. I'll try explaining again. I want to define a set of different structs, each of them would have different variables. Each variable references a device register (by setting the pointer of the variable to the address of the corresponding register). So when the user would write to those registers, for example: peripheral.some_register = 123;
the value would be written to the actual physical register.
In the compiled (optimised) code I don't really want these structs to exist, so the CPU wouldn't need to deal with initialising data, and would instead just see it as a collection of pointers to different peripheral registers. Since it would be read-only data it could also be located in FLASH and so wouldn't need to use up any RAM.
I'm guessing that means I mustn't use constructors, as that would then mean the CPU will need to initialise them, even though the data is, again, read-only. The user also won't need to create his own instances of the structs, in case that helps with anything.
I initally wanted to use constructors because there are some peripherals with over 50 registers each, that have the same offsets per peripheral, but different base addresses, so I was hoping to save myself some work by not needing to copy paste the same address for each register and add a number to it.
So there are a few things going on here. Let me try to tackle them with my also limited knowledge of linker scripts.
.text._ZN4_PMCC2Ev
is typically due to an issue of lacking entries in the linker script. In this case you don't have a place for .text.*, so I would suggest you try to add *(.text.*)
instance.some_register
would not be a symbol. Usually it would be loaded as an offset from the program counter. However, this will depend on how instance
is allocated.instance.ID
is constant, instance
isn't. I would thus not expect that to be located in .rodata
.User contributions licensed under CC BY-SA 3.0