2018-08-01 08:35 AM
I'm developing a bootloader for an STM32L0 MCU that will jump to one of two or more application partitions in flash. I'm using IAR 8.22.2.
To make the application binaries position-independent, I've compiled them with the -ropi option. I've also modified the startup code (.s file) to use a Reset_Handler that doesn't have absolute function references in it. At the start of the application, I copy the vector table to SRAM, adjusting all the flash addresses for the current partition offset. I set the VTOR to point to the SRAM location, set the stack pointer, and I'm good to go.
At least, I thought so. I tried jumping to the second partition and running the code, but after some initial excitement at seeing things working, I realized that somehow execution had wandered back into partition 1. To investigate, I compiled 2 separate binaries with the .icf file configured for two different flash partitions. I did a diff on them, expecting to only see differences in the vector table at the beginning of the file. However, I also see differences at the end of the file, in the initializer bytes.
As I read the IAR documentation, -ropi should take care of data initializers as well. ("ROPI = Read-Only Position Independence. This concerns everything that is readonly in the ELF output from the linker. Note that this includes const data and data initializers, i.e. typically everything that is put in FLASH.") Is this not the case? Do I need to use the -rwpi option as well?
I've tried using the -rwpi option, but then I'm completely lost as to how to handle the resulting binary and there are few examples out there (I've found 1 from IAR, but it's very hard to follow.)
Any idea what's going on here? Do I need to use the -rwpi option? If so, are there any good ST-specific examples out there?
Thanks!
2018-08-01 09:03 AM
You're either going to have to trace down the execution that gets you there, or do a static review of the listing/disassembly to understand what's going on.
Want to look at values placed in literal pools, as this is where most fixed addressed will end up.
2018-08-01 01:25 PM
Thanks for the response.
After some investigation, I discovered that I was failing to account for the vector table partition offset in the bootloader, so I was in fact jumping right to partition 1 instead of partition 2 as I had intended. I fixed that and then voila, I was jumping to the right partition and could easily switch from one to the other.
However, I then erased partition 1, booted into partition 2, and ended up with a Hard fault. I stepped through the dissasembly and found the error occurred within a precompiled function _gLocale_mblenInit (printf->_PrintFull->_gLocale_mblen). In that function, it attempted to branch to 0x08016C99, which was now an erased space in partition 1. I opened the compiled application binary, and as expected, 0x08016C99 shows up in the initializer bytes at the end of ROM_region.
So I guess that brings me back to the questions - shouldn't this be compiled as PIC given the -ropi option? Is there a way to fix this this other than using -rwpi? Are there any good -rwpi examples out there?
2018-10-22 08:11 AM
Great Post
Thanks
Could you please specify how did you modified the startup code (.s file) to use a Reset_Handler that doesn't have absolute function references in it ?
2018-10-22 08:28 AM
I modified the .s file as follows:
MODULE ?cstartup
;; Forward declaration of sections.
SECTION CSTACK:DATA:NOROOT(3)
SECTION .intvec:CODE:NOROOT(2)
EXTERN PI_Reset_Handler
;EXTERN __iar_program_start ; comment out
;EXTERN SystemInit ; comment out
PUBLIC __vector_table
DATA
__vector_table
DCD sfe(CSTACK)
DCD PI_Reset_Handler ; new reset handler to support position independence
DCD NMI_Handler ; NMI Handler
DCD HardFault_Handler ; Hard Fault Handler
and added this function to main.c:
void PI_Reset_Handler(void)
{
SystemInit();
__iar_data_init3();
__iar_program_start();
}
2018-10-23 01:07 AM
dwanninger,
You saved me a week of work
I am going to drink beer now on your behalf
For completeness,
The definition of Reset Handler should be commented out:
; PUBWEAK Reset_Handler
; SECTION .text:CODE:REORDER:NOROOT(2)
;Reset_Handler
; LDR R0, =SystemInit
; BLX R0
; LDR R0, =__iar_program_start
; BX R0
ramfunc should be removed
// #[include "stm32l1xx_hal_flash_ramfunc.h"
And __iar functions may be declared:
extern void __iar_data_init3(void);
extern void __iar_program_start(void);
2019-03-26 09:24 AM
hello , i develop a boot-loader that need to jump to an application that it must be compiled with ROPI option , i have made all the previous modifications but when my boot-loader jump to app the application can't run , the app is compiled with ivect offset in linker ( 0x8000000) and i put the app in address (0x8010000) , i use a STM32L4R5 board . any idea that can help me please ?
2019-03-26 11:44 AM
Hi
I don't know why your code doesn't work. Let me share the difference between your implementation and a version that worked for me.
I used the NVIC from the modified address in flash (0x8010000 in your case), not from RAM.
At the time of writing the binary values to the flash, I added an offset (0x10000 in your case) to the NVIC entries that point to the ISR addresses (there are some addreses in NVIC region that are resereved and should not be modified).
The rest was like you probably did:
Changed the reset handler as described above.
Set the jumpfunction pointer to the value at that is written at 0x8010000 in your case.
Modified VTOR to 0x8010000.
Set the stack pointer according to 0x8010004.
Finally, jumped to the application.
2019-03-28 03:04 AM
Hello Omer , can you share with me your code please? helmi.hadd@gmail.com
2019-03-28 04:39 AM
I can not share the code
But I can share a presentation about the code:
https://www.slideshare.net/OmerKorech/boot-loader-for-stm32l1xx-126547060