How can I relocate firmware for stm32? - linker

I have built firmware for stm32f4, so I have *.elf an *.bin files. If I load *.bin file into internal flash it runs correctly. But if I want load this firmware to another address different from default (0x08000000) and run it from my bootloader, of course it does not works. I fix memory area address in project settings (I use CooCox 1.7.6 if it matter) and it begins runing from the bootloader.
I don't want rebuild project every time I load firmware in standalone mode or using bootloader. So I'm looking for method that will allow me to make *.bin files from *.elf, which will be able to load from the different addresses.
I tried manualy interupt vector table fixing. It allow me to run small blinker project but it doesn't work for more complex projects. I must be missing something.
Then I tried objcopy with --change-addresses but unfortunately it doesn't work. I get the same file without any difference.
I think, it is a general problem and there are solution for it but I must be missing something important.

You have to compile your code as position independent. See the -fpic and -fPIC options of gcc. Or you need a loader that understands the relocation table of the ELF image.

I just happened to complete an odyssey on STM32 Cortex-M4 (and M0) with Position-Independent Code firmware images operated by a bootloader. I will give you and overview and link the full article below. My evaluation board is NUCLEO-L432KC with target MCU STM32L432KCU6U. The magic goes like this:
On high level, there are couple of things needed:
A very simple bootloader. It only needs to read 2 4-byte words from the flash location of the firmware image. First is stack pointer address and second is Reset_Handler address. Bootloader needs to jump to Reset_Handler. But as the firmware is relocated further in the flash, the Reset_Handler is actually a bit further. See this picture for clarification:
So, bootloader adds the correct offset before jumping to Reset_Handler of the firmware image. No other patching is done, but bootloader (in my solution at least) stores location and offset of the firmware image, calculates checksum and passes this information in registers for the firmware image to use.
Then we need modifications in firmware linker file to force the ISR vector table in the beginning of RAM. For Cortex-M4 and VTOR (Vector Offset Table Register) the ISR vector table needs to be aligned to 512 boundary. In the beginning of RAM it is there naturally. In linker script we also dedicate a position in RAM for Global Offset Table (GOT) for easier manipulation. Address ranges should be exported via linker script symbols also.
We need also C compiler options. Basically these:
-fpic
-mpic-register=r9
-msingle-pic-base
-mno-pic-data-is-text-relative
They go to C compiler only! This creates the Global Offset Table (GOT) accounting.
Finally we need dedicated and tedious assembly bootstrap routines in the firmware image project. These routines perform the normal startup task of setting up the C runtime environment, but they additionally also go and read ISR and GOT from flash and copy them to RAM. In RAM, the addresses of those tables pointing to flash are offset by the amount the firmware image is running apart from bootloader. Example pictures:
I spent last 6 months researching this subject and I have written an in-depth article about it here:
https://techblog.paalijarvi.fi/2022/01/16/portable-position-independent-code-pic-bootloader-and-firmware-for-arm-cortex-m0-and-cortex-m4/

I do not think so that would work well in your case because when you are compiling the file to run with boot loader, you also needs to make sure that Interrupt vector also have been moved to the new location else there will be a problem in executing some of the functions.

Related

Where do you load the .text segment in an a.out file to

I am trying to use the a.out format for my bootloader and I recall being able to do it in the past. ELF doesn't support 16 bit very well and produces a lot of undefined behavior when linked with C code. I am using BCC/dev86 to compile the code. The problem I'm having is finding any documentation on to where in memory you are supposed to place the text segment on a position-dependent 8086/real mode a.out file. It's in the header where the entry point is but I am unable to locate any sort of documentation of the loading of an a.out. Any help would be much appreciated
Usually, the first part of a bootloader (the 16 bit part) is written in assembly. This is mainly because a bootloader needs to do such low level tasks that using c is not really worth it. Once the bootloader gets itself to protected or long mode, it can use c. Another reason why using c is a bad idea for a bootloader is that a bootloader's task usually is to get the system into a state in which the kernel can start executing. On x86 this usually means going to protected mode. This involves linking some 16bit c code to some 32 bit c code (and maybe even some 64 bit code). This is really hard to do.
If you really think you want to continue with what you're doing: an a.out file is just an elf file. In bootloaders the cpu starts execution at address 0x7c00. So I suppose you should link the .text section to 0x7c00.
One more comment Id like to make, is that on modern cpus you don't even need to worry much about how to get sections from an a.out file. Usually UEFI can just boot elf files directly. And Qemu can as well.

GCC: Specify target address for actual symbol

knowing that similar questions have been asked a few times already, let me just explain what I'm trying to do and why: I have an embedded system which consists of an ARM Cortex-M4 microcontroller and an FPGA. The FPGA can be configured by an on-board flash memory without even needing the microcontroller. But sometimes it would be nice for the microcontroller to be able to reconfigure the FPGA, so it has access to the required programming signals.
The bitstream which needs to be sent to the FPGA is some 150kBytes, but changes much less frequently than the MCU firmware. Since programming that much data with the programmer/debugger (Segger J-Link) takes some time, I would prefer not to erase and reprogram this bitstream every time the firmware changes (but the bitstream is identical). The debugger does reprogram only those memory blocks which actually have changed, so it happily skipped programming of the bitstream if it would always be located at the same address. But this is obviously not the case if I just include it some way like
static const uint8_t fpga_bitstream[] = {
// ...
};
since the linker is free to decide where to place this data.
Now the question: What would be a (not too intrusive) way to have the linker put this symbol always to the same address? I am aware of the --defsym linker option, but this seems to be ignored when the symbol in question is defined in a source file (instead of just being referenced and declared as extern). The only way I know which works (I've used that some time ago already) is to use a custom linker file which defines a separate partition in the MEMORY part and then creates a new section to put the symbol into, using e.g.
static const uint8_t fpga_bitstream[] __attribute__((section(".fpgabitstream"))) = {
// ...
};
This project uses a small operating system (Nut/OS), however, which brings its own linker files. So I'd be fine if I could append some data to it using the -Tfile.ld option, but I'd prefer not having to change the original script, as this is located in the source tree of the operating system itself.
Thanks,
Philipp
As it doesn't seem to be possible to "add" to an existing linker script, probably the easiest solution would be to reserve a separate area of flash (e.g. an area at a fixed address near end with a little reserve for future growth) for the FPGA configuration and load from that fixed address.
Since there is probably nothing useful you can do to the FPGA bitstream anyway from the MCU side (other than loading it), I don't see any advantage in embedding the FPGA config into your MCU binary. You only need start address and size in your MCU code, both of which can be made known to the MCU by the --defsym linker option (without linker script modification).
I have a very similar configuration (with FPGA config and MCU code living on separate areas of flash) over here which works well. MCU flash is used regularily while FPGA is flashed only now and then.

how to prevent boot region when program the sam4e using jtag

I am using at91sam4e16e and working on bootloader. boot region is defined at 0x400000 and application region is at 0x420000 onwards.
i have downloaded bootloader code into that region and compiled application code with 0x420000 link address. now I want to download that application to 0x420000 using Jtag but when I download it, all the memory goes erased and only application remains.
In avr, I could prevent the boot area in debugger option; How to do the same in sam4e?
regards,
shreyas.
Go to project options.
In Debugger -> Images you can download extra image.
Note that I have only used this with the Debug info only-option enabled, but I have bundled bootloader with my app, so it is a bit different situation. (You can bundle bootloader in Linker -> Input tab.)
I also had a problem that since application wasn't in normal starting location, I had to initialize program counter, and stack pointer registers manually. You can do this by defining a macro file in Debugger -> Setup.
Macro file could look like this (note that this is for different MCU, so you may have different registers/addresses):
execUserReset()
{
// Set the stack pointer
MSP = *(int*)0x00008000;
// Set the program counter
PC = *(int*)0x00008004;
}
This macro file skips bootloader when using debugger reset, but you could also make macro file which enters bootloader on reset by using different addresses.
Edit: Bundling the bootloader:
It's been a while since I have done this, so hopefully I remember everything.
You need to add your bootloader .bin file to Linker -> Input -> Raw binary image. Also define symbol bootloader, and section .bootloader. (I think alignment needs to be specified too, even if you use absolute placement.)
Add your bootloader symbol to Keep symbols: box above. This should make sure that bootloader is always included.
In your linker file, add line
place at address mem:0x00000000 { section .bootloader };
to place bootloader at specific address (change address to match your bootloader address).

AT91 Bootstrap + Bare Metal Application

I am currently trying to understand how AT91 and a bare metal application can work together. I'll try to describe what I have:
IAR as development environment
A simple application which I can download via debugger to SRAM and which toggles some LEDs (working!)
Using SAM-BA I can write this application to SRAM and it will start correctly (LEDs are toggling)
My hardware platform is the ATSAMA5D3x-EK
Now I would like this application to first run the AT91 bootstrap to initialize all the low level hardware (like DDR-RAM), then jump to my application and run it. I have not been able to do that yet successfully. I am able to start the pre-built uboot binary though so I assume it's not the copying or jump that are failing but my application is setup incorrectly.
As far as I understand, if I jump to an application (I assume this is some sort of "LDR pc, appstart_address") the operation at address appstart_address gets executed.
Now, in ARM the first 7 bytes or so are reserved for abort/interrupt vectors, whereas the first instruction is usually some sort of "LDR pc, =main". Are these required if my application is copied to RAM and executed from there? I somehow have the feeling that after copying my application to RAM, the address pointers do not match anymore (although they should be relative - is that correct at all?)
So my questions basically boil down to:
What happens after AT91 has initialized the hardware and jumps to my application
Do I need to setup my application in some specific way? Do I need to tell the linker or any other component that it will be relocated to some other memory location (at91 bootstrap copies it to 0x2600 0000 whereas 0x2000 0000 is the start address of DDR).
Does anyone know of a good tutorial which explains exactely this step (the jump from at91 bootstrap to my application)?
One more question which I probably can answer myself:
Is it safe to assume that I will not need to execute the instructions in board_startup.s at the beginning of my application which enable The floating point unit, setup the sys stack pointer and so on. I would say that the hardware itself has already been setup by AT91 Bootstrap and therefore there is no need for such setup.
After thinking about a few things it comes down to this:
Does it make sense to tell the linker that it should link main to address 0x0 (because this is where bootstrap will jump to) - how would I do that?
Now, in ARM the first 7 bytes or so are reserved for abort/interrupt
vectors, whereas the first instruction is usually some sort of "LDR
pc, =main". Are these required if my application is copied to RAM and
executed from there? I somehow have the feeling that after copying my
application to RAM, the address pointers do not match anymore
(although they should be relative - is that correct at all?)
The first 8 WORDS are exception entry points yes. Of which one is undefined so 7 real ones...
The reset vector does not want to go straight to main implying C code, you have not setup the stack or anything that you need to do to call C code. Also the reset vector is often close enough to use a branch b instead of a ldr pc, but since you only have one word/instruction to get out of the exception table then it either needs to be a branch or a ldr pc,something.
if your binary is position dependent then you build it for that position, you can then place it in non-volatile storage, copy and run if you like there is no problem with that. if you build it for its non-volatile address but you run it in a different address space and it is not position independent then you are right it simply wont work.
What happens after AT91 has initialized the hardware and jumps to my
application
your application runs
Do I need to setup my application in some specific way? Do I need to
tell the linker or any other component that it will be relocated to
some other memory location (at91 bootstrap copies it to 0x2600 0000
whereas 0x2000 0000 is the start address of DDR).
either build it position independent or link it for the address where it will run.
Does anyone know of a good tutorial which explains exactely this step
(the jump from at91 bootstrap to my application)?
I assume when you say at91 bootstrap (need to use a more correct term) you mean some part specific (at91 is a long lived family of devices) you really mean either some atmel part specific code or IAR part specific code. And the answer to your question is in their examples or documentation. You need to demonstrate what you found, examples, etc before posting a question like that.
Is it safe to assume that I will not need to execute the instructions
in board_startup.s at the beginning of my application which enable The
floating point unit, setup the sys stack pointer and so on. I would
say that the hardware itself has already been setup by AT91 Bootstrap
and therefore there is no need for such setup.
if you are relying on someone elses code to for example setup ddr, then it is probably a safe bet that they setup the stack. fpu, thats another story. But if that file name is specific to their project and is something they call/use then well, they called it or used it. Again this is specific to this magic AT91 Bootstrap thing which you have not demonstrated that you looked at or through or read about. Please, do some more research on the topic, show what you tried, etc. For example it should be quite trivial after this bootstrap code to read the registers that enable the fpu and or just use it and see what you see. that is an easy way to tell if it had been run. alternatively insert an infinite loop in that code and re-build if the code hangs at the infinite loop. they they are running it. (careful not to brick your board with such a move, in theory SAM-BA will let you re-load).
Does it make sense to tell the linker that it should link main to
address 0x0 (because this is where bootstrap will jump to) - how would
I do that?
The exception table for this processor is at a well known location (possibly one of two depending on strapping). the exception handlers need to be in the right place for the processor to boot properly. Generally it is the linker that does the final arranging of code and it is linker specific as to how you tell the linker where to put things so the answer is in the documentation for the linker and also either somewhere in the project it specifies this information (linker script, makefile, etc) or a default is used either global default or some variable or command line option tells one of the tools where to look for this information. so how you do it is read the docs and do what the docs say.

ARM bootloader: the value of TEXT_BASE

It's important to calculate correctly the value of TEXT_BASE when we begin to program the bootloader, but I haven't found a tutorial well explaining how to find this value according to platform datasheet or other materials. For example, for arm920t and sumsang s3c24x0, u-boot defines TEXT_BASE=0x33F80000 with this reason:
SMDK2410 has 1 bank of 64 MB DRAM
3000'0000 to 3400'0000
Linux-Kernel is expected to be at 3000'8000, entry 3000'8000 optionally with a ramdisk at 3080'0000
we load ourself to 33F8'0000
download area is 3300'0000
Can anyone explain the logic? Thanks!
ps: I also hope to know the memory layout of u-boot after load into the ram, the address of each data/instruction part, bss, rodata,zi, etc and the size. I expecte someone offer me some concerning tutorials to anaylyse, thank you!
TEXT_BASE is, unsurprisingly, the base address of the U-boot image i.e. where it starts executing from. So if U-boot is running straight from flash, it's the address of the flash. Or if ROM/firmware is responsible for loading U-boot then it's whatever address in RAM U-boot gets loaded to. Thus if you set TEXT_BASE to a different address it'll be linked wrong and will probably break at the relocation step.
As for the image layout, what's to ask? Either read the linker scripts, or just run a build then disassemble the u-boot ELF image that u-boot.bin is created from.

Resources