[lld-macho] Category Merger: add support for addrsig references (#90903)
When generating categories, clang sometimes will generate references in the `.addrsig` section to the various category data items. Since we may erase such items after merging them, we also need to remove them from the `.addrsig` section - otherwise this will cause runtime asserts with the `.addrsig` section trying to access invalid data. Implementation wise, we use a hashset to keep track of all erased `InputSection`'s and then go through all `.addrsig` sections and remove references to any erased `InputSection`.
This commit is contained in:
@@ -420,6 +420,7 @@ private:
|
||||
mergeCategoriesIntoSingleCategory(std::vector<InfoInputCategory> &categories);
|
||||
|
||||
void eraseISec(ConcatInputSection *isec);
|
||||
void removeRefsToErasedIsecs();
|
||||
void eraseMergedCategories();
|
||||
|
||||
void generateCatListForNonErasedCategories(
|
||||
@@ -478,6 +479,8 @@ private:
|
||||
std::vector<ConcatInputSection *> &allInputSections;
|
||||
// Map of base class Symbol to list of InfoInputCategory's for it
|
||||
DenseMap<const Symbol *, std::vector<InfoInputCategory>> categoryMap;
|
||||
// Set for tracking InputSection erased via eraseISec
|
||||
DenseSet<InputSection *> erasedIsecs;
|
||||
|
||||
// Normally, the binary data comes from the input files, but since we're
|
||||
// generating binary data ourselves, we use the below array to store it in.
|
||||
@@ -518,6 +521,8 @@ void ObjcCategoryMerger::collectSectionWriteInfoFromIsec(
|
||||
Symbol *
|
||||
ObjcCategoryMerger::tryGetSymbolAtIsecOffset(const ConcatInputSection *isec,
|
||||
uint32_t offset) {
|
||||
if (!isec)
|
||||
return nullptr;
|
||||
const Reloc *reloc = isec->getRelocAt(offset);
|
||||
|
||||
if (!reloc)
|
||||
@@ -1141,6 +1146,8 @@ void ObjcCategoryMerger::generateCatListForNonErasedCategories(
|
||||
}
|
||||
|
||||
void ObjcCategoryMerger::eraseISec(ConcatInputSection *isec) {
|
||||
erasedIsecs.insert(isec);
|
||||
|
||||
isec->live = false;
|
||||
for (auto &sym : isec->symbols)
|
||||
sym->used = false;
|
||||
@@ -1175,6 +1182,7 @@ void ObjcCategoryMerger::eraseMergedCategories() {
|
||||
continue;
|
||||
|
||||
eraseISec(catInfo.catBodyIsec);
|
||||
|
||||
tryEraseDefinedAtIsecOffset(catInfo.catBodyIsec, catLayout.nameOffset);
|
||||
tryEraseDefinedAtIsecOffset(catInfo.catBodyIsec,
|
||||
catLayout.instanceMethodsOffset);
|
||||
@@ -1188,6 +1196,33 @@ void ObjcCategoryMerger::eraseMergedCategories() {
|
||||
catLayout.instancePropsOffset);
|
||||
}
|
||||
}
|
||||
|
||||
removeRefsToErasedIsecs();
|
||||
}
|
||||
|
||||
// The compiler may generate references to categories inside the addrsig
|
||||
// section. This function will erase these references.
|
||||
void ObjcCategoryMerger::removeRefsToErasedIsecs() {
|
||||
for (InputSection *isec : inputSections) {
|
||||
if (isec->getName() != section_names::addrSig)
|
||||
continue;
|
||||
|
||||
auto removeRelocs = [this](Reloc &r) {
|
||||
auto *isec = dyn_cast_or_null<ConcatInputSection>(
|
||||
r.referent.dyn_cast<InputSection *>());
|
||||
if (!isec) {
|
||||
Defined *sym =
|
||||
dyn_cast_or_null<Defined>(r.referent.dyn_cast<Symbol *>());
|
||||
if (sym)
|
||||
isec = dyn_cast<ConcatInputSection>(sym->isec());
|
||||
}
|
||||
if (!isec)
|
||||
return false;
|
||||
return erasedIsecs.count(isec) > 0;
|
||||
};
|
||||
|
||||
llvm::erase_if(isec->relocs, removeRelocs);
|
||||
}
|
||||
}
|
||||
|
||||
void ObjcCategoryMerger::doMerge() {
|
||||
|
||||
@@ -153,3 +153,6 @@ L_OBJC_IMAGE_INFO:
|
||||
.long 0
|
||||
.long 96
|
||||
.subsections_via_symbols
|
||||
|
||||
.addrsig
|
||||
.addrsig_sym __OBJC_$_CATEGORY_MyBaseClass_$_Category01
|
||||
|
||||
Reference in New Issue
Block a user