Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 142499d

Browse files
MaskRaytru
authored andcommitted
[ELF] Support relocatable files using CREL with explicit addends
... using the temporary section type code 0x40000020 (`clang -c -Wa,--crel,--allow-experimental-crel`). LLVM will change the code and break compatibility (Clang and lld of different versions are not guaranteed to cooperate, unlike other features). CREL with implicit addends are not supported. --- Introduce `RelsOrRelas::crels` to iterate over SHT_CREL sections and update users to check `crels`. (The decoding performance is critical and error checking is difficult. Follow `skipLeb` and `R_*LEB128` handling, do not use `llvm::decodeULEB128`, whichs compiles to a lot of code.) A few users (e.g. .eh_frame, LLDDwarfObj, s390x) require random access. Pass `/*supportsCrel=*/false` to `relsOrRelas` to allocate a buffer and convert CREL to RELA (`relas` instead of `crels` will be used). Since allocating a buffer increases, the conversion is only performed when absolutely necessary. --- Non-alloc SHT_CREL sections may be created in -r and --emit-relocs links. SHT_CREL and SHT_RELA components need reencoding since r_offset/r_symidx/r_type/r_addend may change. (r_type may change because relocations referencing a symbol in a discarded section are converted to `R_*_NONE`). * SHT_CREL components: decode with `RelsOrRelas` and re-encode (`OutputSection::finalizeNonAllocCrel`) * SHT_RELA components: convert to CREL (`relToCrel`). An output section can only have one relocation section. * SHT_REL components: print an error for now. SHT_REL to SHT_CREL conversion for -r/--emit-relocs is complex and unsupported yet. Link: https://discourse.llvm.org/t/rfc-crel-a-compact-relocation-format-for-elf/77600 Pull Request: llvm#98115 (cherry picked from commit 0af07c0)
1 parent 3ee69f2 commit 142499d

23 files changed

+656
-44
lines changed

lld/ELF/DWARF.cpp

+2-1
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,8 @@ template <class ELFT>
136136
std::optional<RelocAddrEntry>
137137
LLDDwarfObj<ELFT>::find(const llvm::DWARFSection &s, uint64_t pos) const {
138138
auto &sec = static_cast<const LLDDWARFSection &>(s);
139-
const RelsOrRelas<ELFT> rels = sec.sec->template relsOrRelas<ELFT>();
139+
const RelsOrRelas<ELFT> rels =
140+
sec.sec->template relsOrRelas<ELFT>(/*supportsCrel=*/false);
140141
if (rels.areRelocsRel())
141142
return findAux(*sec.sec, pos, rels.rels);
142143
return findAux(*sec.sec, pos, rels.relas);

lld/ELF/ICF.cpp

+7-1
Original file line numberDiff line numberDiff line change
@@ -324,6 +324,8 @@ bool ICF<ELFT>::equalsConstant(const InputSection *a, const InputSection *b) {
324324

325325
const RelsOrRelas<ELFT> ra = a->template relsOrRelas<ELFT>();
326326
const RelsOrRelas<ELFT> rb = b->template relsOrRelas<ELFT>();
327+
if (ra.areRelocsCrel())
328+
return constantEq(a, ra.crels, b, rb.crels);
327329
return ra.areRelocsRel() || rb.areRelocsRel()
328330
? constantEq(a, ra.rels, b, rb.rels)
329331
: constantEq(a, ra.relas, b, rb.relas);
@@ -374,6 +376,8 @@ template <class ELFT>
374376
bool ICF<ELFT>::equalsVariable(const InputSection *a, const InputSection *b) {
375377
const RelsOrRelas<ELFT> ra = a->template relsOrRelas<ELFT>();
376378
const RelsOrRelas<ELFT> rb = b->template relsOrRelas<ELFT>();
379+
if (ra.areRelocsCrel())
380+
return variableEq(a, ra.crels, b, rb.crels);
377381
return ra.areRelocsRel() || rb.areRelocsRel()
378382
? variableEq(a, ra.rels, b, rb.rels)
379383
: variableEq(a, ra.relas, b, rb.relas);
@@ -505,7 +509,9 @@ template <class ELFT> void ICF<ELFT>::run() {
505509
for (unsigned cnt = 0; cnt != 2; ++cnt) {
506510
parallelForEach(sections, [&](InputSection *s) {
507511
const RelsOrRelas<ELFT> rels = s->template relsOrRelas<ELFT>();
508-
if (rels.areRelocsRel())
512+
if (rels.areRelocsCrel())
513+
combineRelocHashes(cnt, s, rels.crels);
514+
else if (rels.areRelocsRel())
509515
combineRelocHashes(cnt, s, rels.rels);
510516
else
511517
combineRelocHashes(cnt, s, rels.relas);

lld/ELF/InputFiles.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -834,6 +834,7 @@ void ObjFile<ELFT>::initializeSections(bool ignoreComdats,
834834
case SHT_STRTAB:
835835
case SHT_REL:
836836
case SHT_RELA:
837+
case SHT_CREL:
837838
case SHT_NULL:
838839
break;
839840
case SHT_PROGBITS:

lld/ELF/InputFiles.h

+1
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ class InputFile {
8484
assert(fileKind == ObjKind || fileKind == BinaryKind);
8585
return sections;
8686
}
87+
void cacheDecodedCrel(size_t i, InputSectionBase *s) { sections[i] = s; }
8788

8889
// Returns object file symbols. It is a runtime error to call this
8990
// function on files of other types.

lld/ELF/InputSection.cpp

+53-14
Original file line numberDiff line numberDiff line change
@@ -133,21 +133,56 @@ void InputSectionBase::decompress() const {
133133
compressed = false;
134134
}
135135

136-
template <class ELFT> RelsOrRelas<ELFT> InputSectionBase::relsOrRelas() const {
136+
template <class ELFT>
137+
RelsOrRelas<ELFT> InputSectionBase::relsOrRelas(bool supportsCrel) const {
137138
if (relSecIdx == 0)
138139
return {};
139140
RelsOrRelas<ELFT> ret;
140-
typename ELFT::Shdr shdr =
141-
cast<ELFFileBase>(file)->getELFShdrs<ELFT>()[relSecIdx];
141+
auto *f = cast<ObjFile<ELFT>>(file);
142+
typename ELFT::Shdr shdr = f->template getELFShdrs<ELFT>()[relSecIdx];
143+
if (shdr.sh_type == SHT_CREL) {
144+
// Return an iterator if supported by caller.
145+
if (supportsCrel) {
146+
ret.crels = Relocs<typename ELFT::Crel>(
147+
(const uint8_t *)f->mb.getBufferStart() + shdr.sh_offset);
148+
return ret;
149+
}
150+
InputSectionBase *const &relSec = f->getSections()[relSecIdx];
151+
// Otherwise, allocate a buffer to hold the decoded RELA relocations. When
152+
// called for the first time, relSec is null (without --emit-relocs) or an
153+
// InputSection with zero eqClass[0].
154+
if (!relSec || !cast<InputSection>(relSec)->eqClass[0]) {
155+
auto *sec = makeThreadLocal<InputSection>(*f, shdr, name);
156+
f->cacheDecodedCrel(relSecIdx, sec);
157+
sec->type = SHT_RELA;
158+
sec->eqClass[0] = SHT_RELA;
159+
160+
RelocsCrel<ELFT::Is64Bits> entries(sec->content_);
161+
sec->size = entries.size() * sizeof(typename ELFT::Rela);
162+
auto *relas = makeThreadLocalN<typename ELFT::Rela>(entries.size());
163+
sec->content_ = reinterpret_cast<uint8_t *>(relas);
164+
for (auto [i, r] : llvm::enumerate(entries)) {
165+
relas[i].r_offset = r.r_offset;
166+
relas[i].setSymbolAndType(r.r_symidx, r.r_type, false);
167+
relas[i].r_addend = r.r_addend;
168+
}
169+
}
170+
ret.relas = {ArrayRef(
171+
reinterpret_cast<const typename ELFT::Rela *>(relSec->content_),
172+
relSec->size / sizeof(typename ELFT::Rela))};
173+
return ret;
174+
}
175+
176+
const void *content = f->mb.getBufferStart() + shdr.sh_offset;
177+
size_t size = shdr.sh_size;
142178
if (shdr.sh_type == SHT_REL) {
143-
ret.rels = ArrayRef(reinterpret_cast<const typename ELFT::Rel *>(
144-
file->mb.getBufferStart() + shdr.sh_offset),
145-
shdr.sh_size / sizeof(typename ELFT::Rel));
179+
ret.rels = {ArrayRef(reinterpret_cast<const typename ELFT::Rel *>(content),
180+
size / sizeof(typename ELFT::Rel))};
146181
} else {
147182
assert(shdr.sh_type == SHT_RELA);
148-
ret.relas = ArrayRef(reinterpret_cast<const typename ELFT::Rela *>(
149-
file->mb.getBufferStart() + shdr.sh_offset),
150-
shdr.sh_size / sizeof(typename ELFT::Rela));
183+
ret.relas = {
184+
ArrayRef(reinterpret_cast<const typename ELFT::Rela *>(content),
185+
size / sizeof(typename ELFT::Rela))};
151186
}
152187
return ret;
153188
}
@@ -1248,7 +1283,7 @@ SyntheticSection *EhInputSection::getParent() const {
12481283
// .eh_frame is a sequence of CIE or FDE records.
12491284
// This function splits an input section into records and returns them.
12501285
template <class ELFT> void EhInputSection::split() {
1251-
const RelsOrRelas<ELFT> rels = relsOrRelas<ELFT>();
1286+
const RelsOrRelas<ELFT> rels = relsOrRelas<ELFT>(/*supportsCrel=*/false);
12521287
// getReloc expects the relocations to be sorted by r_offset. See the comment
12531288
// in scanRelocs.
12541289
if (rels.areRelocsRel()) {
@@ -1414,10 +1449,14 @@ template void InputSection::writeTo<ELF32BE>(uint8_t *);
14141449
template void InputSection::writeTo<ELF64LE>(uint8_t *);
14151450
template void InputSection::writeTo<ELF64BE>(uint8_t *);
14161451

1417-
template RelsOrRelas<ELF32LE> InputSectionBase::relsOrRelas<ELF32LE>() const;
1418-
template RelsOrRelas<ELF32BE> InputSectionBase::relsOrRelas<ELF32BE>() const;
1419-
template RelsOrRelas<ELF64LE> InputSectionBase::relsOrRelas<ELF64LE>() const;
1420-
template RelsOrRelas<ELF64BE> InputSectionBase::relsOrRelas<ELF64BE>() const;
1452+
template RelsOrRelas<ELF32LE>
1453+
InputSectionBase::relsOrRelas<ELF32LE>(bool) const;
1454+
template RelsOrRelas<ELF32BE>
1455+
InputSectionBase::relsOrRelas<ELF32BE>(bool) const;
1456+
template RelsOrRelas<ELF64LE>
1457+
InputSectionBase::relsOrRelas<ELF64LE>(bool) const;
1458+
template RelsOrRelas<ELF64BE>
1459+
InputSectionBase::relsOrRelas<ELF64BE>(bool) const;
14211460

14221461
template MergeInputSection::MergeInputSection(ObjFile<ELF32LE> &,
14231462
const ELF32LE::Shdr &, StringRef);

lld/ELF/InputSection.h

+10-4
Original file line numberDiff line numberDiff line change
@@ -35,17 +35,21 @@ class OutputSection;
3535

3636
LLVM_LIBRARY_VISIBILITY extern std::vector<Partition> partitions;
3737

38-
// Returned by InputSectionBase::relsOrRelas. At least one member is empty.
38+
// Returned by InputSectionBase::relsOrRelas. At most one member is empty.
3939
template <class ELFT> struct RelsOrRelas {
4040
Relocs<typename ELFT::Rel> rels;
4141
Relocs<typename ELFT::Rela> relas;
42+
Relocs<typename ELFT::Crel> crels;
4243
bool areRelocsRel() const { return rels.size(); }
44+
bool areRelocsCrel() const { return crels.size(); }
4345
};
4446

4547
#define invokeOnRelocs(sec, f, ...) \
4648
{ \
4749
const RelsOrRelas<ELFT> rs = (sec).template relsOrRelas<ELFT>(); \
48-
if (rs.areRelocsRel()) \
50+
if (rs.areRelocsCrel()) \
51+
f(__VA_ARGS__, rs.crels); \
52+
else if (rs.areRelocsRel()) \
4953
f(__VA_ARGS__, rs.rels); \
5054
else \
5155
f(__VA_ARGS__, rs.relas); \
@@ -209,7 +213,8 @@ class InputSectionBase : public SectionBase {
209213
// used by --gc-sections.
210214
InputSectionBase *nextInSectionGroup = nullptr;
211215

212-
template <class ELFT> RelsOrRelas<ELFT> relsOrRelas() const;
216+
template <class ELFT>
217+
RelsOrRelas<ELFT> relsOrRelas(bool supportsCrel = true) const;
213218

214219
// InputSections that are dependent on us (reverse dependency for GC)
215220
llvm::TinyPtrVector<InputSection *> dependentSections;
@@ -483,7 +488,8 @@ class SyntheticSection : public InputSection {
483488
};
484489

485490
inline bool isStaticRelSecType(uint32_t type) {
486-
return type == llvm::ELF::SHT_RELA || type == llvm::ELF::SHT_REL;
491+
return type == llvm::ELF::SHT_RELA || type == llvm::ELF::SHT_CREL ||
492+
type == llvm::ELF::SHT_REL;
487493
}
488494

489495
inline bool isDebugSection(const InputSectionBase &sec) {

lld/ELF/LinkerScript.cpp

+2
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,8 @@ static StringRef getOutputSectionName(const InputSectionBase *s) {
6161
assert(config->relocatable && (rel->flags & SHF_LINK_ORDER));
6262
return s->name;
6363
}
64+
if (s->type == SHT_CREL)
65+
return saver().save(".crel" + out->name);
6466
if (s->type == SHT_RELA)
6567
return saver().save(".rela" + out->name);
6668
return saver().save(".rel" + out->name);

lld/ELF/MarkLive.cpp

+11-1
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,13 @@ static uint64_t getAddend(InputSectionBase &sec,
8585
return rel.r_addend;
8686
}
8787

88+
// Currently, we assume all input CREL relocations have an explicit addend.
89+
template <class ELFT>
90+
static uint64_t getAddend(InputSectionBase &sec,
91+
const typename ELFT::Crel &rel) {
92+
return rel.r_addend;
93+
}
94+
8895
template <class ELFT>
8996
template <class RelTy>
9097
void MarkLive<ELFT>::resolveReloc(InputSectionBase &sec, RelTy &rel,
@@ -239,7 +246,8 @@ template <class ELFT> void MarkLive<ELFT>::run() {
239246
// all of them. We also want to preserve personality routines and LSDA
240247
// referenced by .eh_frame sections, so we scan them for that here.
241248
for (EhInputSection *eh : ctx.ehInputSections) {
242-
const RelsOrRelas<ELFT> rels = eh->template relsOrRelas<ELFT>();
249+
const RelsOrRelas<ELFT> rels =
250+
eh->template relsOrRelas<ELFT>(/*supportsCrel=*/false);
243251
if (rels.areRelocsRel())
244252
scanEhFrameSection(*eh, rels.rels);
245253
else if (rels.relas.size())
@@ -310,6 +318,8 @@ template <class ELFT> void MarkLive<ELFT>::mark() {
310318
resolveReloc(sec, rel, false);
311319
for (const typename ELFT::Rela &rel : rels.relas)
312320
resolveReloc(sec, rel, false);
321+
for (const typename ELFT::Crel &rel : rels.crels)
322+
resolveReloc(sec, rel, false);
313323

314324
for (InputSectionBase *isec : sec.dependentSections)
315325
enqueue(isec, 0);

0 commit comments

Comments
 (0)