Got the following error when I tried to compile a C application in 64-bit FreeBSD:
relocation R_X86_64_32S can not be used when making a shared object; recompile with -fPIC
What is R_X86_64_32S
relocation and what is R_X86_64_64
?
I've googled about the error, and it's possible causes - It'd be great if anyone could tell what R_X86_64_32S really means.
For any of this to make sense, you must first:
Standards
R_X86_64_64
,R_X86_64_32
andR_X86_64_32S
are all defined by the System V AMD ABI, which contains the AMD64 specifics of the ELF file format.They are all possible values for the
ELF32_R_TYPE
field of a relocation entry, specified in the System V ABI 4.1 (1997) which specifies the architecture neutral parts of the ELF format. That standard only specifies the field, but not it's arch dependant values.Under 4.4.1 "Relocation Types" we see the summary table:
We will explain this table later.
And the note:
Example of R_X86_64_64 and R_X86_64_32
Let's first look into
R_X86_64_64
andR_X86_64_32
:Then:
Contains:
Tested on Ubuntu 14.04, Binutils 2.24.
Ignore the disassembly for now (which is meaningless since this is data), and look only to the labels, bytes and relocations.
The first relocation:
Which means:
0
: acts on byte 0 (labela
)R_X86_64_
: prefix used by all relocation types of the AMD64 system V ABI32
: the 64-bit address of the labels
is truncated to a 32 bit address because we only specified a.long
(4 bytes).text
: we are on the.text
section0xc
: this is the addend, which is a field of the relocation entryThe address of the relocation is calculated as:
Where:
A
: the addend, here0xC
S
: the value of the symbol before relocation, here00 00 00 00 == 0
Therefore, after relocation, the new address will be 0xC == 12 bytes into the
.text
section.This is exactly what we expect, since
s
comes after a.long
(4 bytes) and a.quad
(8 bytes).R_X86_64_64
is analogous, but simpler, since here there is no need to truncate the address ofs
. This is indicated by the standard throughword64
instead ofword32
on theField
column.R_X86_64_32S vs R_X86_64_32
The difference between
R_X86_64_32S
vsR_X86_64_32
is when the linker will complain "with relocation truncated to fit":32
: complains if the truncated after relocation value does not zero extend the old value, i.e. the truncated bytes must be zero:E.g.:
FF FF FF FF 80 00 00 00
to80 00 00 00
generates a complaint becauseFF FF FF FF
is not zero.32S
: complains if the truncated after relocation value does not sign extend the old value.E.g.:
FF FF FF FF 80 00 00 00
to80 00 00 00
is fine, because the last bit of80 00 00 00
and the truncated bits are all 1.See also: What does this GCC error "... relocation truncated to fit..." mean?
R_X86_64_32S
can be generated with:Then:
Gives:
Now we can observe the "relocation" truncated to fit on
32S
with a linker script:Now:
Is fine, because:
0xFFFFFFFF80000000
gets truncated into80000000
, which is a sign extension.But if we change the linker script to:
It now generates the error, because that
0
made it not be a sign extension anymore.Rationale for using
32S
for memory access but32
for immediates: When is it better for an assembler to use sign extended relocation like R_X86_64_32S instead of zero extension like R_X86_64_32?I ran into this problem and found this answer didn't help me. I was trying to link a static library together with a shared library. I also investigated putting the -fPIC switch earlier on the command line (as advised in answers elsewhere). The only thing that fixed the problem, for me, was changing the static library to shared. I suspect the error message about -fPIC can happen due to a number of causes but fundamentally what you want to look at is how your libraries are being built, and be suspicious of libraries that are being built in different ways.
That means that compiled a shared object without using
-fPIC
flag as you should:You need to call
Under ELF platform (Linux) shared objects are compiled with position independent code - code that can run from any location in memory, if this flag is not given, the code that is generated is position dependent, so it is not possible to use this shared object.
The
R_X86_64_32S
andR_X86_64_64
are names of relocation types, for code compiled for the amd64 architecture. You can look all of them up in the amd64 ABI. According to it,R_X86_64_64
is broken down to:and
R_X86_64_32S
to:which basically means "the value of the symbol pointed to by this relocation, plus any addend", in both cases. For
R_X86_64_32S
the linker then verifies that the generated value sign-extends to the original 64-bit value.Now, in an executable file, the code and data segments are given a specified virtual base address. The executable code is not shared, and each executable gets its own fresh address space. This means that the compiler knows exactly where the data section will be, and can reference it directly. Libraries, on the other hand, can only know that their data section will be at a specified offset from the base address; the value of that base address can only be known at runtime. Hence, all libraries must be produced with code that can execute no matter where it is put into memory, known as position independent code (or PIC for short).
Now when it comes to resolving your problem, the error message speaks for itself.
In my case the issue arose because the program to compile expected to find shared libraries in a remote directory, while only the corresponding static libraries were there in a mistake.
Actually, this relocation error was a file-not-found error in disguise.
I have detailed how I coped with it in this other thread https://stackoverflow.com/a/42388145/5459638