Mocking: Darwin interposer
Example: share/doc/aceunit/examples/hello_world_mocked_interpose
How it works
Section titled “How it works”macOS’s dynamic loader supports library interposition. main is still renamed ahead of time with objcopy:
objcopy --redefine-sym main=original_main hello.o mocked_hello.oBut puts is not renamed at all — instead, mock_puts.c declares a static interpose table in a special linker section that Darwin’s dynamic loader recognizes:
__attribute__((section("__DATA,__interpose")))const interpose_t interposing_puts[] = { { (void *) mock_puts, (void *) puts },};That table is built into a small dynamic library and inserted into the process at load time:
cc -dynamiclib mock_puts.c -o libmock.dylibDYLD_INSERT_LIBRARIES=libmock.dylib ./hello_testThe dynamic loader reads the interpose table and substitutes mock_puts for every call to puts in the process, no recompilation or relinking of hello.o needed for that part.
When to use this
Section titled “When to use this”Only relevant on Darwin/macOS — this mechanism doesn’t exist on GNU/Linux linkers. If you need llvm-objcopy and it’s not found, and you installed LLVM via Homebrew, add it to your PATH:
export PATH=$(brew --prefix llvm)/bin:$PATHSee also: Link-time wrap for the equivalent GNU/Clang-on-Linux approach.