2
votes

I know how to load an immediate value using the LDR instruction in ARM.

For example:

LDR R0,=0x0804c088 This instruction loads the value (0x0804c088) to the register r0. When I try to access the address it is stored in using x/x $r0 using gdb. I get the message: Cannot access memory at address0x0804c088. But that is not the address, it is the value stored in that register and the address is a PC relative address which is stored in the literal pool.

What is the mistake that I doing there? did I understand something wrong there?

Moreover, How should I set the literal pool, can you give me an example please?

@Carl Norum: Here is the code.

__asm__("LDR R0,=0x0804c088");
__asm__("LDR R1,[PC, #34];");

O/p from gdb

(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 <test46+34>
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 <test46+34>:     0x1022f8df
2
@Jake'Alquimista'LEE : so it is possible. The question is very unclear. You got a meaning from it I didn't consider; which is valid and interesting, but not very useful for anything. In the other question, I asked to describe the higher level purpose of what pistal is trying to do. He seems very confused about assembler to me.artless noise
Agreed, the OP seems to be confused. He want's to know something that he doesn't have to, for whatever the reason might be.Jake 'Alquimista' LEE

2 Answers

1
votes

The gdb x command has an inherent dereferencing operation. If you want to print the value in r0, just use p:

p/x $r0

The form of LDR you're using isn't a real instruction - it's an assembler macro-instruction that gets converted into a pc-relative ldr instruction and a literal value someplace in memory (probably close to the location you're using it). If you want to find the address of the constant in the literal pool, you need to look at the output binary. Your source assembly code doesn't contain it.

For example, let's take this simple example program:

    .globl f
f:
    ldr r0,=0x12345678

And then build and disassemble it:

$ 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 <f>:
   0:   e51f0004    ldr r0, [pc, #-4]   ; 4 <f+0x4>
   4:   12345678    .word   0x12345678

You can see the literal is right there at offset 4.

You don't need to do anything to "set up the literal pool". Any necessary literals will be set up for you by the assembler.

1
votes

If you want to know the actual address of the literal pool at runtime, try this :

adr r12, literal_pool_label
.
.
. // your code here
.
.
.
literal_pool_label:
.ltorg

Then you can read r12 which contains the address of the literal pool at runtime.

ltorg is a directive forcing where the literal pool is placed. For short codes, they are automatically attached at the end of the code, but if the code gets larger than 4KB, the LDR pseudo instruction will cause an error at assembly time since the pc-relative offset gets bigger than 4096, and thus out of allowed range.

To avoid this, you can put ltorg middle in the code where it's safe from being misinterpreted as an instruction. (after an absolute branch for example)