Skip to content

Commit 9bb4cd5

Browse files
authored
[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: #97521
1 parent 68a8ae0 commit 9bb4cd5

File tree

5 files changed

+196
-11
lines changed

5 files changed

+196
-11
lines changed

llvm/lib/ObjCopy/ELF/ELFObject.cpp

Lines changed: 40 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include "llvm/ADT/Twine.h"
1414
#include "llvm/ADT/iterator_range.h"
1515
#include "llvm/BinaryFormat/ELF.h"
16+
#include "llvm/MC/MCELFExtras.h"
1617
#include "llvm/MC/MCTargetOptions.h"
1718
#include "llvm/Object/ELF.h"
1819
#include "llvm/Object/ELFObjectFile.h"
@@ -107,12 +108,29 @@ Error ELFSectionSizer<ELFT>::visit(SymbolTableSection &Sec) {
107108
return Error::success();
108109
}
109110

111+
template <bool Is64>
112+
static SmallVector<char, 0> encodeCrel(ArrayRef<Relocation> Relocations) {
113+
using uint = std::conditional_t<Is64, uint64_t, uint32_t>;
114+
SmallVector<char, 0> Content;
115+
raw_svector_ostream OS(Content);
116+
ELF::encodeCrel<Is64>(OS, Relocations, [&](const Relocation &R) {
117+
uint32_t CurSymIdx = R.RelocSymbol ? R.RelocSymbol->Index : 0;
118+
return ELF::Elf_Crel<Is64>{static_cast<uint>(R.Offset), CurSymIdx, R.Type,
119+
std::make_signed_t<uint>(R.Addend)};
120+
});
121+
return Content;
122+
}
123+
110124
template <class ELFT>
111125
Error ELFSectionSizer<ELFT>::visit(RelocationSection &Sec) {
112-
Sec.EntrySize = Sec.Type == SHT_REL ? sizeof(Elf_Rel) : sizeof(Elf_Rela);
113-
Sec.Size = Sec.Relocations.size() * Sec.EntrySize;
114-
// Align to the largest field in Elf_Rel(a).
115-
Sec.Align = ELFT::Is64Bits ? sizeof(Elf_Xword) : sizeof(Elf_Word);
126+
if (Sec.Type == SHT_CREL) {
127+
Sec.Size = encodeCrel<ELFT::Is64Bits>(Sec.Relocations).size();
128+
} else {
129+
Sec.EntrySize = Sec.Type == SHT_REL ? sizeof(Elf_Rel) : sizeof(Elf_Rela);
130+
Sec.Size = Sec.Relocations.size() * Sec.EntrySize;
131+
// Align to the largest field in Elf_Rel(a).
132+
Sec.Align = ELFT::Is64Bits ? sizeof(Elf_Xword) : sizeof(Elf_Word);
133+
}
116134
return Error::success();
117135
}
118136

@@ -874,6 +892,8 @@ StringRef RelocationSectionBase::getNamePrefix() const {
874892
return ".rel";
875893
case SHT_RELA:
876894
return ".rela";
895+
case SHT_CREL:
896+
return ".crel";
877897
default:
878898
llvm_unreachable("not a relocation section");
879899
}
@@ -966,12 +986,16 @@ static void writeRel(const RelRange &Relocations, T *Buf, bool IsMips64EL) {
966986
template <class ELFT>
967987
Error ELFSectionWriter<ELFT>::visit(const RelocationSection &Sec) {
968988
uint8_t *Buf = reinterpret_cast<uint8_t *>(Out.getBufferStart()) + Sec.Offset;
969-
if (Sec.Type == SHT_REL)
989+
if (Sec.Type == SHT_CREL) {
990+
auto Content = encodeCrel<ELFT::Is64Bits>(Sec.Relocations);
991+
memcpy(Buf, Content.data(), Content.size());
992+
} else if (Sec.Type == SHT_REL) {
970993
writeRel(Sec.Relocations, reinterpret_cast<Elf_Rel *>(Buf),
971994
Sec.getObject().IsMips64EL);
972-
else
995+
} else {
973996
writeRel(Sec.Relocations, reinterpret_cast<Elf_Rela *>(Buf),
974997
Sec.getObject().IsMips64EL);
998+
}
975999
return Error::success();
9761000
}
9771001

@@ -1684,6 +1708,7 @@ Expected<SectionBase &> ELFBuilder<ELFT>::makeSection(const Elf_Shdr &Shdr) {
16841708
switch (Shdr.sh_type) {
16851709
case SHT_REL:
16861710
case SHT_RELA:
1711+
case SHT_CREL:
16871712
if (Shdr.sh_flags & SHF_ALLOC) {
16881713
if (Expected<ArrayRef<uint8_t>> Data = ElfFile.getSectionContents(Shdr))
16891714
return Obj.addSection<DynamicRelocationSection>(*Data);
@@ -1861,7 +1886,15 @@ template <class ELFT> Error ELFBuilder<ELFT>::readSections(bool EnsureSymtab) {
18611886

18621887
const typename ELFFile<ELFT>::Elf_Shdr *Shdr =
18631888
Sections->begin() + RelSec->Index;
1864-
if (RelSec->Type == SHT_REL) {
1889+
if (RelSec->Type == SHT_CREL) {
1890+
auto RelsOrRelas = ElfFile.crels(*Shdr);
1891+
if (!RelsOrRelas)
1892+
return RelsOrRelas.takeError();
1893+
if (Error Err = initRelocations(RelSec, RelsOrRelas->first))
1894+
return Err;
1895+
if (Error Err = initRelocations(RelSec, RelsOrRelas->second))
1896+
return Err;
1897+
} else if (RelSec->Type == SHT_REL) {
18651898
Expected<typename ELFFile<ELFT>::Elf_Rel_Range> Rels =
18661899
ElfFile.rels(*Shdr);
18671900
if (!Rels)

llvm/lib/ObjCopy/ELF/ELFObject.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -881,7 +881,8 @@ class RelocationSectionBase : public SectionBase {
881881
StringRef getNamePrefix() const;
882882

883883
static bool classof(const SectionBase *S) {
884-
return S->OriginalType == ELF::SHT_REL || S->OriginalType == ELF::SHT_RELA;
884+
return is_contained({ELF::SHT_REL, ELF::SHT_RELA, ELF::SHT_CREL},
885+
S->OriginalType);
885886
}
886887
};
887888

@@ -925,7 +926,7 @@ class RelocationSection
925926
static bool classof(const SectionBase *S) {
926927
if (S->OriginalFlags & ELF::SHF_ALLOC)
927928
return false;
928-
return S->OriginalType == ELF::SHT_REL || S->OriginalType == ELF::SHT_RELA;
929+
return RelocationSectionBase::classof(S);
929930
}
930931
};
931932

Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
# RUN: yaml2obj %s -o %t
2+
# RUN: llvm-objcopy --remove-section=.foo --strip-symbol=unused %t %t.out
3+
# RUN: llvm-readelf -Sr %t.out | FileCheck %s
4+
5+
# CHECK: [Nr] Name Type Address Off Size ES Flg Lk Inf Al
6+
# CHECK-NEXT: [ 0] NULL 0000000000000000 000000 000000 00 0 0 0
7+
# CHECK-NEXT: [ 1] .text PROGBITS 0000000000000000 {{.*}} 000008 00 A 0 0 0
8+
# CHECK-NEXT: [ 2] .crel.text CREL 0000000000000000 {{.*}} 000022 00 5 1 0
9+
# CHECK-NEXT: [ 3] nonalloc PROGBITS 0000000000000000 {{.*}} 000030 00 0 0 0
10+
# CHECK-NEXT: [ 4] .crelnonalloc CREL 0000000000000000 {{.*}} 00000b 00 5 3 0
11+
12+
# CHECK: Relocation section '.crel.text' at offset {{.*}} contains 4 entries:
13+
# CHECK-NEXT: Offset Info Type Symbol's Value Symbol's Name + Addend
14+
# CHECK-NEXT: 0000000000000001 {{.*}} R_X86_64_32 0000000000000000 g1 + 1
15+
# CHECK-NEXT: 0000000000000002 {{.*}} R_X86_64_64 0000000000000000 l1 + 2
16+
# CHECK-NEXT: 0000000000000000 {{.*}} R_X86_64_32S 0000000000000000 g1 - 1
17+
# CHECK-NEXT: 0000000000000004 {{.*}} R_X86_64_32S 0000000000000000 .text - 8000000000000000
18+
# CHECK-EMPTY:
19+
# CHECK-NEXT: Relocation section '.crelnonalloc' at offset {{.*}} contains 3 entries:
20+
# CHECK-NEXT: Offset Info Type Symbol's Value Symbol's Name + Addend
21+
# CHECK-NEXT: 0000000000000010 {{.*}} R_X86_64_64 0000000000000000 g1 + 1
22+
# CHECK-NEXT: 0000000000000020 {{.*}} R_X86_64_64 0000000000000000 g2 + 2
23+
# CHECK-NEXT: 0000000000000030 {{.*}} R_X86_64_64 0
24+
25+
--- !ELF
26+
FileHeader:
27+
Class: ELFCLASS64
28+
Data: ELFDATA2LSB
29+
Type: ET_REL
30+
Machine: EM_X86_64
31+
32+
Sections:
33+
- Name: .foo
34+
Type: SHT_PROGBITS
35+
Flags: [SHF_ALLOC]
36+
- Name: .text
37+
Type: SHT_PROGBITS
38+
Content: "0000000000000000"
39+
Flags: [SHF_ALLOC]
40+
- Name: .crel.text
41+
Type: SHT_CREL
42+
Info: .text
43+
Link: .symtab
44+
Relocations:
45+
- Offset: 0x1
46+
Symbol: g1
47+
Type: R_X86_64_32
48+
Addend: 1
49+
- Offset: 0x2
50+
Symbol: l1
51+
Type: R_X86_64_64
52+
Addend: 2
53+
- Offset: 0x0
54+
Symbol: g1
55+
Type: R_X86_64_32S
56+
Addend: 0xffffffffffffffff
57+
- Offset: 0x4
58+
Symbol: .text
59+
Type: R_X86_64_32S
60+
Addend: 0x8000000000000000
61+
- Name: nonalloc
62+
Type: SHT_PROGBITS
63+
Size: 0x30
64+
- Name: .crelnonalloc
65+
Type: SHT_CREL
66+
Info: nonalloc
67+
Link: .symtab
68+
Relocations:
69+
- Offset: 0x10
70+
Symbol: g1
71+
Type: R_X86_64_64
72+
Addend: 1
73+
- Offset: 0x20
74+
Symbol: g2
75+
Type: R_X86_64_64
76+
Addend: 2
77+
- Offset: 0x30
78+
Symbol: 0
79+
Type: R_X86_64_64
80+
81+
Symbols:
82+
- Name: unused
83+
Section: .text
84+
- Name: .text
85+
Type: STT_SECTION
86+
Section: .text
87+
- Name: l1
88+
- Name: g1
89+
Section: .text
90+
Value: 0x0
91+
Size: 4
92+
Binding: STB_GLOBAL
93+
- Name: g2
94+
Binding: STB_GLOBAL
95+
96+
# RUN: yaml2obj --docnum=2 %s -o %t.32
97+
# RUN: llvm-objcopy %t.32 %t.32.out
98+
# RUN: llvm-readobj -r %t.32.out | FileCheck %s --check-prefix=CHECK2
99+
100+
# CHECK2: Relocations [
101+
# CHECK2-NEXT: Section (2) .crel.text {
102+
# CHECK2-NEXT: 0x0 R_X86_64_32S g1 0xFFFFFFFF
103+
# CHECK2-NEXT: 0x4 R_X86_64_32S .text 0x80000000
104+
# CHECK2-NEXT: }
105+
# CHECK2-NEXT: ]
106+
107+
--- !ELF
108+
FileHeader:
109+
Class: ELFCLASS32
110+
Data: ELFDATA2LSB
111+
Type: ET_REL
112+
Machine: EM_X86_64
113+
114+
Sections:
115+
- Name: .text
116+
Type: SHT_PROGBITS
117+
Content: "0000000000000000"
118+
Flags: [SHF_ALLOC]
119+
- Name: .crel.text
120+
Type: SHT_CREL
121+
Info: .text
122+
Link: .symtab
123+
Relocations:
124+
- Offset: 0x0
125+
Symbol: g1
126+
Type: R_X86_64_32S
127+
Addend: 0xffffffff
128+
- Offset: 0x4
129+
Symbol: .text
130+
Type: R_X86_64_32S
131+
Addend: 0x80000000
132+
133+
Symbols:
134+
- Name: .text
135+
Type: STT_SECTION
136+
Section: .text
137+
- Name: g1
138+
Section: .text
139+
Size: 4
140+
Binding: STB_GLOBAL

llvm/test/tools/llvm-objcopy/ELF/reloc-error-remove-symtab.test

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@
33
# RUN: cp %t %t3
44
# RUN: not llvm-strip --no-strip-all -R .symtab %t3 2>&1 >/dev/null | FileCheck %s --check-prefix=ERR2 -DINPUT=%t3
55

6+
# RUN: yaml2obj -DTYPE=SHT_CREL %s -o %t.crel
7+
# RUN: not llvm-objcopy -R .symtab %t.crel %t2.crel 2>&1 >/dev/null | FileCheck %s --check-prefix=ERR1 -DINPUT=%t.crel
8+
69
!ELF
710
FileHeader:
811
Class: ELFCLASS64
@@ -17,7 +20,7 @@ Sections:
1720
AddressAlign: 0x0000000000000010
1821
Content: "0000000000000000"
1922
- Name: .rel.text
20-
Type: SHT_REL
23+
Type: [[TYPE=SHT_REL]]
2124
Link: .symtab
2225
Info: .text
2326
Relocations:
@@ -40,6 +43,12 @@ Symbols:
4043
# RUN: llvm-strip --no-strip-all --allow-broken-links -R .symtab %t5
4144
# RUN: llvm-readobj --sections %t5 | FileCheck %s --check-prefix=SECTIONS --implicit-check-not=.symtab
4245

46+
# RUN: llvm-objcopy --allow-broken-links -R .symtab %t.crel %t4.crel
47+
# RUN: llvm-readobj --sections %t4.crel | FileCheck %s --check-prefix=SECTIONS --implicit-check-not=.symtab
48+
# RUN: cp %t.crel %t5.crel
49+
# RUN: llvm-strip --no-strip-all --allow-broken-links -R .symtab %t5.crel
50+
# RUN: llvm-readobj --sections %t5.crel | FileCheck %s --check-prefix=SECTIONS --implicit-check-not=.symtab
51+
4352
# SECTIONS: Name: .rel.text
4453
# SECTIONS: Link
4554
# SECTIONS-SAME: : 0

llvm/test/tools/llvm-objcopy/ELF/strip-reloc-symbol.test

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
# RUN: yaml2obj %s -o %t
22
# RUN: not llvm-objcopy -N foo %t %t2 2>&1 | FileCheck %s -DFILE=%t
3+
# RUN: yaml2obj -DTYPE=SHT_CREL %s -o %t1
4+
# RUN: not llvm-objcopy -N foo %t1 /dev/null 2>&1 | FileCheck %s -DFILE=%t1
35

46
!ELF
57
FileHeader:
@@ -15,7 +17,7 @@ Sections:
1517
AddressAlign: 0x0000000000000010
1618
Size: 64
1719
- Name: .rel.text
18-
Type: SHT_REL
20+
Type: [[TYPE=SHT_REL]]
1921
Info: .text
2022
Relocations:
2123
- Offset: 0x1000

0 commit comments

Comments
 (0)