When I tried to get Fabio Busatto's libkeepalive working on a MacOSX 10.4.x machine I discovered that the runtime linker (dyld) doesn't support LD_PRELOAD but the dyld manual page hinted that DYLD_INSERT_LIBRARIES did the same thing. Alas! not that simple.
Not having much sucess I consulted my copy of Mac OS X internals: a systems approach (Amit Singh) in the hope of better understanding the runtime loader. And on page 73 (sect. 2.6.3.4 dyld Interposing) was exactly what I was looking for!
Basically dyld looks in any shared library specified in DYLD_INSERT_LIBRARIES for sections named
__DATA __interpose
In those sections there are pairs of function pointers (addresses.) The first pointer is the address of your function to be interposed while the second pointer is the address of the original function to be replaced.
The code looks pretty much like this (from my macosx hack of libkeepalive)
[An updated version can be found under http://toves.freeshell.org/interpose/files/]
/* // MacOSX defines the socket level to be the protocol number // Or we could just // #define SOL_TCP (6) */ static int sol_tcp = 0; static int get_sol_tcp(void) { int result = 0; struct protoent* p = getprotobyname ("tcp"); if (p) { result = p->p_proto; } endprotoent(); return result; } # define SOL_TCP (sol_tcp>0?sol_tcp:(sol_tcp = get_sol_tcp())) /* // Note that you can use the old function by name without further ado. */ int my_socket (int dom, int type, int proto) { int result = socket (dom, type, proto); if (result >= 0) { if (dom == PF_INET && type == SOCK_STREAM) { int on = 1; int idle = 240; /* seconds ?*/ setsockopt (result, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof(on)); setsockopt (result, SOL_TCP, TCP_KEEPALIVE, &idle, sizeof(idle)); } } return result; } struct interpose { /* the struct/typenames are arbitrary */ void* new; void* old; }; typedef struct interpose interpose_t; /* The __attribute__/section definition is the critical part. // If you have only one function then myreplacements doesn't have // to be an array. Obviously the name myreplacements is also arbitrary. // You can define multiple sections with the name __DATA, __interpose // and the static linker will combine them just like any other section. */ static const interpose_t myreplacements[] \ __attribute__((section("__DATA, __interpose"))) = { { (void*) my_socket, (void*) socket} };
The compilation is simple compared with ELF/ECOFF systems.
gcc -Wall -dynamiclib -o libkeepalive.dylib libkeepalive.c cp libkeepalive.dylib ${HOME}/lib
EXAMPLE
env DYLD_INSERT_LIBRARIES=${HOME}/lib/libkeepalive.dylib ssh sdf.lonestar.org
LICENSE
Creative Commons CC0
http://creativecommons.org/publicdomain/zero/1.0/legalcode
AUTHOR
James Sainsbury