title: What are the details of dynamic symbol binding on OS X?
body: <p>I have a really odd situation with dynamic symbol binding on OS X that I'm hoping to get some clues on how to resolve.</p>
  
  <p>I have an application, written in C, which uses <code>dlopen()</code> to dynamically load modules at runtime. Some of these modules export global symbols, which may be used by other modules loaded later.</p>
  
  <p>We have one module (which I'll call <code>weird_module.so</code>) which exports global symbols, one of which is <code>weird_module_function</code>. If weird_module.so gets linked with a particular library (which I'll call <code>libsomething.dylib</code>), then <code>weird_module_function</code> can't be bound to. But if I remove the <code>-lsomething</code> when linking <code>weird_module.so</code>, then I <em>can</em> bind to <code>weird_module_function</code>.</p>
  
  <p>What could possibly be going on with <code>libsomething.dylib</code> that would cause <code>weird_module.so</code> to not export symbols? Are there things I can do to debug how symbols get exported (similar to how I can use <code>DYLD_PRINT_BINDINGS</code> to debug how they get bound)?</p>
  
  <pre><code>$ LDFLAGS="-bundle -mmacosx-version-min=10.6 -Xlinker -undefined -Xlinker dynamic_lookup /usr/lib/bundle1.o"
  
  $ gcc -o weird_module.so ${LDFLAGS} weird_module.o -lsomething
  $ nm weird_module.so | grep '_weird_module_function$'
  00000000000026d0 T _weird_module_function
  
  $ gcc -o other_module.so ${LDFLAGS} other_module.o -lsomething
  $ nm other_module.so | grep '_weird_module_function$'
                   U _weird_module_function
  
  $ run-app
  Loading weird_module.so
  Loading other_module.so
  dyld: lazy symbol binding failed: Symbol not found: _weird_module_function
    Referenced from: other_module.so
    Expected in: flat namespace
  
  dyld: Symbol not found: _weird_module_function
    Referenced from: other_module.so
    Expected in: flat namespace
  
  # Now relink without -lsomething
  $ gcc -o weird_module.so ${LDFLAGS} weird_module.o
  $ nm weird_module.so | grep '_weird_module_function$'
  00000000000026d0 T _weird_module_function
  $ run-app
  Loading weird_module.so
  Loading other_module.so
  # No error!
  </code></pre>
  
  <p><em>Edit</em>:</p>
  
  <p>I tried putting together a minimal app to duplicate the problem, and in the course of doing so at least figured it out one thing we were doing wrong. There are two other pertinent facts relevant to duplicating the issue.</p>
  
  <p>First is that <code>run-app</code> preloads the module with <code>RTLD_LAZY | RTLD_LOCAL</code> to inspect its metadata. The module is then <code>dlclose()</code>ed and reopened with either <code>RTLD_LAZY | RTLD_GLOBAL</code> or <code>RTLD_NOW | RTLD_LOCAL</code>, depending on the metadata. (For both modules in question, it reopens with <code>RTLD_LAZY | RTLD_GLOBAL</code>).</p>
  
  <p>Secondly, there turns out to be a symbol collision in <code>weird_module.so</code> and <code>libsomething.dylib</code> for a <code>const</code> global.</p>
  
  <pre><code>$ nm weird_module.so | grep '_something_global`
  00000000000158f0 S _something_global
  
  $ nm libsomething.dylib | grep '_something_global'
  0000000000031130 S _something_global
  </code></pre>
  
  <p>I'm willing to consider that the duplicate symbol would put me in the realm of undefined behavior, so I'm dropping the question.</p>