I am trying to understand how the linking works. I have a simple C++ code
#include "a.h"
int Other() {
return 1;
}
int SomeFunction() {
Other();
Other();
Other();
return 0;
}
which generates the following Relocation table.
$ readelf -r a.o
Relocation section '.rela.text' at offset 0x240 contains 3 entries:
Offset Info Type Sym. Value Sym. Name + Addend
000000000018 000900000004 R_X86_64_PLT32 0000000000000000 _Z5Otherv - 4
00000000001d 000900000004 R_X86_64_PLT32 0000000000000000 _Z5Otherv - 4
000000000022 000900000004 R_X86_64_PLT32 0000000000000000 _Z5Otherv - 4
Relocation section '.rela.eh_frame' at offset 0x288 contains 2 entries:
Offset Info Type Sym. Value Sym. Name + Addend
000000000020 000200000002 R_X86_64_PC32 0000000000000000 .text + 0
000000000040 000200000002 R_X86_64_PC32 0000000000000000 .text + f
It looks like the callsites of Other() functions are all marked as R_X86_64_PLT32 type. When I check the definition of R_X86_64_PLT32, it says L + A - P, where L represents the place (section offset or address) of the Procedure Linkage Table entry for a symbol, A represents the addend used to compute the value of the relocatable field and P represents the place (section offset or address) of the storage unit being relocated (computed using r_offset).
I am not sure what it mean by the place of the PLT for a symbol. My questions are
What would be the value of L, A, P for that case?
From my understanding, PLTs are used by dynamic objects. Why Other() is marked as PLT32 even when this is just a static function.
How to find the PLT of the ELF file and how to find Other() in it?
I'm not an expert and a little bit late but as far as I understand it newer GCC versions use R_X86_64_PLT32 instead of R_X86_64_PC32 to mark 32-bit PC-relative branches.
"On x86-64, for 32-bit PC-relative branches, we can generate PLT32 relocation, instead of PC32 relocation, which can also be used as a marker for 32-bit PC-relative branches. Linker can always reduce PLT32 relocation to PC32 if function is defined locally. Local functions should use PC32 relocation." (Related Commit)
So despite the fact that the type of the relocation entry is R_X86_64_PLT32 the linker will still use the R_X86_64_PC32 computation (S + A - P) for the relocation target being modified, where:
S is the value of the symbol (st_value of Elf64_Sym)A is the addend (-4 in your case)P is the address of the memory location being relocated (the start of the address of the call to Other)because Other is a local function. So the PLT actually doesn't play a role at all in your case.
If you want to get an overview over all section headers (incl. .plt, .got, .got.plt, ...) you can use readelf -S on an EXEC/ DYN elf file (compiled and linked). Or just use objdump -d <file which also shows the different sections together with the dump.
I hope that this explains it a little bit.
Short example similar to yours for the sake of completeness (I used C but that shouldn't make a difference):
I have a file rel.c that calls the function Other within other.c. First I compile both files gcc -c -o <name>.o <name>.c.
readelf -r rel.o:
Relocation section '.rela.text' at offset 0x198 contains 1 entry:
Offset Info Type Sym. Value Sym. Name + Addend
000000000015 000500000004 R_X86_64_PLT32 0000000000000000 Other - 4
As you can see the A (addend) is -4 the final addresses S and P are not known yet.
After linking everything using gcc -o main rel.o other.o I used objdump -M intel -d main to get the complete dump of the binary.
The interesting part is shown below.
...
0000000000001139 <main>:
1139: 55 push rbp
113a: 48 89 e5 mov rbp,rsp
113d: 48 83 ec 10 sub rsp,0x10
1141: 89 7d fc mov DWORD PTR [rbp-0x4],edi
1144: 48 89 75 f0 mov QWORD PTR [rbp-0x10],rsi
1148: b8 00 00 00 00 mov eax,0x0
114d: e8 07 00 00 00 call 1159 <Other>
1152: b8 00 00 00 00 mov eax,0x0
1157: c9 leave
1158: c3 ret
0000000000001159 <Other>:
1159: 55 push rbp
115a: 48 89 e5 mov rbp,rsp
...
As one can see the DWORD at 0x114e holds the offset 0x7 that can be used together with the IP to jump to the address of the Other subroutine (0x1152 + 0x7 = 0x1159).
This is calculated using S + A - P = 0x1159 - 0x4 - 0x114e = 7.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With