Skip to content

Commit c416e43

Browse files
authored
[lld-macho] Add support for non-lazy categories to ObjC category merger (#91548)
In ObjC we can have categories that define a `+load` method that is called when the category is loaded. In such cases, we shouldn't optimize the category. These categories are present in the `__objc_nlcatlist` section. So we scan these section for such categories and ignore them from optimization.
1 parent b1b4652 commit c416e43

File tree

2 files changed

+71
-0
lines changed

2 files changed

+71
-0
lines changed

lld/MachO/ObjC.cpp

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -428,6 +428,7 @@ class ObjcCategoryMerger {
428428
static void doCleanup();
429429

430430
private:
431+
DenseSet<const Symbol *> collectNlCategories();
431432
void collectAndValidateCategoriesData();
432433
void
433434
mergeCategoriesIntoSingleCategory(std::vector<InfoInputCategory> &categories);
@@ -1060,7 +1061,27 @@ void ObjcCategoryMerger::createSymbolReference(Defined *refFrom,
10601061
refFrom->isec()->relocs.push_back(r);
10611062
}
10621063

1064+
// Get the list of categories in the '__objc_nlcatlist' section. We can't
1065+
// optimize these as they have a '+load' method that has to be called at
1066+
// runtime.
1067+
DenseSet<const Symbol *> ObjcCategoryMerger::collectNlCategories() {
1068+
DenseSet<const Symbol *> nlCategories;
1069+
1070+
for (InputSection *sec : allInputSections) {
1071+
if (sec->getName() != section_names::objcNonLazyCatList)
1072+
continue;
1073+
1074+
for (auto &r : sec->relocs) {
1075+
const Symbol *sym = r.referent.dyn_cast<Symbol *>();
1076+
nlCategories.insert(sym);
1077+
}
1078+
}
1079+
return nlCategories;
1080+
}
1081+
10631082
void ObjcCategoryMerger::collectAndValidateCategoriesData() {
1083+
auto nlCategories = collectNlCategories();
1084+
10641085
for (InputSection *sec : allInputSections) {
10651086
if (sec->getName() != section_names::objcCatList)
10661087
continue;
@@ -1074,6 +1095,9 @@ void ObjcCategoryMerger::collectAndValidateCategoriesData() {
10741095
assert(categorySym &&
10751096
"Failed to get a valid category at __objc_catlit offset");
10761097

1098+
if (nlCategories.count(categorySym))
1099+
continue;
1100+
10771101
// We only support ObjC categories (no swift + @objc)
10781102
// TODO: Support swift + @objc categories also
10791103
if (!categorySym->getName().starts_with(objc::symbol_names::category))

lld/test/MachO/objc-category-merging-complete-test.s

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ MERGE_CATS-NEXT: name {{.*}} MyProtocol02Prop
8888
MERGE_CATS-NEXT: attributes {{.*}} Ti,R,D
8989
MERGE_CATS-NEXT: name {{.*}} MyProtocol03Prop
9090
MERGE_CATS-NEXT: attributes {{.*}} Ti,R,D
91+
MERGE_CATS: __OBJC_$_CATEGORY_MyBaseClass_$_Category04
9192

9293

9394
NO_MERGE_CATS-NOT: __OBJC_$_CATEGORY_MyBaseClass(Category02|Category03)
@@ -431,6 +432,15 @@ L_OBJC_IMAGE_INFO:
431432
## @dynamic MyProtocol03Prop;
432433
## @end
433434
##
435+
## // This category shouldn't be merged
436+
## @interface MyBaseClass(Category04)
437+
## + (void)load;
438+
## @end
439+
##
440+
## @implementation MyBaseClass(Category04)
441+
## + (void)load {}
442+
## @end
443+
##
434444
## int main() {
435445
## return 0;
436446
## }
@@ -493,6 +503,12 @@ L_OBJC_IMAGE_INFO:
493503
b _OUTLINED_FUNCTION_0
494504
.cfi_endproc
495505
; -- End function
506+
.p2align 2
507+
"+[MyBaseClass(Category04) load]":
508+
.cfi_startproc
509+
; %bb.0:
510+
ret
511+
.cfi_endproc
496512
.globl _main ; -- Begin function main
497513
.p2align 2
498514
_main: ; @main
@@ -746,11 +762,42 @@ __OBJC_$_CATEGORY_MyBaseClass_$_Category03:
746762
.quad 0
747763
.long 64 ; 0x40
748764
.space 4
765+
.section __TEXT,__objc_classname,cstring_literals
766+
l_OBJC_CLASS_NAME_.15:
767+
.asciz "Category04"
768+
.section __TEXT,__objc_methname,cstring_literals
769+
l_OBJC_METH_VAR_NAME_.16:
770+
.asciz "load"
771+
.section __DATA,__objc_const
772+
.p2align 3, 0x0
773+
__OBJC_$_CATEGORY_CLASS_METHODS_MyBaseClass_$_Category04:
774+
.long 24
775+
.long 1
776+
.quad l_OBJC_METH_VAR_NAME_.16
777+
.quad l_OBJC_METH_VAR_TYPE_
778+
.quad "+[MyBaseClass(Category04) load]"
779+
.p2align 3, 0x0
780+
__OBJC_$_CATEGORY_MyBaseClass_$_Category04:
781+
.quad l_OBJC_CLASS_NAME_.15
782+
.quad _OBJC_CLASS_$_MyBaseClass
783+
.quad 0
784+
.quad __OBJC_$_CATEGORY_CLASS_METHODS_MyBaseClass_$_Category04
785+
.quad 0
786+
.quad 0
787+
.quad 0
788+
.long 64
789+
.space 4
749790
.section __DATA,__objc_catlist,regular,no_dead_strip
750791
.p2align 3, 0x0 ; @"OBJC_LABEL_CATEGORY_$"
751792
l_OBJC_LABEL_CATEGORY_$:
752793
.quad __OBJC_$_CATEGORY_MyBaseClass_$_Category02
753794
.quad __OBJC_$_CATEGORY_MyBaseClass_$_Category03
795+
.quad __OBJC_$_CATEGORY_MyBaseClass_$_Category04
796+
.section __DATA,__objc_nlcatlist,regular,no_dead_strip
797+
.p2align 3, 0x0
798+
l_OBJC_LABEL_NONLAZY_CATEGORY_$:
799+
.quad __OBJC_$_CATEGORY_MyBaseClass_$_Category04
800+
754801
.no_dead_strip __OBJC_LABEL_PROTOCOL_$_MyProtocol02
755802
.no_dead_strip __OBJC_LABEL_PROTOCOL_$_MyProtocol03
756803
.no_dead_strip __OBJC_PROTOCOL_$_MyProtocol02

0 commit comments

Comments
 (0)