kernelthread.com

Mac OS X: Re-routing Dynamic Library Calls

I have run across situations analogous to the following multiple times: you need to run some program P that you acquired somehow - maybe your company bought it, perhaps you downloaded its binary, maybe it's even open source ... P intends to do something to a network interface, but you have multiple interfaces on your system. You want P to use a certain interface, but P does not have provision for specifying that. It simply chooses the first interface on the system as determined by a call to the SIOCGIFCONF ioctl.

I realize that the above sounded terribly contrived, but what do you do?

A commonly used solution to such "problems" is to "pre-load" a library that "fixes" the issue. In the above case, you would write your own version of ioctl() that makes a call to the "original" function/stub in the C library, say, and then post-processes the result to make it look the way you want. You may not even want to call the original function and cook up a result entirely on your own. Traditional ELF systems let you direct the dynamic linker/loader to load specified libraries before all others. This is most commonly done via the LD_PRELOAD environment variable, and files such as /etc/ld.so.preload for global effect.

Mac OS X does not use ELF. Its runtime model certainly supports dynamic shared libraries, but uses the Mach-O and PEF binary file formats. dyld, the dynamic linker (Mac OS X analog of ld.so) and CFM (Code Fragment Manager) use these formats, respectively. Just as the operating system kernel in ELF systems executes ELF binaries through execve(), Mac OS X kernel does the same with Mach-O. Moreover, the dl* API (dlopen, dlsym, ...) is not supported.

dyld does support a number of environment variables that direct its behavior. The closest thing to LD_PRELOAD is the variable DYLD_INSERT_LIBRARIES, but there is one big caveat: this has no effect on images using two-level namespaces. The variable DYLD_FORCE_FLAT_NAMESPACE needs to be set in order for DYLD_INSERT_LIBRARIES to "work". This forces all images in the program to be linked as flat-namespace images (ignoring any two-level bindings). If there are multiply-defined symbols because of a forced flat namespace, applications may fail to run properly, or to even run.