I want to store the address of a procedure in a register as follows :
extern _printf
section .text
global _foo
_foo :
mov rax, [rel _printf]
call rax
ret
but i get this error when compiling with a main written in C :
ld: warning: PIE disabled. Absolute addressing (perhaps -mdynamic-no-pic) not allowed in code signed PIE, but used in _foo from procedure.o. To fix this warning, don't compile with -mdynamic-no-pic or link with -Wl,-no_pie
final section layout:
__TEXT/__text addr=0x100000E70, size=0x000000AD, fileOffset=0x00000E70, type=1
__TEXT/__stubs addr=0x100000F1E, size=0x00000018, fileOffset=0x00000F1E, type=28
__TEXT/__stub_helper addr=0x100000F38, size=0x00000038, fileOffset=0x00000F38, type=32
__TEXT/__cstring addr=0x100000F70, size=0x00000036, fileOffset=0x00000F70, type=13
__TEXT/__unwind_info addr=0x100000FA8, size=0x00000050, fileOffset=0x00000FA8, type=22
__DATA/__nl_symbol_ptr addr=0x100001000, size=0x00000008, fileOffset=0x00001000, type=29
__DATA/__got addr=0x100001008, size=0x00000010, fileOffset=0x00001008, type=29
__DATA/__la_symbol_ptr addr=0x100001018, size=0x00000020, fileOffset=0x00001018, type=27
ld: 32-bit RIP relative reference out of range (-4294971162 max is +/-2GB): from _foo (0x100000F13) to _printf@0x00000000 (0x00000000) in '_foo' from procedure.o for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
i tried compiling with -Wl,-no_pie and i got this :
ld: illegal text-relocation to '_printf' in /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/lib/libSystem.tbd from '_foo' in procedure.o for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
so how could i resolve this problem ??
Two possible ways to do this: static linking and dynamic linking. I'll show both. I suspect (based on your code) you are statically linking.
The first two sections are for Linux. The last section is for Macs.
The following works the way you want, I think. I don't use rel because I don't need to; since printf is statically linked, I can just get its address directly.
The push rbp (8 bytes) is necessary; it makes sure the stack is 16-byte aligned after the return address (8 more bytes) is pushed by the call to printf. Calling functions that may use the xmm registers requires that you have the stack aligned on a 16-byte boundary, or you can get a segfault, and printf uses those registers.
Also, printf expects the number of fp arguments to be in rax, so I set it to zero and use rdx instead to hold the address.
; hello-static.asm
; nasm -felf64 hello-static.asm && gcc -static -o hello-static hello-static.o
extern printf
section .text
global main
main: push rbp
mov rdx, printf
mov rdi, fmt
xor eax, eax
call rdx
pop rbp
ret
fmt: db "Hello", 10, 0
The traditional way to do this in a dynamically linked executable is via the PLT. The following does it that way.
; hello.asm
; nasm -felf64 hello.asm && gcc -o hello hello.o
extern printf
section .text
global main
main: push rbp
lea rdx, [rel printf wrt ..plt]
mov rdi, fmt
xor eax, eax
call rdx
pop rbp
ret
fmt: db "Hello", 10, 0
A few words of explanation. First, pushing rbp makes sure the stack is aligned on a 16-byte boundary by the call to printf. Second, I used rel to get the address of the jump in the PLT with respect to the value of rip. Third, I used rdx instead of rax; the latter register is used by printf for the number of floating point arguments.
The address in rdx will not contain the actual address of printf. For that you would need to go to the GOT and fetch it from there.
The following code fetches the address from the GOT.
; hello-got.asm
; nasm -felf64 hello-got.asm && gcc -o hello-got hello-got.o
extern printf
extern _GLOBAL_OFFSET_TABLE_
section .text
global main
main: push rbx
lea rbx, [rel _GLOBAL_OFFSET_TABLE_]
lea rdx, [printf wrt ..got]
add rdx, rbx
mov rdx, [rdx]
mov rdi, fmt
xor eax, eax
call rdx
pop rbx
ret
fmt: db "Hello", 10, 0
Here I first get the address of the GOT using rip-relative addressing. Then I get the offset into the GOT of the printf function's vector. Then I add the offset to the base address of the GOT to get the absolute address of the printf vector. Finally, I move the vector into rdx so I can call it later.
I don't push rbp because I don't need to save the stack frame here; I have to preserve rbx (it is traditionally used to hold the base address of the GOT) because it's a callee-saved register, and that takes care of stack alignment.
The procedure for the Mac is nearly the same: look up the symbol in the global offset table to find the vector, and then de-reference it to obtain the actual address of the procedure. Use wrt ..gotpcrel instead of finding the GOT and then using wrt ..got.
; hello-mac.asm
; nasm -fmacho64 hello-mac.asm && ld -o hello-mac hello-mac.o -lc
extern _printf
global _main
section .text
_main: push rbp
mov rbp, rsp
mov rdi, msg
mov rsi, 17
lea rsi, [rel _printf wrt ..gotpcrel]
xor eax, eax
call [rsi]
xor eax, eax
leave
ret
section .data
msg: db "printf: 0x%lx", 10, 0
User contributions licensed under CC BY-SA 3.0