问题
Edit: Made title a bit clearer.
I am trying to wrap glibc's __assert_fail and __assert_perror_fail functions with my own that log the messages using syslog.
I have verified that if I fail an assert my functions get called. The problem lies in libzmq's assertions. libzmq's assertions only invoke my wrapper functions when I build with -static.
NOTES
I patched libzmq to call
__assert_*instead offprintf(stderr, ...), and I have verified that it correctly calls__assert_*.I also patched libzmq to randomly have assertion failures from within the zmq_assert macros so that I can easily reproduce. If the patch is wanted, I will put it up.
Here is some test code
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include <errno.h>
#include <string.h>
#include <zmq.h>
extern "C" void
__wrap___assert_perror_fail(int __errnum, const char *__file,
unsigned int __line, const char *__function)
{
fprintf(stderr, "TESTING123:: %s:%u %s: Unexpected error: %s.\n",
__file, __line, __function, strerror(__errnum));
abort();
}
extern "C" void
__wrap___assert_fail(const char *__assertion, const char *__file,
unsigned int __line, const char *__function)
{
fprintf(stderr, "TESTING123:: %s:%u %s: Assertion '%s' failed.\n",
__file, __line, __function, __assertion);
abort();
}
int main()
{
#ifdef DO_ASSERT
assert(1 == 0);
#endif
void *ctx = zmq_init(0);
void *req = zmq_socket(ctx, ZMQ_REQ);
void *rep = zmq_socket(ctx, ZMQ_REQ);
zmq_bind(rep, "inproc://inproc-1");
zmq_connect(req, "inproc://inproc-1");
unsigned long long c = 0;
while (1) {
zmq_msg_t msg;
zmq_msg_init_size(&msg, 1024);
zmq_send(req, &msg, 0);
zmq_msg_close(&msg);
zmq_msg_init(&msg);
zmq_recv(rep, &msg, 0);
zmq_send(rep, &msg, 0);
zmq_msg_close(&msg);
zmq_msg_init(&msg);
zmq_recv(req, &msg, 0);
zmq_msg_close(&msg);
++c;
if (c % 1000000 == 0) {
fprintf(stderr, "processed %llu messages\n", c);
}
}
return 0;
}
Which I build 4 ways with/without DO_ASSERT, dynamic/static
$ g++ -DDO_ASSERT -o t-me-dyn t.cc -Wl,-wrap,__assert_fail -Wl,-wrap,__asser_perror_fail -lzmq -lpthread -luuid -lrt
$ g++ -static -DDO_ASSERT -o t-me-sta t.cc -Wl,-wrap,__assert_fail -Wl,-wrap,__asser_perror_fail -lzmq -lpthread -luuid -lrt
$ g++ -o t-zmq-dyn t.cc -Wl,-wrap,__assert_fail -Wl,-wrap,__asser_perror_fail -lzmq -lpthread -luuid -lrt
$ g++ -static -o t-zmq-sta t.cc -Wl,-wrap,__assert_fail -Wl,-wrap,__asser_perror_fail -lzmq -lpthread -luuid -lrt
/usr/lib/gcc/x86_64-unknown-linux-gnu/4.7.1/../../../../lib/libzmq.a(libzmq_la-ip.o): In function 'zmq::resolve_ip_interface(sockaddr_storage*, unsigned int*, char const*)':
(.text+0x49b): warning: Using 'getaddrinfo' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking
And I get the following when running them
$ for bin in t-{me,zmq}-{dyn,sta}; do echo ==== $bin ====; ./$bin; done
==== t-me-dyn ====
TESTING123:: t.cc:29 int main(): Assertion '1 == 0' failed.
Aborted
==== t-me-sta ====
TESTING123:: t.cc:29 int main(): Assertion '1 == 0' failed.
Aborted
==== t-zmq-dyn ====
t-zmq-dyn: lb.cpp:142: int zmq::lb_t::send(zmq_msg_t*, int): Assertion 'rc == 0' failed.
Aborted
==== t-zmq-sta ====
TESTING123:: lb.cpp:142 int zmq::lb_t::send(zmq_msg_t*, int): Assertion 'rc == 0' failed.
Aborted
So what am I doing wrong? According to man ld
If you link other code with this file using --wrap malloc, then all calls to "malloc" will call the function "__wrap_malloc" instead.
which is not what I am seeing.
回答1:
Your mental model of how --wrap linker option works is likely all wrong.
It's quite simple really: when you are linking a particular ELF executable or shared library with --wrap foo, all the linker does is:
- if it sees a reference to
foo, it replaces it with a reference to__wrap_foo, - if it sees a reference to
__real_foo, it replaces with a reference tofoo.
I repeat, that is all it does. In particular, since you have not relinked libzmq.so with --wrap, libzmq.so continues to call __assert_fail (i.e. no renaming whatsoever is happening inside libzmq.so).
In order to interpose libc function, forget the --wrap.
Instead, simply define a new __assert_fail in your main executable. When you do that, your definition will get called regardless of whether the call comes from the main executable, or from libzmq.so (or from anywhere else).
If you don't want to call the version of __assert_fail from libc, you are done. If you do, you'll have to look it up dynamically (via dlsym).
来源:https://stackoverflow.com/questions/12736251/wrapped-function-is-only-called-from-linked-library-when-linking-as-static