21
21
#include " llvm/Bitcode/BitcodeReader.h"
22
22
#include " llvm/Support/TimeProfiler.h"
23
23
24
+ #include < unordered_set>
25
+
24
26
using namespace llvm ;
25
27
using namespace llvm ::MachO;
26
28
using namespace lld ;
@@ -431,6 +433,7 @@ class ObjcCategoryMerger {
431
433
mergeCategoriesIntoSingleCategory (std::vector<InfoInputCategory> &categories);
432
434
433
435
void eraseISec (ConcatInputSection *isec);
436
+ void removeRefsToErasedIsecs (std::unordered_set<InputSection *> erasedIsecs);
434
437
void eraseMergedCategories ();
435
438
436
439
void generateCatListForNonErasedCategories (
@@ -472,7 +475,9 @@ class ObjcCategoryMerger {
472
475
Defined *tryGetDefinedAtIsecOffset (const ConcatInputSection *isec,
473
476
uint32_t offset);
474
477
void tryEraseDefinedAtIsecOffset (const ConcatInputSection *isec,
475
- uint32_t offset);
478
+ uint32_t offset,
479
+ std::unordered_set<InputSection *> &erased);
480
+ void eraseSymbolAtIsecOffset (ConcatInputSection *isec, uint32_t offset);
476
481
477
482
// Allocate a null-terminated StringRef backed by generatedSectionData
478
483
StringRef newStringData (const char *str);
@@ -533,6 +538,8 @@ void ObjcCategoryMerger::collectSectionWriteInfoFromIsec(
533
538
Symbol *
534
539
ObjcCategoryMerger::tryGetSymbolAtIsecOffset (const ConcatInputSection *isec,
535
540
uint32_t offset) {
541
+ if (!isec)
542
+ return nullptr ;
536
543
const Reloc *reloc = isec->getRelocAt (offset);
537
544
538
545
if (!reloc)
@@ -551,7 +558,8 @@ ObjcCategoryMerger::tryGetDefinedAtIsecOffset(const ConcatInputSection *isec,
551
558
// Given an ConcatInputSection or CStringInputSection and an offset, if there is
552
559
// a symbol(Defined) at that offset, then erase the symbol (mark it not live)
553
560
void ObjcCategoryMerger::tryEraseDefinedAtIsecOffset (
554
- const ConcatInputSection *isec, uint32_t offset) {
561
+ const ConcatInputSection *isec, uint32_t offset,
562
+ std::unordered_set<InputSection *> &erased) {
555
563
const Reloc *reloc = isec->getRelocAt (offset);
556
564
557
565
if (!reloc)
@@ -561,9 +569,11 @@ void ObjcCategoryMerger::tryEraseDefinedAtIsecOffset(
561
569
if (!sym)
562
570
return ;
563
571
564
- if (auto *cisec = dyn_cast_or_null<ConcatInputSection>(sym->isec ()))
572
+ if (auto *cisec = dyn_cast_or_null<ConcatInputSection>(sym->isec ())) {
565
573
eraseISec (cisec);
566
- else if (auto *csisec = dyn_cast_or_null<CStringInputSection>(sym->isec ())) {
574
+ erased.insert (cisec);
575
+ } else if (auto *csisec =
576
+ dyn_cast_or_null<CStringInputSection>(sym->isec ())) {
567
577
uint32_t totalOffset = sym->value + reloc->addend ;
568
578
StringPiece &piece = csisec->getStringPiece (totalOffset);
569
579
piece.live = false ;
@@ -1183,26 +1193,66 @@ void ObjcCategoryMerger::eraseMergedCategories() {
1183
1193
// the references to the ones we merged.
1184
1194
generateCatListForNonErasedCategories (catListToErasedOffsets);
1185
1195
1196
+ // We use erasedIsecs below to track erased sections so we can later remove
1197
+ // references to it.
1198
+ std::unordered_set<InputSection *> erasedIsecs;
1199
+ erasedIsecs.reserve (categoryMap.size ());
1200
+
1186
1201
// Erase the old method lists & names of the categories that were merged
1187
1202
for (auto &mapEntry : categoryMap) {
1188
1203
for (InfoInputCategory &catInfo : mapEntry.second ) {
1189
1204
if (!catInfo.wasMerged )
1190
1205
continue ;
1191
1206
1207
+ erasedIsecs.insert (catInfo.catBodyIsec );
1208
+ erasedIsecs.insert (catInfo.catListIsec );
1209
+
1192
1210
eraseISec (catInfo.catBodyIsec );
1193
- tryEraseDefinedAtIsecOffset (catInfo.catBodyIsec , catLayout.nameOffset );
1211
+ tryEraseDefinedAtIsecOffset (catInfo.catBodyIsec , catLayout.nameOffset ,
1212
+ erasedIsecs);
1194
1213
tryEraseDefinedAtIsecOffset (catInfo.catBodyIsec ,
1195
- catLayout.instanceMethodsOffset );
1214
+ catLayout.instanceMethodsOffset , erasedIsecs );
1196
1215
tryEraseDefinedAtIsecOffset (catInfo.catBodyIsec ,
1197
- catLayout.classMethodsOffset );
1216
+ catLayout.classMethodsOffset , erasedIsecs );
1198
1217
tryEraseDefinedAtIsecOffset (catInfo.catBodyIsec ,
1199
- catLayout.protocolsOffset );
1218
+ catLayout.protocolsOffset , erasedIsecs );
1200
1219
tryEraseDefinedAtIsecOffset (catInfo.catBodyIsec ,
1201
- catLayout.classPropsOffset );
1220
+ catLayout.classPropsOffset , erasedIsecs );
1202
1221
tryEraseDefinedAtIsecOffset (catInfo.catBodyIsec ,
1203
- catLayout.instancePropsOffset );
1222
+ catLayout.instancePropsOffset , erasedIsecs );
1204
1223
}
1205
1224
}
1225
+
1226
+ removeRefsToErasedIsecs (erasedIsecs);
1227
+ }
1228
+
1229
+ // The compiler may generate references to categories inside the addrsig
1230
+ // section. This function will erase these references.
1231
+ void ObjcCategoryMerger::removeRefsToErasedIsecs (
1232
+ std::unordered_set<InputSection *> erasedIsecs) {
1233
+ for (InputSection *isec : inputSections) {
1234
+ if (isec->getName () != section_names::addrSig)
1235
+ continue ;
1236
+
1237
+ auto removeRelocs = [&erasedIsecs](Reloc &r) {
1238
+ ConcatInputSection *isec = nullptr ;
1239
+ isec = dyn_cast_or_null<ConcatInputSection>(
1240
+ r.referent .dyn_cast <InputSection *>());
1241
+ if (!isec) {
1242
+ Defined *sym =
1243
+ dyn_cast_or_null<Defined>(r.referent .dyn_cast <Symbol *>());
1244
+ if (sym)
1245
+ isec = dyn_cast<ConcatInputSection>(sym->isec ());
1246
+ }
1247
+ if (!isec)
1248
+ return false ;
1249
+ return erasedIsecs.count (isec) > 0 ;
1250
+ };
1251
+
1252
+ isec->relocs .erase (
1253
+ std::remove_if (isec->relocs .begin (), isec->relocs .end (), removeRelocs),
1254
+ isec->relocs .end ());
1255
+ }
1206
1256
}
1207
1257
1208
1258
void ObjcCategoryMerger::doMerge () {
0 commit comments