作为链接-static当包装的函数只从链接库调用(Wrapped function is only

2019-09-23 12:48发布

编辑 :标题制造一个更清楚一点。

我试图总结的glibc的__assert_fail__assert_perror_fail我自己是登录使用邮件功能的syslog

我已经验证了,如果我不能断言我的函数被调用。 问题在于libzmq的说法。 当我建立与libzmq的说法只是调用我的包装功能-static

笔记

  • 我修补libzmq打电话__assert_*代替fprintf(stderr, ...)我已经验证它正确地调用__assert_*

  • 我还修补libzmq随机有断言失败从zmq_assert宏中,这样我可以很容易地重现。 如果补丁是想要的,我会把它。

下面是一些测试代码

#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;
}

我所要建造4点的方式有/无DO_ASSERT,动态/静态

$ 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

我跑的时候他们得到以下

$ 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

所以我在做什么错? 据man ld

如果您使用的malloc --wrap此文件链接其他代码,然后将所有来电“的malloc”将调用函数“--wrap malloc中调用”代替。

这不是我所看到的。

Answer 1:

你的心理如何模型--wrap连接选项的工作可能都错了。

这真的很简单:当你连接一个特定的ELF可执行文件或共享库--wrap foo所有的连接器的作用是:

  • 如果看到一个参考foo ,它与参考替换它__wrap_foo
  • 如果看到一个参考__real_foo ,它与一个参考替换foo

我再说一遍,这是所有它。 特别是,因为你还没有重新链接libzmq.so--wraplibzmq.so继续呼吁__assert_fail (即没有任何重命名为内部发生libzmq.so )。

为了干预libc功能,忘了--wrap

相反,简单地定义一个新的__assert_fail在主可执行文件。 当你这样做,你的定义将获得无论电话是否来自主可执行文件,或者从所谓libzmq.so (或其他地方)。

如果您不想打电话的版本做__assert_fail从libc中,你做。 如果你这样做,你必须看看它动态(通过dlsym )。



文章来源: Wrapped function is only called from linked library when linking as -static