[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:
alx32
2024-05-06 09:45:32 -07:00
committed by GitHub
parent 52187b9f2e
commit 5fa24ac277
2 changed files with 38 additions and 0 deletions

View File

@@ -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() {

View File

@@ -153,3 +153,6 @@ L_OBJC_IMAGE_INFO:
.long 0
.long 96
.subsections_via_symbols
.addrsig
.addrsig_sym __OBJC_$_CATEGORY_MyBaseClass_$_Category01