I don't have much experience with linker scripts, so maybe I'm just misunderstanding something here. The LD linker script for the ATmega32u4 (avr5.x) specifies that data memory (SRAM) starts at 0x800060. I know that 0x800000 is just a special offset that the compiler uses for SRAM pointers, but why use 0x60 as the base of RAM? The ATmega32u4 datasheet shows that 0x60 is the start of external I/O registers and that SRAM actually starts at 0x100. Doesn't that mean the external I/O registers will be clobbered when the .data section is copied into SRAM?
Apparently, this is something GCC accounts for if you invoke avr-ld through it. GCC overrides the virtual address of the .data section depending on what you passed to -mmcu=. If you link with avr-ld directly, the .data section is at the default 0x800060.
Related
I have to produce an ELF binary with gcc from a Hello World-program written in C, where the mem size equals the file size in all LOAD-segments of the ELF file. My experience says me, that I can prevent this if I move .bss into .data in a custom linker script. But in my case, I want to achieve this without a custom linker script.
Is there a way I can force all LOAD-segments to have the same file size as mem size with an option for GCC?
Background: I'm working on enabling Linux binaries on a custom OS. The ELF-Loader so far is pretty basic and testing/developing will be much simpler, if I just can map the ELF as it is (as long as all LOAD-segments are page-aligned)..
For completeness, I provide the solution that includes a dedicated linker script. The relevant excerpt is the following:
.data ALIGN(4K) :
{
*(.data .data.*)
/* Putting .bss into the .data segment simplifies loading an ELF file especially in kernel
scenarios. Some basic ELF loaders in OS dev space require MEMSIZE==FILESIZE for each
LOAD segment. The zeroed memory will land "as is" in the ELF and increase its size.
I'm not sure why but "*(COMMON)" must be specified as well so that the .bss section
actually lands in .data. But the GNU ld doc also does it like this:
https://sourceware.org/binutils/docs/ld/Input-Section-Common.html */
*(COMMON)
*(.bss .bss.*)
} : rw
It is important that the output section is not called ".bss" and that
the section contains more than just ".bss". Otherwise, the "FILESIZE != MEMSIZE" optimization is done where the ELF loader needs to provide zeroed memory.
I have an embedded system with flash storage. The program is stored in flash. I have a function that calculates the checksum of the .text section of flash where my non volatile code is stored. I would like to compare the computed checksum with a value fixed and known at compile time stored in flash. I made a new flash section in the linker. I want to fill it with 0xABCD, which is the checksum. How can I do this in the linker? The compiler is GCC
The code that you are check-summing is generated by the linker, so getting the linker to generate it directly in one pass is not possible.
A simpler approach perhaps is to simply reserve the checksum storage area in the linker script unprogrammed (0xFFFF) and the add then calculate and add the checksum post-link using a tool such as the SRecord utilities. Essentially doing what your PROM burner (mentioned in comment) used to do.
Let's focus only on Rect_IsEmpty() function.
The nm command gives me this output:
(...)
00021af0 T Rect_IsEmpty
(...)
On the other hand, when I launch gdb and see the address of this function, I get:
(gdb) info address Rect_IsEmpty
Symbol "Rect_IsEmpty" is at 0x8057c84 in a file compiled without debugging.
Could anyone, please, explain why these addresses are not the same? Where does gdb get this address from?
nm gives you mangled name symbol table's address offset while gdb gives you actual virtual process's memory address which is changed every time you run the process. (Before run or start in GDB, it uses the same method as nm to get symbol addresses, using the same placeholder base address in PIE executables.)
nm is just a tool which shows you offset from the beginning of the code segment. In your case:
00021af0 T Rect_IsEmpty
simply means, that the symbol Rect_IsEmpty would have address 00021af0 if the executable were mapped at an image base of 0x1000, a dummy placeholder value that ld uses by default when linking a PIE. Normally the code segment is first with .text at the start of that, so the start of it will show an address of 0x1000 in nm or objdump -d.
When running a Position-Independent Executable on Linux, the ASLR mechanism is used for randomizing the base addresses of the whole thing, to something other than 0x1000. (Segments keep the same relative offset from each other, so PC-relative addressing can work, e.g. for x86-64 RIP-relative addressing of .data and .rodata from .text.)
GDB disables actual randomization, but the kernel still uses a high base address, not 0x1000. It will be the same one every time.
(If you built a traditional non-PIE executable, the kernel would have no choice where to load it, it would be the linker's choice, for example at 0x400000, which nm and objdump can see, as could GDB without starting the program. gcc -fno-pie -no-pie if you want that.)
When looking up the address of the function using debugger, you see the address of a symbol inside the process' code segment after having ASLR already done its job.
Here is a good article from IBM about shared libraries and another one about Procedure Linkage Table and Global Offset Table.
The executable will start at different memory locations, making any allocation within it different. Any function will therefore have different memory addresses from it's prior execution.
Regarding your question GDB gets the address from the debug information - it will show the absolute memory address.
I'm writing bare-metal C software for the ARM Cortex-M3 microcontroller STM32F4 using Em::Blocks IDE.
Here's the content of the startup_stm32f429x.S file which is included with the IDE.
At line 169 to 192 you see that the .data section is filled with the initial values.
At line 199 it is branching to the _start symbol, which is defined in crt0.s file of my GCC toolchain
At line 211 to 223 is providing it's own code for clearing the .bss section. (Here, _start is defined again, but weak. Hence this code is only active in case the _start symbol wasn't defined anywhere else.)
My questions are:
Why is the startup file providing code for initializing .data and clearing .bss? I thought that's the job of crt0.s?!
As I mentioned, the code for clearing .bss seems only to be active in case crt0.s is missing.
This sounds like crt0.s could be missing sometimes. Why would crt0.s be missing? Why can't you rely on it being available? Under which circumstances would it be missing?
Why is, in contrast to that, the initialization of the .data section always active, independently of crt0.s being available or not?
Update
I've just read, that setting up the exception vectors is another thing crt0.s is responsible for. So again: Why is this in my startup file done at line 41 to 151?
exactly because you don't want to use gcc's crt0 on a bare-metal microcontroller, if you don't need its functionality. If you don't use crt0, then you'll have to do it yourself.
I am programming an ARM Cortex-R4 and I have a few binary files that I'd like to execute them from TCRAM, just to see if the increase in performance is good enough.
I know I'd have to write a function to copy the binaries to the RAM (which can be accomplished with the linker script, and knowing the size of the binaries). But how would they run?
Imagine this: The first binary has func1(), func2(), func3() and func4(). I'd copy the entire module to TCRAM and how would I call a function there? I'd have to use a function pointer to that specific function? And what if func4(), calls func2() and func3()? If I'm not mistaken they'd point to the piece of code located in the flash. Does that mean I'd have to re write those funcs? Use entirely function pointers? I've been told that just the linker script is enough to do all of this and I needn't worry about anything, but I still don't understand how it works.
On GCC: Just put the function in the .data section:
__attribute__( ( section(".data") ) )
It will be copied over with the rest of your initialzed variables by the startup code (no need to mess with the linker scipt). You may also need a "long_call" option as well if the function ends up "far away" from the rest of the code after being placed into RAM.
__attribute__( ( long_call, section(".data") ) )
Example:
__attribute__( ( long_call, section(".data") ) ) void ram_foobar (void) { ... }
You may get an compiler warning that can be safely ignored:
Warning: ignoring changed section attributes for .data
You have two options.
Copy them as you suggest, compile with pc relative.
Use a linker file with a different load/run address.
A simple copy will only work if the routines do not use any absolute addresses. It maybe fine if they do use the absolute address as I guess you are going to leave a copy in standard RAM. However, this may not get the full benefit of the TCM.
With a linker script, you can specify a different LOAD and RUN locations.
sections {
.text { *(.text); } >FLASH
.tcm {
*(.tcm);
} >TCM_MEM AT>FLASH
.data { *(.data); } > RAM
.bss : NOLOAD { *(.bss); } > RAM
}
Note especially AT>FLASH.
See also: gnu linker map file... and many more on stackoverflow. The Gnu Ld manual has information on LMA sections (LOAD address). Your LMA would be flash, but the VMA (RUN address) would be TCM. The manual link above also shows how to copy. The RAM, FLASH, and TCM_MEM are defined with ld MEMORY information, depending on the addresses are for your board. All of this will be documented in a MAP file. Be sure to generate a MAP file and examine the addresses to double check your ld script.
The 2nd case also requires a copy (at start-up or at least before the first TCM function use). However, the compiler can use absolute addresses and they will be in the TCM memory. Also any function within the main DRAM can call the TCM function directly. With the first case, you must use function pointers to call the TCM code. If you wish global variables to be placed in this memory, you can use attributes to put them in different sections and use gnu ld to place them appropriately. I think there is ITCM and DTCM? So maybe this doesn't apply for you, or you need two sections.
The linker script is more generic and will work best if you put complicated functionality in the TCM. Just using -fpic, etc and copying may get things working quickly, especially if you only have a single pure function.
Nowadays (then-a-days as well?) you can just use the macro __RAM_FUNC, __RAMFUNC_EXT(bank, name) or __RAMFUNC(bank)