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 (
@@ -471,8 +474,11 @@ class ObjcCategoryMerger {
471
474
uint32_t offset);
472
475
Defined *tryGetDefinedAtIsecOffset (const ConcatInputSection *isec,
473
476
uint32_t offset);
477
+ Defined *tryFindDefinedOnIsec (const InputSection *isec, uint32_t offset);
474
478
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);
476
482
477
483
// Allocate a null-terminated StringRef backed by generatedSectionData
478
484
StringRef newStringData (const char *str);
@@ -533,12 +539,23 @@ void ObjcCategoryMerger::collectSectionWriteInfoFromIsec(
533
539
Symbol *
534
540
ObjcCategoryMerger::tryGetSymbolAtIsecOffset (const ConcatInputSection *isec,
535
541
uint32_t offset) {
542
+ if (!isec)
543
+ return nullptr ;
536
544
const Reloc *reloc = isec->getRelocAt (offset);
537
545
538
546
if (!reloc)
539
547
return nullptr ;
540
548
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;
542
559
}
543
560
544
561
Defined *
@@ -548,10 +565,20 @@ ObjcCategoryMerger::tryGetDefinedAtIsecOffset(const ConcatInputSection *isec,
548
565
return dyn_cast_or_null<Defined>(sym);
549
566
}
550
567
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
+
551
577
// Given an ConcatInputSection or CStringInputSection and an offset, if there is
552
578
// a symbol(Defined) at that offset, then erase the symbol (mark it not live)
553
579
void ObjcCategoryMerger::tryEraseDefinedAtIsecOffset (
554
- const ConcatInputSection *isec, uint32_t offset) {
580
+ const ConcatInputSection *isec, uint32_t offset,
581
+ std::unordered_set<InputSection *> &erased) {
555
582
const Reloc *reloc = isec->getRelocAt (offset);
556
583
557
584
if (!reloc)
@@ -561,9 +588,11 @@ void ObjcCategoryMerger::tryEraseDefinedAtIsecOffset(
561
588
if (!sym)
562
589
return ;
563
590
564
- if (auto *cisec = dyn_cast_or_null<ConcatInputSection>(sym->isec ()))
591
+ if (auto *cisec = dyn_cast_or_null<ConcatInputSection>(sym->isec ())) {
565
592
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 ())) {
567
596
uint32_t totalOffset = sym->value + reloc->addend ;
568
597
StringPiece &piece = csisec->getStringPiece (totalOffset);
569
598
piece.live = false ;
@@ -1183,26 +1212,66 @@ void ObjcCategoryMerger::eraseMergedCategories() {
1183
1212
// the references to the ones we merged.
1184
1213
generateCatListForNonErasedCategories (catListToErasedOffsets);
1185
1214
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
+
1186
1220
// Erase the old method lists & names of the categories that were merged
1187
1221
for (auto &mapEntry : categoryMap) {
1188
1222
for (InfoInputCategory &catInfo : mapEntry.second ) {
1189
1223
if (!catInfo.wasMerged )
1190
1224
continue ;
1191
1225
1226
+ erasedIsecs.insert (catInfo.catBodyIsec );
1227
+ erasedIsecs.insert (catInfo.catListIsec );
1228
+
1192
1229
eraseISec (catInfo.catBodyIsec );
1193
- tryEraseDefinedAtIsecOffset (catInfo.catBodyIsec , catLayout.nameOffset );
1230
+ tryEraseDefinedAtIsecOffset (catInfo.catBodyIsec , catLayout.nameOffset ,
1231
+ erasedIsecs);
1194
1232
tryEraseDefinedAtIsecOffset (catInfo.catBodyIsec ,
1195
- catLayout.instanceMethodsOffset );
1233
+ catLayout.instanceMethodsOffset , erasedIsecs );
1196
1234
tryEraseDefinedAtIsecOffset (catInfo.catBodyIsec ,
1197
- catLayout.classMethodsOffset );
1235
+ catLayout.classMethodsOffset , erasedIsecs );
1198
1236
tryEraseDefinedAtIsecOffset (catInfo.catBodyIsec ,
1199
- catLayout.protocolsOffset );
1237
+ catLayout.protocolsOffset , erasedIsecs );
1200
1238
tryEraseDefinedAtIsecOffset (catInfo.catBodyIsec ,
1201
- catLayout.classPropsOffset );
1239
+ catLayout.classPropsOffset , erasedIsecs );
1202
1240
tryEraseDefinedAtIsecOffset (catInfo.catBodyIsec ,
1203
- catLayout.instancePropsOffset );
1241
+ catLayout.instancePropsOffset , erasedIsecs );
1204
1242
}
1205
1243
}
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
+ }
1206
1275
}
1207
1276
1208
1277
void ObjcCategoryMerger::doMerge () {
0 commit comments