Apple systems use a two-level namespace. When a client Mach-O image imports a symbol from a shared library, the symbol is referenced by name within that shared library.
When you export a C++ class from a Mach-O image, it exports various symbols that are mangled to embed the name of the class.
These two factoids combine to determine how C++ linkage works. When you link the client Mach-O image, the linker finds the first library that exports the class’s symbols. It then embeds into the client a reference to that library and references to the symbols that make up the class.
Note This is in stark contrast to Objective-C, where all classes within a process live within a single flat namespace.
The critical thing here is that this resolution happens when you link the client. After that, the client has a reference to the shared library containing the symbols and that’s what will be used when you load the client.
There are two standard tools used for investigating this:
otool -L
will show you a list of shared libraries being imported by the client. For example, this:
$ otool -L MyTestTool
MyTestTool:
/System/Library/Frameworks/Foundation.framework/Versions/C/Foundation (compatibility version 300.0.0, current version 1570.15.0)
/usr/lib/libobjc.A.dylib (compatibility version 1.0.0, current version 228.0.0)
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1252.250.1)
shows that
MyTestTool
is importing the shared libraries Foundation
, libobjc
and libSystem
.nm
will show you a list of symbols being imported by the client library. Pass the -m
option to see which shared library these are coming from. For example, in the following:
$ nm -m MyTestTool
(undefined) external ___stderrp (from libSystem)
0000000100000000 (__TEXT,__text) [referenced dynamically] external __mh_execute_header
(undefined) external _fprintf (from libSystem)
(undefined) external _getprogname (from libSystem)
0000000100000ee0 (__TEXT,__text) external _main
(undefined) external _objc_autoreleasePoolPop (from libobjc)
(undefined) external _objc_autoreleasePoolPush (from libobjc)
(undefined) external dyld_stub_binder (from libSystem)
imported symbols are those without an address, and for each imported symbol there is both the symbol name and the library in which it’s expected to be found. As you can see, the
fprintf
function is being imported from libSystem
.
You can see this info to confirm which shared library is being referenced by your client. Once you do that, you can try various things to change that, the most likely candidate being the order in which A and B are presented to the linker.
Share and Enjoy
—
Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware
let myEmail = "eskimo" + "1" + "@apple.com"