Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Where is the definition of __warn_memset_zero_len in string3.h

Tags:

c

linux

gcc

linker

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?

like image 420
Hani Avatar asked Oct 29 '22 10:10

Hani


1 Answers

__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.

like image 122
gzh Avatar answered Nov 15 '22 05:11

gzh