I was trying to make a basic printf
example in x86-64 assembly code for OSX, here's my first version:
section .data
msg db 'hello', 0Ah
section .text
extern _printf
global _main
_main:
sub rsp, 8
mov rdi, msg
mov rax, 0
call _printf
add rsp, 8
ret
So this code is moving the absolute address of msg
into rdi
for the first argument to _printf
, and gcc then complains about the lack of position-independent code. The binary still works though:
→ nasm -f macho64 new.asm && gcc -m64 -o new new.o && ./new
ld: warning: PIE disabled. Absolute addressing (perhaps -mdynamic-no-pic) not allowed in code signed PIE, but used in _main from new.o. To fix this warning, don't compile with -mdynamic-no-pic or link with -Wl,-no_pie
hello
So when I change the code to use RIP-relative addressing, using the [rel ...]
nasm syntax, the warning disappears but the executable now seg faults:
section .data
msg db 'hello', 0Ah
section .text
extern _printf
global _main
_main:
sub rsp, 8
mov rdi, [rel msg]
mov rax, 0
call _printf
add rsp, 8
ret
And when I compile and run it:
→ nasm -f macho64 new.asm && gcc -m64 -o new new.o && ./new
zsh: segmentation fault ./new
Does anyone know what's going wrong?
The problem is that the original mov rdi, msg
loaded the memory address of msg
into rdi
at assemble time.
When it was changed to mov rdi, [rel msg]
, this produced code which used the value in msg
as the relative address, as seen when debugging:
Program received signal EXC_BAD_ACCESS, Could not access memory.
Reason: KERN_INVALID_ADDRESS at address: 0x00000a6f6c6c6568
Notice how the address contains the bytes from msg
, 0x00000a<olleh>
.
The correct solution is to use the lea
instruction to load the effective RIP-relative address of msg
at runtime, like so:
lea rdi, [rel msg]
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With