Skip to content

Commit d4ec334

Browse files
committed
[lld-macho][nfc] Refactor to accommodate paired relocs
This is a refactor to pave the way for supporting paired-ADDEND for ARM64. The only paired reloc type for X86_64 is SUBTRACTOR. In a later diff, I will add SUBTRACTOR for both X86_64 and ARM64. * s/`getImplicitAddend`/`getAddend`/ because it handles all forms of addend: implicit, explicit, paired. * add predicate `bool isPairedReloc()` * check range of `relInfo.r_symbolnum` is internal, unrelated to user-input, so use `assert()`, not `error()` * minor cleanups & rearrangements in `InputFile::parseRelocations()` Differential Revision: https://reviews.llvm.org/D90614
1 parent ed6a135 commit d4ec334

File tree

3 files changed

+55
-26
lines changed

3 files changed

+55
-26
lines changed

lld/MachO/Arch/X86_64.cpp

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,9 @@ namespace {
2525
struct X86_64 : TargetInfo {
2626
X86_64();
2727

28-
uint64_t getImplicitAddend(MemoryBufferRef, const section_64 &,
29-
const relocation_info &) const override;
28+
bool isPairedReloc(relocation_info) const override;
29+
uint64_t getAddend(MemoryBufferRef, const section_64 &, relocation_info,
30+
relocation_info) const override;
3031
void relocateOne(uint8_t *loc, const Reloc &, uint64_t val) const override;
3132

3233
void writeStub(uint8_t *buf, const macho::Symbol &) const override;
@@ -43,15 +44,15 @@ struct X86_64 : TargetInfo {
4344
} // namespace
4445

4546
static std::string getErrorLocation(MemoryBufferRef mb, const section_64 &sec,
46-
const relocation_info &rel) {
47+
relocation_info rel) {
4748
return ("invalid relocation at offset " + std::to_string(rel.r_address) +
4849
" of " + sec.segname + "," + sec.sectname + " in " +
4950
mb.getBufferIdentifier())
5051
.str();
5152
}
5253

5354
static void validateLength(MemoryBufferRef mb, const section_64 &sec,
54-
const relocation_info &rel,
55+
relocation_info rel,
5556
ArrayRef<uint8_t> validLengths) {
5657
if (find(validLengths, rel.r_length) != validLengths.end())
5758
return;
@@ -68,8 +69,13 @@ static void validateLength(MemoryBufferRef mb, const section_64 &sec,
6869
fatal(msg);
6970
}
7071

71-
uint64_t X86_64::getImplicitAddend(MemoryBufferRef mb, const section_64 &sec,
72-
const relocation_info &rel) const {
72+
bool X86_64::isPairedReloc(relocation_info rel) const {
73+
return rel.r_type == X86_64_RELOC_SUBTRACTOR;
74+
}
75+
76+
uint64_t X86_64::getAddend(MemoryBufferRef mb, const section_64 &sec,
77+
relocation_info rel,
78+
relocation_info pairedRel) const {
7379
auto *buf = reinterpret_cast<const uint8_t *>(mb.getBufferStart());
7480
const uint8_t *loc = buf + sec.offset + rel.r_address;
7581

@@ -139,7 +145,7 @@ void X86_64::relocateOne(uint8_t *loc, const Reloc &r, uint64_t val) const {
139145
break;
140146
default:
141147
llvm_unreachable(
142-
"getImplicitAddend should have flagged all unhandled relocation types");
148+
"getAddend should have flagged all unhandled relocation types");
143149
}
144150

145151
switch (r.length) {

lld/MachO/InputFiles.cpp

Lines changed: 37 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -206,31 +206,53 @@ static InputSection *findContainingSubsection(SubsectionMap &map,
206206
void ObjFile::parseRelocations(const section_64 &sec,
207207
SubsectionMap &subsecMap) {
208208
auto *buf = reinterpret_cast<const uint8_t *>(mb.getBufferStart());
209-
ArrayRef<any_relocation_info> anyRelInfos(
210-
reinterpret_cast<const any_relocation_info *>(buf + sec.reloff),
211-
sec.nreloc);
212-
213-
for (const any_relocation_info &anyRelInfo : anyRelInfos) {
214-
if (anyRelInfo.r_word0 & R_SCATTERED)
209+
ArrayRef<relocation_info> relInfos(
210+
reinterpret_cast<const relocation_info *>(buf + sec.reloff), sec.nreloc);
211+
212+
for (size_t i = 0; i < relInfos.size(); i++) {
213+
// Paired relocations serve as Mach-O's method for attaching a
214+
// supplemental datum to a primary relocation record. ELF does not
215+
// need them because the *_RELOC_RELA records contain the extra
216+
// addend field, vs. *_RELOC_REL which omit the addend.
217+
//
218+
// The {X86_64,ARM64}_RELOC_SUBTRACTOR record holds the subtrahend,
219+
// and the paired *_RELOC_UNSIGNED record holds the minuend. The
220+
// datum for each is a symbolic address. The result is the runtime
221+
// offset between two addresses.
222+
//
223+
// The ARM64_RELOC_ADDEND record holds the addend, and the paired
224+
// ARM64_RELOC_BRANCH26 or ARM64_RELOC_PAGE21/PAGEOFF12 holds the
225+
// base symbolic address.
226+
//
227+
// Note: X86 does not use *_RELOC_ADDEND because it can embed an
228+
// addend into the instruction stream. On X86, a relocatable address
229+
// field always occupies an entire contiguous sequence of byte(s),
230+
// so there is no need to merge opcode bits with address
231+
// bits. Therefore, it's easy and convenient to store addends in the
232+
// instruction-stream bytes that would otherwise contain zeroes. By
233+
// contrast, RISC ISAs such as ARM64 mix opcode bits with with
234+
// address bits so that bitwise arithmetic is necessary to extract
235+
// and insert them. Storing addends in the instruction stream is
236+
// possible, but inconvenient and more costly at link time.
237+
238+
relocation_info pairedInfo = relInfos[i];
239+
relocation_info relInfo =
240+
target->isPairedReloc(pairedInfo) ? relInfos[++i] : pairedInfo;
241+
assert(i < relInfos.size());
242+
if (relInfo.r_address & R_SCATTERED)
215243
fatal("TODO: Scattered relocations not supported");
216244

217-
auto relInfo = reinterpret_cast<const relocation_info &>(anyRelInfo);
218-
219245
Reloc r;
220246
r.type = relInfo.r_type;
221247
r.pcrel = relInfo.r_pcrel;
222248
r.length = relInfo.r_length;
223-
uint64_t rawAddend = target->getImplicitAddend(mb, sec, relInfo);
224-
249+
r.offset = relInfo.r_address;
250+
// For unpaired relocs, pairdInfo (just a copy of relInfo) is ignored
251+
uint64_t rawAddend = target->getAddend(mb, sec, relInfo, pairedInfo);
225252
if (relInfo.r_extern) {
226253
r.referent = symbols[relInfo.r_symbolnum];
227254
r.addend = rawAddend;
228255
} else {
229-
if (relInfo.r_symbolnum == 0 || relInfo.r_symbolnum > subsections.size())
230-
fatal("invalid section index in relocation for offset " +
231-
std::to_string(r.offset) + " in section " + sec.sectname +
232-
" of " + getName());
233-
234256
SubsectionMap &referentSubsecMap = subsections[relInfo.r_symbolnum - 1];
235257
const section_64 &referentSec = sectionHeaders[relInfo.r_symbolnum - 1];
236258
uint32_t referentOffset;
@@ -250,7 +272,6 @@ void ObjFile::parseRelocations(const section_64 &sec,
250272
r.addend = referentOffset;
251273
}
252274

253-
r.offset = relInfo.r_address;
254275
InputSection *subsec = findContainingSubsection(subsecMap, &r.offset);
255276
subsec->relocs.push_back(r);
256277
}

lld/MachO/Target.h

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,11 @@ class TargetInfo {
3737
virtual ~TargetInfo() = default;
3838

3939
// Validate the relocation structure and get its addend.
40-
virtual uint64_t
41-
getImplicitAddend(llvm::MemoryBufferRef, const llvm::MachO::section_64 &,
42-
const llvm::MachO::relocation_info &) const = 0;
40+
virtual uint64_t getAddend(llvm::MemoryBufferRef,
41+
const llvm::MachO::section_64 &,
42+
llvm::MachO::relocation_info,
43+
llvm::MachO::relocation_info) const = 0;
44+
virtual bool isPairedReloc(llvm::MachO::relocation_info) const = 0;
4345
virtual void relocateOne(uint8_t *loc, const Reloc &, uint64_t val) const = 0;
4446

4547
// Write code for lazy binding. See the comments on StubsSection for more

0 commit comments

Comments
 (0)