Skip to content

Commit e97bd03

Browse files
authored
[lld-macho] Category Merging: Detect correct class language for classes with aliased symbols (#97454)
Currently we rely on detecting the source language of a class by the name of the symbol pointing to it. This generally works, but there are scenarios where Swift generates both an ObjC name and a Swift name for the symbol - by aliasing the ObjC name to the Swift name, as follows: ``` .globl _OBJC_CLASS_$__TtC11MyTestClass11MyTestClass .private_extern _OBJC_CLASS_$__TtC11MyTestClass11MyTestClass .set _OBJC_CLASS_$__TtC11MyTestClass11MyTestClass, _$s11MyTestClassAACN ``` So to correctly detect the source language in all cases, we need to handle scenarios where both an ObjC symbol and a Swift symbol is defined for a class - in this case the symbol is always a Swift class.
1 parent 7f0d9ba commit e97bd03

File tree

2 files changed

+467
-8
lines changed

2 files changed

+467
-8
lines changed

lld/MachO/ObjC.cpp

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -496,6 +496,7 @@ class ObjcCategoryMerger {
496496
Defined *tryGetDefinedAtIsecOffset(const ConcatInputSection *isec,
497497
uint32_t offset);
498498
Defined *getClassRo(const Defined *classSym, bool getMetaRo);
499+
SourceLanguage getClassSymSourceLang(const Defined *classSym);
499500
void mergeCategoriesIntoBaseClass(const Defined *baseClass,
500501
std::vector<InfoInputCategory> &categories);
501502
void eraseSymbolAtIsecOffset(ConcatInputSection *isec, uint32_t offset);
@@ -1400,21 +1401,37 @@ void objc::mergeCategories() {
14001401

14011402
void objc::doCleanup() { ObjcCategoryMerger::doCleanup(); }
14021403

1404+
ObjcCategoryMerger::SourceLanguage
1405+
ObjcCategoryMerger::getClassSymSourceLang(const Defined *classSym) {
1406+
if (classSym->getName().starts_with(objc::symbol_names::swift_objc_klass))
1407+
return SourceLanguage::Swift;
1408+
1409+
// If the symbol name matches the ObjC prefix, we don't necessarely know this
1410+
// comes from ObjC, since Swift creates ObjC-like alias symbols for some Swift
1411+
// classes. Ex:
1412+
// .globl _OBJC_CLASS_$__TtC11MyTestClass11MyTestClass
1413+
// .private_extern _OBJC_CLASS_$__TtC11MyTestClass11MyTestClass
1414+
// .set _OBJC_CLASS_$__TtC11MyTestClass11MyTestClass, _$s11MyTestClassAACN
1415+
//
1416+
// So we scan for symbols with the same address and check for the Swift class
1417+
if (classSym->getName().starts_with(objc::symbol_names::klass)) {
1418+
for (auto &sym : classSym->originalIsec->symbols)
1419+
if (sym->value == classSym->value)
1420+
if (sym->getName().starts_with(objc::symbol_names::swift_objc_klass))
1421+
return SourceLanguage::Swift;
1422+
return SourceLanguage::ObjC;
1423+
}
1424+
1425+
llvm_unreachable("Unexpected class symbol name during category merging");
1426+
}
14031427
void ObjcCategoryMerger::mergeCategoriesIntoBaseClass(
14041428
const Defined *baseClass, std::vector<InfoInputCategory> &categories) {
14051429
assert(categories.size() >= 1 && "Expected at least one category to merge");
14061430

14071431
// Collect all the info from the categories
14081432
ClassExtensionInfo extInfo(catLayout);
14091433
extInfo.baseClass = baseClass;
1410-
1411-
if (baseClass->getName().starts_with(objc::symbol_names::klass))
1412-
extInfo.baseClassSourceLanguage = SourceLanguage::ObjC;
1413-
else if (baseClass->getName().starts_with(
1414-
objc::symbol_names::swift_objc_klass))
1415-
extInfo.baseClassSourceLanguage = SourceLanguage::Swift;
1416-
else
1417-
llvm_unreachable("Unexpected base class symbol name");
1434+
extInfo.baseClassSourceLanguage = getClassSymSourceLang(baseClass);
14181435

14191436
for (auto &catInfo : categories) {
14201437
parseCatInfoToExtInfo(catInfo, extInfo);

0 commit comments

Comments
 (0)