APP重定位資料段、清除BSS段
使用的IDE為MDK。
散列檔案:
; *************************************************************
; *** Scatter-Loading Description File generated by uVision ***
; *************************************************************
LR_IROM1 0x800B000 0x75000 { ; load region size_region 75000
ER_IROM1 0x800B000 0x75000 { ; load address = execution address 75000
*.o (RESET, +First)
; *(InRoot$$Sections)
.ANY (+RO)
.ANY (+XO)
;.ANY (+RW +ZI)
}
RW_IRAM1 0x20000000 0x00010000 { ; RW data
.ANY (+RW +ZI)
}
}
-
和RW 段
的加載位址和連結位址不一緻ZI段
Bootloader程式:
PRESERVE8 ; instruct is aligned by 8 bytes 指令集8位元組對齊
THUMB ; use Thumb instruction set 使用thumb指令集
AREA RESET, DATA, READONLY ;DATA定義資料段,READONLY隻讀
EXPORT __Vectors
__Vectors DCD 0 ; CPU自動将該處的值設定給sp,Top of Stack
DCD Reset_Handler ; Reset Handler 指令位址,CPU首先執行此句
AREA |.text|, CODE, READONLY ; CODE表示定義代碼段,READONLY隻讀
; Reset handler
Reset_Handler PROC ; 子程式開始标志
EXPORT Reset_Handler [WEAK] ; 導出Reset_Handler全局可見以及弱定義
IMPORT main ; 導入main,類似C語言的extern main,聲明main由外部定義
LDR sp, = (0x20000000+0x10000) ; 手動設定棧,隻有設定了棧才能跳到C語言的世界執行
BL main ; 跳到C語言世界執行
ENDP ; 子程式結束标志
boot_app PROC ; 彙編标号即函數名或者說函數位址
EXPORT boot_app
STR R0, [R1] ; 向中斷向量寄存器寫入程式連結位址0x800B000
LDR sp, [R0] ; 取0x800B000位址處的值寫入sp即設定棧
LDR R3, [R1]
LDR R2, [R0, #4] ; 0x800B000 + 4 = 0x800B004,取出0x800B004位址處的值指派給R2
BX R2 ; 跳去執行APP
ENDP
END ;彙編檔案結
#include "usart.h"
//#include "stdio.h"
#define BOOTLOADER_VERSION "1.3"
#define APP_ADDR 0x800B000 /* APP起始位址 */
#define VECTOR_REG_ADDR 0xE000ED08
void boot_app(unsigned int start_addr, unsigned int vector_reg);
int main(void)
{
unsigned int s_addr = APP_ADDR;
unsigned int vector_addr = VECTOR_REG_ADDR;
uart_init();
myputstr("\r\nBootloader: ");
myputstr(BOOTLOADER_VERSION);
//printf("\r\n");
myputstr(__DATE__);
//printf(" %s\r\n", __TIME__);
boot_app(s_addr, vector_addr);
return 0;
}
APP程式:
#include "usart.h"
void uart_init(void);
void delay(int times)
{
while (--times);
}
char buf[100] = {"Hello, My App!!!"};
int xmain(void)
{
static unsigned int global;
uart_init();
myputstr("\r\nApp Start\r\n");
myputstr(buf);
myputstr("\r\n");
while (1)
{
myputstr("app runing\r\n");
//myputstr("App runing\r\n");
delay(1000000);
}
}
-
,列印資料為亂碼,因為buf是全局變量,屬于資料段,它的加載位址則是FLASH上,散列檔案定義的資料段連結位址是myputstr(buf)
,資料段的加載位址和連結不一緻,是以需要重定位,而bootloader和APP都沒有做重定位,是以列印出來是亂碼。0x20000000
修改APP實作重定位資料段和清除BSS段:
/* 重定位資料段 */
void c_relocate_data(char *from, char *to, unsigned int len)
{
while (len--)
{
*to = *from;
to++;
from++;
}
}
/* 清除bss段 */
void c_clear_bss(char *dest, unsigned int len, char val)
{
while (len--)
{
*dest++ = val;
}
}
PRESERVE8 ; instruct is aligned by 8 bytes 指令集8位元組對齊
THUMB ; use Thumb instruction set 使用thumb指令集
AREA RESET, DATA, READONLY ;DATA定義資料段,READONLY隻讀
EXPORT __Vectors
CODE_START_ADDR EQU 0x800B000
__Vectors DCD 0x20000000+0x10000 ; CPU自動取改處的值設定為棧頂 Top of Stack
DCD Reset_Handler ; Reset Handler
AREA |.text|, CODE, READONLY ; CODE表示定義代碼段,READONLY隻讀
; Reset handler
Reset_Handler PROC ; 子程式開始标志
EXPORT Reset_Handler [WEAK] ; 導出Reset_Handler全局可見以及弱定義
IMPORT xmain ; 導入main,類似C語言的extern main,聲明main由外部定義
IMPORT |Load$$RW_IRAM1$$RW$$Base| ; 加載于RW段的起始位址
IMPORT |Image$$RW_IRAM1$$RW$$Base| ; 資料段的加載起始位址(源)
IMPORT |Image$$RW_IRAM1$$RW$$Length| ; 資料段的長度(長度)
IMPORT |Image$$RW_IRAM1$$ZI$$Base| ; ZI段的連結起始位址
IMPORT |Image$$RW_IRAM1$$ZI$$Length| ; ZI段的長度
LDR sp, = (0x20000000+0x10000) ; 設定棧
LDR R0, = |Load$$RW_IRAM1$$RW$$Base|
LDR R1, = |Image$$RW_IRAM1$$RW$$Base|
LDR R2, = |Image$$RW_IRAM1$$RW$$Length|
BL c_relocate_data
LDR R0, = |Image$$RW_IRAM1$$ZI$$Base|
LDR R1, = |Image$$RW_IRAM1$$ZI$$Length|
MOV R2 , #0
BL c_clear_bss
BL xmain
ENDP ; 子程式結束标志
END ;彙編檔案結束
-
在調用xmain之前重定位資料段BL c_relocate_data
-
在調用xmain之前清除BSS段BL c_clear_bss
APP自我複制所有段實作重定位
修改散列檔案如下:
; *************************************************************
; *** Scatter-Loading Description File generated by uVision ***
; *************************************************************
LR_IROM1 0x800B000 0x75000 { ; load region size_region 75000
ER_IROM1 0x20000000 0x00010000 { ; load address = execution address 75000
*.o (RESET, +First)
; *(InRoot$$Sections)
.ANY (+RO)
.ANY (+XO)
.ANY (+RW +ZI)
}
; RW_IRAM1 0x20000000 0x00010000 { ; RW data
; .ANY (+RW +ZI)
;}
}
- 加載位址是0x800B000
- 連結位址是0x20000000
- 加載位址和連結位址不一緻,需要對APP程式進行重定位
針對加載位址和連結位址不一緻的情況,有一種特殊情況不需要進行重定位代碼,隻要跳到第一條指令位址的正确位置
這種情況就是APP程式是位置無關碼。
位置無關碼無論放在記憶體的哪個位址,都能正确運作,能正确運作的原因是代碼沒有用到絕對位址進行跳轉, 對于代碼指令的執行都是相對PC指針的偏移,根據偏移就能準确下一條指令或資料。
當程式連結完成,各個指令之間偏移位址都是固定的,即使燒錄在flash上,也是根據偏移找到對應的位址。
跟位置無關碼相反的就是位置有關碼,位置有關碼的程式指令使用了絕對尋址指令,它的位址與代碼所處的位置有關,也就是跟我們自己編譯連結程式時指定的連結位址有關。
一些常見絕對跳轉,彙編如
LDR pc , = mymain
絕對跳轉執行函數,
C語言如通過函數指針調用一個函數,此時函數指針指向的就是函數的絕對位址,絕對位址由于跟連結位址有關,但程式不進行重定位則程式無法執行,因為絕對位址處無指令。
APP程式,位置有關碼:通過函數指針調用函數
void (*fputstr)(char *);
char buf[100] = {"Hello, My App!!!"};
int xmain(void)
{
static unsigned int global;
uart_init();
fputstr = myputstr;
fputstr ("\r\nApp Start\r\n");
fputstr (buf);
fputstr ("\r\n");
while (1)
{
myputstr("app runing\r\n");
//myputstr("App runing\r\n");
delay(1000000);
}
}
對于應用程式,不應該限制代碼的編寫,如果寫成位置無關碼,代碼的編寫就會受限,是以一般連結位址和加載位址不一緻,就要實作代碼重定位。
代碼重定位實作:
void relocate_app(char *from, char *to, unsigned int len)
{
while (len--)
{
*to++ = *from++;
}
}
PRESERVE8 ; instruct is aligned by 8 bytes 指令集8位元組對齊
THUMB ; use Thumb instruction set 使用thumb指令集
AREA RESET, DATA, READONLY ;DATA定義資料段,READONLY隻讀
EXPORT __Vectors
CODE_START_ADDR EQU 0x800B000
__Vectors DCD 0x20000000+0x10000 ; CPU自動取改處的值設定為棧頂 Top of Stack
DCD Reset_Handler ; Reset Handler
AREA |.text|, CODE, READONLY ; CODE表示定義代碼段,READONLY隻讀
; Reset handler
Reset_Handler PROC ; 子程式開始标志
EXPORT Reset_Handler [WEAK] ; 導出Reset_Handler全局可見以及弱定義
IMPORT xmain ; 導入xmain,類似C語言的extern xmain,聲明xmain由外部定義
IMPORT relocate_app
IMPORT |Load$$ER_IROM1$$Base| ; 加載域的代碼起始位址
IMPORT |Image$$ER_IROM1$$Base|
IMPORT |Image$$ER_IROM1$$Length|
LDR sp, = (0x20000000+0x10000) ; 設定棧
LDR R0, = |Load$$ER_IROM1$$Base|
LDR R1, = |Image$$ER_IROM1$$Base|
LDR R2, = |Image$$ER_IROM1$$Length|
BL relocate_app
LDR pc, = xmain ; 代碼已經重定位,絕對跳轉到RAM中的xmain,用BL xmain也可以,不過跳轉執行的是APP中的代碼
ENDP ; 子程式結束标志
END ;彙編檔案結束
參考文章:
[012] [STM32] 代碼重定位與清除BSS段深入分析_柯西的彷徨的部落格-CSDN部落格_stm32向量表重定位
https://blog.csdn.net/kouxi1/article/details/123492797
(轉)位置無關碼、位置有關碼 位置無關代碼,即該段代碼無論放在記憶體的哪個位址,都能正确運作