[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