[lld] [lld-macho] Fix erasing category names for ObjC categories (PR #98417)
via llvm-commits
llvm-commits at lists.llvm.org
Wed Jul 10 18:18:00 PDT 2024
https://github.com/alx32 updated https://github.com/llvm/llvm-project/pull/98417
>From 7efaeb576752e8864cfd126d99cdf0d56ec51a66 Mon Sep 17 00:00:00 2001
From: Alex B <alexborcan at meta.com>
Date: Wed, 10 Jul 2024 16:42:39 -0700
Subject: [PATCH] [lld-macho] Fix erasing category names for ObjC categories
---
lld/MachO/ObjC.cpp | 16 +-
...jc-category-merging-erase-objc-name-test.s | 306 ++++++++++++++++++
2 files changed, 317 insertions(+), 5 deletions(-)
create mode 100644 lld/test/MachO/objc-category-merging-erase-objc-name-test.s
diff --git a/lld/MachO/ObjC.cpp b/lld/MachO/ObjC.cpp
index 740ebaf7e0403..c0216117efc7c 100644
--- a/lld/MachO/ObjC.cpp
+++ b/lld/MachO/ObjC.cpp
@@ -1308,12 +1308,18 @@ void ObjcCategoryMerger::eraseMergedCategories() {
continue;
eraseISec(catInfo.catBodyIsec);
- // We can't erase 'catLayout.nameOffset' for Swift categories because the
- // name will be referenced for generating relative offsets
- // See usages of 'l_.str.11.SimpleClass' in objc-category-merging-swift.s
+
+ // We can't erase 'catLayout.nameOffset' for either Swift or ObjC
+ // categories because the name will sometimes also be used for other
+ // purposes.
+ // For Swift, see usages of 'l_.str.11.SimpleClass' in
+ // objc-category-merging-swift.s
+ // For ObjC, see usages of 'l_OBJC_CLASS_NAME_.1' in
+ // objc-category-merging-erase-objc-name-test.s
// TODO: handle the above in a smarter way
- if (catInfo.sourceLanguage != SourceLanguage::Swift)
- tryEraseDefinedAtIsecOffset(catInfo.catBodyIsec, catLayout.nameOffset);
+
+ // tryEraseDefinedAtIsecOffset(catInfo.catBodyIsec, catLayout.nameOffset);
+
tryEraseDefinedAtIsecOffset(catInfo.catBodyIsec,
catLayout.instanceMethodsOffset);
tryEraseDefinedAtIsecOffset(catInfo.catBodyIsec,
diff --git a/lld/test/MachO/objc-category-merging-erase-objc-name-test.s b/lld/test/MachO/objc-category-merging-erase-objc-name-test.s
new file mode 100644
index 0000000000000..7f5753705c30d
--- /dev/null
+++ b/lld/test/MachO/objc-category-merging-erase-objc-name-test.s
@@ -0,0 +1,306 @@
+# REQUIRES: aarch64
+
+
+### Here we test that if we defined a protocl MyTestProtocol and also a category MyTestProtocol
+### then when merging the category into the base class (and deleting the category), we don't
+### delete the 'MyTestProtocol' name
+
+# RUN: llvm-mc -filetype=obj -triple=arm64-apple-macos -o erase-objc-name.o %s
+# RUN: %lld -arch arm64 -dylib -o erase-objc-name.dylib erase-objc-name.o -objc_category_merging
+# RUN: llvm-objdump --objc-meta-data --macho erase-objc-name.dylib | FileCheck %s --check-prefixes=MERGE_CATS
+
+#### Check merge categories enabled ###
+# Check that the original categories are not there
+# MERGE_CATS-NOT: __OBJC_$_CATEGORY_MyBaseClass_$_Category01
+# MERGE_CATS-NOT: __OBJC_$_CATEGORY_MyBaseClass_$_Category02
+
+# Check that we get the expected output - most importantly that the protocol is named `MyTestProtocol`
+; MERGE_CATS: Contents of (__DATA_CONST,__objc_classlist) section
+; MERGE_CATS-NEXT: _OBJC_CLASS_$_MyBaseClass
+; MERGE_CATS-NEXT: isa {{.*}} _OBJC_METACLASS_$_MyBaseClass
+; MERGE_CATS-NEXT: superclass {{.*}}
+; MERGE_CATS-NEXT: cache {{.*}}
+; MERGE_CATS-NEXT: vtable {{.*}}
+; MERGE_CATS-NEXT: data {{.*}} (struct class_ro_t *)
+; MERGE_CATS-NEXT: flags {{.*}} RO_ROOT
+; MERGE_CATS-NEXT: instanceStart 0
+; MERGE_CATS-NEXT: instanceSize 0
+; MERGE_CATS-NEXT: reserved {{.*}}
+; MERGE_CATS-NEXT: ivarLayout {{.*}}
+; MERGE_CATS-NEXT: name {{.*}} MyBaseClass
+; MERGE_CATS-NEXT: baseMethods {{.*}} (struct method_list_t *)
+; MERGE_CATS-NEXT: entsize 24
+; MERGE_CATS-NEXT: count 2
+; MERGE_CATS-NEXT: name {{.*}} getValue
+; MERGE_CATS-NEXT: types {{.*}} i16 at 0:8
+; MERGE_CATS-NEXT: imp -[MyBaseClass(MyTestProtocol) getValue]
+; MERGE_CATS-NEXT: name {{.*}} baseInstanceMethod
+; MERGE_CATS-NEXT: types {{.*}} v16 at 0:8
+; MERGE_CATS-NEXT: imp -[MyBaseClass baseInstanceMethod]
+; MERGE_CATS-NEXT: baseProtocols {{.*}}
+; MERGE_CATS-NEXT: count 1
+; MERGE_CATS-NEXT: list[0] {{.*}} (struct protocol_t *)
+; MERGE_CATS-NEXT: isa {{.*}}
+; MERGE_CATS-NEXT: name {{.*}} MyTestProtocol
+; MERGE_CATS-NEXT: protocols {{.*}}
+; MERGE_CATS-NEXT: instanceMethods {{.*}} (struct method_list_t *)
+; MERGE_CATS-NEXT: entsize 24
+; MERGE_CATS-NEXT: count 1
+; MERGE_CATS-NEXT: name {{.*}} getValue
+; MERGE_CATS-NEXT: types {{.*}} i16 at 0:8
+; MERGE_CATS-NEXT: imp {{.*}}
+; MERGE_CATS-NEXT: classMethods {{.*}} (struct method_list_t *)
+; MERGE_CATS-NEXT: optionalInstanceMethods {{.*}}
+; MERGE_CATS-NEXT: optionalClassMethods {{.*}}
+; MERGE_CATS-NEXT: instanceProperties {{.*}}
+; MERGE_CATS-NEXT: ivars {{.*}}
+; MERGE_CATS-NEXT: weakIvarLayout {{.*}}
+; MERGE_CATS-NEXT: baseProperties {{.*}}
+; MERGE_CATS-NEXT: Meta Class
+; MERGE_CATS-NEXT: isa {{.*}} _OBJC_METACLASS_$_MyBaseClass
+; MERGE_CATS-NEXT: superclass {{.*}} _OBJC_CLASS_$_MyBaseClass
+; MERGE_CATS-NEXT: cache {{.*}}
+; MERGE_CATS-NEXT: vtable {{.*}}
+; MERGE_CATS-NEXT: data {{.*}} (struct class_ro_t *)
+; MERGE_CATS-NEXT: flags {{.*}} RO_META RO_ROOT
+; MERGE_CATS-NEXT: instanceStart 40
+; MERGE_CATS-NEXT: instanceSize 40
+; MERGE_CATS-NEXT: reserved {{.*}}
+; MERGE_CATS-NEXT: ivarLayout {{.*}}
+; MERGE_CATS-NEXT: name {{.*}} MyBaseClass
+; MERGE_CATS-NEXT: baseMethods {{.*}} (struct method_list_t *)
+; MERGE_CATS-NEXT: baseProtocols {{.*}}
+; MERGE_CATS-NEXT: count 1
+; MERGE_CATS-NEXT: list[0] {{.*}} (struct protocol_t *)
+; MERGE_CATS-NEXT: isa {{.*}}
+; MERGE_CATS-NEXT: name {{.*}} MyTestProtocol
+; MERGE_CATS-NEXT: protocols {{.*}}
+; MERGE_CATS-NEXT: instanceMethods {{.*}} (struct method_list_t *)
+; MERGE_CATS-NEXT: entsize 24
+; MERGE_CATS-NEXT: count 1
+; MERGE_CATS-NEXT: name {{.*}} getValue
+; MERGE_CATS-NEXT: types {{.*}} i16 at 0:8
+; MERGE_CATS-NEXT: imp {{.*}}
+; MERGE_CATS-NEXT: classMethods {{.*}} (struct method_list_t *)
+; MERGE_CATS-NEXT: optionalInstanceMethods {{.*}}
+; MERGE_CATS-NEXT: optionalClassMethods {{.*}}
+; MERGE_CATS-NEXT: instanceProperties {{.*}}
+; MERGE_CATS-NEXT: ivars {{.*}}
+; MERGE_CATS-NEXT: weakIvarLayout {{.*}}
+; MERGE_CATS-NEXT: baseProperties {{.*}}
+; MERGE_CATS-NEXT: Contents of (__DATA_CONST,__objc_protolist) section
+; MERGE_CATS-NEXT: {{.*}} {{.*}} __OBJC_PROTOCOL_$_MyTestProtocol
+; MERGE_CATS-NEXT: Contents of (__DATA_CONST,__objc_imageinfo) section
+; MERGE_CATS-NEXT: version 0
+; MERGE_CATS-NEXT: flags {{.*}} OBJC_IMAGE_HAS_CATEGORY_CLASS_PROPERTIES
+
+
+; ================== repro.sh ====================
+; # Write the Objective-C code to a file
+; cat << EOF > MyClass.m
+; @protocol MyTestProtocol
+; - (int)getValue;
+; @end
+;
+; __attribute__((objc_root_class))
+; @interface MyBaseClass
+; - (void)baseInstanceMethod;
+; @end
+;
+; @implementation MyBaseClass
+; - (void)baseInstanceMethod {}
+; @end
+;
+; @interface MyBaseClass (MyTestProtocol) <MyTestProtocol>
+; @end
+;
+; @implementation MyBaseClass (MyTestProtocol)
+;
+; - (int)getValue {
+; return 0x30;
+; }
+;
+; @end
+; EOF
+;
+; # Compile the Objective-C file to assembly
+; xcrun clang -S -arch arm64 MyClass.m -o MyClass.s
+
+
+ .section __TEXT,__text,regular,pure_instructions
+ .p2align 2 ; -- Begin function -[MyBaseClass baseInstanceMethod]
+"-[MyBaseClass baseInstanceMethod]": ; @"\01-[MyBaseClass baseInstanceMethod]"
+ .cfi_startproc
+; %bb.0:
+ sub sp, sp, #16
+ .cfi_def_cfa_offset 16
+ str x0, [sp, #8]
+ str x1, [sp]
+ add sp, sp, #16
+ ret
+ .cfi_endproc
+ ; -- End function
+ .p2align 2 ; -- Begin function -[MyBaseClass(MyTestProtocol) getValue]
+"-[MyBaseClass(MyTestProtocol) getValue]": ; @"\01-[MyBaseClass(MyTestProtocol) getValue]"
+ .cfi_startproc
+; %bb.0:
+ sub sp, sp, #16
+ .cfi_def_cfa_offset 16
+ str x0, [sp, #8]
+ str x1, [sp]
+ mov w0, #48 ; =0x30
+ add sp, sp, #16
+ ret
+ .cfi_endproc
+ ; -- End function
+ .section __DATA,__objc_data
+ .globl _OBJC_CLASS_$_MyBaseClass ; @"OBJC_CLASS_$_MyBaseClass"
+ .p2align 3, 0x0
+_OBJC_CLASS_$_MyBaseClass:
+ .quad _OBJC_METACLASS_$_MyBaseClass
+ .quad 0
+ .quad __objc_empty_cache
+ .quad 0
+ .quad __OBJC_CLASS_RO_$_MyBaseClass
+ .globl _OBJC_METACLASS_$_MyBaseClass ; @"OBJC_METACLASS_$_MyBaseClass"
+ .p2align 3, 0x0
+_OBJC_METACLASS_$_MyBaseClass:
+ .quad _OBJC_METACLASS_$_MyBaseClass
+ .quad _OBJC_CLASS_$_MyBaseClass
+ .quad __objc_empty_cache
+ .quad 0
+ .quad __OBJC_METACLASS_RO_$_MyBaseClass
+ .section __TEXT,__objc_classname,cstring_literals
+l_OBJC_CLASS_NAME_: ; @OBJC_CLASS_NAME_
+ .asciz "MyBaseClass"
+ .section __DATA,__objc_const
+ .p2align 3, 0x0 ; @"_OBJC_METACLASS_RO_$_MyBaseClass"
+__OBJC_METACLASS_RO_$_MyBaseClass:
+ .long 131 ; 0x83
+ .long 40 ; 0x28
+ .long 40 ; 0x28
+ .space 4
+ .quad 0
+ .quad l_OBJC_CLASS_NAME_
+ .quad 0
+ .quad 0
+ .quad 0
+ .quad 0
+ .quad 0
+ .section __TEXT,__objc_methname,cstring_literals
+l_OBJC_METH_VAR_NAME_: ; @OBJC_METH_VAR_NAME_
+ .asciz "baseInstanceMethod"
+ .section __TEXT,__objc_methtype,cstring_literals
+l_OBJC_METH_VAR_TYPE_: ; @OBJC_METH_VAR_TYPE_
+ .asciz "v16 at 0:8"
+ .section __DATA,__objc_const
+ .p2align 3, 0x0 ; @"_OBJC_$_INSTANCE_METHODS_MyBaseClass"
+__OBJC_$_INSTANCE_METHODS_MyBaseClass:
+ .long 24 ; 0x18
+ .long 1 ; 0x1
+ .quad l_OBJC_METH_VAR_NAME_
+ .quad l_OBJC_METH_VAR_TYPE_
+ .quad "-[MyBaseClass baseInstanceMethod]"
+ .p2align 3, 0x0 ; @"_OBJC_CLASS_RO_$_MyBaseClass"
+__OBJC_CLASS_RO_$_MyBaseClass:
+ .long 130 ; 0x82
+ .long 0 ; 0x0
+ .long 0 ; 0x0
+ .space 4
+ .quad 0
+ .quad l_OBJC_CLASS_NAME_
+ .quad __OBJC_$_INSTANCE_METHODS_MyBaseClass
+ .quad 0
+ .quad 0
+ .quad 0
+ .quad 0
+ .section __TEXT,__objc_classname,cstring_literals
+l_OBJC_CLASS_NAME_.1: ; @OBJC_CLASS_NAME_.1
+ .asciz "MyTestProtocol"
+ .section __TEXT,__objc_methname,cstring_literals
+l_OBJC_METH_VAR_NAME_.2: ; @OBJC_METH_VAR_NAME_.2
+ .asciz "getValue"
+ .section __TEXT,__objc_methtype,cstring_literals
+l_OBJC_METH_VAR_TYPE_.3: ; @OBJC_METH_VAR_TYPE_.3
+ .asciz "i16 at 0:8"
+ .section __DATA,__objc_const
+ .p2align 3, 0x0 ; @"_OBJC_$_CATEGORY_INSTANCE_METHODS_MyBaseClass_$_MyTestProtocol"
+__OBJC_$_CATEGORY_INSTANCE_METHODS_MyBaseClass_$_MyTestProtocol:
+ .long 24 ; 0x18
+ .long 1 ; 0x1
+ .quad l_OBJC_METH_VAR_NAME_.2
+ .quad l_OBJC_METH_VAR_TYPE_.3
+ .quad "-[MyBaseClass(MyTestProtocol) getValue]"
+ .p2align 3, 0x0 ; @"_OBJC_$_PROTOCOL_INSTANCE_METHODS_MyTestProtocol"
+__OBJC_$_PROTOCOL_INSTANCE_METHODS_MyTestProtocol:
+ .long 24 ; 0x18
+ .long 1 ; 0x1
+ .quad l_OBJC_METH_VAR_NAME_.2
+ .quad l_OBJC_METH_VAR_TYPE_.3
+ .quad 0
+ .p2align 3, 0x0 ; @"_OBJC_$_PROTOCOL_METHOD_TYPES_MyTestProtocol"
+__OBJC_$_PROTOCOL_METHOD_TYPES_MyTestProtocol:
+ .quad l_OBJC_METH_VAR_TYPE_.3
+ .private_extern __OBJC_PROTOCOL_$_MyTestProtocol ; @"_OBJC_PROTOCOL_$_MyTestProtocol"
+ .section __DATA,__data
+ .globl __OBJC_PROTOCOL_$_MyTestProtocol
+ .weak_definition __OBJC_PROTOCOL_$_MyTestProtocol
+ .p2align 3, 0x0
+__OBJC_PROTOCOL_$_MyTestProtocol:
+ .quad 0
+ .quad l_OBJC_CLASS_NAME_.1
+ .quad 0
+ .quad __OBJC_$_PROTOCOL_INSTANCE_METHODS_MyTestProtocol
+ .quad 0
+ .quad 0
+ .quad 0
+ .quad 0
+ .long 96 ; 0x60
+ .long 0 ; 0x0
+ .quad __OBJC_$_PROTOCOL_METHOD_TYPES_MyTestProtocol
+ .quad 0
+ .quad 0
+ .private_extern __OBJC_LABEL_PROTOCOL_$_MyTestProtocol ; @"_OBJC_LABEL_PROTOCOL_$_MyTestProtocol"
+ .section __DATA,__objc_protolist,coalesced,no_dead_strip
+ .globl __OBJC_LABEL_PROTOCOL_$_MyTestProtocol
+ .weak_definition __OBJC_LABEL_PROTOCOL_$_MyTestProtocol
+ .p2align 3, 0x0
+__OBJC_LABEL_PROTOCOL_$_MyTestProtocol:
+ .quad __OBJC_PROTOCOL_$_MyTestProtocol
+ .section __DATA,__objc_const
+ .p2align 3, 0x0 ; @"_OBJC_CATEGORY_PROTOCOLS_$_MyBaseClass_$_MyTestProtocol"
+__OBJC_CATEGORY_PROTOCOLS_$_MyBaseClass_$_MyTestProtocol:
+ .quad 1 ; 0x1
+ .quad __OBJC_PROTOCOL_$_MyTestProtocol
+ .quad 0
+ .p2align 3, 0x0 ; @"_OBJC_$_CATEGORY_MyBaseClass_$_MyTestProtocol"
+__OBJC_$_CATEGORY_MyBaseClass_$_MyTestProtocol:
+ .quad l_OBJC_CLASS_NAME_.1
+ .quad _OBJC_CLASS_$_MyBaseClass
+ .quad __OBJC_$_CATEGORY_INSTANCE_METHODS_MyBaseClass_$_MyTestProtocol
+ .quad 0
+ .quad __OBJC_CATEGORY_PROTOCOLS_$_MyBaseClass_$_MyTestProtocol
+ .quad 0
+ .quad 0
+ .long 64 ; 0x40
+ .space 4
+ .section __DATA,__objc_classlist,regular,no_dead_strip
+ .p2align 3, 0x0 ; @"OBJC_LABEL_CLASS_$"
+l_OBJC_LABEL_CLASS_$:
+ .quad _OBJC_CLASS_$_MyBaseClass
+ .section __DATA,__objc_catlist,regular,no_dead_strip
+ .p2align 3, 0x0 ; @"OBJC_LABEL_CATEGORY_$"
+l_OBJC_LABEL_CATEGORY_$:
+ .quad __OBJC_$_CATEGORY_MyBaseClass_$_MyTestProtocol
+ .no_dead_strip __OBJC_PROTOCOL_$_MyTestProtocol
+ .no_dead_strip __OBJC_LABEL_PROTOCOL_$_MyTestProtocol
+ .section __DATA,__objc_imageinfo,regular,no_dead_strip
+L_OBJC_IMAGE_INFO:
+ .long 0
+ .long 64
+
+__objc_empty_cache:
+_$sBOWV:
+ .quad 0
+
+.subsections_via_symbols
More information about the llvm-commits
mailing list