1
votes

I have written a simple assembly code which I am trying to compile in 64-bit mode. Here is the code:

extern printf

section .rodata
readinfo db `%d\n`, 0

section .text
global main
main:
mov rbp, rsp ; for correct debugging

mov rax, 5
push rax
push readinfo
call printf
add rsp, 8

xor rax, rax
mov rsp, rbp
ret

And here are the instructions I give to nasm and gcc (as I have read on other posts, gcc automatically links the object file with the default c libraries):

nasm -f elf64 -o test.o test.asm -D UNIX
gcc -o test test.o

However, I get the following relocation error:

/usr/bin/x86_64-linux-gnu-ld: test.o: relocation R_X86_64_32S against `.rodata' can not be used when making a PIE object; recompile with -fPIC

/usr/bin/x86_64-linux-gnu-ld: final link failed: Nonrepresentable section on output

collect2: error: ld returned 1 exit status

When I compile with the '-no-pic' option to disable positionally-independent code, it compiles without errors, but after execution I get a segfault with no output. When I recompile the code in 32-bit (replacing 64-bit registers with 32-bit), I get no error. The commands are:

nasm -f elf32 -o test.o test.asm -D UNIX
gcc -o test test.o -m32

My question is: why can't I compile the code with PIC in 64bit mode?

PS: This is not a duplicate of Can't link a shared library from an x86-64 object from assembly because of PIC , since the error is different and the solution found in that post has nothing in relation with my problem. I have edited the error output to specify.

1
push readinfo is not position independent. You could do lea rax, [rel readinfo] push rax. But forget that. In 64-bit Linux code the first parameters are passed in registers.(not on the stack). You'd also need to change call printf to call printf wrt ..pltMichael Petch
To to the print you want try xor eax, eax lea rdi, [rel readinfo] mov esi, 5 call printf wrt ..plt . Register AL has to be set to the number of vector registers use which in this case is 0. So I use XOR EAX, EAX to zero RAX. First integer class parameter is in RDI, second in RSIMichael Petch
The 64-bit ABI can be found here that discusses the calling convention: github.com/hjl-tools/x86-psABI/wiki/x86-64-psABI-1.0.pdf . Note,printf is a variadic function (not a fixed number of arguments) and variadic functions are also covered in the ABI.Michael Petch
You can find a summary of the calling convention here: en.wikipedia.org/wiki/…Michael Petch

1 Answers

3
votes

The mistake was that I was using the wrong calling convention. In architecture x86_64 the first two arguments are passed in rdi and rsi, respectively, without using the stack. Also, I needed to add "wrt ..plt" to the call. The following code works:

extern printf

section .rodata
readinfo db `%d\n`, 0

section .text
global main
main:
mov rbp, rsp ; for correct debugging

mov rsi, 5
mov rdi, readinfo
xor rax, rax
call printf wrt ..plt

xor rax, rax
mov rsp, rbp
ret

The commands for nasm and gcc haven't changed.