The problem
I'm currently reading this book and with the chapter about dynamic linking with the following code:
link_example.s
.globl main
.section .data
output:
.ascii "Yeet\n\0"
.section .text
main:
enter $0, $0
movq stdout, %rdi
movq $output, %rsi
call fprintf
movq $0, %rax
leave
ret
Now according to the book, I need to compile it as follows to link the C-library dynamically:
gcc -rdynamic link_example.s -o link_example
But I'm getting the following error message:
/usr/bin/ld: /tmp/cchUlvqS.o: relocation R_X86_64_32S against symbol `stdout@@GLIBC_2.2.5' can not be used when making a PIE object; recompile with -fPIE
/usr/bin/ld: failed to set dynamic section sizes: bad value
collect2: error: ld returned 1 exit status
What am I doing wrong?
What have you tried?
Adding -fPIE
flag
I tried what the compiler suggested by adding the -fPIE
flag:
gcc -rdynamic -fPIE link_example.s -o link_example
but I'm still getting the same error again.
Searching similar posts
I found a similar post which said, that I just need to use the -shared
flag:
gcc -shared link_example.s -o link_example
but this gives me:
/usr/bin/ld: /tmp/ccxktZan.o: relocation R_X86_64_32S against symbol `stdout@@GLIBC_2.2.5' can not be used when making a shared object; recompile with -fPIC
/usr/bin/ld: failed to set dynamic section sizes: bad value
collect2: error: ld returned 1 exit status
and if I add the -fPIC
flag:
gcc -shared -fPIC link_example.s -o link_example
then I'm getting this:
/usr/bin/ld: /tmp/ccKIQ9sl.o: relocation R_X86_64_32S against symbol `stdout@@GLIBC_2.2.5' can not be used when making a shared object; recompile with -fPIC
/usr/bin/ld: failed to set dynamic section sizes: bad value
collect2: error: ld returned 1 exit status
CodePudding user response:
Let me show you how to fix up the assembly language from your book so it works with your compiler's default settings.
As the comments on the question say, the problem is that your compiler defaults to generating position-independent executables. This means the addresses of stdout
, fprintf
, and output
are not known at link time, so the linker is unable to "relocate" the instructions that refer to them.
What is known at link time, however, is the offsets between the addresses of these things and the program counter. That means, if you just write the assembly a little differently, it will work. Like this:
.globl main
.section .data
output:
.ascii "Yeet\n\0"
.section .text
main:
enter $0, $0
movq stdout(%rip), %rdi
leaq output(%rip), %rsi
call fprintf@PLT
movq $0, %rax
leave
ret
Notice that the change is a little different for all three. mov stdout, %rdi
becomes mov stdout(%rip), %rdi
-- just a different addressing mode for the same instruction. Loading from memory at the fixed address stdout
becomes loading from memory at the fixed displacement stdout
from the RIP register (aka the program counter). Loading the fixed address output
with mov $output, %rsi
, on the other hand, becomes lea output(%rip), %rsi
. I would suggest you think of this one as always having been a load-effective-address operation, but the old code, with the executable at a fixed address, was able to express that operation with move-immediate instead of an actual lea instruction. Finally, call fprintf
becomes call fprintf@PLT
. This is telling the linker that the call needs to go through the procedure linkage table -- your book should explain what this is and why it's needed.
Incidentally, I see several other problems with this assembly language, of which the most important are:
- The string
"Yeet\n\0"
belongs in the read-only data section. - The x86-64 ABI says that variadic functions like
fprintf
need to be told the number of floating point arguments they are receiving, by settingeax
appropriately. enter
andleave
are unnecessary on x86-64. (Also,enter
is a painfully slow microcoded instruction that shouldn't be used at all.)
I would have written something like this instead:
.section .rodata, "a", @progbits
.output:
.string "Yeet\n"
.section .text, "ax", @progbits
.globl main
.type main, @function
main:
sub $8, %rsp
mov stdout(%rip), %rdi
lea .output(%rip), %rsi
xor