Skip to content

Commit 51ed383

Browse files
authored
[lld-macho] Make relative method lists work on x86-64 (#103905)
Local data is referenced in Objective-C metadata via section + offset relocations on x86-64 rather than via symbols. Without this change, we would crash on incorrect casts of the referents to `Defined`. A basic test based on the existing `objc-relative-method-lists-simple.s` adopted to x86-64 is added.
1 parent 23617f2 commit 51ed383

File tree

5 files changed

+299
-36
lines changed

5 files changed

+299
-36
lines changed

lld/MachO/ObjC.cpp

Lines changed: 4 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -186,28 +186,6 @@ ObjcCategoryChecker::ObjcCategoryChecker()
186186
roClassLayout(target->wordSize), listHeaderLayout(target->wordSize),
187187
methodLayout(target->wordSize) {}
188188

189-
// \p r must point to an offset within a CStringInputSection or a
190-
// ConcatInputSection
191-
static StringRef getReferentString(const Reloc &r) {
192-
if (auto *isec = r.referent.dyn_cast<InputSection *>())
193-
return cast<CStringInputSection>(isec)->getStringRefAtOffset(r.addend);
194-
195-
auto *sym = cast<Defined>(r.referent.get<Symbol *>());
196-
auto *symIsec = sym->isec();
197-
auto symOffset = sym->value + r.addend;
198-
199-
if (auto *s = dyn_cast_or_null<CStringInputSection>(symIsec))
200-
return s->getStringRefAtOffset(symOffset);
201-
202-
if (isa<ConcatInputSection>(symIsec)) {
203-
auto strData = symIsec->data.slice(symOffset);
204-
const char *pszData = reinterpret_cast<const char *>(strData.data());
205-
return StringRef(pszData, strnlen(pszData, strData.size()));
206-
}
207-
208-
llvm_unreachable("unknown reference section in getReferentString");
209-
}
210-
211189
void ObjcCategoryChecker::parseMethods(const ConcatInputSection *methodsIsec,
212190
const Symbol *methodContainerSym,
213191
const ConcatInputSection *containerIsec,
@@ -219,7 +197,7 @@ void ObjcCategoryChecker::parseMethods(const ConcatInputSection *methodsIsec,
219197
methodLayout.nameOffset)
220198
continue;
221199

222-
CachedHashStringRef methodName(getReferentString(r));
200+
CachedHashStringRef methodName(r.getReferentString());
223201
// +load methods are special: all implementations are called by the runtime
224202
// even if they are part of the same class. Thus there is no need to check
225203
// for duplicates.
@@ -251,14 +229,14 @@ void ObjcCategoryChecker::parseMethods(const ConcatInputSection *methodsIsec,
251229
->getReferentInputSection();
252230
nameReloc = roIsec->getRelocAt(roClassLayout.nameOffset);
253231
}
254-
StringRef containerName = getReferentString(*nameReloc);
232+
StringRef containerName = nameReloc->getReferentString();
255233
StringRef methPrefix = mKind == MK_Instance ? "-" : "+";
256234

257235
// We should only ever encounter collisions when parsing category methods
258236
// (since the Class struct is parsed before any of its categories).
259237
assert(mcKind == MCK_Category);
260238
StringRef newCatName =
261-
getReferentString(*containerIsec->getRelocAt(catLayout.nameOffset));
239+
containerIsec->getRelocAt(catLayout.nameOffset)->getReferentString();
262240

263241
auto formatObjAndSrcFileName = [](const InputSection *section) {
264242
lld::macho::InputFile *inputFile = section->getFile();
@@ -809,7 +787,7 @@ void ObjcCategoryMerger::parseCatInfoToExtInfo(const InfoInputCategory &catInfo,
809787
assert(extInfo.objFileForMergeData &&
810788
"Expected to already have valid objextInfo.objFileForMergeData");
811789

812-
StringRef catName = getReferentString(*catNameReloc);
790+
StringRef catName = catNameReloc->getReferentString();
813791
extInfo.mergedContainerName += catName.str();
814792

815793
// Parse base class

lld/MachO/Relocations.cpp

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,31 @@ InputSection *Reloc::getReferentInputSection() const {
3131
}
3232
}
3333
34+
StringRef Reloc::getReferentString() const {
35+
if (auto *isec = referent.dyn_cast<InputSection *>()) {
36+
const auto *cisec = dyn_cast<CStringInputSection>(isec);
37+
assert(cisec && "referent must be a CStringInputSection");
38+
return cisec->getStringRefAtOffset(addend);
39+
}
40+
41+
auto *sym = dyn_cast<Defined>(referent.get<Symbol *>());
42+
assert(sym && "referent must be a Defined symbol");
43+
44+
auto *symIsec = sym->isec();
45+
auto symOffset = sym->value + addend;
46+
47+
if (auto *s = dyn_cast_or_null<CStringInputSection>(symIsec))
48+
return s->getStringRefAtOffset(symOffset);
49+
50+
if (isa<ConcatInputSection>(symIsec)) {
51+
auto strData = symIsec->data.slice(symOffset);
52+
const char *pszData = reinterpret_cast<const char *>(strData.data());
53+
return StringRef(pszData, strnlen(pszData, strData.size()));
54+
}
55+
56+
llvm_unreachable("unknown reference section in getReferentString");
57+
}
58+
3459
bool macho::validateSymbolRelocation(const Symbol *sym,
3560
const InputSection *isec, const Reloc &r) {
3661
const RelocAttrs &relocAttrs = target->getRelocAttrs(r.type);

lld/MachO/Relocations.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,10 @@ struct Reloc {
6969
addend(addend), referent(referent) {}
7070

7171
InputSection *getReferentInputSection() const;
72+
73+
// Must point to an offset within a CStringInputSection or a
74+
// ConcatInputSection.
75+
llvm::StringRef getReferentString() const;
7276
};
7377

7478
bool validateSymbolRelocation(const Symbol *, const InputSection *,

lld/MachO/SyntheticSections.cpp

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2010,11 +2010,8 @@ void ObjCMethListSection::setUp() {
20102010
while (methodNameOff < isec->data.size()) {
20112011
const Reloc *reloc = isec->getRelocAt(methodNameOff);
20122012
assert(reloc && "Relocation expected at method list name slot");
2013-
auto *def = dyn_cast_or_null<Defined>(reloc->referent.get<Symbol *>());
2014-
assert(def && "Expected valid Defined at method list name slot");
2015-
auto *cisec = cast<CStringInputSection>(def->isec());
2016-
assert(cisec && "Expected method name to be in a CStringInputSection");
2017-
auto methname = cisec->getStringRefAtOffset(def->value);
2013+
2014+
StringRef methname = reloc->getReferentString();
20182015
if (!ObjCSelRefsHelper::getSelRef(methname))
20192016
ObjCSelRefsHelper::makeSelRef(methname);
20202017

@@ -2114,19 +2111,23 @@ void ObjCMethListSection::writeRelativeOffsetForIsec(
21142111
uint32_t &outSecOff, bool useSelRef) const {
21152112
const Reloc *reloc = isec->getRelocAt(inSecOff);
21162113
assert(reloc && "Relocation expected at __objc_methlist Offset");
2117-
auto *def = dyn_cast_or_null<Defined>(reloc->referent.get<Symbol *>());
2118-
assert(def && "Expected all syms in __objc_methlist to be defined");
2119-
uint32_t symVA = def->getVA();
21202114

2115+
uint32_t symVA = 0;
21212116
if (useSelRef) {
2122-
auto *cisec = cast<CStringInputSection>(def->isec());
2123-
auto methname = cisec->getStringRefAtOffset(def->value);
2117+
StringRef methname = reloc->getReferentString();
21242118
ConcatInputSection *selRef = ObjCSelRefsHelper::getSelRef(methname);
21252119
assert(selRef && "Expected all selector names to already be already be "
21262120
"present in __objc_selrefs");
21272121
symVA = selRef->getVA();
21282122
assert(selRef->data.size() == sizeof(target->wordSize) &&
21292123
"Expected one selref per ConcatInputSection");
2124+
} else if (reloc->referent.is<Symbol *>()) {
2125+
auto *def = dyn_cast_or_null<Defined>(reloc->referent.get<Symbol *>());
2126+
assert(def && "Expected all syms in __objc_methlist to be defined");
2127+
symVA = def->getVA();
2128+
} else {
2129+
auto *isec = reloc->referent.get<InputSection *>();
2130+
symVA = isec->getVA(reloc->addend);
21302131
}
21312132

21322133
uint32_t currentVA = isec->getVA() + outSecOff;

0 commit comments

Comments
 (0)