-
Notifications
You must be signed in to change notification settings - Fork 11.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[BOLT] Fix order of R_*_IRELATIVE in .rela.plt #106515
base: main
Are you sure you want to change the base?
Conversation
@llvm/pr-subscribers-bolt Author: sinan (linsinan1995) ChangesGNU ld might place R_*_IRELATIVE in .rela.plt, and have a layout like Relocation section '.rela.plt' ... Right now this layout in BOLTed binary will be So that the reloc_index is incorrect and then the dynamic linker fails to resolve the address in .got.plt R_IRELATIVE entries all come after JUMP_SLOT entries. This patch will change the allocatable rela patching order to keep this layout if we find R_IRELATIVE is in .rela.plt section. Full diff: https://github.com/llvm/llvm-project/pull/106515.diff 5 Files Affected:
diff --git a/bolt/include/bolt/Core/Relocation.h b/bolt/include/bolt/Core/Relocation.h
index 933f62a31f8fd7..d925f87f762b30 100644
--- a/bolt/include/bolt/Core/Relocation.h
+++ b/bolt/include/bolt/Core/Relocation.h
@@ -117,6 +117,9 @@ struct Relocation {
/// Return code for a RELATIVE relocation
static uint64_t getRelative();
+ /// Return code for a IRELATIVE relocation
+ static uint64_t getIRelative();
+
/// Return true if this relocation is PC-relative. Return false otherwise.
bool isPCRelative() const { return isPCRelative(Type); }
diff --git a/bolt/lib/Core/Relocation.cpp b/bolt/lib/Core/Relocation.cpp
index 4e888a5b147aca..7caf0446dfe34b 100644
--- a/bolt/lib/Core/Relocation.cpp
+++ b/bolt/lib/Core/Relocation.cpp
@@ -1009,6 +1009,19 @@ uint64_t Relocation::getRelative() {
}
}
+uint64_t Relocation::getIRelative() {
+ switch (Arch) {
+ default:
+ llvm_unreachable("Unsupported architecture");
+ case Triple::aarch64:
+ return ELF::R_AARCH64_IRELATIVE;
+ case Triple::riscv64:
+ llvm_unreachable("not implemented");
+ case Triple::x86_64:
+ return ELF::R_X86_64_IRELATIVE;
+ }
+}
+
size_t Relocation::emit(MCStreamer *Streamer) const {
const size_t Size = getSizeForType(Type);
const auto *Value = createExpr(Streamer);
diff --git a/bolt/lib/Rewrite/RewriteInstance.cpp b/bolt/lib/Rewrite/RewriteInstance.cpp
index adacb50dc167c8..71c92d616c6915 100644
--- a/bolt/lib/Rewrite/RewriteInstance.cpp
+++ b/bolt/lib/Rewrite/RewriteInstance.cpp
@@ -5185,12 +5185,15 @@ RewriteInstance::patchELFAllocatableRelaSections(ELFObjectFile<ELFT> *File) {
DynamicRelativeRelocationsCount = 0;
+ const bool HasIRelativeInPLT =
+ IsJmpRelocation.contains(Relocation::getIRelative());
+
auto writeRela = [&OS](const Elf_Rela *RelA, uint64_t &Offset) {
OS.pwrite(reinterpret_cast<const char *>(RelA), sizeof(*RelA), Offset);
Offset += sizeof(*RelA);
};
- auto writeRelocations = [&](bool PatchRelative) {
+ auto writeRelocations = [&](bool PatchRelative, bool PatchIRelativeInPLT) {
for (BinarySection &Section : BC->allocatableSections()) {
const uint64_t SectionInputAddress = Section.getAddress();
uint64_t SectionAddress = Section.getOutputAddress();
@@ -5199,9 +5202,14 @@ RewriteInstance::patchELFAllocatableRelaSections(ELFObjectFile<ELFT> *File) {
for (const Relocation &Rel : Section.dynamicRelocations()) {
const bool IsRelative = Rel.isRelative();
+ const bool IsIRelativeInPLT = HasIRelativeInPLT && Rel.isIRelative();
+
if (PatchRelative != IsRelative)
continue;
+ if (PatchIRelativeInPLT != IsIRelativeInPLT)
+ continue;
+
if (IsRelative)
++DynamicRelativeRelocationsCount;
@@ -5249,8 +5257,13 @@ RewriteInstance::patchELFAllocatableRelaSections(ELFObjectFile<ELFT> *File) {
// The dynamic linker expects all R_*_RELATIVE relocations in RELA
// to be emitted first.
if (!DynamicRelrAddress)
- writeRelocations(/* PatchRelative */ true);
- writeRelocations(/* PatchRelative */ false);
+ writeRelocations(/* PatchRelative */ true, /* PatchIRelativeInPLT */ false);
+ writeRelocations(/* PatchRelative */ false, /* PatchIRelativeInPLT */ false);
+
+ // Place R_*_IRELATIVE after all R_*_JUMP_SLOT relocations emitted if
+ // R_*_IRELATIVE is presented at .rela.plt
+ if (HasIRelativeInPLT)
+ writeRelocations(/* PatchRelative */ false, /* PatchIRelativeInPLT */ true);
auto fillNone = [&](uint64_t &Offset, uint64_t EndOffset) {
if (!Offset)
diff --git a/bolt/test/X86/Inputs/ifunc-ld.yaml b/bolt/test/X86/Inputs/ifunc-ld.yaml
new file mode 100644
index 00000000000000..18032397e107e8
--- /dev/null
+++ b/bolt/test/X86/Inputs/ifunc-ld.yaml
@@ -0,0 +1,424 @@
+--- !ELF
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ OSABI: ELFOSABI_GNU
+ Type: ET_EXEC
+ Machine: EM_X86_64
+ Entry: 0x401050
+ProgramHeaders:
+ - Type: PT_PHDR
+ Flags: [ PF_R ]
+ VAddr: 0x400040
+ Align: 0x8
+ Offset: 0x40
+ - Type: PT_INTERP
+ Flags: [ PF_R ]
+ FirstSec: .interp
+ LastSec: .interp
+ VAddr: 0x400270
+ Offset: 0x270
+ - Type: PT_LOAD
+ Flags: [ PF_R ]
+ FirstSec: .interp
+ LastSec: .rela.plt
+ VAddr: 0x400000
+ Align: 0x1000
+ Offset: 0x0
+ - Type: PT_LOAD
+ Flags: [ PF_X, PF_R ]
+ FirstSec: .plt
+ LastSec: .text
+ VAddr: 0x401000
+ Align: 0x1000
+ Offset: 0x1000
+ - Type: PT_LOAD
+ Flags: [ PF_R ]
+ FirstSec: .rodata
+ LastSec: .eh_frame
+ VAddr: 0x402000
+ Align: 0x1000
+ Offset: 0x2000
+ - Type: PT_LOAD
+ Flags: [ PF_W, PF_R ]
+ FirstSec: .dynamic
+ LastSec: .got.plt
+ VAddr: 0x403EB8
+ Align: 0x1000
+ Offset: 0x2EB8
+ - Type: PT_DYNAMIC
+ Flags: [ PF_W, PF_R ]
+ FirstSec: .dynamic
+ LastSec: .dynamic
+ VAddr: 0x403EB8
+ Align: 0x8
+ Offset: 0x2EB8
+ - Type: PT_GNU_EH_FRAME
+ Flags: [ PF_R ]
+ FirstSec: .eh_frame_hdr
+ LastSec: .eh_frame_hdr
+ VAddr: 0x402004
+ Align: 0x4
+ Offset: 0x2004
+ - Type: PT_GNU_STACK
+ Flags: [ PF_W, PF_R ]
+ Align: 0x10
+ Offset: 0x0
+ - Type: PT_GNU_RELRO
+ Flags: [ PF_R ]
+ FirstSec: .dynamic
+ LastSec: .got
+ VAddr: 0x403EB8
+ Offset: 0x2EB8
+Sections:
+ - Name: .interp
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC ]
+ Address: 0x400270
+ AddressAlign: 0x1
+ Content: 2F6C696236342F6C642D6C696E75782D7838362D36342E736F2E3200
+ - Name: .gnu.hash
+ Type: SHT_GNU_HASH
+ Flags: [ SHF_ALLOC ]
+ Address: 0x400290
+ Link: .dynsym
+ AddressAlign: 0x8
+ Header:
+ SymNdx: 0x1
+ Shift2: 0x0
+ BloomFilter: [ 0x0 ]
+ HashBuckets: [ 0x0 ]
+ HashValues: [ ]
+ - Name: .dynsym
+ Type: SHT_DYNSYM
+ Flags: [ SHF_ALLOC ]
+ Address: 0x4002B0
+ Link: .dynstr
+ AddressAlign: 0x8
+ - Name: .dynstr
+ Type: SHT_STRTAB
+ Flags: [ SHF_ALLOC ]
+ Address: 0x400310
+ AddressAlign: 0x1
+ - Name: .rela.dyn
+ Type: SHT_RELA
+ Flags: [ SHF_ALLOC ]
+ Address: 0x400330
+ Link: .dynsym
+ AddressAlign: 0x8
+ Relocations:
+ - Offset: 0x403FF8
+ Symbol: memcpy
+ Type: R_X86_64_GLOB_DAT
+ - Name: .rela.plt
+ Type: SHT_RELA
+ Flags: [ SHF_ALLOC, SHF_INFO_LINK ]
+ Address: 0x400348
+ Link: .dynsym
+ AddressAlign: 0x8
+ Info: .got.plt
+ Relocations:
+ - Offset: 0x404018
+ Symbol: printf
+ Type: R_X86_64_JUMP_SLOT
+ - Offset: 0x404028
+ Symbol: rand
+ Type: R_X86_64_JUMP_SLOT
+ - Offset: 0x404030
+ Type: R_X86_64_IRELATIVE
+ Addend: 4198480
+ - Offset: 0x404020
+ Type: R_X86_64_IRELATIVE
+ Addend: 4198496
+ - Name: .plt
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ Address: 0x401000
+ AddressAlign: 0x10
+ EntSize: 0x10
+ Offset: 0x1000
+ Content: FF3502300000FF25043000000F1F4000FF25023000006800000000E9E0FFFFFFFF25FA2F00006803000000E9D0FFFFFFFF25F22F00006801000000E9C0FFFFFFFF25EA2F00006802000000E9B0FFFFFF
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ Address: 0x401050
+ AddressAlign: 0x10
+ Content: 488D0579000000C30F1F840000000000488B05912F0000C30F1F840000000000554889E54883EC10C745FC00000000C745F8EFBEADDEC745F400000000488D7DF4488D75F8BA04000000E881FFFFFF8B45F83B45F40F840C000000C745FCFFFFFFFFE907000000B000E882FFFFFF8B45FC4883C4105DC3660F1F840000000000554889E54883EC10E853FFFFFF8945FC8B75FC488D3D160F0000B000E81FFFFFFF4883C4105DC3
+ - Name: .rodata
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_MERGE, SHF_STRINGS ]
+ Address: 0x402000
+ AddressAlign: 0x1
+ EntSize: 0x1
+ Offset: 0x2000
+ Content: '256400'
+ - Name: .eh_frame_hdr
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC ]
+ Address: 0x402004
+ AddressAlign: 0x4
+ Content: 011B033B3000000005000000FCEFFFFFB40000004CF0FFFF4C0000005CF0FFFF600000006CF0FFFF74000000CCF0FFFF94000000
+ - Name: .eh_frame
+ Type: SHT_X86_64_UNWIND
+ Flags: [ SHF_ALLOC ]
+ Address: 0x402038
+ AddressAlign: 0x8
+ Content: 1400000000000000017A5200017810011B0C070890010000100000001C000000F8EFFFFF08000000000000001000000030000000F4EFFFFF08000000000000001C00000044000000F0EFFFFF5700000000410E108602430D0602520C070800001C0000006400000030F0FFFF2700000000410E108602430D06620C0708000000200000008400000040EFFFFF50000000000E10460E184A0F0B770880003F1A3B2A332422
+ - Name: .dynamic
+ Type: SHT_DYNAMIC
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ Address: 0x403EB8
+ Link: .dynstr
+ AddressAlign: 0x8
+ Offset: 0x2EB8
+ Entries:
+ - Tag: DT_NEEDED
+ Value: 0x1
+ - Tag: DT_GNU_HASH
+ Value: 0x400290
+ - Tag: DT_STRTAB
+ Value: 0x400310
+ - Tag: DT_SYMTAB
+ Value: 0x4002B0
+ - Tag: DT_STRSZ
+ Value: 0x1F
+ - Tag: DT_SYMENT
+ Value: 0x18
+ - Tag: DT_DEBUG
+ Value: 0x0
+ - Tag: DT_PLTGOT
+ Value: 0x404000
+ - Tag: DT_PLTRELSZ
+ Value: 0x60
+ - Tag: DT_PLTREL
+ Value: 0x7
+ - Tag: DT_JMPREL
+ Value: 0x400348
+ - Tag: DT_RELA
+ Value: 0x400330
+ - Tag: DT_RELASZ
+ Value: 0x18
+ - Tag: DT_RELAENT
+ Value: 0x18
+ - Tag: DT_NULL
+ Value: 0x0
+ - Tag: DT_NULL
+ Value: 0x0
+ - Tag: DT_NULL
+ Value: 0x0
+ - Tag: DT_NULL
+ Value: 0x0
+ - Tag: DT_NULL
+ Value: 0x0
+ - Tag: DT_NULL
+ Value: 0x0
+ - Name: .got
+ Type: SHT_PROGBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ Address: 0x403FF8
+ AddressAlign: 0x8
+ EntSize: 0x8
+ Content: '0000000000000000'
+ - Name: .got.plt
+ Type: SHT_PROGBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ Address: 0x404000
+ AddressAlign: 0x8
+ EntSize: 0x8
+ Content: B83E400000000000000000000000000000000000000000001610400000000000261040000000000036104000000000004610400000000000
+ - Name: .comment
+ Type: SHT_PROGBITS
+ Flags: [ SHF_MERGE, SHF_STRINGS ]
+ AddressAlign: 0x1
+ EntSize: 0x1
+ Content: 636C616E672076657273696F6E2031372E302E362028416C696261626120436C6F756420436F6D70696C65722031372E302E362E312D32342E30352E31302E616C696F73372900
+ - Name: .rela.text
+ Type: SHT_RELA
+ Flags: [ SHF_INFO_LINK ]
+ Link: .symtab
+ AddressAlign: 0x8
+ Info: .text
+ Relocations:
+ - Offset: 0x401063
+ Symbol: memcpy
+ Type: R_X86_64_REX_GOTPCRELX
+ Addend: -4
+ - Offset: 0x40109B
+ Symbol: imemcpy
+ Type: R_X86_64_PLT32
+ Addend: -4
+ - Offset: 0x4010BA
+ Symbol: ifoo
+ Type: R_X86_64_PLT32
+ Addend: -4
+ - Offset: 0x4010D9
+ Symbol: rand
+ Type: R_X86_64_PLT32
+ Addend: -4
+ - Offset: 0x4010E6
+ Symbol: .L.str
+ Type: R_X86_64_PC32
+ Addend: -4
+ - Offset: 0x4010ED
+ Symbol: printf
+ Type: R_X86_64_PLT32
+ Addend: -4
+ - Name: .rela.eh_frame
+ Type: SHT_RELA
+ Flags: [ SHF_INFO_LINK ]
+ Link: .symtab
+ AddressAlign: 0x8
+ Info: .eh_frame
+ Relocations:
+ - Offset: 0x402058
+ Symbol: .text
+ Type: R_X86_64_PC32
+ - Offset: 0x40206C
+ Symbol: .text
+ Type: R_X86_64_PC32
+ Addend: 16
+ - Offset: 0x402080
+ Symbol: .text
+ Type: R_X86_64_PC32
+ Addend: 32
+ - Offset: 0x4020A0
+ Symbol: .text
+ Type: R_X86_64_PC32
+ Addend: 128
+ - Type: SectionHeaderTable
+ Sections:
+ - Name: .interp
+ - Name: .gnu.hash
+ - Name: .dynsym
+ - Name: .dynstr
+ - Name: .rela.dyn
+ - Name: .rela.plt
+ - Name: .plt
+ - Name: .text
+ - Name: .rela.text
+ - Name: .rodata
+ - Name: .eh_frame_hdr
+ - Name: .eh_frame
+ - Name: .rela.eh_frame
+ - Name: .dynamic
+ - Name: .got
+ - Name: .got.plt
+ - Name: .comment
+ - Name: .symtab
+ - Name: .strtab
+ - Name: .shstrtab
+Symbols:
+ - Name: .interp
+ Type: STT_SECTION
+ Section: .interp
+ Value: 0x400270
+ - Name: .gnu.hash
+ Type: STT_SECTION
+ Section: .gnu.hash
+ Value: 0x400290
+ - Name: .dynsym
+ Type: STT_SECTION
+ Section: .dynsym
+ Value: 0x4002B0
+ - Name: .dynstr
+ Type: STT_SECTION
+ Section: .dynstr
+ Value: 0x400310
+ - Name: .rela.dyn
+ Type: STT_SECTION
+ Section: .rela.dyn
+ Value: 0x400330
+ - Name: .rela.plt
+ Type: STT_SECTION
+ Section: .rela.plt
+ Value: 0x400348
+ - Name: .plt
+ Type: STT_SECTION
+ Section: .plt
+ Value: 0x401000
+ - Name: .text
+ Type: STT_SECTION
+ Section: .text
+ Value: 0x401050
+ - Name: .rodata
+ Type: STT_SECTION
+ Section: .rodata
+ Value: 0x402000
+ - Name: .eh_frame_hdr
+ Type: STT_SECTION
+ Section: .eh_frame_hdr
+ Value: 0x402004
+ - Name: .eh_frame
+ Type: STT_SECTION
+ Section: .eh_frame
+ Value: 0x402038
+ - Name: .dynamic
+ Type: STT_SECTION
+ Section: .dynamic
+ Value: 0x403EB8
+ - Name: .got
+ Type: STT_SECTION
+ Section: .got
+ Value: 0x403FF8
+ - Name: .got.plt
+ Type: STT_SECTION
+ Section: .got.plt
+ Value: 0x404000
+ - Name: .comment
+ Type: STT_SECTION
+ Section: .comment
+ - Name: .L.str
+ Type: STT_OBJECT
+ Section: .rodata
+ Value: 0x402000
+ Size: 0x3
+ - Name: printf
+ Type: STT_FUNC
+ Binding: STB_GLOBAL
+ - Name: imemcpy
+ Type: STT_GNU_IFUNC
+ Section: .text
+ Binding: STB_GLOBAL
+ Value: 0x401060
+ Size: 0x8
+ - Name: memcpy
+ Type: STT_FUNC
+ Binding: STB_GLOBAL
+ - Name: rand
+ Type: STT_FUNC
+ Binding: STB_GLOBAL
+ - Name: __bss_start
+ Section: .got.plt
+ Binding: STB_GLOBAL
+ Value: 0x404038
+ - Name: main
+ Type: STT_FUNC
+ Section: .text
+ Binding: STB_GLOBAL
+ Value: 0x401070
+ Size: 0x57
+ - Name: _edata
+ Section: .got.plt
+ Binding: STB_GLOBAL
+ Value: 0x404038
+ - Name: _end
+ Section: .got.plt
+ Binding: STB_GLOBAL
+ Value: 0x404038
+ - Name: ifoo
+ Type: STT_GNU_IFUNC
+ Section: .text
+ Binding: STB_GLOBAL
+ Value: 0x401050
+ Size: 0x8
+DynamicSymbols:
+ - Name: printf
+ Type: STT_FUNC
+ Binding: STB_GLOBAL
+ - Name: memcpy
+ Type: STT_FUNC
+ Binding: STB_GLOBAL
+ - Name: rand
+ Type: STT_FUNC
+ Binding: STB_GLOBAL
+...
diff --git a/bolt/test/X86/ifunc-ld.test b/bolt/test/X86/ifunc-ld.test
new file mode 100644
index 00000000000000..64cbd6d758fed7
--- /dev/null
+++ b/bolt/test/X86/ifunc-ld.test
@@ -0,0 +1,13 @@
+// This test checks R_X86_64_IRELATIVE in .rela.plt can be properly
+// placed after R_X86_64_JUMP_SLOT entries by BOLT
+
+RUN: yaml2obj %p/Inputs/ifunc-ld.yaml &> %t.exe
+RUN: llvm-bolt %t.exe -o %t.bolt
+RUN: llvm-readelf -aW %t.bolt | FileCheck %s
+
+# CHECK: Relocation section '.rela.plt'
+# CHECK-NEXT: Offset
+# CHECK-NEXT: R_X86_64_JUMP_SLOT
+# CHECK-NEXT: R_X86_64_JUMP_SLOT
+# CHECK-NEXT: R_X86_64_IRELATIVE
+# CHECK-NEXT: R_X86_64_IRELATIVE
|
The testcase is generated from bolt/test/runtime/iplt.c with gnu-ld
with commands |
GNU ld might place R_*_IRELATIVE in .rela.plt, and have a layout like Relocation section '.rela.plt' ... Offset Type cc9040 R_X86_64_JUMP_SLOT cc9048 R_X86_64_JUMP_SLOT cc9060 R_X86_64_JUMP_SLOT cc9050 R_X86_64_IRELATIVE R_*_IRELATIVE entries all come after JUMP_SLOT entries. This patch will change the allocatable rela patching order to keep this layout if we find R_*_IRELATIVE is in .rela.plt section.
b7dbc07
to
7d731c2
Compare
Reproduce from a real-world case.
The order of jump_slop entries are messed up with R_X86_64_IRELATIVE. So when dl_fixup tries to resolve _ZNSt12out_of_rangeC1E@PLT, then it will find
This issue depends on the Arch and linker you use, and I only found it happened with X86 & gnu-ld so far. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good. Please check the comment.
@@ -899,7 +899,7 @@ bool Relocation::isIRelative(uint64_t Type) { | |||
case Triple::aarch64: | |||
return Type == ELF::R_AARCH64_IRELATIVE; | |||
case Triple::riscv64: | |||
llvm_unreachable("not implemented"); | |||
return Type == ELF::R_RISCV_IRELATIVE; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we replace the whole function body with return Type == getIRelative();
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we replace the whole function body with
return Type == getIRelative();
?
Some extensions may introduce new variants(R_AARCH64_AUTH_[I]RELATIVE), but currently, BOLT has no plans to support them, so I think we can make this chang. Do you have any suggestions?
51559b5
to
7d731c2
Compare
GNU ld might place R_*_IRELATIVE in .rela.plt, and have a layout like
Relocation section '.rela.plt' ...
Offset Type
cc9040 R_X86_64_JUMP_SLOT
cc9048 R_X86_64_JUMP_SLOT
cc9060 R_X86_64_JUMP_SLOT
cc9050 R_X86_64_IRELATIVE
Right now this layout in BOLTed binary will be
Relocation section '.rela.plt' ...
Offset Type
cc9040 R_X86_64_JUMP_SLOT
cc9048 R_X86_64_JUMP_SLOT
cc9050 R_X86_64_IRELATIVE
cc9060 R_X86_64_JUMP_SLOT
So that the reloc_index is incorrect and then the dynamic linker fails to resolve the address in .got.plt
R_IRELATIVE entries all come after JUMP_SLOT entries. This patch will change the allocatable rela patching order to keep this layout if we find R_IRELATIVE is in .rela.plt section.