More questions about non_lazy_ptr

I have a problem where my LLVM-generated code works on Linux but not on OS X, and the problem involves non_lazy_ptr.

I have an external symbol named “@gc_safepoint_map”, which is generated by the linker’s GCStrategy plugin. Since it is not generated until link time, I declared it as an external symbol so that the modules that use it can compile without error.

Here’s what the generated IR looks like:

@gc_safepoint_map = external global [0 x i32]

The runtime startup code gets the safepoint map and calls GC_init with the safepoint map. Here’s what the code looks like in IR:

%init = invoke {} @GC_init(i32* getelementptr inbounds ([0 x i32]* @gc_safepoint_map, i32 0, i32 0))
to label %nounwind unwind label %catch

When lowered to assembly, the code looks like this on OS X:

Ltmp426:
movl L_gc_safepoint_map$non_lazy_ptr, %eax
movl %eax, (%esp)
calll _GC_init

(and later on in the same file):

L_gc_safepoint_map$non_lazy_ptr:
.indirect_symbol _gc_safepoint_map
.long 0

This looks correct to me - it’s dereferencing the non_lazy_ptr version of the global.

The GC_init function, which is written in C, simply looks like this:

void GC_init(size_t * safepointMap) {

// … details omitted…
}

On Linux, everything works as expected, however in OS X, the ‘safepointMap’ pointer is completely wrong - I’m not sure where it’s getting the value from but it isn’t sensible.

Unfortunately, gdb won’t let me print out the value of of L_gc_safepoint_map$non_lazy_ptr (No symbol “L_gc_safepoint_map$non_lazy_ptr” in current context) so it’s hard to tell what’s actually going on.

Thanks to Ben Karel who supplied the answer to me off-list. The solution was to add the following line to my GCStrategy:

outStream.EmitSymbolAttribute(gcSafepointSymbol, MCSA_Global);