addr_dime : .word dime
無情地過度複雜。該地址已經是鏈接時間常數。將地址存儲在內存中(在具有自己地址的另一個地方)並不能完全幫助你,它只是增加了另一層間接尋址。 (這實際上是你的問題的根源。)
無論如何,cmp
不取消它的寄存器操作數,所以你比較指針。如果您單獨使用調試器,您會看到寄存器中的值是指針。
要在dime
加載單個字節,零擴展到R3,做
ldrb r3, dime
使用ldr
做一個32位的負荷也將獲得\n
字節,和一個32位的比較將有以匹配eq
也是如此。
但是,只有當dime
足夠接近PC相對尋址模式才能適用;像大多數RISC機器一樣,ARM不能使用任意的絕對地址,因爲指令寬度是固定的。
對於常量,最容易避免的方法是而不是首先將其存儲在內存中。使用.equ dime, 'D'
定義數值常量,那麼你可以使用
cmp r2, dime @ compare with immediate operand
或者ldr r3, =dime
要求彙編得到不斷的進入你的寄存器。你可以用地址做到這一點,那麼你可以做
ldr r2, =inputVal @ r2 = &inputVal
ldrb r2, [r2] @ load first byte of inputVal
這是處理來自這可能是太遙遠的PC相對尋址模式的靜態數據加載的通用方法。
你可以通過使用堆棧地址(sub sp, #16
/mov r5, sp
或其他)來避免這種情況。那麼你已經有了一個寄存器中的地址。
這正是一個C編譯器:
char dime[4] = "D\n";
char input[4] = "xyz";
int foo(int start) {
if (dime[0] == input[0])
start += 10;
return start;
}
從ARM32 gcc6.3上Godbolt compiler explorer:
foo:
ldr r3, .L4 @ load a pointer to the data section at dime/input
ldrb r2, [r3]
ldrb r3, [r3, #4]
cmp r2, r3
addeq r0, r0, #10
bx lr
.L4:
@ gcc greated this "literal pool" next to the code
@ holding a pointer it can use to access the data section,
@ wherever the linker ends up putting it.
.word .LANCHOR0
.section .data
.p2align 2
@@@ These are in a different section, near each other.
@@@ On Godbolt, click the .text button to see full assembler directives.
.LANCHOR0: @ actually defined with a .set directive, but same difference.
dime:
.ascii "D\012\000"
input:
.ascii "xyz\000"
嘗試改變C到用文字字符,而不是比較全局編譯器不能優化成一個常量,並看看你得到了什麼。
當我這樣做,我得到一個錯誤,說internal_relocation(類型:OFFSET_IMM)沒有修復 – PCRevolt
@PCRevolt:啊,是啊,我想知道如果彙編程序會神奇地照顧使用尋址模式,可以達到的數據。 ARM使用固定寬度的指令,而且它們沒有空間存放任意的32位絕對地址。有一個偏移量小的PC相對尋址模式,因此ARM代碼通常使用「文字池」從實際代碼附近的塊中加載數據。看看C編譯器的功能:https://godbolt.org/g/xnRrNa。如果你只是爲你的緩衝區使用堆棧內存,而不是靜態的,你可以避免這種情況。所以你只需要在一個指針和'ldrb r3,[r5]'中獲得地址。 –
但是在這種情況下r5會是什麼 – PCRevolt