[LLVMdev] Trouble Resolving Objective-C Symbols in lli

Chris Lattner
Thu, 19 Jul 2007 21:56:34 -0000

On Thu, 19 Jul 2007, Andy Kitchen wrote:
> Hi there, I'm trying to run trivial Objective-C code that uses the
> Foundation framework under MacOS X in lli. It seems that the code will
> compile and run using llc, however fails to work in lli.

Nice!  this is a great project, unfortunately, there are some issues here
:)

I'm CC'ing Marcel, as he has some experience with dynamic generation of
code with the objc runtime library.

> SimpleFoundation.m:
> ----
>
> #import <Foundation/Foundation.h>
>
> int main (int argc, const char * argv[]) {
>    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
>
>    // insert code here...
>    NSLog(@"Hello, World!");
>    [pool release];
>    return 0;
> }
>
> ----
>
> $ llvm-gcc -c -emit-llvm SimpleFoundation.m -o SimpleFoundation.bc
> $ llc SimpleFoundation.bc -o SimpleFoundation.s
> $ gcc /System/Library/Frameworks/Foundation.framework/Foundation
> SimpleFoundation.s -o SimpleFoundation.exe
> $ ./SimpleFoundation.exe
>
> 2007-07-19 17:42:32.667 SimpleFoundation.exe[2535] Hello, World!

yay :)

> $ lli -load=/System/Library/Frameworks/Foundation.framework/Foundation
> SimpleFoundation.bc
>
> Segmentation fault
>
> $ lli -force-interpreter
> -load=/System/Library/Frameworks/Foundation.framework/Foundation
> SimpleFoundation.bc
>
> Could not resolve external global address:
.objc_class_name_NSAutoreleasePool
> Abort trap
>
> $ nm /System/Library/Frameworks/Foundation.framework/Foundation |
> grep .objc_class_name_NSAutoreleasePool
>
> 00000000 A .objc_class_name_NSAutoreleasePool

Ok, as you figured out, you do need to tell lli explicitly what frameworks
to load.  Once you have that, you are hitting another problem.
Specifically, the JIT::getPointerToNamedFunction method in
lib/ExecutionEngine/JIT/Intercept.cpp just does a dlsym on missing
symbols.  If dlsym returns null, you get the error message.

The problem here is that .objc_class_name_* are special symbols that are
used by the objc linker support and they have magic meaning.  This itself
isn't a problem, the problem is that they are absolute symbols (which is
why nm prints 'A' for the symbol) and their absolute value is 0.  When
dlsym correctly returns the address of this symbol, it returns a null
pointer (which is the address of the symbol) and lli aborts because it
thinks dlsym returned failure.

After consulting with our dynamic linker guru, I don't think there is a
wonderful clean way to do this.  I suggest adding a memcmp to the error
path in getPointerToNamedFunction that checks to see if the symbol starts
with ".objc_class_name_".  If so, getPointerToNamedFunction should
return
null without aborting.  There may be one or two other prefixes you will
have to add, for selectors or categories.

Once this is done, your example above should work.  However, when you move
on to more interesting examples, you'll probably hit other issues.  For
example, the objc runtime needs to be informed of any new classes that are
added to an address space.  I think the runtime has API calls that are
used to do this, but the LLVM JIT currently doesn't know how to do any of
them.

If you're interested in investigating this and adding support to LLVM, it
would be greatly appreciated.

-Chris

--