LDR – 文字池 – ARM
我知道如何使用ARM中的LDR指令加载立即值。
例如:
LDR R0,=0x0804c088
该指令将值( 0x0804c088
)加载到寄存器r0
。 当我尝试访问地址时,它使用gdb
使用x/x $r0
存储。 我收到消息: Cannot access memory at address
0x0804c088的Cannot access memory at address
。 但这不是地址,它是存储在该寄存器中的值,地址是存储在文字池中的
PC
相对地址。
我在那里做的错误是什么? 我明白了吗?
而且,我该如何设置文字池,你能给我一个例子吗?
@Carl Norum:这是代码。
__asm__("LDR R0,=0x0804c088"); __asm__("LDR R1,[PC, #34];");
来自gdb的O / p
(gdb) info registers r0 0x804c088 134529160 r1 0xf2c00300 4072669952 r2 0x0 0 r3 0x1 1 r4 0x8961 35169 r5 0x0 0 r6 0x0 0 r7 0xbe8f4b74 3197062004 r8 0x0 0 r9 0xef99 61337 r10 0xf00d 61453 r11 0x0 0 r12 0x0 0 sp 0xbe8f4b74 0xbe8f4b74 lr 0x89a7 35239 pc 0x8a62 0x8a62 cpsr 0x60000030 1610612784 (gdb) x/x $r0 0x804c088: Cannot access memory at address 0x804c088 (gdb) p/x$r0 $1 = 0x804c088 (gdb) p/x $r1 $2 = 0xf2c00300 (gdb) x/x $r1 0xf2c00300: Cannot access memory at address 0xf2c00300 (gdb) x/x $r15 0x8a62 : 0x1022f8df
gdb x
命令具有固有的解除引用操作。 如果要在r0
打印值,只需使用p
:
p/x $r0
你正在使用的LDR
forms不是真正的指令 – 它是一个汇编程序宏指令,它被转换成pc相对ldr
指令和内存中某个位置的文字值(可能靠近你正在使用它的位置) 。 如果要在文字池中查找常量的地址,则需要查看输出二进制文件。 源汇编代码不包含它。
例如,让我们来看看这个简单的示例程序:
.globl f f: ldr r0,=0x12345678
然后构建和反汇编它:
$ arm-none-eabi-clang -c example.s $ arm-none-eabi-objdump -d example.o example.o: file format elf32-littlearm Disassembly of section .text: 00000000 : 0: e51f0004 ldr r0, [pc, #-4] ; 4 4: 12345678 .word 0x12345678
您可以在偏移4
处看到文字就在那里。
您无需执行任何操作来“设置文字池”。 汇编程序将为您设置任何必要的文字。
如果您想在运行时知道文字池的实际地址,请尝试以下方法:
adr r12, literal_pool_label . . . // your code here . . . literal_pool_label: .ltorg
然后,您可以在运行时读取包含文字池地址的r12。
ltorg是强制放置文字池的指令。 对于短代码,它们自动附加在代码的末尾,但是如果代码大于4KB,LDR伪指令将在汇编时导致错误,因为pc相对偏移量大于4096,因此允许的范围。
为避免这种情况,您可以将ltorg放在代码中间,以免被误解为指令。 (以绝对分支为例)