2
votes

I'm working on making a bootloader and giving it the ability to update itself. This process involves copying the binary to a new location, jumping to it, and using it to flash the new bootloader in the original location. This is all being developed for an M4 processor in Eclipse, using the ARM GCC toolchain.

To do this, I've gathered that I need to compile as Position Independent Code (PIC).

I've searched around and found this excellent article, so when I added "-fPIC" to the ARM GCC compiler call I expected to see linker errors about GOT and PLT being missing https://eli.thegreenplace.net/2011/11/03/position-independent-code-pic-in-shared-libraries/

In my linker script, I added these location to the .data section as follows:

.data : AT(__DATA_ROM)
{
. = ALIGN(4);
__DATA_RAM = .;
__data_start__ = .; /* Create a global symbol at data start. */
*(.got*) /* .got and .plt for position independent code */
*(.data) /* .data sections */
*(.data*) /* .data* sections */
KEEP(*(.jcr*))
. = ALIGN(4);
__data_end__ = .; /* Define a global symbol at data end. */
} > m_data

However, this code fails to copy-up from ROM to RAM.

My next thought was that perhaps my linker needed to be aware it was linking a PIC executable. To find out, I added "--pic-executable" to the LD linker script call. However, the linker now generated sections for "interp", "dyn", "rel.dyn" and "hash". I tried throwing these into the data section as well, but got the following errors:

gcc-arm-none-eabi-4_9/bin/../lib/gcc/arm-none-eabi/4.9.3/../../../../arm-none-eabi/bin/ld.exe: could not find output section .hash

gcc-arm-none-eabi-4_9/bin/../lib/gcc/arm-none-eabi/4.9.3/../../../../arm-none-eabi/bin/ld.exe: final link failed: Nonrepresentable section on output

I assume this means the compiler didn't actually fill the ".hash" section with anything, so the link failed.

Am I going about this correctly? Is there anything else I need to add to get the compiler to do? Any help would be greatly appreciated.

3
this is not the only solution and is somewhat of a painful way to do it. just copy and jump to run the bootloader from ram. - old_timer
have you asked this question before as a different user, this was already covered, seems very familiar to a prior question trying to do the same thing. - old_timer
@old_timer I agree, but copying to another location and running does not work if the program was compiled for a static location. Inevitably, the compiler decides to throw in a BLX [address from original location] and the program crashes if there's nothing there. It must be compiled to be position independent, or there needs to be a compiler instruction I am not aware of. No, I have not asked this question before. - Drewster
of course it works, just like any other bootloader, you link it for the location where it will run, not for the location where it wont be running. - old_timer
@old_timer This bootloader normally resides at (for example) 0x10000, as its primary job is to flash firmware. It needs to be compiled to run at 0x10000 or ideally anywhere else. I would greatly appreciate help in compiling it to run in other locations........ - Drewster

3 Answers

0
votes

Booting a code and relocating involves many careful steps and initialization of configuration of RAM, SPI and other necessary peripherals.

I know U-Boot does the sequence you are trying to achieve. So a better starting is to walk through u-boot documentation and sources in, machine specific folders for the processor or board of interest.

0
votes

For what it's worth, neither I nor NXP's technical support team were able to get their S32DS IDE to compile truly position independent code.

To this day, we have two bootloaders - one compiled for location A, the other is an intermediate for location B. Both of which are required for an update.

0
votes

TI does this with the Tivaware bootloader. You can do it with linker gnu ld trickery:

.text 0x20000000 : AT (0x00000000)
{
_text = .;
KEEP(*(.isr_vector))
*(.text*)
*(.rodata*)
_etext = .;
}

Startup code that copies this code from Flash at 0x0 to SRAM at 0x2000_0000 is left as an exercise to the reader.