我正在嘗試使用 ARM Thumb 程式集執行一個非常簡單的程式,該程式將關閉我的 Arduino Due 上的 LED(默認情況下,與其鏈接的 ATSAM3X8E 引腳似乎在內部被拉高)。在組裝中做更復雜的事情之前,我正在做這個測驗。
我已經將初始 SP 值以及所有 15 個強制性系統例外向量放在一個部分中,并做了一個快速的 GPIO 硬體暫存器初始化例程(將引腳定義為我可以寫入的輸出,禁用上拉,以便只要我沒有實際寫入輸出資料暫存器,輸出引腳就應該保持關閉狀態)。(我沒有做任何 RAM 加載例程,因為我目前在程式中沒有只讀常量以外的值,所以也沒有資料部分)。
我使用了 GNU Assembler,ld 帶有一個簡單的聯結器腳本,以確保向量表位于二進制檔案的最開頭,從 elf 中進行了快速 objcopy 并獲得了一個不錯的原始二進制檔案,我將其寫入 MCU 的內部閃存中使用 BOSSA 命令列。(見下面的代碼)
但什么也沒發生,LED 保持高電平。
.thumb
.syntax unified
.section .vectors
.word 0x20001000 @StackTop, somewhere near the end of the SRAM
.word Reset_Handler
.word No_Handler @NMI_Handler
.word No_Handler @HardFault_Handler
.word No_Handler @MemFault_Handler
.word No_Handler @BusFault_Handler
.word No_Handler @UsageFault_Handler
.word 0
.word 0
.word 0
.word 0
.word No_Handler @SVC_Handler
.word No_Handler @DebugMon_Handler
.word 0
.word No_Handler @PendSV_Handler
.word No_Handler @SysTick_Handler
.word No_Handler @IRQ0
@... (same with all IRQ's until 28)
.word No_Handler @IRQ29
.section .text
.thumb_func
Reset_Handler:
BL init
BL main
B No_Handler
.thumb_func
No_Handler:
B No_Handler
.thumb_func
init:
LDR r0, =WDT_MR @Disable Watchdog Timer
LDR r1, [r0]
ORR r1, r1, #0x8000
STR r1, [r0]
LDR r0, =PIOB_WPMR @Disable GPIO Write Protection
LDR r1, [r0]
LDR r2, =PIOB_KEY
LDR r3, [r2]
ORR r1, r1, r3
STR r1, [r0]
LDR r0, =PIOB_PER @Disable peripeheral function (pure GPIO)
LDR r1, [r0]
LDR r2, =PIOB27
LDR r3, [r2]
ORR r1, r1, r3
STR r1, [r0]
LDR r0, =PIOB_OER @Define pin as output
LDR r1, [r0]
ORR r1, r1, r3
STR r1, [r0]
LDR r0, =PIOB_OWER @Allow writes to ODSR
LDR r1, [r0]
ORR r1, r1, r3
STR r1, [r0]
LDR r0, =PIOB_PUDR @Disable internal pull-up for the pin
LDR r1, [r0]
ORR r1, r1, r3
STR r1, [r0]
BX lr
.thumb_func
main:
@nothing much here
B main
WDT_MR: .word 0x400E1A54
PIOB_WPMR: .word 0x400E10E4
PIOB_KEY: .word 0x50494F00
PIOB_PER: .word 0x400E1000
PIOB_OER: .word 0x400E1010
PIOB_OWER: .word 0x400E10A0
PIOB_PUDR: .word 0x400E1060
PIOB_ODSR: .word 0x400E1038
PIOB27: .word 0x8000000 @ 0x1u<<27
我在 C 中用完全相同的暫存器做了同樣的事情(但讓 Microchip Studio 為我使用 ARM GCC),這次它作業了。如果錯誤出在我的自定義聯結器腳本中,這里是:
MEMORY
{
flash (rx) : ORIGIN = 0x00080000, LENGTH = 0x00080000
ram (rwx) : ORIGIN = 0x20000000, LENGTH = 0x00018000
}
SECTIONS
{
.text :
{
*(.vectors)
*(.text)
} > flash
}
我擔心的是該程式實際上似乎并沒有達到任何初始化代碼。
uj5u.com熱心網友回復:
如果我取你程式的一個子集
.thumb
.syntax unified
.section .vectors
.word 0x20001000
.word Reset_Handler
.section .text
.thumb_func
Reset_Handler:
BL init
BL main
B No_Handler
.thumb_func
No_Handler:
B No_Handler
.thumb_func
init:
LDR r0, =WDT_MR @Disable Watchdog Timer
LDR r1, [r0]
ORR r1, r1, #0x8000
STR r1, [r0]
BX lr
.thumb_func
main:
@nothing much here
B main
WDT_MR: .word 0x400E1A54
組裝并與您的聯結器腳本鏈接,然后反匯編。
Disassembly of section .text:
00080000 <Reset_Handler-0x8>:
80000: 20001000 andcs r1, r0, r0
80004: 00080009 andeq r0, r8, r9
00080008 <Reset_Handler>:
80008: f000 f804 bl 80014 <init>
8000c: f000 f808 bl 80020 <main>
80010: e7ff b.n 80012 <No_Handler>
00080012 <No_Handler>:
80012: e7fe b.n 80012 <No_Handler>
00080014 <init>:
80014: 4804 ldr r0, [pc, #16] ; (80028 <WDT_MR 0x6>)
80016: 6801 ldr r1, [r0, #0]
80018: f441 4100 orr.w r1, r1, #32768 ; 0x8000
8001c: 6001 str r1, [r0, #0]
8001e: 4770 bx lr
00080020 <main>:
80020: e7fe b.n 80020 <main>
00080022 <WDT_MR>:
80022: 400e1a54 andmi r1, lr, r4, asr sl
80026: 00220000 eoreq r0, r2, r0
8002a: Address 0x000000000008002a is out of bounds.
您必須檢查的第一件事是向量表。
00080000 <Reset_Handler-0x8>:
80000: 20001000 andcs r1, r0, r0
80004: 00080009 andeq r0, r8, r9
00080008 <Reset_Handler>:
第一個條目是 sp init 值,看起來不錯,第二個是重置向量,必須設定 lsbit,這是正確的,所以你不會立即失敗,有一些希望。
As pointed out in comments though
00080014 <init>:
80014: 4804 ldr r0, [pc, #16] ; (80028 <WDT_MR 0x6>)
...
00080022 <WDT_MR>:
80022: 400e1a54 andmi r1, lr, r4, asr sl
Is NOT putting the value 0x400e1a54 in r0, but instead the ADDRESS OF WDT_MR in r0. Which the disassembler sort of mangled. But basically it puts 0x00080022 in r0. Which is not what you want.
So if I do this:
.thumb
.syntax unified
.section .vectors
.word 0x20001000
.word Reset_Handler
.section .text
.equ WDT_MR, 0x400E1A54
.thumb_func
Reset_Handler:
BL init
BL main
B No_Handler
.thumb_func
No_Handler:
B No_Handler
.thumb_func
init:
LDR r0, =WDT_MR @Disable Watchdog Timer
LDR r1, [r0]
ORR r1, r1, #0x8000
STR r1, [r0]
BX lr
.thumb_func
main:
@nothing much here
B main
.align
.word 0x12345678
And the .align at the bottom and that extra word (not really needed I assume) is to make the disassembly easier to read.
Gives this
00080014 <init>:
80014: 4804 ldr r0, [pc, #16] ; (80028 <main 0x8>)
80016: 6801 ldr r1, [r0, #0]
80018: f441 4100 orr.w r1, r1, #32768 ; 0x8000
8001c: 6001 str r1, [r0, #0]
8001e: 4770 bx lr
00080020 <main>:
80020: e7fe b.n 80020 <main>
80022: bf00 nop
80024: 12345678 eorsne r5, r4, #120, 12 ; 0x7800000
80028: 400e1a54 andmi r1, lr, r4, asr sl
And now 0x400e1a54 IS being loaded into r0, so that you can then control that register in the logic.
Visually inspect the disassemble to see if it is doing what you think it is doing.
WDT_MR in your code is a label, which is basically an address. So when you do ldr r0,=WDT_MR you are asking for the ADDRESS OF. Now here is another thing you could do:
.thumb
.syntax unified
.section .vectors
.word 0x20001000
.word Reset_Handler
.section .text
.thumb_func
Reset_Handler:
BL init
BL main
B No_Handler
.thumb_func
No_Handler:
B No_Handler
.thumb_func
init:
LDR r0, WDT_MR @Disable Watchdog Timer
LDR r1, [r0]
ORR r1, r1, #0x8000
STR r1, [r0]
BX lr
.thumb_func
main:
@nothing much here
B main
.align
WDT_MR: .word 0x400E1A54
so you were one character away from success
00080014 <init>:
80014: 4803 ldr r0, [pc, #12] ; (80024 <WDT_MR>)
80016: 6801 ldr r1, [r0, #0]
80018: f441 4100 orr.w r1, r1, #32768 ; 0x8000
8001c: 6001 str r1, [r0, #0]
8001e: 4770 bx lr
00080020 <main>:
80020: e7fe b.n 80020 <main>
80022: bf00 nop
00080024 <WDT_MR>:
80024: 400e1a54 andmi r1, lr, r4, asr sl
Now it is loading the value at that label not the address of the label. And I suspect this is actually what you want to do rather than the .equ thing. YMMV. if you do the .EQU thing then the assembler is creating the pool, if you do it then you can control where these things live.
Now you potentially had a second problem that was shown and talked about above, and I solved it:
00080022 <WDT_MR>:
80022: 400e1a54 andmi r1, lr, r4, asr sl
80026: 00220000 eoreq r0, r2, r0
8002a: Address 0x000000000008002a is out of bounds.
Had you gotten the ldr right you would have been doing a 32 bit load from 0x80022, which is not a 32 bit aligned address. Before a pool like that you want to align on at least a 4 byte boundary and for arm gas, the .align will suffice:
.thumb_func
main:
@nothing much here
B main
.align
WDT_MR: .word 0x400E1A54
00080020 <main>:
80020: e7fe b.n 80020 <main>
80022: bf00 nop
00080024 <WDT_MR>:
80024: 400e1a54 andmi r1, lr, r4, asr sl
Notice the nop the tool added as padding, if we were to:
.thumb_func
main:
@nothing much here
B main
adds r0,#1
.align
WDT_MR: .word 0x400E1A54
00080020 <main>:
80020: e7fe b.n 80020 <main>
80022: 3001 adds r0, #1
00080024 <WDT_MR>:
80024: 400e1a54 andmi r1, lr, r4, asr sl
It is still properly aligned.
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/332881.html
