Question: ```
ldr r0, #0x28

```

What is the `ldr` instruction ? Does it load a string from some offset?
How can I find the string/value that is actually loaded ?

Answer: 
LDR loads a 32-bit constant (LDRH (halfword): 16 bit, LDRB (byte): 8 bit) from memory into the specified target register (r0 in your example).

Since 32-bit constants cannot be encoded in 32-bit opcodes (or 16-bit for Thumb instructions), the assembler stores the constant in the text segment close to the referencing instruction and then references the value using (usually) PC-relative addressing, i.e. some offset from r15.

Thus, ldr is in fact a pseudo instruction. The following code

```
    .code 32
main:
    ldr r0, =0x12345678
    bx lr

```

is translated by the assembler into

```
00000000 <main>:
       0:   e51f0000    ldr r0, [pc, #-0]   ; 8 <main+0x8>
       4:   e12fff1e    bx  lr
       8:   12345678    .word   0x12345678

```

As you can see, the constant referenced in the original ldr instruction is in fact stored at address 0x8 instead of in the instruction itself. The ldr instruction at address 0 then references this value using PC-relative addressing. The offset to the PC is 0 (instead of 8), since the actual PC value is always the address of the current instruction + 8 - this is an effect of the early ARM processor pipeline which has to be preserved for compatibility.
**`ldr` without `=` does PC relative loads**

This is true for both labels and numbers.

But you will of course rarely use numbers directly in your assembly. Maybe you have provided some disassembly without labels?

Both of the following work in GNU GAS ARMv8. With a label:

```
    ldr x0, pc_relative_ldr
    b 1f
pc_relative_ldr:
    .quad 0x123456789ABCDEF0
1:
    /* x0 == 0x123456789ABCDEF0 */

```

with an offset:

```
    ldr x0, 0x8
    b 1f
    .quad 0x123456789ABCDEF0
1:
    /* x0 == 0x123456789ABCDEF0 */

```

Both are equivalent. The assembler just happens to convert the label into the correct offset for you.

[GitHub upstream with assertions](https://github.com/cirosantilli/arm-assembly-cheat/blob/c4e0662e334052cbdbb18faedf67c78bd792e718/v8/pc.S#L40).

STR does not have PC-relative addressing like LDR in ARMv8, you just have to calculate the address into registers first: <https://stackoverflow.com/questions/28638981/howto-write-pc-relative-adressing-on-arm-asm/54480999#54480999>