[llvm] 9bb4cd5 - [llvm-objcopy] Support CREL

via llvm-commits llvm-commits at lists.llvm.org
Mon Jul 8 09:32:11 PDT 2024


Author: Fangrui Song
Date: 2024-07-08T09:32:08-07:00
New Revision: 9bb4cd5977f8a0d6f1d6cc00cb707ed2db27f1c0

URL: https://github.com/llvm/llvm-project/commit/9bb4cd5977f8a0d6f1d6cc00cb707ed2db27f1c0
DIFF: https://github.com/llvm/llvm-project/commit/9bb4cd5977f8a0d6f1d6cc00cb707ed2db27f1c0.diff

LOG: [llvm-objcopy] Support CREL

llvm-objcopy may modify the symbol table and need to rewrite
relocations. For CREL, while we can reuse the decoder from #91280, we
need an encoder to support CREL.

Since MC/ELFObjectWriter.cpp has an existing encoder, and MC is at a
lower layer than Object, extract the encoder to a new header file
llvm/MC/MCELFExtras.h.

Link: https://discourse.llvm.org/t/rfc-crel-a-compact-relocation-format-for-elf/77600

Pull Request: https://github.com/llvm/llvm-project/pull/97521

Added: 
    llvm/test/tools/llvm-objcopy/ELF/crel.test

Modified: 
    llvm/lib/ObjCopy/ELF/ELFObject.cpp
    llvm/lib/ObjCopy/ELF/ELFObject.h
    llvm/test/tools/llvm-objcopy/ELF/reloc-error-remove-symtab.test
    llvm/test/tools/llvm-objcopy/ELF/strip-reloc-symbol.test

Removed: 
    


################################################################################
diff  --git a/llvm/lib/ObjCopy/ELF/ELFObject.cpp b/llvm/lib/ObjCopy/ELF/ELFObject.cpp
index 02591e6f987c26..5e6d19b9bfa54b 100644
--- a/llvm/lib/ObjCopy/ELF/ELFObject.cpp
+++ b/llvm/lib/ObjCopy/ELF/ELFObject.cpp
@@ -13,6 +13,7 @@
 #include "llvm/ADT/Twine.h"
 #include "llvm/ADT/iterator_range.h"
 #include "llvm/BinaryFormat/ELF.h"
+#include "llvm/MC/MCELFExtras.h"
 #include "llvm/MC/MCTargetOptions.h"
 #include "llvm/Object/ELF.h"
 #include "llvm/Object/ELFObjectFile.h"
@@ -107,12 +108,29 @@ Error ELFSectionSizer<ELFT>::visit(SymbolTableSection &Sec) {
   return Error::success();
 }
 
+template <bool Is64>
+static SmallVector<char, 0> encodeCrel(ArrayRef<Relocation> Relocations) {
+  using uint = std::conditional_t<Is64, uint64_t, uint32_t>;
+  SmallVector<char, 0> Content;
+  raw_svector_ostream OS(Content);
+  ELF::encodeCrel<Is64>(OS, Relocations, [&](const Relocation &R) {
+    uint32_t CurSymIdx = R.RelocSymbol ? R.RelocSymbol->Index : 0;
+    return ELF::Elf_Crel<Is64>{static_cast<uint>(R.Offset), CurSymIdx, R.Type,
+                               std::make_signed_t<uint>(R.Addend)};
+  });
+  return Content;
+}
+
 template <class ELFT>
 Error ELFSectionSizer<ELFT>::visit(RelocationSection &Sec) {
-  Sec.EntrySize = Sec.Type == SHT_REL ? sizeof(Elf_Rel) : sizeof(Elf_Rela);
-  Sec.Size = Sec.Relocations.size() * Sec.EntrySize;
-  // Align to the largest field in Elf_Rel(a).
-  Sec.Align = ELFT::Is64Bits ? sizeof(Elf_Xword) : sizeof(Elf_Word);
+  if (Sec.Type == SHT_CREL) {
+    Sec.Size = encodeCrel<ELFT::Is64Bits>(Sec.Relocations).size();
+  } else {
+    Sec.EntrySize = Sec.Type == SHT_REL ? sizeof(Elf_Rel) : sizeof(Elf_Rela);
+    Sec.Size = Sec.Relocations.size() * Sec.EntrySize;
+    // Align to the largest field in Elf_Rel(a).
+    Sec.Align = ELFT::Is64Bits ? sizeof(Elf_Xword) : sizeof(Elf_Word);
+  }
   return Error::success();
 }
 
@@ -874,6 +892,8 @@ StringRef RelocationSectionBase::getNamePrefix() const {
     return ".rel";
   case SHT_RELA:
     return ".rela";
+  case SHT_CREL:
+    return ".crel";
   default:
     llvm_unreachable("not a relocation section");
   }
@@ -966,12 +986,16 @@ static void writeRel(const RelRange &Relocations, T *Buf, bool IsMips64EL) {
 template <class ELFT>
 Error ELFSectionWriter<ELFT>::visit(const RelocationSection &Sec) {
   uint8_t *Buf = reinterpret_cast<uint8_t *>(Out.getBufferStart()) + Sec.Offset;
-  if (Sec.Type == SHT_REL)
+  if (Sec.Type == SHT_CREL) {
+    auto Content = encodeCrel<ELFT::Is64Bits>(Sec.Relocations);
+    memcpy(Buf, Content.data(), Content.size());
+  } else if (Sec.Type == SHT_REL) {
     writeRel(Sec.Relocations, reinterpret_cast<Elf_Rel *>(Buf),
              Sec.getObject().IsMips64EL);
-  else
+  } else {
     writeRel(Sec.Relocations, reinterpret_cast<Elf_Rela *>(Buf),
              Sec.getObject().IsMips64EL);
+  }
   return Error::success();
 }
 
@@ -1684,6 +1708,7 @@ Expected<SectionBase &> ELFBuilder<ELFT>::makeSection(const Elf_Shdr &Shdr) {
   switch (Shdr.sh_type) {
   case SHT_REL:
   case SHT_RELA:
+  case SHT_CREL:
     if (Shdr.sh_flags & SHF_ALLOC) {
       if (Expected<ArrayRef<uint8_t>> Data = ElfFile.getSectionContents(Shdr))
         return Obj.addSection<DynamicRelocationSection>(*Data);
@@ -1861,7 +1886,15 @@ template <class ELFT> Error ELFBuilder<ELFT>::readSections(bool EnsureSymtab) {
 
       const typename ELFFile<ELFT>::Elf_Shdr *Shdr =
           Sections->begin() + RelSec->Index;
-      if (RelSec->Type == SHT_REL) {
+      if (RelSec->Type == SHT_CREL) {
+        auto RelsOrRelas = ElfFile.crels(*Shdr);
+        if (!RelsOrRelas)
+          return RelsOrRelas.takeError();
+        if (Error Err = initRelocations(RelSec, RelsOrRelas->first))
+          return Err;
+        if (Error Err = initRelocations(RelSec, RelsOrRelas->second))
+          return Err;
+      } else if (RelSec->Type == SHT_REL) {
         Expected<typename ELFFile<ELFT>::Elf_Rel_Range> Rels =
             ElfFile.rels(*Shdr);
         if (!Rels)

diff  --git a/llvm/lib/ObjCopy/ELF/ELFObject.h b/llvm/lib/ObjCopy/ELF/ELFObject.h
index 2b1895a30b41ed..e3c0e7abda16b9 100644
--- a/llvm/lib/ObjCopy/ELF/ELFObject.h
+++ b/llvm/lib/ObjCopy/ELF/ELFObject.h
@@ -881,7 +881,8 @@ class RelocationSectionBase : public SectionBase {
   StringRef getNamePrefix() const;
 
   static bool classof(const SectionBase *S) {
-    return S->OriginalType == ELF::SHT_REL || S->OriginalType == ELF::SHT_RELA;
+    return is_contained({ELF::SHT_REL, ELF::SHT_RELA, ELF::SHT_CREL},
+                        S->OriginalType);
   }
 };
 
@@ -925,7 +926,7 @@ class RelocationSection
   static bool classof(const SectionBase *S) {
     if (S->OriginalFlags & ELF::SHF_ALLOC)
       return false;
-    return S->OriginalType == ELF::SHT_REL || S->OriginalType == ELF::SHT_RELA;
+    return RelocationSectionBase::classof(S);
   }
 };
 

diff  --git a/llvm/test/tools/llvm-objcopy/ELF/crel.test b/llvm/test/tools/llvm-objcopy/ELF/crel.test
new file mode 100644
index 00000000000000..daf4567d0c8a2b
--- /dev/null
+++ b/llvm/test/tools/llvm-objcopy/ELF/crel.test
@@ -0,0 +1,140 @@
+# RUN: yaml2obj %s -o %t
+# RUN: llvm-objcopy --remove-section=.foo --strip-symbol=unused %t %t.out
+# RUN: llvm-readelf -Sr %t.out | FileCheck %s
+
+# CHECK:      [Nr] Name              Type            Address          Off    Size   ES Flg Lk Inf Al
+# CHECK-NEXT: [ 0]                   NULL            0000000000000000 000000 000000 00      0   0  0
+# CHECK-NEXT: [ 1] .text             PROGBITS        0000000000000000 {{.*}} 000008 00   A  0   0  0
+# CHECK-NEXT: [ 2] .crel.text        CREL            0000000000000000 {{.*}} 000022 00      5   1  0
+# CHECK-NEXT: [ 3] nonalloc          PROGBITS        0000000000000000 {{.*}} 000030 00      0   0  0
+# CHECK-NEXT: [ 4] .crelnonalloc     CREL            0000000000000000 {{.*}} 00000b 00      5   3  0
+
+# CHECK:      Relocation section '.crel.text' at offset {{.*}} contains 4 entries:
+# CHECK-NEXT:     Offset             Info             Type               Symbol's Value  Symbol's Name + Addend
+# CHECK-NEXT: 0000000000000001  {{.*}}           R_X86_64_32            0000000000000000 g1 + 1
+# CHECK-NEXT: 0000000000000002  {{.*}}           R_X86_64_64            0000000000000000 l1 + 2
+# CHECK-NEXT: 0000000000000000  {{.*}}           R_X86_64_32S           0000000000000000 g1 - 1
+# CHECK-NEXT: 0000000000000004  {{.*}}           R_X86_64_32S           0000000000000000 .text - 8000000000000000
+# CHECK-EMPTY:
+# CHECK-NEXT: Relocation section '.crelnonalloc' at offset {{.*}} contains 3 entries:
+# CHECK-NEXT:     Offset             Info             Type               Symbol's Value  Symbol's Name + Addend
+# CHECK-NEXT: 0000000000000010  {{.*}}           R_X86_64_64            0000000000000000 g1 + 1
+# CHECK-NEXT: 0000000000000020  {{.*}}           R_X86_64_64            0000000000000000 g2 + 2
+# CHECK-NEXT: 0000000000000030  {{.*}}           R_X86_64_64                       0
+
+--- !ELF
+FileHeader:
+  Class: ELFCLASS64
+  Data: ELFDATA2LSB
+  Type: ET_REL
+  Machine: EM_X86_64
+
+Sections:
+- Name: .foo
+  Type: SHT_PROGBITS
+  Flags: [SHF_ALLOC]
+- Name: .text
+  Type: SHT_PROGBITS
+  Content: "0000000000000000"
+  Flags: [SHF_ALLOC]
+- Name: .crel.text
+  Type: SHT_CREL
+  Info: .text
+  Link: .symtab
+  Relocations:
+    - Offset: 0x1
+      Symbol: g1
+      Type:   R_X86_64_32
+      Addend: 1
+    - Offset: 0x2
+      Symbol: l1
+      Type:   R_X86_64_64
+      Addend: 2
+    - Offset: 0x0
+      Symbol: g1
+      Type:   R_X86_64_32S
+      Addend: 0xffffffffffffffff
+    - Offset: 0x4
+      Symbol: .text
+      Type:   R_X86_64_32S
+      Addend: 0x8000000000000000
+- Name: nonalloc
+  Type: SHT_PROGBITS
+  Size: 0x30
+- Name: .crelnonalloc
+  Type: SHT_CREL
+  Info: nonalloc
+  Link: .symtab
+  Relocations:
+    - Offset: 0x10
+      Symbol: g1
+      Type:   R_X86_64_64
+      Addend: 1
+    - Offset: 0x20
+      Symbol: g2
+      Type:   R_X86_64_64
+      Addend: 2
+    - Offset: 0x30
+      Symbol: 0
+      Type:   R_X86_64_64
+
+Symbols:
+  - Name: unused
+    Section: .text
+  - Name: .text
+    Type: STT_SECTION
+    Section: .text
+  - Name:    l1
+  - Name:    g1
+    Section: .text
+    Value:   0x0
+    Size:    4
+    Binding: STB_GLOBAL
+  - Name:    g2
+    Binding: STB_GLOBAL
+
+# RUN: yaml2obj --docnum=2 %s -o %t.32
+# RUN: llvm-objcopy %t.32 %t.32.out
+# RUN: llvm-readobj -r %t.32.out | FileCheck %s --check-prefix=CHECK2
+
+# CHECK2:      Relocations [
+# CHECK2-NEXT:   Section (2) .crel.text {
+# CHECK2-NEXT:     0x0 R_X86_64_32S g1 0xFFFFFFFF
+# CHECK2-NEXT:     0x4 R_X86_64_32S .text 0x80000000
+# CHECK2-NEXT:   }
+# CHECK2-NEXT: ]
+
+--- !ELF
+FileHeader:
+  Class: ELFCLASS32
+  Data: ELFDATA2LSB
+  Type: ET_REL
+  Machine: EM_X86_64
+
+Sections:
+- Name: .text
+  Type: SHT_PROGBITS
+  Content: "0000000000000000"
+  Flags: [SHF_ALLOC]
+- Name: .crel.text
+  Type: SHT_CREL
+  Info: .text
+  Link: .symtab
+  Relocations:
+    - Offset: 0x0
+      Symbol: g1
+      Type:   R_X86_64_32S
+      Addend: 0xffffffff
+    - Offset: 0x4
+      Symbol: .text
+      Type:   R_X86_64_32S
+      Addend: 0x80000000
+
+Symbols:
+  - Name: .text
+    Type: STT_SECTION
+    Section: .text
+  - Name:    g1
+    Section: .text
+    Size:    4
+    Binding: STB_GLOBAL

diff  --git a/llvm/test/tools/llvm-objcopy/ELF/reloc-error-remove-symtab.test b/llvm/test/tools/llvm-objcopy/ELF/reloc-error-remove-symtab.test
index 54820180258627..cda9b8115d0e69 100644
--- a/llvm/test/tools/llvm-objcopy/ELF/reloc-error-remove-symtab.test
+++ b/llvm/test/tools/llvm-objcopy/ELF/reloc-error-remove-symtab.test
@@ -3,6 +3,9 @@
 # RUN: cp %t %t3
 # RUN: not llvm-strip --no-strip-all -R .symtab %t3 2>&1 >/dev/null | FileCheck %s --check-prefix=ERR2 -DINPUT=%t3
 
+# RUN: yaml2obj -DTYPE=SHT_CREL %s -o %t.crel
+# RUN: not llvm-objcopy -R .symtab %t.crel %t2.crel 2>&1 >/dev/null | FileCheck %s --check-prefix=ERR1 -DINPUT=%t.crel
+
 !ELF
 FileHeader:
   Class:           ELFCLASS64
@@ -17,7 +20,7 @@ Sections:
     AddressAlign:    0x0000000000000010
     Content:         "0000000000000000"
   - Name:            .rel.text
-    Type:            SHT_REL
+    Type:            [[TYPE=SHT_REL]]
     Link:            .symtab
     Info:            .text
     Relocations:
@@ -40,6 +43,12 @@ Symbols:
 # RUN: llvm-strip --no-strip-all --allow-broken-links -R .symtab %t5
 # RUN: llvm-readobj --sections %t5 | FileCheck %s --check-prefix=SECTIONS --implicit-check-not=.symtab
 
+# RUN: llvm-objcopy --allow-broken-links -R .symtab %t.crel %t4.crel
+# RUN: llvm-readobj --sections %t4.crel | FileCheck %s --check-prefix=SECTIONS --implicit-check-not=.symtab
+# RUN: cp %t.crel %t5.crel
+# RUN: llvm-strip --no-strip-all --allow-broken-links -R .symtab %t5.crel
+# RUN: llvm-readobj --sections %t5.crel | FileCheck %s --check-prefix=SECTIONS --implicit-check-not=.symtab
+
 # SECTIONS:        Name: .rel.text
 # SECTIONS:        Link
 # SECTIONS-SAME: : 0

diff  --git a/llvm/test/tools/llvm-objcopy/ELF/strip-reloc-symbol.test b/llvm/test/tools/llvm-objcopy/ELF/strip-reloc-symbol.test
index 941dacce2edf29..7f2cd726b15c8f 100644
--- a/llvm/test/tools/llvm-objcopy/ELF/strip-reloc-symbol.test
+++ b/llvm/test/tools/llvm-objcopy/ELF/strip-reloc-symbol.test
@@ -1,5 +1,7 @@
 # RUN: yaml2obj %s -o %t
 # RUN: not llvm-objcopy -N foo %t %t2 2>&1 | FileCheck %s -DFILE=%t
+# RUN: yaml2obj -DTYPE=SHT_CREL %s -o %t1
+# RUN: not llvm-objcopy -N foo %t1 /dev/null 2>&1 | FileCheck %s -DFILE=%t1
 
 !ELF
 FileHeader:
@@ -15,7 +17,7 @@ Sections:
     AddressAlign:    0x0000000000000010
     Size:            64
   - Name:            .rel.text
-    Type:            SHT_REL
+    Type:            [[TYPE=SHT_REL]]
     Info:            .text
     Relocations:
       - Offset: 0x1000


        


More information about the llvm-commits mailing list