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.
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.
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
; 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