Linking libboost_log.so makes boost::asio::io_serv

2019-07-09 02:43发布

问题:

Here is the setup:

boost1::asio::io_service         _ios;
boost::asio::ip::tcp::acceptor  _acceptor;`
...
_acceptor(_ios)
...
boost::system::error_code ec;
int rc = _ios.run(ec);

with gdb I see that run call jump into boost::asio::impl::io_service::run
Here is a bit of boost

boost/asio/impl/io_service.ipp:

std::size_t io_service::run(boost::system::error_code& ec)
{
  return impl_.run(ec);
}

Here is proof that impl_ is task_io_service for linux case.

boost/boost/asio/io_service.hpp

#if defined(BOOST_ASIO_HAS_IOCP)
namespace detail { typedef win_iocp_io_service io_service_impl; }
#else
namespace detail { typedef task_io_service io_service_impl; }
#endif

...

private:
  typedef detail::io_service_impl impl_type;
#if defined(BOOST_ASIO_HAS_IOCP)
  friend class detail::win_iocp_overlapped_ptr;
#endif

...

impl_type& impl_;

If I don't link -lboost_log during compilation, then impl_run call is resolved (through plt stub call, ld_trampoline.S dl-runtime_resolve and dl-runtime.c _dl_fixup) to boost::asio::detail::impl::task_io_service::run in my binary and run() starts waiting for work provided by acceptor.

If I do link boost, through GDB i see this call to be resolved to libboost_log.so symbol _ZN5boost4asio6detail15task_io_service3runERNS_6system10error_codeE and exits run nearly immediately.

nm -D libboost_log.so confirms that the symbol is there and it is not my linking issue.

Why is this task_io_service3run symbol in libboost_log.so? It seems like boost bug, doesn't it? Are there ways to ensure intended method resolution?

回答1:

In a nutshell, runtime symbol resolution on Linux works in terms of symbol visibility. If a symbol is externally visible in one or several of the shared objects that are loaded with your application then the runtime linker is free to choose any one of the implementations and use it in all other shared objects. This is very much like the compile time linking process and it allows for several language rules to hold (for example, taking address of a function must yield the same address, wherever in the program that address is taken).

Boost.Log does indeed use Boost.ASIO to implement some of its features (network-based syslog sink, in particular). Boost.ASIO marks its symbols as externally visible, so they are exported from Boost.Log shared object.

Now Boost.ASIO does not use an ABI namespace or any other technique to make the symbol names different depending on the library version or configuration. It means that any application or library that uses Boost.Log and Boost.ASIO must be using the same version of Boost.ASIO, configured the same way as it was configured when building Boost.Log. Otherwise due to ABI incompatibilities you may observe all kinds of undefined behavior in your or Boost.Log's use of Boost.ASIO. I suspect this might be the reason why you could be having problems.

Check that you're using the same version of Boost.ASIO when building your code and Boost.Log. Check that all macros are defined the same way in both cases. Check if you're using any ABI-related compiler switches.



标签: c++ boost