Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ld64.lld: Add support for _objc_msgSend stubs from Xcode 14 #56034

Closed
keith opened this issue Jun 14, 2022 · 12 comments
Closed

ld64.lld: Add support for _objc_msgSend stubs from Xcode 14 #56034

keith opened this issue Jun 14, 2022 · 12 comments
Assignees

Comments

@keith
Copy link
Member

keith commented Jun 14, 2022

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:

@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 foo.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 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:

_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:

_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)
@keith keith self-assigned this Jun 14, 2022
@llvmbot
Copy link
Collaborator

llvmbot commented Jun 14, 2022

@llvm/issue-subscribers-lld-macho

@keith
Copy link
Member Author

keith commented Jun 17, 2022

I've submitted a WIP version of this here https://reviews.llvm.org/D128108 for early feedback. See the diff for more info

@ebdjinming
Copy link

How can I pass -fno-objc-msgsend-selector-stubs to all clang invocations?

@keith
Copy link
Member Author

keith commented Aug 2, 2022

That depends on your build system, but you should add that flag however you generally pass C/C++/Objective-C compiler flags

@keith keith changed the title Add support for _objc_msgSend stubs from Xcode 14 ld64.lld: Add support for _objc_msgSend stubs from Xcode 14 Aug 5, 2022
@keith
Copy link
Member Author

keith commented Aug 5, 2022

The patch is now ready for actual review. Currently it supports x86_64 (which clang doesn't enable selector stubs by default for in Xcode 14 beta 4) and arm64 (no watchOS CPUs), and it only implements the "fast" mode for now.

@keith
Copy link
Member Author

keith commented Aug 11, 2022

I just landed https://reviews.llvm.org/D128108 which covers all except the cases mentioned above, I will leave this issue open to track those

rolfbjarne added a commit to rolfbjarne/xamarin-macios that referenced this issue Oct 4, 2022
Clang will by default emit objc_msgSend stubs in Xcode 14, which ld from
earlier Xcodes doesn't understand. We disable this by passing
-fno-objc-msgsend-selector-stubs to clang.

Ref: https://developer.apple.com/videos/play/wwdc2022/110363/
Ref: https://www.wwdcnotes.com/notes/wwdc22/110363/
Ref: llvm/llvm-project#56034

Fixes xamarin#16223.
rolfbjarne added a commit to rolfbjarne/xamarin-macios that referenced this issue Oct 4, 2022
Clang will by default emit objc_msgSend stubs in Xcode 14, which ld from
earlier Xcodes doesn't understand. We disable this by passing
-fno-objc-msgsend-selector-stubs to clang.

Ref: https://developer.apple.com/videos/play/wwdc2022/110363/
Ref: https://www.wwdcnotes.com/notes/wwdc22/110363/
Ref: llvm/llvm-project#56034

Fixes xamarin#16223.
vs-mobiletools-engineering-service2 pushed a commit to vs-mobiletools-engineering-service2/xamarin-macios that referenced this issue Oct 4, 2022
Clang will by default emit objc_msgSend stubs in Xcode 14, which ld from
earlier Xcodes doesn't understand. We disable this by passing
-fno-objc-msgsend-selector-stubs to clang.

Ref: https://developer.apple.com/videos/play/wwdc2022/110363/
Ref: https://www.wwdcnotes.com/notes/wwdc22/110363/
Ref: llvm/llvm-project#56034

Fixes xamarin#16223.
vs-mobiletools-engineering-service2 pushed a commit to vs-mobiletools-engineering-service2/xamarin-macios that referenced this issue Oct 4, 2022
Clang will by default emit objc_msgSend stubs in Xcode 14, which ld from
earlier Xcodes doesn't understand. We disable this by passing
-fno-objc-msgsend-selector-stubs to clang.

Ref: https://developer.apple.com/videos/play/wwdc2022/110363/
Ref: https://www.wwdcnotes.com/notes/wwdc22/110363/
Ref: llvm/llvm-project#56034

Fixes xamarin#16223.
rolfbjarne added a commit to xamarin/xamarin-macios that referenced this issue Oct 5, 2022
Clang will by default emit objc_msgSend stubs in Xcode 14, which ld from
earlier Xcodes doesn't understand. We disable this by passing
-fno-objc-msgsend-selector-stubs to clang.

Ref: https://developer.apple.com/videos/play/wwdc2022/110363/
Ref: https://www.wwdcnotes.com/notes/wwdc22/110363/
Ref: llvm/llvm-project#56034

Fixes #16223.
rolfbjarne added a commit to xamarin/xamarin-macios that referenced this issue Oct 5, 2022
 #16223. (#16232)

Clang will by default emit objc_msgSend stubs in Xcode 14, which ld from
earlier Xcodes doesn't understand. We disable this by passing
-fno-objc-msgsend-selector-stubs to clang.

Ref: https://developer.apple.com/videos/play/wwdc2022/110363/
Ref: https://www.wwdcnotes.com/notes/wwdc22/110363/
Ref: llvm/llvm-project#56034

Fixes #16223.

Backport of #16231

Co-authored-by: Rolf Bjarne Kvinge <rolf@xamarin.com>
rolfbjarne added a commit to xamarin/xamarin-macios that referenced this issue Oct 5, 2022
…16236)

Clang will by default emit objc_msgSend stubs in Xcode 14, which ld from
earlier Xcodes doesn't understand. We disable this by passing
-fno-objc-msgsend-selector-stubs to clang.

Ref: https://developer.apple.com/videos/play/wwdc2022/110363/
Ref: https://www.wwdcnotes.com/notes/wwdc22/110363/
Ref: llvm/llvm-project#56034

Fixes #16223.

Backport of #16231

Co-authored-by: Rolf Bjarne Kvinge <rolf@xamarin.com>
@jacksonon
Copy link

How can I pass -fno-objc-msgsend-selector-stubs to all clang invocations?

Xcode build-setttings other c flags

@russelltg
Copy link
Contributor

I set it in OTHER_CFLAGS, seemed to work for C++ and Obj-C++ code at least.

@keith
Copy link
Member Author

keith commented Oct 13, 2022

With the newest ld64.lld this should no longer be necessary though. Please report any issues you find!

@russelltg
Copy link
Contributor

The fix is not released yet right? It didn't seem to work for me in ld64.lld 15....

@keith
Copy link
Member Author

keith commented Oct 13, 2022

Yea you're right. In the meantime if you'd like you can build from HEAD or use my binary releases here https://github.com/keith/ld64.lld

@keith
Copy link
Member Author

keith commented Oct 14, 2022

I'm actually going to close this one to make it clear that this is supported in LLVM @ HEAD, and will be in LLVM 16. Please open new issues and cc me for anything you find!

qtprojectorg pushed a commit to qt/qtbase that referenced this issue Apr 13, 2023
Xcode 14's Clang will emit objc_msgSend stubs by default, which ld from
earlier Xcode versions will fail to understand. Disable these stubs
explicitly for static libs, for as long as we support Xcode < 14.

 See llvm/llvm-project#56034

Pick-to: 6.5
Fixes: QTBUG-112820
Change-Id: Id762873d61b9d147bf3eb6292297e7b80b7393e1
Reviewed-by: Timur Pocheptsov <timur.pocheptsov@qt.io>
Reviewed-by: Alexandru Croitor <alexandru.croitor@qt.io>
qtprojectorg pushed a commit to qt/qtbase that referenced this issue Apr 14, 2023
Xcode 14's Clang will emit objc_msgSend stubs by default, which ld from
earlier Xcode versions will fail to understand. Disable these stubs
explicitly for static libs, for as long as we support Xcode < 14.

 See llvm/llvm-project#56034

Fixes: QTBUG-112820
Change-Id: Id762873d61b9d147bf3eb6292297e7b80b7393e1
Reviewed-by: Timur Pocheptsov <timur.pocheptsov@qt.io>
Reviewed-by: Alexandru Croitor <alexandru.croitor@qt.io>
(cherry picked from commit c91ae57)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants