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