Interesting linker error
When you are programing a x64 program, it’s high likely that you encounter such a error: “relocation truncated to fit: R_X86_64_32S against symbol“. What happened? especially when you can run this program successfully on an old machine with same / old version. It may appears when you write inline assembly or after you changed your linker script.
This article may also help you: relocation truncated to fit - WTF?
Although forward is not recommended, this article is pretty useful for me and this can be treated as a replication just in case.
Following is forwarded from above article;
1 | (.text+0x3): relocation truncated to fit: R_X86_64_32S against symbol 'array' defined in foo section in ./pcrel8.o |
Consider following code snippet:
1 | $ cat foo.s |
The C program may be like this:
1 | int foovar = 0; |
And when you disassembly the code:
1 | $ gcc -c foo.s |
You may have found that mov
only has 4 byted allocated for linked to put in the address of foovar.
If you check the relocation:
1 | $ readelf --relocs ./foo.o |
Type R_X86_64_32S
is only a 32-bit relocation. So you have figurred the problem.
1 | $ cat test.lds |
This now means that we can not fit the address of foovar inside the space allocated by the relocation. When we try it:
1 | $ ld -Ttest.lds ./foo.o |
What this means is that the full 64-bit address of foovar, which now lives somewhere above 5 gigabytes, can’t be represented within the 32-bit space allocated for it.
For code optimisation purposes, the default immediate size to the mov instructions is a 32-bit value. This makes sense because, for the most part, programs can happily live within a 32-bit address space, and people don’t do things like keep their data so far away from their code it requires more than a 32-bit address to represent it. Defaulting to using 32-bit immediates therefore cuts the code size considerably, because you don’t have to make room for a possible 64-bit immediate for every mov.
So, if you want to really move a full 64-bit immediate into a register, you want the movabs
instruction. Try it out with the code above - with movabs
you should get a R_X86_64_64
relocation and 64-bits worth of room to patch up the address, too.
If you’re seeing this and you’re not hand-coding, you probably want to check out the -mmodel argument to gcc.
So, you may need to change the origin address in your linker script or use movabs
instead to avoid this problem.