Skip to content

Commit 9a44efb

Browse files
committed
[lld-macho] Category Merger: add support for addrsig references
1 parent ad7ee90 commit 9a44efb

File tree

2 files changed

+83
-11
lines changed

2 files changed

+83
-11
lines changed

lld/MachO/ObjC.cpp

Lines changed: 80 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121
#include "llvm/Bitcode/BitcodeReader.h"
2222
#include "llvm/Support/TimeProfiler.h"
2323

24+
#include <unordered_set>
25+
2426
using namespace llvm;
2527
using namespace llvm::MachO;
2628
using namespace lld;
@@ -431,6 +433,7 @@ class ObjcCategoryMerger {
431433
mergeCategoriesIntoSingleCategory(std::vector<InfoInputCategory> &categories);
432434

433435
void eraseISec(ConcatInputSection *isec);
436+
void removeRefsToErasedIsecs(std::unordered_set<InputSection *> erasedIsecs);
434437
void eraseMergedCategories();
435438

436439
void generateCatListForNonErasedCategories(
@@ -471,8 +474,11 @@ class ObjcCategoryMerger {
471474
uint32_t offset);
472475
Defined *tryGetDefinedAtIsecOffset(const ConcatInputSection *isec,
473476
uint32_t offset);
477+
Defined *tryFindDefinedOnIsec(const InputSection *isec, uint32_t offset);
474478
void tryEraseDefinedAtIsecOffset(const ConcatInputSection *isec,
475-
uint32_t offset);
479+
uint32_t offset,
480+
std::unordered_set<InputSection *> &erased);
481+
void eraseSymbolAtIsecOffset(ConcatInputSection *isec, uint32_t offset);
476482

477483
// Allocate a null-terminated StringRef backed by generatedSectionData
478484
StringRef newStringData(const char *str);
@@ -533,12 +539,23 @@ void ObjcCategoryMerger::collectSectionWriteInfoFromIsec(
533539
Symbol *
534540
ObjcCategoryMerger::tryGetSymbolAtIsecOffset(const ConcatInputSection *isec,
535541
uint32_t offset) {
542+
if (!isec)
543+
return nullptr;
536544
const Reloc *reloc = isec->getRelocAt(offset);
537545

538546
if (!reloc)
539547
return nullptr;
540548

541-
return reloc->referent.get<Symbol *>();
549+
Symbol *sym = reloc->referent.get<Symbol *>();
550+
551+
if (reloc->addend) {
552+
assert(isa<Defined>(sym) && "Expected defined for non-zero addend");
553+
Defined *definedSym = dyn_cast<Defined>(sym);
554+
InputSection *targetIsec = definedSym->isec();
555+
sym = tryFindDefinedOnIsec(targetIsec, definedSym->value + reloc->addend);
556+
}
557+
558+
return sym;
542559
}
543560

544561
Defined *
@@ -548,10 +565,20 @@ ObjcCategoryMerger::tryGetDefinedAtIsecOffset(const ConcatInputSection *isec,
548565
return dyn_cast_or_null<Defined>(sym);
549566
}
550567

568+
Defined *ObjcCategoryMerger::tryFindDefinedOnIsec(const InputSection *isec,
569+
uint32_t offset) {
570+
for (Defined *sym : isec->symbols)
571+
if ((sym->value <= offset) && (sym->value + sym->size > offset))
572+
return sym;
573+
574+
return nullptr;
575+
}
576+
551577
// Given an ConcatInputSection or CStringInputSection and an offset, if there is
552578
// a symbol(Defined) at that offset, then erase the symbol (mark it not live)
553579
void ObjcCategoryMerger::tryEraseDefinedAtIsecOffset(
554-
const ConcatInputSection *isec, uint32_t offset) {
580+
const ConcatInputSection *isec, uint32_t offset,
581+
std::unordered_set<InputSection *> &erased) {
555582
const Reloc *reloc = isec->getRelocAt(offset);
556583

557584
if (!reloc)
@@ -561,9 +588,11 @@ void ObjcCategoryMerger::tryEraseDefinedAtIsecOffset(
561588
if (!sym)
562589
return;
563590

564-
if (auto *cisec = dyn_cast_or_null<ConcatInputSection>(sym->isec()))
591+
if (auto *cisec = dyn_cast_or_null<ConcatInputSection>(sym->isec())) {
565592
eraseISec(cisec);
566-
else if (auto *csisec = dyn_cast_or_null<CStringInputSection>(sym->isec())) {
593+
erased.insert(cisec);
594+
} else if (auto *csisec =
595+
dyn_cast_or_null<CStringInputSection>(sym->isec())) {
567596
uint32_t totalOffset = sym->value + reloc->addend;
568597
StringPiece &piece = csisec->getStringPiece(totalOffset);
569598
piece.live = false;
@@ -1183,26 +1212,66 @@ void ObjcCategoryMerger::eraseMergedCategories() {
11831212
// the references to the ones we merged.
11841213
generateCatListForNonErasedCategories(catListToErasedOffsets);
11851214

1215+
// We use erasedIsecs below to track erased sections so we can later remove
1216+
// references to it.
1217+
std::unordered_set<InputSection *> erasedIsecs;
1218+
erasedIsecs.reserve(categoryMap.size());
1219+
11861220
// Erase the old method lists & names of the categories that were merged
11871221
for (auto &mapEntry : categoryMap) {
11881222
for (InfoInputCategory &catInfo : mapEntry.second) {
11891223
if (!catInfo.wasMerged)
11901224
continue;
11911225

1226+
erasedIsecs.insert(catInfo.catBodyIsec);
1227+
erasedIsecs.insert(catInfo.catListIsec);
1228+
11921229
eraseISec(catInfo.catBodyIsec);
1193-
tryEraseDefinedAtIsecOffset(catInfo.catBodyIsec, catLayout.nameOffset);
1230+
tryEraseDefinedAtIsecOffset(catInfo.catBodyIsec, catLayout.nameOffset,
1231+
erasedIsecs);
11941232
tryEraseDefinedAtIsecOffset(catInfo.catBodyIsec,
1195-
catLayout.instanceMethodsOffset);
1233+
catLayout.instanceMethodsOffset, erasedIsecs);
11961234
tryEraseDefinedAtIsecOffset(catInfo.catBodyIsec,
1197-
catLayout.classMethodsOffset);
1235+
catLayout.classMethodsOffset, erasedIsecs);
11981236
tryEraseDefinedAtIsecOffset(catInfo.catBodyIsec,
1199-
catLayout.protocolsOffset);
1237+
catLayout.protocolsOffset, erasedIsecs);
12001238
tryEraseDefinedAtIsecOffset(catInfo.catBodyIsec,
1201-
catLayout.classPropsOffset);
1239+
catLayout.classPropsOffset, erasedIsecs);
12021240
tryEraseDefinedAtIsecOffset(catInfo.catBodyIsec,
1203-
catLayout.instancePropsOffset);
1241+
catLayout.instancePropsOffset, erasedIsecs);
12041242
}
12051243
}
1244+
1245+
removeRefsToErasedIsecs(erasedIsecs);
1246+
}
1247+
1248+
// The compiler may generate references to categories inside the addrsig
1249+
// section. This function will erase these references.
1250+
void ObjcCategoryMerger::removeRefsToErasedIsecs(
1251+
std::unordered_set<InputSection *> erasedIsecs) {
1252+
for (InputSection *isec : inputSections) {
1253+
if (isec->getName() != section_names::addrSig)
1254+
continue;
1255+
1256+
auto removeRelocs = [&erasedIsecs](Reloc &r) {
1257+
ConcatInputSection *isec = nullptr;
1258+
isec = dyn_cast_or_null<ConcatInputSection>(
1259+
r.referent.dyn_cast<InputSection *>());
1260+
if (!isec) {
1261+
Defined *sym =
1262+
dyn_cast_or_null<Defined>(r.referent.dyn_cast<Symbol *>());
1263+
if (sym)
1264+
isec = dyn_cast<ConcatInputSection>(sym->isec());
1265+
}
1266+
if (!isec)
1267+
return false;
1268+
return erasedIsecs.count(isec) > 0;
1269+
};
1270+
1271+
isec->relocs.erase(
1272+
std::remove_if(isec->relocs.begin(), isec->relocs.end(), removeRelocs),
1273+
isec->relocs.end());
1274+
}
12061275
}
12071276

12081277
void ObjcCategoryMerger::doMerge() {

lld/test/MachO/objc-category-merging-extern-class-minimal.s

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,3 +153,6 @@ L_OBJC_IMAGE_INFO:
153153
.long 0
154154
.long 96
155155
.subsections_via_symbols
156+
157+
.addrsig
158+
.addrsig_sym __OBJC_$_CATEGORY_MyBaseClass_$_Category01

0 commit comments

Comments
 (0)