# REQUIRES: aarch64 # UNSUPPORTED: system-windows # due to awk usage # RUN: rm -rf %t; split-file %s %t && cd %t ############ Test merging multiple categories into a single category ############ ## Create a dylib with a fake base class to link against in when merging between categories # RUN: llvm-mc -filetype=obj -triple=arm64-apple-macos -o a64_fakedylib.o a64_fakedylib.s # RUN: %lld -arch arm64 a64_fakedylib.o -o a64_fakedylib.dylib -dylib ## Create our main testing dylib - linking against the fake dylib above # RUN: llvm-mc -filetype=obj -triple=arm64-apple-macos -o merge_cat_minimal.o merge_cat_minimal.s # RUN: %lld -arch arm64 -dylib -o merge_cat_minimal_no_merge.dylib a64_fakedylib.dylib merge_cat_minimal.o # RUN: %lld -arch arm64 -dylib -o merge_cat_minimal_merge.dylib -objc_category_merging a64_fakedylib.dylib merge_cat_minimal.o ## Now verify that the flag caused category merging to happen appropriatelly # RUN: llvm-objdump --objc-meta-data --macho merge_cat_minimal_no_merge.dylib | FileCheck %s --check-prefixes=NO_MERGE_CATS # RUN: llvm-objdump --objc-meta-data --macho merge_cat_minimal_merge.dylib | FileCheck %s --check-prefixes=MERGE_CATS ############ Test merging multiple categories into the base class ############ # RUN: llvm-mc -filetype=obj -triple=arm64-apple-macos -o merge_base_class_minimal.o merge_base_class_minimal.s # RUN: %lld -arch arm64 -dylib -o merge_base_class_minimal_yes_merge.dylib -objc_category_merging merge_base_class_minimal.o merge_cat_minimal.o # RUN: %lld -arch arm64 -dylib -o merge_base_class_minimal_no_merge.dylib merge_base_class_minimal.o merge_cat_minimal.o # RUN: llvm-objdump --objc-meta-data --macho merge_base_class_minimal_no_merge.dylib | FileCheck %s --check-prefixes=NO_MERGE_INTO_BASE # RUN: llvm-objdump --objc-meta-data --macho merge_base_class_minimal_yes_merge.dylib | FileCheck %s --check-prefixes=YES_MERGE_INTO_BASE ############ Test merging swift category into the base class ############ # RUN: llvm-mc -filetype=obj -triple=arm64-apple-macos -o MyBaseClassSwiftExtension.o MyBaseClassSwiftExtension.s # RUN: %lld -no_objc_relative_method_lists -arch arm64 -dylib -o merge_base_class_swift_minimal_yes_merge.dylib -objc_category_merging MyBaseClassSwiftExtension.o merge_base_class_minimal.o # RUN: llvm-objdump --objc-meta-data --macho merge_base_class_swift_minimal_yes_merge.dylib | FileCheck %s --check-prefixes=YES_MERGE_INTO_BASE_SWIFT ############ Test merging skipped due to invalid category name ############ # Modify __OBJC_$_CATEGORY_MyBaseClass_$_Category01's name to point to L_OBJC_IMAGE_INFO+3 # RUN: awk '/^__OBJC_\$_CATEGORY_MyBaseClass_\$_Category01:/ { print; getline; sub(/^[ \t]*\.quad[ \t]+l_OBJC_CLASS_NAME_$/, "\t.quad\tL_OBJC_IMAGE_INFO+3"); print; next } { print }' merge_cat_minimal.s > merge_cat_minimal_bad_name.s # Assemble the modified source # RUN: llvm-mc -filetype=obj -triple=arm64-apple-macos -o merge_cat_minimal_bad_name.o merge_cat_minimal_bad_name.s # Run lld and check for the specific warning # RUN: %no-fatal-warnings-lld -arch arm64 -dylib -objc_category_merging -o merge_cat_minimal_merge.dylib a64_fakedylib.dylib merge_cat_minimal_bad_name.o 2>&1 | FileCheck %s --check-prefix=MERGE_WARNING # Check that lld emitted the warning about skipping category merging MERGE_WARNING: warning: ObjC category merging skipped for class symbol' _OBJC_CLASS_$_MyBaseClass' #### 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 the merged cateogry is there, in the correct format MERGE_CATS: __OBJC_$_CATEGORY_MyBaseClass(Category01|Category02) MERGE_CATS-NEXT: name {{.*}} Category01|Category02 MERGE_CATS: instanceMethods MERGE_CATS-NEXT: entsize 12 (relative) MERGE_CATS-NEXT: count 2 MERGE_CATS-NEXT: name {{.*}} cat01_InstanceMethod MERGE_CATS-NEXT: types {{.*}} v16@0:8 MERGE_CATS-NEXT: imp {{.*}} -[MyBaseClass(Category01) cat01_InstanceMethod] MERGE_CATS-NEXT: name {{.*}} cat02_InstanceMethod MERGE_CATS-NEXT: types {{.*}} v16@0:8 MERGE_CATS-NEXT: imp {{.*}} -[MyBaseClass(Category02) cat02_InstanceMethod] MERGE_CATS-NEXT: classMethods 0x0 MERGE_CATS-NEXT: protocols 0x0 MERGE_CATS-NEXT: instanceProperties 0x0 #### Check merge categories disabled ### # Check that the merged category is not there NO_MERGE_CATS-NOT: __OBJC_$_CATEGORY_MyBaseClass(Category01|Category02) # Check that the original categories are there NO_MERGE_CATS: __OBJC_$_CATEGORY_MyBaseClass_$_Category01 NO_MERGE_CATS: __OBJC_$_CATEGORY_MyBaseClass_$_Category02 #### Check merge cateogires into base class is disabled #### NO_MERGE_INTO_BASE: __OBJC_$_CATEGORY_MyBaseClass_$_Category01 NO_MERGE_INTO_BASE: __OBJC_$_CATEGORY_MyBaseClass_$_Category02 #### Check merge cateogires into base class is enabled and categories are merged into base class #### YES_MERGE_INTO_BASE-NOT: __OBJC_$_CATEGORY_MyBaseClass_$_Category01 YES_MERGE_INTO_BASE-NOT: __OBJC_$_CATEGORY_MyBaseClass_$_Category02 YES_MERGE_INTO_BASE: _OBJC_CLASS_$_MyBaseClass YES_MERGE_INTO_BASE-NEXT: _OBJC_METACLASS_$_MyBaseClass YES_MERGE_INTO_BASE: baseMethods YES_MERGE_INTO_BASE-NEXT: entsize 12 (relative) YES_MERGE_INTO_BASE-NEXT: count 3 YES_MERGE_INTO_BASE-NEXT: name {{.*}} cat01_InstanceMethod YES_MERGE_INTO_BASE-NEXT: types {{.*}} v16@0:8 YES_MERGE_INTO_BASE-NEXT: imp {{.*}} -[MyBaseClass(Category01) cat01_InstanceMethod] YES_MERGE_INTO_BASE-NEXT: name {{.*}} cat02_InstanceMethod YES_MERGE_INTO_BASE-NEXT: types {{.*}} v16@0:8 YES_MERGE_INTO_BASE-NEXT: imp {{.*}} -[MyBaseClass(Category02) cat02_InstanceMethod] YES_MERGE_INTO_BASE-NEXT: name {{.*}} baseInstanceMethod YES_MERGE_INTO_BASE-NEXT: types {{.*}} v16@0:8 YES_MERGE_INTO_BASE-NEXT: imp {{.*}} -[MyBaseClass baseInstanceMethod] #### Check merge swift category into base class ### YES_MERGE_INTO_BASE_SWIFT: _OBJC_CLASS_$_MyBaseClass YES_MERGE_INTO_BASE_SWIFT-NEXT: _OBJC_METACLASS_$_MyBaseClass YES_MERGE_INTO_BASE_SWIFT: baseMethods YES_MERGE_INTO_BASE_SWIFT-NEXT: entsize 24 YES_MERGE_INTO_BASE_SWIFT-NEXT: count 2 YES_MERGE_INTO_BASE_SWIFT-NEXT: name {{.*}} swiftMethod YES_MERGE_INTO_BASE_SWIFT-NEXT: types {{.*}} v16@0:8 YES_MERGE_INTO_BASE_SWIFT-NEXT: imp _$sSo11MyBaseClassC0abC14SwiftExtensionE11swiftMethodyyFTo YES_MERGE_INTO_BASE_SWIFT-NEXT: name {{.*}} baseInstanceMethod YES_MERGE_INTO_BASE_SWIFT-NEXT: types {{.*}} v16@0:8 YES_MERGE_INTO_BASE_SWIFT-NEXT: imp -[MyBaseClass baseInstanceMethod] #--- a64_fakedylib.s .section __DATA,__objc_data .globl _OBJC_CLASS_$_MyBaseClass _OBJC_CLASS_$_MyBaseClass: .quad 0 #--- merge_cat_minimal.s ; ================== Generated from ObjC: ================== ; __attribute__((objc_root_class)) ; @interface MyBaseClass ; - (void)baseInstanceMethod; ; @end ; ; @interface MyBaseClass(Category01) ; - (void)cat01_InstanceMethod; ; @end ; ; @implementation MyBaseClass(Category01) ; - (void)cat01_InstanceMethod {} ; @end ; ; @interface MyBaseClass(Category02) ; - (void)cat02_InstanceMethod; ; @end ; ; @implementation MyBaseClass(Category02) ; - (void)cat02_InstanceMethod {} ; @end ; ================== Generated from ObjC: ================== .section __TEXT,__text,regular,pure_instructions .p2align 2 ; -- Begin function -[MyBaseClass(Category01) cat01_InstanceMethod] "-[MyBaseClass(Category01) cat01_InstanceMethod]": ; @"\01-[MyBaseClass(Category01) cat01_InstanceMethod]" .cfi_startproc ret .cfi_endproc ; -- End function .p2align 2 ; -- Begin function -[MyBaseClass(Category02) cat02_InstanceMethod] "-[MyBaseClass(Category02) cat02_InstanceMethod]": ; @"\01-[MyBaseClass(Category02) cat02_InstanceMethod]" .cfi_startproc ret .cfi_endproc ; -- End function .section __TEXT,__objc_classname,cstring_literals l_OBJC_CLASS_NAME_: ; @OBJC_CLASS_NAME_ .asciz "Category01" .section __TEXT,__objc_methname,cstring_literals l_OBJC_METH_VAR_NAME_: ; @OBJC_METH_VAR_NAME_ .asciz "cat01_InstanceMethod" .section __TEXT,__objc_methtype,cstring_literals l_OBJC_METH_VAR_TYPE_: ; @OBJC_METH_VAR_TYPE_ .asciz "v16@0:8" .section __DATA,__objc_const .p2align 3, 0x0 ; @"_OBJC_$_CATEGORY_INSTANCE_METHODS_MyBaseClass_$_Category01" __OBJC_$_CATEGORY_INSTANCE_METHODS_MyBaseClass_$_Category01: .long 24 ; 0x18 .long 1 ; 0x1 .quad l_OBJC_METH_VAR_NAME_ .quad l_OBJC_METH_VAR_TYPE_ .quad "-[MyBaseClass(Category01) cat01_InstanceMethod]" .p2align 3, 0x0 ; @"_OBJC_$_CATEGORY_MyBaseClass_$_Category01" __OBJC_$_CATEGORY_MyBaseClass_$_Category01: .quad l_OBJC_CLASS_NAME_ .quad _OBJC_CLASS_$_MyBaseClass .quad __OBJC_$_CATEGORY_INSTANCE_METHODS_MyBaseClass_$_Category01 .quad 0 .quad 0 .quad 0 .quad 0 .long 64 ; 0x40 .space 4 .section __DATA,__objc_const l_OBJC_CLASS_NAME_.1: ; @OBJC_CLASS_NAME_.1 .asciz "Category02" .section __TEXT,__objc_methname,cstring_literals l_OBJC_METH_VAR_NAME_.2: ; @OBJC_METH_VAR_NAME_.2 .asciz "cat02_InstanceMethod" .section __DATA,__objc_const .p2align 3, 0x0 ; @"_OBJC_$_CATEGORY_INSTANCE_METHODS_MyBaseClass_$_Category02" __OBJC_$_CATEGORY_INSTANCE_METHODS_MyBaseClass_$_Category02: .long 24 ; 0x18 .long 1 ; 0x1 .quad l_OBJC_METH_VAR_NAME_.2 .quad l_OBJC_METH_VAR_TYPE_ .quad "-[MyBaseClass(Category02) cat02_InstanceMethod]" .p2align 3, 0x0 ; @"_OBJC_$_CATEGORY_MyBaseClass_$_Category02" __OBJC_$_CATEGORY_MyBaseClass_$_Category02: .quad l_OBJC_CLASS_NAME_.1 .quad _OBJC_CLASS_$_MyBaseClass .quad __OBJC_$_CATEGORY_INSTANCE_METHODS_MyBaseClass_$_Category02 .quad 0 .quad 0 .quad 0 .quad 0 .long 64 ; 0x40 .space 4 .section __DATA,__objc_catlist,regular,no_dead_strip .p2align 3, 0x0 ; @"OBJC_LABEL_CATEGORY_$" l_OBJC_LABEL_CATEGORY_$: .quad __OBJC_$_CATEGORY_MyBaseClass_$_Category01 .quad __OBJC_$_CATEGORY_MyBaseClass_$_Category02 .section __DATA,__objc_imageinfo,regular,no_dead_strip L_OBJC_IMAGE_INFO: .long 0 .long 96 .subsections_via_symbols .addrsig .addrsig_sym __OBJC_$_CATEGORY_MyBaseClass_$_Category01 #--- merge_base_class_minimal.s ; clang -c merge_base_class_minimal.mm -O3 -target arm64-apple-macos -arch arm64 -S -o merge_base_class_minimal.s ; ================== Generated from ObjC: ================== ; __attribute__((objc_root_class)) ; @interface MyBaseClass ; - (void)baseInstanceMethod; ; @end ; ; @implementation MyBaseClass ; - (void)baseInstanceMethod {} ; @end ; ================== Generated from ObjC ================== .section __TEXT,__text,regular,pure_instructions .build_version macos, 11, 0 .p2align 2 "-[MyBaseClass baseInstanceMethod]": .cfi_startproc ; %bb.0: ret .cfi_endproc .section __DATA,__objc_data .globl _OBJC_CLASS_$_MyBaseClass .p2align 3, 0x0 _OBJC_CLASS_$_MyBaseClass: .quad _OBJC_METACLASS_$_MyBaseClass .quad 0 .quad 0 .quad 0 .quad __OBJC_CLASS_RO_$_MyBaseClass .globl _OBJC_METACLASS_$_MyBaseClass .p2align 3, 0x0 _OBJC_METACLASS_$_MyBaseClass: .quad _OBJC_METACLASS_$_MyBaseClass .quad _OBJC_CLASS_$_MyBaseClass .quad 0 .quad 0 .quad __OBJC_METACLASS_RO_$_MyBaseClass .section __TEXT,__objc_classname,cstring_literals l_OBJC_CLASS_NAME_: .asciz "MyBaseClass" .section __DATA,__objc_const .p2align 3, 0x0 __OBJC_METACLASS_RO_$_MyBaseClass: .long 3 .long 40 .long 40 .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_: .asciz "baseInstanceMethod" .section __TEXT,__objc_methtype,cstring_literals l_OBJC_METH_VAR_TYPE_: .asciz "v16@0:8" .section __DATA,__objc_const .p2align 3, 0x0 __OBJC_$_INSTANCE_METHODS_MyBaseClass: .long 24 .long 1 .quad l_OBJC_METH_VAR_NAME_ .quad l_OBJC_METH_VAR_TYPE_ .quad "-[MyBaseClass baseInstanceMethod]" .p2align 3, 0x0 __OBJC_CLASS_RO_$_MyBaseClass: .long 2 .long 0 .long 0 .space 4 .quad 0 .quad l_OBJC_CLASS_NAME_ .quad __OBJC_$_INSTANCE_METHODS_MyBaseClass .quad 0 .quad 0 .quad 0 .quad 0 .section __DATA,__objc_classlist,regular,no_dead_strip .p2align 3, 0x0 l_OBJC_LABEL_CLASS_$: .quad _OBJC_CLASS_$_MyBaseClass .section __DATA,__objc_imageinfo,regular,no_dead_strip L_OBJC_IMAGE_INFO: .long 0 .long 64 .subsections_via_symbols #--- MyBaseClassSwiftExtension.s ; xcrun -sdk macosx swiftc -emit-assembly MyBaseClassSwiftExtension.swift -import-objc-header YourProject-Bridging-Header.h -o MyBaseClassSwiftExtension.s ; ================== Generated from Swift: ================== ; import Foundation ; extension MyBaseClass { ; @objc func swiftMethod() { ; } ; } ; ================== Generated from Swift =================== .private_extern _$sSo11MyBaseClassC0abC14SwiftExtensionE11swiftMethodyyF .globl _$sSo11MyBaseClassC0abC14SwiftExtensionE11swiftMethodyyF .p2align 2 _$sSo11MyBaseClassC0abC14SwiftExtensionE11swiftMethodyyF: .cfi_startproc mov w0, #0 ret .cfi_endproc .p2align 2 _$sSo11MyBaseClassC0abC14SwiftExtensionE11swiftMethodyyFTo: .cfi_startproc mov w0, #0 ret .cfi_endproc .section __TEXT,__cstring,cstring_literals .p2align 4, 0x0 l_.str.25.MyBaseClassSwiftExtension: .asciz "MyBaseClassSwiftExtension" .section __TEXT,__objc_methname,cstring_literals "L_selector_data(swiftMethod)": .asciz "swiftMethod" .section __TEXT,__cstring,cstring_literals "l_.str.7.v16@0:8": .asciz "v16@0:8" .section __DATA,__objc_data .p2align 3, 0x0 __CATEGORY_INSTANCE_METHODS_MyBaseClass_$_MyBaseClassSwiftExtension: .long 24 .long 1 .quad "L_selector_data(swiftMethod)" .quad "l_.str.7.v16@0:8" .quad _$sSo11MyBaseClassC0abC14SwiftExtensionE11swiftMethodyyFTo .section __DATA,__objc_const .p2align 3, 0x0 __CATEGORY_MyBaseClass_$_MyBaseClassSwiftExtension: .quad l_.str.25.MyBaseClassSwiftExtension .quad _OBJC_CLASS_$_MyBaseClass .quad __CATEGORY_INSTANCE_METHODS_MyBaseClass_$_MyBaseClassSwiftExtension .quad 0 .quad 0 .quad 0 .quad 0 .long 60 .space 4 .section __DATA,__objc_catlist,regular,no_dead_strip .p2align 3, 0x0 _objc_categories: .quad __CATEGORY_MyBaseClass_$_MyBaseClassSwiftExtension .no_dead_strip _main .no_dead_strip l_entry_point .subsections_via_symbols