1

For a binary instrumentation project I wrote a chunk of assembly code in NASM, which gets mapped into a binary's address space at runtime.

The chunk gets loaded at address instrument_addr, and needs to access data at address instrument_addr+data_offset, where data_offset is some fixed 31-bit number. Due to ASLR I don't know the value of instrument_addr at compile time.

Since I don't know the absolute address of my instrumentation code, but the relative offset of my data, I would like to use RIP-relative addressing:

; Example for data_offset = 0x1000
0:  48 8b 05 f9 0f 00 00    mov    rax, QWORD PTR [rip+0xff9]    # 1000

However, the most straightforward approach

; This is offset 0 of my assembly file
instrument:
    mov rax, qword [rel 0x1000]

only leads to:

$ nasm -f elf64 -o instrument.o instrument.asm
instrument.asm:3: warning: absolute address can not be RIP-relative [-w+other]

Using [absolute 0x1000] with a dummy label produces the same warning.

How can I force NASM to generate RIP-relative accesses to a certain fixed offset?

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
janw
  • 8,758
  • 11
  • 40
  • 62

2 Answers2

4

The syntax you're looking for is [rel $+0x1000] for an offset from the current location, or [rel instrument+0x1000] for an offset from the label. In the example in your question, those happen to be the same since the mov is the first thing after the label, but if there were anything in between, they'd be different.

2

Nasm interprets your code as "access address 0x1000 using rip-relative addressing" and so it fails. What you can do is specify a relative address using the $ symbol, which stands for the address of the current instruction:

mov rax, qword [rel $+0x1000]
Dario Petrillo
  • 980
  • 7
  • 15
  • 1
    This only works if the instruction is the very first in the file, as `$` always points to the current instruction, as you said - for other instructions one would need to manually subtract their offset, so using the first label as shown in the other answer is more elegant. Technically, it still solves the problem for the simplified example in the question :) – janw Nov 05 '21 at 14:31
  • 3
    @janw: fun fact, YASM doesn't fail to assemble. It assembles `mov eax, [rel 0x1000]` to `mov eax,DWORD PTR [rip+0x0] # 0x6 2: R_X86_64_PC32 *ABS*+0xffc` (`objdump -drwC -Mintel` output for a `.o`) which uses a relocation that tells the linker to reach absolute address 0x1000 from whatever location this code gets linked to. It will only link successfully into a non-PIE executable so static code+data go in the low 2GiB of address space, which is in range of `0x1000`. – Peter Cordes Nov 05 '21 at 15:07