简体   繁体   English

使用LLVM ExecutionEngine调用Objective-C方法时,无法识别所有选择器

[英]All selectors unrecognised when invoking Objective-C methods using the LLVM ExecutionEngine

I'm running on OSX, using Clang to compile some Obj-C code that uses the OSX Cocoa classes, and I'm trying to run the result with the LLVM JIT compiler. 我正在运行OSX,使用Clang编译一些使用OSX Cocoa类的Obj-C代码,我正在尝试使用LLVM JIT编译器运行结果。 I'm using the latest bleeding-edge version of LLVM/Clang. 我正在使用LLVM / Clang的最新版本。

There are no problems compiling or linking my code, and I can happily make C and C++ system calls without any trouble. 编译或链接我的代码没有问题,我可以毫无困难地愉快地进行C和C ++系统调用。 But all my Obj-C invocations are failing miserably, and I'm out of my depth trying to work out why! 但是我所有的Obj-C调用都惨遭失败,而且我不能深入研究原因! The objc_msgSend() function appears to be getting called correctly, but the runtime is refusing to recognise even the simplest selectors. objc_msgSend()函数似乎被正确调用,但运行时拒绝识别最简单的选择器。

I've managed to reproduce the problem using just Clang and LLI, and this is how to do it: 我设法使用Clang和LLI重现问题,这是如何做到的:

Create a simple file test.mm: 创建一个简单的文件test.mm:

#include <Cocoa/Cocoa.h>
#include <cstdio>
#include <iostream>

extern "C" int main (int, char**)
{
    std::cout << "==== step 1" << std::endl;

    NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
    [pool release];

    std::cout << "==== step 2" << std::endl;

    return 0;
}

..compile it to bitcode with clang: ..用clang将它编译成bitcode:

clang -emit-llvm test.mm -c -o test.bc

Then run it with lli: 然后用lli运行它:

lli -load=/System/Library/Frameworks/Foundation.framework/Versions/Current/Foundation test.bc

The output of lli looks like this: lli的输出如下所示:

==== step 1
objc[45353]: Object 0x101a362a0 of class __NSCFString autoreleased with no pool in place - just leaking - break on objc_autoreleaseNoPool() to debug
2012-04-29 20:07:35.384 lli[45353:707] -[NSAutoreleasePool init]: unrecognized selector sent to instance 0x101a35170
2012-04-29 20:07:35.386 lli[45353:707] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[NSAutoreleasePool init]: unrecognized selector sent to instance 0x101a35170'
*** First throw call stack:
(
    0   CoreFoundation                      0x00007fff89c76fc6 __exceptionPreprocess + 198
    1   libobjc.A.dylib                     0x00007fff8c9e6d5e objc_exception_throw + 43
    2   CoreFoundation                      0x00007fff89d032ae -[NSObject doesNotRecognizeSelector:] + 190
    3   CoreFoundation                      0x00007fff89c63e73 ___forwarding___ + 371
    4   CoreFoundation                      0x00007fff89c63c88 _CF_forwarding_prep_0 + 232
    5   ???                                 0x0000000101929111 0x0 + 4321349905
    6   lli                                 0x000000010148f36b _ZN4llvm15ExecutionEngine17runFunctionAsMainEPNS_8FunctionERKSt6vectorISsSaISsEEPKPKc + 1259
    7   lli                                 0x0000000101016657 main + 3095
    8   lli                                 0x0000000101015a34 start + 52
    9   ???                                 0x0000000000000003 0x0 + 3
)
terminate called throwing an exception0  lli               0x00000001015c5b02 _ZL15PrintStackTracePv + 34
1  lli               0x00000001015c5fd9 _ZL13SignalHandleri + 633
2  libsystem_c.dylib 0x00007fff8f8bccfa _sigtramp + 26
3  libsystem_c.dylib 0x0000000000000001 _sigtramp + 18446603338107859745
4  libsystem_c.dylib 0x00007fff8f85ba7a abort + 143
5  libc++abi.dylib   0x00007fff8518a7bc abort_message + 214
6  libc++abi.dylib   0x00007fff85187fcf default_terminate() + 28
7  libobjc.A.dylib   0x00007fff8c9e71b9 _objc_terminate + 94
8  libc++abi.dylib   0x00007fff85188001 safe_handler_caller(void (*)()) + 11
9  libc++abi.dylib   0x00007fff8518805c __cxa_bad_typeid + 0
10 libc++abi.dylib   0x00007fff85189152 __gxx_exception_cleanup(_Unwind_Reason_Code, _Unwind_Exception*) + 0
11 libobjc.A.dylib   0x00007fff8c9e6e7a _objc_exception_destructor + 0
12 CoreFoundation    0x00007fff89d032ae -[NSObject doesNotRecognizeSelector:] + 190
13 CoreFoundation    0x00007fff89c63e73 ___forwarding___ + 371
14 CoreFoundation    0x00007fff89c63c88 _CF_forwarding_prep_0 + 232
15 CoreFoundation    0x0000000101929111 _CF_forwarding_prep_0 + 18446603342526043505
16 lli               0x000000010148f36b llvm::ExecutionEngine::runFunctionAsMain(llvm::Function*, std::vector<std::string, std::allocator<std::string> > const&, char const* const*) + 1259
17 lli               0x0000000101016657 main + 3095
18 lli               0x0000000101015a34 start + 52
19 lli               0x0000000000000003 start + 18446744069397718531
Stack dump:
0.  Program arguments: Release/bin/lli -load=/System/Library/Frameworks/Foundation.framework/Versions/Current/Foundation /Users/jules/Desktop/test.bc 
Abort trap: 6

As you can see in the log, it says that -[NSAutoreleasePool init] is an unrecognised selector. 正如您在日志中看到的那样,它表示-[NSAutoreleasePool init]是一个无法识别的选择器。 The same happens for any other selector, eg -[NSString init] or other things that clearly should work. 对于任何其他选择器-[NSString init]发生同样的情况,例如-[NSString init]或其他显然应该工作的事情。

Any help or clues would be much appreciated! 任何帮助或线索将不胜感激! I am a bit lost as to whether this is a bug, or something I'm doing wrong, or maybe just a feature that hasn't been finished yet. 我有点迷失这是一个错误,或者我做错了什么,或者可能只是一个尚未完成的功能。 I can't find any references to this issue anywhere in the LLVM docs or interwebs. 我在LLVM文档或互联网中的任何地方都找不到任何对此问题的引用。

I've tried different clang options such as the legacy Obj-C fragile ABI, but had no luck. 我尝试了不同的铿锵选项,如遗留的Obj-C脆弱的ABI,但没有运气。 I'm no expert on either LLVM or the Obj-C runtime, and this one has got me stumped. 我不是LLVM或Obj-C运行时的专家,这个让我很难过。

--EDIT-- - 编辑 -

Just a bit more info, in the hope that it might ring a bell with someone.. 只是更多的信息,希望它可能与某人敲响钟声..

When I tried replacing the normal obj-C message invocation with an explicit call to objc_msgSend, I found this: 当我尝试用显式调用objc_msgSend替换正常的obj-C消息调用时,我发现了这个:

SEL s = sel_getUid ("init");
objc_msgSend (myObject, s);   // Succeeds!

SEL s = @selector (init);
objc_msgSend (myObject, s);   // Fails!

..so it seems that when clang auto-generates the SEL value, it's producing a value that's not useable by the runtime. ..因此,当clang自动生成SEL值时,它会生成一个运行时无法使用的值。 Can anyone even suggest where in the LLVM/Clang codebase I should look to try to understand what might be going on? 任何人都可以建议在LLVM / Clang代码库中我应该尝试了解可能会发生什么?

Objective-C uses specially-named globals to refer to selectors, and the linker and ObjC runtime have special knowledge of these globals which makes everything work normally. Objective-C使用特殊命名的全局变量来引用选择器,链接器和ObjC运行时具有这些全局变量的特殊知识,使一切正常工作。 lli has no knowledge of Objective-C; lli不了解Objective-C; therefore, the ObjC runtime never runs its special handling for the globals in question. 因此,ObjC运行时永远不会对所讨论的全局变量运行其特殊处理。

Off the top of my head, I have no idea what exactly you need to do to make it work, though. 不过,我不知道你究竟需要做些什么才能让它发挥作用。

After a few months of research on this topic I would like to share my findings. 经过几个月的研究,我想分享我的发现。 To quote myself: 引用自己:

It is possible to run Objective-C and Swift code with LLVM JIT on macOS system. 可以在macOS系统上使用LLVM JIT运行Objective-C和Swift代码。 One way to make it work is to subclass a SectionMemoryManager used by LLVM JIT engine, intercept memory sections related to Objective-C as they get allocated in memory, find the Objective-C metadata in these sections, parse the Objective-C class information from this metadata, use a number of Objective-C Runtime API methods to register found Objective-C classes in Objective-C runtime. 使其工作的一种方法是子类化LLVM JIT引擎使用的SectionMemoryManager,拦截与Objective-C相关的内存部分,因为它们在内存中分配,在这些部分中查找Objective-C元数据,从中解析Objective-C类信息这个元数据,使用一些Objective-C运行时API方法在Objective-C运行时中注册找到的Objective-C类。

Although this approach only targets Objective-C code and the Objective-C Runtime, it also seems to enable support for combined Swift and Objective-C code: given that the Objective-C classes are registered, Swift code with enabled Objective-C interoperability seems to run without any major issues in LLVM JIT. 虽然这种方法仅针对Objective-C代码和Objective-C运行时,但它似乎也支持Swift和Objective-C组合代码:假设Objective-C类已注册,具有启用的Objective-C互操作性的Swift代码似乎在LLVM JIT中运行时没有任何重大问题。

See full article for the details: 详情请参阅完整文章:

LLVM JIT, Objective-C and Swift on macOS: knowledge dump . 在macOS上的LLVM JIT,Objective-C和Swift:知识转储

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM