簡體   English   中英

使用 ldr 從匯編器中的文字池加載變量

[英]Load variable from literal pool in assembler with ldr

我想從文字池加載變量。 文字池位於 asm 文件的末尾。

literal_pool_label:
.WORD POOL_EVENT_CHANNEL_2_START_REG_ADDR
.WORD POOL_EVENT_CHANNEL_4_START_REG_ADDR

在我寫的代碼中:

adr r12, literal_pool_label
ldr r5, [r12, #0]

ldr r5, [r12, #4]

在 C 模塊中,變量的定義如下:

const uint32_t POOL_EVENT_CHANNEL_2_START_REG_ADDR = 0x4100e030;
const uint32_t POOL_EVENT_CHANNEL_4_START_REG_ADDR = 0x4100e040;

如果我按照以下方式在池中寫入,則該值是正確的。

.WORD 0x4100e030 // POOL_EVENT_CHANNEL_2_START_REG_ADDR
.WORD 0x4100e040 // POOL_EVENT_CHANNEL_4_START_REG_ADDR

我必須怎么做才能通過一條指令從變量中獲取值?

ARM 沒有像 pdp11 或其他我想不到的(msp430?)那樣的雙間接尋址模式。

您的另一個問題是基於 cortex-m 的,也許這就是您嘗試在 ram 中執行此操作的原因,您為此付出了很多努力而沒有解釋為什么需要此功能以及是否會在項目中保存一條指令在某些成功與失敗中。 如果這是一個性能問題,那么還有其他方法可以解決這個問題,並且很可能代碼,一條指令,不會以顯着的方式提高性能。 (實際上可能會使情況變得更糟,取決於)。

所以

ldr r0,hello
ldr r1,world_addr
ldr r2,[r1]
b .

hello: .word 0x12345678
world_addr: .word world_data
.data
world_data: .word 0x87654321

Disassembly of section .text:

00001000 <hello-0x10>:
    1000:   e59f0008    ldr r0, [pc, #8]    ; 1010 <hello>
    1004:   e59f1008    ldr r1, [pc, #8]    ; 1014 <world_addr>
    1008:   e5912000    ldr r2, [r1]
    100c:   eafffffe    b   100c <hello-0x4>

00001010 <hello>:
    1010:   12345678    eorsne  r5, r4, #120, 12    ; 0x7800000

00001014 <world_addr>:
    1014:   00002000    andeq   r2, r0, r0

Disassembly of section .data:

00002000 <__data_start>:
    2000:   87654321    strbhi  r4, [r5, -r1, lsr #6]!

可以很容易地要求在該部分內生成與 pc 相關的尋址。 在該部分之外,您通常會對地址進行相對於 pc 的加載,然后第二級間接訪問是訪問項目本身。

如果你嘗試這個 gnu 匯編器會抱怨。

ldr r0,hello
ldr r1,world_addr
ldr r2,[r1]
ldr r3,world_data
b .

hello: .word 0x12345678
world_addr: .word world_data
.data
world_data: .word 0x87654321

現在是的,它在技術上是可能的,因為有一種相對於 pc 的尋址模式,如果您可以通過這種方式訪問​​變量,那么您可以在一條指令中完成它,這是告訴匯編程序的問題。

    1000:   e59f0008    ldr r0, [pc, #8]    ; 1010 <hello>
    ...
    1010:   12345678    eorsne  r5, r4, #120, 12    ; 0x7800000

范圍更廣。

.cpu cortex-m4
.thumb
ldr r0,hello
b .
.space 0x20000000
.align
world_data: .word 0x87654321

但是組裝商抱怨。

由於您正在編寫匯編語言,因此您和我都在屏幕上打開了 arm 架構參考手冊,您可以看到拇指編碼允許 5 位偏移,拇指 2 編碼允許 12 位偏移(均帶符號)最佳情況.

指定從 的值中添加或減去的立即偏移量以形成地址。 允許的值為 0-124 范圍內的 4 倍數用於編碼 T1,0-1020 范圍內的 4 倍數用於編碼 T2,0-4095 范圍內的任何值用於編碼 T3,以及 0-255 范圍內的任何值用於編碼 T4。 對於偏移尋址語法, <imm>可以省略,表示偏移量為 0。

cortex-m 代碼低於 0x20000000,而 ram 高於 0x20000000 到某個限制,例如 0x40000000。

如果您可以讓匯編器和鏈接器協同工作來完成它(例如,它們可以使用分支指令),那么這將超過您在閃存中的單個指令所能達到的。

所以 ram 解決方案,你標記了 gnu,所以假設 gnu binutils。

.cpu cortex-m4
.thumb
ldr r0,hello
b .
.align
hello: .word 0x87654321
.data
.word 0x12345

MEMORY
{
    rom : ORIGIN = 0x00000000, LENGTH = 0x1000
    ram : ORIGIN = 0x20000000, LENGTH = 0x1000
}
SECTIONS
{
    .text   : { *(.text*)   } > rom
    .rodata : { *(.rodata*) } > rom
    .bss    : { *(.bss*)    } > ram
    .data : { *(.rodata*) } > ram AT > rom
}

Disassembly of section .text:

00000000 <hello-0x4>:
   0:   4800        ldr r0, [pc, #0]    ; (4 <hello>)
   2:   e7fe        b.n 2 <hello-0x2>

00000004 <hello>:
   4:   87654321

Disassembly of section .data:

20000000 <.data>:
20000000:   00012345

00000000  00 48 fe e7 21 43 65 87  45 23 01 00              |.H..!Ce.E#..|
0000000c

S00A0000736F2E7372656338
S30D000000000048FEE72143658775
S309000000084523010085
S70500000000FA

所以使用 .data 我們會看到類似的東西,你可以看到 .data 項目在閃存中,然后你將標簽/變量添加到鏈接器腳本,然后使用這些標簽/變量復制編譯時初始化的基於 ram 的項目在執行主程序之前 ram (假設是 C,但在您的情況下,如果這純粹是一個匯編程序,您可以隨時執行此操作)。

.cpu cortex-m4
.thumb
.thumb_func
fun:
    ldr r0,something
    bx lr
.align
something: .word 0x11223344

MEMORY
{
    rom : ORIGIN = 0x00000000, LENGTH = 0x1000
    ram : ORIGIN = 0x20000000, LENGTH = 0x1000
}
SECTIONS
{
    .text   : { so.o(.text*)  } > rom
    .rodata : { *(.rodata*) } > rom
    .bss    : { *(.bss*)    } > ram
    .data : { *(.rodata*) } > ram AT > rom
    .fun  : { fun.o(.text*) } > ram AT > rom
}

Disassembly of section .text:

00000000 <hello-0x4>:
   0:   4800        ldr r0, [pc, #0]    ; (4 <hello>)
   2:   e7fe        b.n 2 <hello-0x2>

00000004 <hello>:
   4:   87654321    strbhi  r4, [r5, -r1, lsr #6]!

Disassembly of section .fun:

20000004 <fun>:
20000004:   46c0        nop         ; (mov r8, r8)
20000006:   4770        bx  lr

(srec)
S00A0000736F2E7372656338
S30D000000000048FEE72143658775
S309000000084523010085
S3090000000CC04670472D
S70500000000FA

與 .data 一樣,您可以添加鏈接器變量並使用它們將函數從閃存復制到內存,然后再執行,最好是在引導程序中,但如果這是一個沒有 C 的純 asm 程序,那么在您使用它之前的任何地方。

(不,這不是有效的 cortex-m 程序,只是演示了工具)

您可能希望從與您正在使用的 C 庫關聯的鏈接器腳本開始,因為鏈接器腳本和引導程序通常位於固定設置(SDK、工具鏈、C 庫等的一部分)中,復制 .data並從那里開始,但要明白你會遇到問題,因為我已經解決了上面的臀部方式

.text   : { *(.text*)   } > ram

將要獲取所有 .text,包括來自其他部分/文件。 至少在我的情況下,首先出現的是什么(當你想控制向量表等時,你可能需要做更多的工作,而不是簡單地將它放在 .text 中並將文件按順序放在命令行上)。 因此,與任何鏈接器腳本和引導程序工作一樣,您必須迭代、構建和反匯編,直到獲得它。

如果你的原因是性能(或感知性能),那么你可以像有人提到的那樣用完 ram 但你可以在 ram 中運行整個項目,如果你有空間,這會讓生活更輕松,你應該獲得最佳的提取性能,(盡管是 cortex-m7,但它可能不是最好的)。

.cpu cortex-m4
.thumb
ldr r0,hello
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
b .
.align
hello: .word 0x87654321

MEMORY
{
    ram : ORIGIN = 0x20000000, LENGTH = 0x1000
}
SECTIONS
{
    .text   : { *(.text*)   } > ram
    .rodata : { *(.rodata*) } > ram
    .data   : { *(.data*)   } > ram
    .bss    : { *(.bss*)    } > ram
}


Disassembly of section .text:

20000000 <hello-0x1c>:
20000000:   4806        ldr r0, [pc, #24]   ; (2000001c <hello>)
20000002:   46c0        nop         ; (mov r8, r8)
20000004:   46c0        nop         ; (mov r8, r8)
20000006:   46c0        nop         ; (mov r8, r8)
20000008:   46c0        nop         ; (mov r8, r8)
2000000a:   46c0        nop         ; (mov r8, r8)
2000000c:   46c0        nop         ; (mov r8, r8)
2000000e:   46c0        nop         ; (mov r8, r8)
20000010:   46c0        nop         ; (mov r8, r8)
20000012:   46c0        nop         ; (mov r8, r8)
20000014:   46c0        nop         ; (mov r8, r8)
20000016:   46c0        nop         ; (mov r8, r8)
20000018:   46c0        nop         ; (mov r8, r8)
2000001a:   e7fe        b.n 2000001a <hello-0x2>

2000001c <hello>:
2000001c:   87654321    strbhi  r4, [r5, -r1, lsr #6]!

幾行 C 代碼可以獲取輸出並生成這個

copybase: .word 0x20000000
copysize: .word 0x00000008
copydata:
.word 0x46C04806 @0x20000000
.word 0x46C046C0 @0x20000004
.word 0x46C046C0 @0x20000008
.word 0x46C046C0 @0x2000000C
.word 0x46C046C0 @0x20000010
.word 0x46C046C0 @0x20000014
.word 0xE7FE46C0 @0x20000018
.word 0x87654321 @0x2000001C

然后在同一個臨時 C 程序中或外部,您可以執行以下操作:

.cpu cortex-m4
.thumb
.syntax unified
.globl _start
_start:
.word 0x20001000
.word reset
.thumb_func
reset:
    ldr r0,copybase
    ldr r1,copysize
    ldr r2,=copydata
    .align
copy_loop:
    ldr r3,[r0],#4
    str r3,[r2],#4
    subs r1,#1
    bne copy_loop
    ldr r0,copybase
    orr r0,#1
    bx r0

    copybase: .word 0x20000000
    copysize: .word 0x00000008
    copydata:
    .word 0x46C04806 @0x20000000
    .word 0x46C046C0 @0x20000004
    .word 0x46C046C0 @0x20000008
    .word 0x46C046C0 @0x2000000C
    .word 0x46C046C0 @0x20000010
    .word 0x46C046C0 @0x20000014
    .word 0xE7FE46C0 @0x20000018
    .word 0x87654321 @0x2000001C

這甚至不一定需要鏈接器腳本 -Ttext=0 就足夠了,但如果不需要

MEMORY
{
    rom : ORIGIN = 0x00000000, LENGTH = 0x1000
}
SECTIONS
{
    .text   : { *(.text*)   } > rom
}

gnu 鏈接器確實存在與此類相關的錯誤,因此鏈接器腳本更清晰。

在這兩種情況下,鏈接器腳本和 C 的引導程序都變得微不足道,如果您制作得當,您的引導程序可以是:

reset:
   bl main
   b .

對於基於 ram 的程序。

您的讀取性能通常是 sram 的一個時鍾,其中閃存很慢,並且隨着您在許多 mcus 上使用更快的處理器時鍾速度而變得更糟。

你得到你的單周期ldr。

如果在 armv6-m 而不是 armv7-m 上,那么這是一個簡單的調整......復制/跳轉顯然不會按原樣工作。

請注意,如果只是 ldr,您可以這樣做

    ldr r0,something
...
something: .word 0x11223344

並且兩者都將落在 .text 中,並且理想情況下是相對於 pc 的,具體取決於指令集和距離。 以上都不是必需的。 如果您想從其他地方讀寫該值並讓此代碼簡單地讀取它,那么是的,數據需要在 ram 中。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM