Recently I moved my project to ubuntu 16.04 from ubuntu 14.04. When I compiled my project with gcc 4.8.5, which is installed from os repository, I encountered an error, "undefined __warn_memset_zero_len". I've never seen that error on ubuntu 14.04 with gcc 4.8.4.
__warn_memset_zero_len, which is declared in string3.h, is called from memset to warn programmer's mistake. To reproduce the error I made the following sample code and compiled it with gcc --save-temps test_mem.c -D_FORTIFY_SOURCE=1 -Wall -O1 -v -Wl,-v
#include <stdio.h>
#include <string.h>
int main ()
{
char str[] = "almost every programmer should know memset!";
memset (str, 1, 0);
puts (str);
return 0;
}
This code is also compiled only in ubuntu 14.04 with gcc 4.8.4. So, First, I assumed that the new libc might be missing the definition of __warn_memset_zero_len. To find out the definition, I compared the old libc of ubuntu 14.04 with that of ubuntu 16.04. The both versions do not have it and only have the function's declaration in string3.h. I was wrong. :<
As the next step, I assumed gcc might drop the reference to the function during compile as it is a special warning function. However, the object files created by both systems still have the reference, checked by nm. Then, the source code still need the definition of __warn_memset_zero_len. My thought moved on shared objects linked with the test code.
/usr/bin/ld --sysroot=/ --build-id --eh-frame-hdr -m elf_x86_64 \
--hash-style=gnu --as-needed -dynamic-linker /lib64/ld-linux-x86-64.so.2 \
-z relro /usr/lib/gcc/x86_64-linux-gnu/4.8/../../../x86_64-linux-gnu/crt1.o \
/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../x86_64-linux-gnu/crti.o \
/usr/lib/gcc/x86_64-linux-gnu/4.8/crtbegin.o \
-L/usr/lib/gcc/x86_64-linux-gnu/4.8 \
-L/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../x86_64-linux-gnu \
-L/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../../lib \
-L/lib/x86_64-linux-gnu -L/lib/../lib -L/usr/lib/x86_64-linux-gnu \
-L/usr/lib/../lib -L/usr/lib/gcc/x86_64-linux-gnu/4.8/../../..
test_mem.o -v -lgcc --as-needed -lgcc_s --no-as-needed -lc -lgcc \
--as-needed -lgcc_s --no-as-needed \
/usr/lib/gcc/x86_64-linux-gnu/4.8/crtend.o \
/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../x86_64-linux-gnu/crtn.o
This is the link commmand gcc uses to link the test code on ubuntu 14.04. I looked up all symbols of the linked objects and libraries, but cannot find __warn_memset_zero_len. The mystery is getting serious.
As the final try, I assumed that the attribute "warning" __warn_memset_zero_len's declaration uses might allow the old gcc to compile a code without definition. So I made the following test code.
extern void __warning_test (void) __attribute__((__warning__ ("test_warning")));
int main(){
__warning_test();
return 0;
}
Now, I can get the undefined symbol error on both systems.
/tmp/ccN1UbZh.o: In function `main':
test.c:(.text+0x5): undefined reference to `__warning_test'
collect2: error: ld returned 1 exit status
I have no clue why the compilation succeed in the old system without the definition of __warn_memset_zero_len and why it fail in the new one. In addition, why does the custom function which looks exactly same with __warn_memset_zero_len fail even on the old system? Do you have any idea on this issue?
__warn_memset_zero_len() is declared in /usr/lib/x86_64-linux-gnu/libc.a, which is a implicit library for gcc. you can use nm command to confirm it.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With