Skip to content
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

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

linsinan1995
Copy link
Member

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.

@llvmbot
Copy link
Collaborator

llvmbot commented Aug 29, 2024

@llvm/pr-subscribers-bolt

Author: sinan (linsinan1995)

Changes

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.


Full diff: https://github.com/llvm/llvm-project/pull/106515.diff

5 Files Affected:

  • (modified) bolt/include/bolt/Core/Relocation.h (+3)
  • (modified) bolt/lib/Core/Relocation.cpp (+13)
  • (modified) bolt/lib/Rewrite/RewriteInstance.cpp (+16-3)
  • (added) bolt/test/X86/Inputs/ifunc-ld.yaml (+424)
  • (added) bolt/test/X86/ifunc-ld.test (+13)
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

@linsinan1995
Copy link
Member Author

The testcase is generated from bolt/test/runtime/iplt.c with gnu-ld

#include "../Inputs/stub.h"

static void foo() { int i = rand(); printf("%d", i); }

static void *resolver_foo(void) { return foo; }

__attribute__((ifunc("resolver_foo"))) void ifoo();

static void *resolver_memcpy(void) { return memcpy; }

__attribute__((ifunc("resolver_memcpy"))) void *
imemcpy(void *dest, const void *src, unsigned long n);

int main() {
  int a = 0xdeadbeef, b = 0;
  imemcpy(&b, &a, sizeof(b));
  if (a != b)
    return -1;

  ifoo();
}

with commands
clang -nostdlib -fpic bolt/test/runtime/iplt.c -o iplt.o -Wl,-q -nostdlib -nodefaultlibs -c
clang -nostdlib -fpic bolt/test/Inputs/stub.c -o stub.o -Wl,-q -nostdlib -nodefaultlibs -c
clang -nostdlib -fpic -shared stub.o -Wl,-q -nostdlib -nodefaultlibs -o libstub.so
clang -nostdlib -fpic iplt.o -Wl,-q -nostdlib -nodefaultlibs -L. -lstub -o test
llvm-strip --strip-unneeded test -o test

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.
@linsinan1995
Copy link
Member Author

linsinan1995 commented Aug 29, 2024

Reproduce from a real-world case.

  1. BUILD
# CentOS 7 X86
# GCC 9.2.1
# LD 2.32
git clone https://github.com/intel/hyperscan.git

mkdir build
pushd build
cmake -DCMAKE_C_FLAGS="-fno-reorder-blocks-and-partition"   \
      -DCMAKE_CXX_FLAGS="-fno-reorder-blocks-and-partition" \
      -DCMAKE_EXE_LINKER_FLAGS="-Wl,-q" \
      -DCMAKE_POSITION_INDEPENDENT_CODE=ON \
      -DBUILD_AVX512=off \
      -DBUILD_AVX512VBMI=off ..
make -j32 all
popd
  1. DO BOLT
llvm-bolt build/bin/unit-hyperscan -o build/bin/unit-hyperscan.opt
  1. CHECK
    unit-hyperscan works well, but BOLTed unit-hyperscan.opt SEGV.
$./build/bin/unit-hyperscan | head
[==========] Running 4130 tests from 33 test cases.
[----------] Global test environment set-up.
[----------] 9 tests from CustomAllocator
[ RUN      ] CustomAllocator.DatabaseInfoBadAlloc
[       OK ] CustomAllocator.DatabaseInfoBadAlloc (0 ms)
[ RUN      ] CustomAllocator.TwoAlignedCompile
[       OK ] CustomAllocator.TwoAlignedCompile (0 ms)
[ RUN      ] CustomAllocator.TwoAlignedCompileError
[       OK ] CustomAllocator.TwoAlignedCompileError (1 ms)
[ RUN      ] CustomAllocator.TwoAlignedDatabaseInfo
$./build/bin/unit-hyperscan.opt
Segmentation fault
  1. Check .rela.plt

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 R_X86_64_IRELATIV 12584c0 (DT_JMPREL + RELASZ * reloc_index => now the entry of .rela.plt changed from _ZNSt12out_of_rangeC1E to an IRELATIVE entry).

$readelf -r ./build/bin/unit-hyperscan | grep ".rela.plt" -A 10
Relocation section '.rela.plt' at offset 0x17b80 contains 215 entries:
  Offset          Info           Type           Sym. Value    Sym. Name + Addend
000000ca8018  000100000007 R_X86_64_JUMP_SLO 0000000000000000 ftell@GLIBC_2.2.5 + 0
000000ca8020  000200000007 R_X86_64_JUMP_SLO 0000000000000000 _Znam@GLIBCXX_3.4 + 0
000000ca8028  000300000007 R_X86_64_JUMP_SLO 0000000000000000 _ZNSo3putEc@GLIBCXX_3.4 + 0
000000ca8030  000400000007 R_X86_64_JUMP_SLO 0000000000000000 __errno_location@GLIBC_2.2.5 + 0
000000ca8038  000500000007 R_X86_64_JUMP_SLO 0000000000000000 printf@GLIBC_2.2.5 + 0
000000ca8040  000600000007 R_X86_64_JUMP_SLO 0000000000000000 _ZNSt8__detail15_List_@GLIBCXX_3.4.15 + 0
000000ca8048  000700000007 R_X86_64_JUMP_SLO 0000000000000000 isspace@GLIBC_2.2.5 + 0
000000ca8058  000800000007 R_X86_64_JUMP_SLO 0000000000000000 _ZNSt12out_of_rangeC1E@GLIBCXX_3.4.21 + 0
000000ca8068  000900000007 R_X86_64_JUMP_SLO 0000000000000000 _ZSt29_Rb_tree_insert_@GLIBCXX_3.4 + 0
$readelf -r ./build/bin/unit-hyperscan.opt | grep ".rela.plt" -A 100
Relocation section '.rela.plt' at offset 0x17b80 contains 215 entries:
  Offset          Info           Type           Sym. Value    Sym. Name + Addend
000000ca8018  000100000007 R_X86_64_JUMP_SLO 0000000000000000 ftell@GLIBC_2.2.5 + 0
000000ca8020  000200000007 R_X86_64_JUMP_SLO 0000000000000000 _Znam@GLIBCXX_3.4 + 0
000000ca8028  000300000007 R_X86_64_JUMP_SLO 0000000000000000 _ZNSo3putEc@GLIBCXX_3.4 + 0
000000ca8030  000400000007 R_X86_64_JUMP_SLO 0000000000000000 __errno_location@GLIBC_2.2.5 + 0
000000ca8038  000500000007 R_X86_64_JUMP_SLO 0000000000000000 printf@GLIBC_2.2.5 + 0
000000ca8040  000600000007 R_X86_64_JUMP_SLO 0000000000000000 _ZNSt8__detail15_List_@GLIBCXX_3.4.15 + 0
000000ca8048  000700000007 R_X86_64_JUMP_SLO 0000000000000000 isspace@GLIBC_2.2.5 + 0
000000ca8050  000000000025 R_X86_64_IRELATIV                    12584c0
000000ca8058  000800000007 R_X86_64_JUMP_SLO 0000000000000000 _ZNSt12out_of_rangeC1E@GLIBCXX_3.4.21 + 0
000000ca8060  000000000025 R_X86_64_IRELATIV                    1257e80

This issue depends on the Arch and linker you use, and I only found it happened with X86 & gnu-ld so far.

Copy link
Contributor

@maksfb maksfb left a 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;
Copy link
Contributor

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();?

Copy link
Member Author

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?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants