STM32下載ELF檔案、可執行bin檔案的最小size測試

2023-04-21 21:00:32

1、STM32能下載ELF格式的檔案嗎?

答:可以。因為所謂的bin檔案就是ELF檔案的.text程式碼段。

當然前提是下載工具能識別ELF檔案格式,STM32下載ELF檔案並不意味著STM32可以把ELF download到Flash上,而是下載工具能從ELF提取到bin檔案,下載時通訊鏈路上傳輸的也只有要bin檔案。

例如有elf檔案:

$ arm-none-eabi-objdump.exe -s main2.elf

main2.elf:     file format elf32-littlearm

Contents of section .text:
 8000000 00100020 09000008 01488546 fee70000  ... .....H.F....
 8000010 00100020                             ...
Contents of section .ARM.attributes:
 0000 41200000 00616561 62690001 16000000  A ...aeabi......
 0010 05436f72 7465782d 4d340006 0d074d09  .Cortex-M4....M.
 0020 02

 arm-none-eabi-objcopy -O binary main2.elf main2.bin, 它生成bin檔案為:

address        00 01 02 03 04 05 06 07   08 09 10 11 12 13 14 15            AscII
00000000    00 10 00 20 09 00 00 08      01 48 85 46 fe e7 00 00        ... .....H.F....
00000010    00 10 00 20            ...

使用STM32 cube programmer直接開啟elf檔案不僅可以預覽,還能直接下載ELF檔案,看到的資料和上面使用objump生成的bin檔案一樣的。

 在cube programmer裡連下載地址都不用設定,若開啟的是bin檔案,無論Segger J-Flash還是cube programmer,都是需要手動設定Flash下載地址的。

 

2、STM32最小的可執行bin檔案是多大?

答:10位元組。

  1. 按照STM32程式設計手冊,STM32啟動是從0x0地址取堆疊指標(MSP),從0x04地址取復位入口的PC指標,還需要設定堆疊地址(1或2條指令),最後是mian函數loop,所以最小的程式碼至少是4+4+4+2合計14位元組或4+4+8+2合計18位元組。
  2. 倘若不考慮程式碼通用性,可以把堆疊地址去掉,合計10位元組即可,實際程式碼只有1條2位元組。

0x00地址:MSP值。

0X04地址:reset handler地址,值為0x08

0x08地址:BL . (死迴圈,thumb指令2位元組)

  1. 舉例如下:

下面的組合程式碼中0x04地址為PC初始值: 09 00 00 08,小端格式實際值為0x08000009,為何是奇數?

答:cortex MCU不可能產生奇數指令,ARM模式4位元組對齊低2位是0,Thumb模式2位元組對齊低1位是0,所以PC最低位就屬於空閒的,而Cortex MCU需要識別當前是ARM模式還是Thumb模式,所以使用PC最低位就能識別這兩種模式。

R15是程式計數器,在組合程式碼中用PC表示,ARM規定PC最低位LSB用於表示是ARM指令(0)還是Thumb指令(1)。

設計程式碼,直接寫組合

.syntax unified
.cpu cortex-m4
.fpu softvfp
.thumb

// Global memory locations.
.global vtable
.global reset_handler

// The actual vector table.
.type vtable, %object
vtable:
    .word _estack
    .word reset_handler
.size vtable, .-vtable

/*
 * The Reset handler. Called on reset.
 */
.type reset_handler, %function
reset_handler:
    // Set the stack pointer to the end of the stack.
    //LDR  r0, =_estack
    //MOV  sp, r0

    //MOVS r0, #0
    main_loop:
        //ADDS r0, r0, #1
        B    main_loop
.size reset_handler, .-reset_handler

編譯生成二進位制檔案

$ arm-none-eabi-objdump.exe -d main2.elf

main2.elf:     file format elf32-littlearm


Disassembly of section .text:

08000000 <vtable>:
 8000000:       00 10 00 20 09 00 00 08                             ... ....

08000008 <reset_handler>:
 8000008:       e7fe            b.n     8000008 <reset_handler>

這並不是一個理論demo,而是一個可以執行的程式。

第一步下載:

 第二步,執行,由於這個程式沒有任何有效的命令,所以無論如何單步都看不到變化,只能看到SP和PC指標已經正確的load了。

 

簡單修改,加一個暫存器做累加計算方便看到效果,每點一次單步暫存器值加1,程式碼由10位元組變為了14位元組。

$ arm-none-eabi-objdump.exe -d main2.elf

main2.elf:     file format elf32-littlearm


Disassembly of section .text:

08000000 <vtable>:
 8000000:       00 10 00 20 09 00 00 08                             ... ....

08000008 <reset_handler>:
 8000008:       2000            movs    r0, #0

0800000a <main_loop>:
 800000a:       3001            adds    r0, #1
 800000c:       e7fd            b.n     800000a <main_loop>

 

第一步:下載

第二步:復位,執行指令

8000000: 00 10 00 20 09 00 00 08

8000008: 2000 movs r0, #0

 單步:執行指令 ,累加和迴圈

0800000a <main_loop>:

800000a: 3001 adds r0, #1

800000c: e7fd b.n 800000a <main_loop>

 單步:

 單步:

 單步

 單步:

 直接全速run後暫停: