<table border="1" cellspacing="0" cellpadding="8">
    <tr>
        <th>Issue</th>
        <td>
            <a href=https://github.com/llvm/llvm-project/issues/56034>56034</a>
        </td>
    </tr>

    <tr>
        <th>Summary</th>
        <td>
            Add support for _objc_msgSend stubs from Xcode 14
        </td>
    </tr>

    <tr>
      <th>Labels</th>
      <td>
            lld:MachO
      </td>
    </tr>

    <tr>
      <th>Assignees</th>
      <td>
            keith
      </td>
    </tr>

    <tr>
      <th>Reporter</th>
      <td>
          keith
      </td>
    </tr>
</table>

<pre>
    In Xcode 14 / ld 816 Apple implemented a size / performance optimization where they deduplicate _objc_msgSend setup infrastructure by Objective-C selectors. This comes in the form of undefined symbols in each object file:

```objc
@import Foundation;

@interface Foo : NSObject
@end

@implementation Foo
- (void)bar {
    NSLog(@"%@", self);
}

@end

int main() {
    Foo *foo = [[Foo alloc] init];
    [foo bar];
    return 0;
}
```

```
% DEVELOPER_DIR=/Applications/Xcode-14.0.0-beta1.app clang foo.m -o foo.o -fmodules -c
% nm easy.o | grep objc_msg
                 U _objc_msgSend$bar
```

Then the linker inserts these stubs during link, one for each selector string after the `$` (see the final symbol):

```
% nm -format=darwin foo
0000000100003ecc (__TEXT,__text) non-external -[Foo bar]
                 (undefined) external _NSLog (from Foundation)
00000001000080c8 (__DATA,__objc_data) external _OBJC_CLASS_$_Foo
                 (undefined) external _OBJC_CLASS_$_NSObject (from libobjc)
00000001000080a0 (__DATA,__objc_data) external _OBJC_METACLASS_$_Foo
                 (undefined) external _OBJC_METACLASS_$_NSObject (from libobjc)
0000000100003f80 (__TEXT,__objc_methlist) non-external __OBJC_$_INSTANCE_METHODS_Foo
0000000100008048 (__DATA,__objc_const) non-external __OBJC_CLASS_RO_$_Foo
0000000100008000 (__DATA,__objc_const) non-external __OBJC_METACLASS_RO_$_Foo
                 (undefined) external ___CFConstantStringClassReference (from CoreFoundation)
0000000100000000 (__TEXT,__text) [referenced dynamically] external __mh_execute_header
                 (undefined) external __objc_empty_cache (from libobjc)
0000000100003f04 (__TEXT,__text) external _main
                 (undefined) external _objc_alloc_init (from libobjc)
                 (undefined) external _objc_msgSend (from libobjc)
0000000100003f60 (__TEXT,__objc_stubs) non-external (was a private external) _objc_msgSend$bar
```

This new feature is enabled by default in Apple clang 14, and doesn't seem to be in Apple's public fork. It can be disabled in the meantime by passing `-fno-objc-msgsend-selector-stubs` to all clang compiles.

The reason behind this feature is explained in [this WWDC session](https://developer.apple.com/wwdc22/110363) but the gist is them trying to dedup the duplicate setup code that was previously inlined for each objc_msgSend call.

The implementation of these symbols is also described in that session, the linker has 2 modes, the default mode (which is the same as passing `-objc_stubs_fast`) produces this asm on arm64:

```s
_objc_msgSend$bar:
adrp       x1, #0x100008000                            ; 0x100008090@PAGE, CODE XREF=_main+48
ldr        x1, [x1, #0x90]                             ; 0x100008090@PAGEOFF, "bar",@selector(bar)
adrp       x16, #0x100004000                           ; 0x100004010@PAGE
ldr        x16, [x16, #0x10]                           ; 0x100004010@PAGEOFF, _objc_msgSend_100004010,_objc_msgSend
br         x16                                         ; _objc_msgSend
```

Where the other mode optimizing for size, controlled by passing `-objc_stubs_small` produces this asm on arm64:

```s
_objc_msgSend$bar:
adrp       x1, #0x100008000                            ; 0x100008090@PAGE, CODE XREF=_main+48
ldr        x1, [x1, #0x90]                             ; 0x100008090@PAGEOFF, argument "selector" for method imp___stubs__objc_msgSend, "bar",@selector(bar)
b          imp___stubs__objc_msgSend                   ; objc_msgSend
```

The major difference here being the extra inline instruction size, vs the extra jump to the objc_msgSend stub.

Some other various notes:

- Apple implements these stubs in the `__TEXT,__objc_stubs` section
- The addresses of the selector loads points to the selectors in the `__selrefs` section which lld does not currently implement
- Passing `-fno-objc-msgsend-selector-stubs` to all clang invocations is the only way I see to disable (note this flag is undocumented)
</pre>
<img width="1px" height="1px" alt="" src="http://email.email.llvm.org/o/eJztWF1z4rgS_TXkRQVlzMfAAw-Ej725NTuZCtk78-aSbRk8I1suSSZhf_2elm3AhOQOtfu4FMWHJXWfbh11HztU8WH2kLPvkYoF6w9Zx18zGbNJf8zmRSEFSzN8ZiK3ImacmfRP4eYUQidKZzyPBFOFTbP0T25TlbOXndCC2Z04sFjEZSHTiFvBAhX-iILMbDcij5kRtixYmieaG6vLyJZYEx7YY_hDRDbdi-4CcyR-K2167HmXGhapTBisIduMfDOVsDKPRZLmwGYOWaikmyB4tGPKmWJJKkVnMO94y47XfI696k2Q6ktDD3EqbdlawaSLpDO4b63CFCRBJxwRr5VisMq-bCrExykI7nJRk78qPVhZDXWRxslepXHHn4Zcs86n2h3D68vms9piHOs7vt_xR80Pl5YES07oPi0vPF5gAGqW8TQnc_607cfF4c8TF86SdUb3eNNFLqWKOqMl0plafB_d0SrMoRVAfTmisa86Z94VdE3Sr-5E_dcfseXqf6vPj19XT8Hy4QmYwDXiIZEI6TP466ja7Q97Xs_rhsLyfo8XBYskz7fgheplrKvcD8W6SabiUoI33ejkI89AEXPAeOfTgm21KFjDzlMordcfbf52_CEF_35gzztR8VSm-U-hkUUjtDV0yQhmbBkaFpc6BWKaQfuqcsfqirwN9zHVTeIJmOcMkiN_iE-ijxGiOg1pzmV9Ahw3rvO9lYGuO74WKY65fsGpSRpmetWrTx8DEUXkKQieV9-fgTMIrHi1RKRc5V38FJp8d2ve1Jy4nkXYOZ5XsnBcHTi-03iiVXZ-BhHMG0wTL5pUmJbz57nD5DYHS3jb7OP9fxfB4vN8swmQtOB49m5AdmGiOfBHrDINXRm5DpR7NwD9ffU8_wfAts3cBHiQTLyL3a5oL-xOpubttgeVS3L08GXzPP-yWJH__zwuN6cA2ikZXt27CGf7XfNVNE-P7by0zXpXM_2h2VOiLk3fkPIgWKwX5IXnduMO60JyY55EgjZIzbHJ-0Jp8X-I7R2jeHPYcLx0YzJm8SHnGUqilAeq0Wdosl0gXkVUWhHsBI-Fvj0glziRFfYQRKhF4heZ4w3fgX4y7brQrXgcHNeOAupF76K51WQjRX4tuvHVc-EK-Rt6YeILNxBLhU73pH2aEZp5ax-B8MnFC0sEdxoJf0XOQwkShCSwEl5KS5qnEmtVE-wPqaFwBBcrYcC1TxYdRWTMokCL42xcN6woQzRX6jw_e-zBsojnNCdOTeWl1luZAL_TzIm0AvympgSs3SRXXYqoi4gMIuo2natb5QZ5s05N1NAg4gooMtO76JZQDtwocr1LgdtS3OcxvxaSO5kHPDgLbvzbtyXJIYDBeULT8Sc7awtD3c9f4x2LvZAKQpX0gRQ9-MbVl5c4IiW17ve9wXhAexKW1gW5RYkjb_iNXOkDBQn0Tsa6CSc5WwlYJ5rtjltGG15osU9VaeQBKKVDe2zoLcrRwX2TgAudCG1bi4VG14JR0hAaE-k0bLaG22MKsOdnkmMHRD6D_BGmGWnoQhcdS3cpoFUBM8OxuxTF2e6eSB4kEOpOe0wRJzRVJEy1S9xAiOeM62w8fE94mOr_Ne43K3isi_rgvvYJcMcfeK-n4v7BC2KTHadOPSjgr_PfVmRj8bhcse9PqzVUTlV9_PvhpHIoY83aDkf3Z55hB5X1dreP63Vlw6fonGTHSHMqkHR3eXol6HE76uHHUZ95H6JINUG_DW18jO3cwcfBXTdeh9baxeA0CVWxtb8OSnhEQlA-zOclgCvWrtbIb80NJ1P40BW761vS1N0SaHfbStihB6xWsi6f71DdZDifVLn-JfoHbms2cL0tqWoR408s913WSTaqmCobZFKV24vM_OpBCU9o3rX2DvJfZBGV4Iz_AOo4TRrt5pgVCtcHdq6Pa17Xdrqlc08uqFg39Nqbs3k_yqyg9uGY2Xr4Aeyt8r9RWUPePdfUQiAorDAXLOtePpFp30_WnRpxXZcpILQRDm9jjmLmcazRP0DyquOcbj2l4jHagUqdI9UabHvDVYjTcw-sai1SVhKEwmFRqZFVS92xCaAB8vVvKIo036v64UDTylQOJy_8wB6Yu0NWjZyhpkeZrfWF5FtaApWoorJ6xAXG3cWzQTwdTPmdTa0Us3mMLSsL93SIWB282UyYIgXZPEO7K7WctaXINrU7bHqlQKTcN19dlBj3_Mhfp8aU1KrXo7E3GN7tZtNBNJz640l_PJ2OvdF0OIj8yWCSiEGU8HHfu5M8FNLM6KGN7yPV8PY7tMYjHabR8i6d-Z7ve-P-sD_2R4NJb8iFNxXcn4pJfzQQU3pUhFohe4Skp_T2Ts8cqLDcGgzSHZ85DdIebXMhaoc_BWKqXfESB13P3KU7F8jMRfEXYPEUDw">