After long investigation I finally found solution for the issue.
First of all I looked at the executable file dependencies:
ldd -v <executable_name>
My build is built with Cmake and only its Release version has the following dependency:
Version information:
./build/Release/products/<executable_name>:
libc.so.6 (GLIBC_2.16) => /lib/i386-linux-gnu/libc.so.6
On analyzing this file with objdump, I retrieved that it needs __poll_chk symbol:
00000000 F *UND* 00000000 __poll_chk@@GLIBC_2.16
Though Glibc uses so called _symbol versioning _, this particular function was added only in Glibc 2.16.
Therefore I tried investigating what caused the difference between Debug and Release builds.
When CMAKE_BUILD_TYPE is set, Cmake defines domestic variables, which determine compiler flags. For GCC 4.8.4 they are:
- Debug: -g
- Release: -NDEBUG -O3
Glibc poll.h includes poll2.h, which contains tricky _poll_chk yet unavailable in GLibc 2.16. This include goes under _USE_FORTIFY_LEVEL define.
And according to Linux man pages (see quotes below) in Release build I have -D_FORTIFY_SOURCE=2 due to -O3 level.
man gcc
NOTE: In Ubuntu 8.10 and later versions, -D_FORTIFY_SOURCE=2 is set by
default, and is activated when -O is set to 2 or higher. This
enables additional compile-time and run-time checks for several libc
functions. To disable, specify either -U_FORTIFY_SOURCE or
-D_FORTIFY_SOURCE=0.
man feature_test_macros
_FORTIFY_SOURCE (since glibc 2.3.4) Defining this macro causes some lightweight checks to be performed to detect some buffer overflow
errors when employing various string and memory manipulation
functions. Not all buffer overflows are detected, just some
common cases. In the current implementation, checks are added
for calls to memcpy(3), mempcpy(3), memmove(3), memset(3), stpcpy(3),
strcpy(3), strncpy(3), strcat(3), strncat(3), sprintf(3), snprintf(3),
vsprintf(3), vsnprintf(3), and gets(3). If _FORTIFY_SOURCE is set to
1, with compiler optimization level 1 (gcc -O1) and above, checks that
shouldn't change the behavior of conforming programs are performed.
With _FORTIFY_SOURCE set to 2 some more checking is added, but some
conforming programs might fail. Some of the checks can be performed
at compile time, and result in compiler warnings; other checks take
place at run time, and result in a run-time error if the check fails.
Use of this macro requires compiler support, available with gcc(1)
since version 4.0.
or just use
man -K _FORTIFY_SOURCE
I checked every static library my executable includes, whose code uses poll function and ultimately had found it:
objdump -t lib.a | grep poll
00000000 *UND* 00000000 Curl_poll
00000000 l d .text.Curl_poll 00000000 .text.Curl_poll
00000000 *UND* 00000000 poll
00000000 *UND* 00000000 __poll_chk
00000000 g F .text.Curl_poll 0000025c Curl_poll
This optimization may be disabled by adding -U_FORTIFY_SOURCE to the compiler flags within target CmakeLists.txt. This eliminate any lately detected GLIBC2.16 dependencies:
Version information:
products/<executable>:
ld-linux.so.2 (GLIBC_2.3) => /lib/ld-linux.so.2
librt.so.1 (GLIBC_2.2) => /lib/i386-linux-gnu/librt.so.1
libdl.so.2 (GLIBC_2.0) => /lib/i386-linux-gnu/libdl.so.2
libdl.so.2 (GLIBC_2.1) => /lib/i386-linux-gnu/libdl.so.2
libpthread.so.0 (GLIBC_2.2) => /lib/i386-linux-gnu/libpthread.so.0
libpthread.so.0 (GLIBC_2.3.2) => /lib/i386-linux-gnu/libpthread.so.0
libpthread.so.0 (GLIBC_2.1) => /lib/i386-linux-gnu/libpthread.so.0
libpthread.so.0 (GLIBC_2.0) => /lib/i386-linux-gnu/libpthread.so.0
libpulse.so.0 (PULSE_0) => /usr/lib/i386-linux-gnu/libpulse.so.0
libsndfile.so.1 (libsndfile.so.1.0) => /usr/lib/i386-linux-gnu/libsndfile.so.1
libc.so.6 (GLIBC_2.15) => /lib/i386-linux-gnu/libc.so.6
libc.so.6 (GLIBC_2.11) => /lib/i386-linux-gnu/libc.so.6
libc.so.6 (GLIBC_2.1.3) => /lib/i386-linux-gnu/libc.so.6
libc.so.6 (GLIBC_2.2.4) => /lib/i386-linux-gnu/libc.so.6
libc.so.6 (GLIBC_2.4) => /lib/i386-linux-gnu/libc.so.6
libc.so.6 (GLIBC_2.1) => /lib/i386-linux-gnu/libc.so.6
libc.so.6 (GLIBC_2.3) => /lib/i386-linux-gnu/libc.so.6
libc.so.6 (GLIBC_2.2) => /lib/i386-linux-gnu/libc.so.6
libc.so.6 (GLIBC_2.7) => /lib/i386-linux-gnu/libc.so.6
libc.so.6 (GLIBC_2.0) => /lib/i386-linux-gnu/libc.so.6
libc.so.6 (GLIBC_2.3.4) => /lib/i386-linux-gnu/libc.so.6
The only thing I can't get is why I donn't have such problems in other static libraries which invokes GLibc poll as well?
To make the situation clear I used special GCC flag to display preprocessor output:
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -E")
.c.o includes poll.h and poll2.h and its content goes as following:
# 1 "/usr/include/i386-linux-gnu/bits/poll2.h" 1 3 4
# 24 "/usr/include/i386-linux-gnu/bits/poll2.h" 3 4
extern int __poll_alias (struct pollfd *__fds, nfds_t __nfds, int __timeout) __asm__ ("" "poll")
;
extern int __poll_chk (struct pollfd *__fds, nfds_t __nfds, int __timeout,
unsigned int __fdslen);
extern int __poll_chk_warn (struct pollfd *__fds, nfds_t __nfds, int __timeout, unsigned int __fdslen) __asm__ ("" "__poll_chk")
__attribute__((__warning__ ("poll called with fds buffer too small file nfds entries")));
extern __inline __attribute__ ((__always_inline__)) __attribute__ ((__gnu_inline__)) __attribute__ ((__artificial__)) int
poll (struct pollfd *__fds, nfds_t __nfds, int __timeout)
{
if (__builtin_object_size (__fds, 2 > 1) != (unsigned int) -1)
{
if (! __builtin_constant_p (__nfds))
return __poll_chk (__fds, __nfds, __timeout, __builtin_object_size (__fds, 2 > 1));
else if (__builtin_object_size (__fds, 2 > 1) / sizeof (*__fds) < __nfds)
return __poll_chk_warn (__fds, __nfds, __timeout, __builtin_object_size (__fds, 2 > 1));
}
return __poll_alias (__fds, __nfds, __timeout);
}
But library object file still has only upper poll symbol:
objdump -t lib.a | grep poll
00000000 UND 00000000 poll
So far I can't explain why tricky __poll_chk symbol is not added to the other libraries. But now my binary runs on any of target Linux hosts.