Kürzlich habe ich mein Projekt auf Ubuntu 16.04 von Ubuntu 14.04 verschoben. Als ich mein Projekt mit gcc 4.8.5 kompiliert habe, das von os-Repository installiert wird, habe ich einen Fehler gefunden, "undefined __warn_memset_zero_len". Ich habe diesen Fehler auf ubuntu 14.04 mit gcc 4.8.4 noch nie gesehen.Wo ist die Definition von __warn_memset_zero_len in string3.h
__warn_memset_zero_len, das in string3.h deklariert ist, wird von memset aufgerufen, um den Fehler des Programmierers zu melden. Um den Fehler zu reproduzieren habe ich den folgenden Beispielcode und es kompiliert mit 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;
}
Dieser Code auch nur in Ubuntu 14.04 mit gcc 4.8.4 kompiliert wird. Also, zuerst nahm ich an, dass die neue libc möglicherweise die Definition von __warn_memset_zero_len nicht enthält. Um die Definition herauszufinden, habe ich die alte libc von ubuntu 14.04 mit der von ubuntu 16.04 verglichen. Die beiden Versionen haben es nicht und haben nur die Erklärung der Funktion in string3.h. Ich habe mich geirrt. : <
Als nächsten Schritt nahm ich an, gcc könnte den Verweis auf die Funktion während der Kompilierung fallen lassen, da es eine spezielle Warnfunktion ist. Die Objektdateien, die von beiden Systemen erstellt werden, haben jedoch immer noch die Referenz, die von nm überprüft wird. Dann benötigt der Quellcode immer noch die Definition von __warn_memset_zero_len. Mein Gedanke ging mit dem Testcode verknüpfte gemeinsame Objekte weiter.
/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
Dies ist der gcc Link commmand verwendet den Testcode auf Ubuntu 14.04 zu verbinden. Ich habe alle Symbole der verknüpften Objekte und Bibliotheken nachgeschlagen, aber __warn_memset_zero_len nicht gefunden. Das Geheimnis wird ernst.
Als letzten Versuch, nahm ich an, dass das Attribut "Warnung" __warn_memset_zero_len Deklaration verwendet möglicherweise die alten gcc einen Code ohne Definition zu kompilieren. Also habe ich den folgenden Testcode erstellt.
extern void __warning_test (void) __attribute__((__warning__ ("test_warning")));
int main(){
__warning_test();
return 0;
}
Jetzt kann ich den undefinierten Symbolfehler auf beiden Systemen erhalten.
/tmp/ccN1UbZh.o: In function `main':
test.c:(.text+0x5): undefined reference to `__warning_test'
collect2: error: ld returned 1 exit status
Ich habe keine Ahnung, warum die Zusammenstellung ohne die Definition von __warn_memset_zero_len im alten System erfolgreich zu sein und warum es in dem neuen scheitern. Warum schlägt die benutzerdefinierte Funktion, die mit __warn_memset_zero_len identisch aussieht, auch auf dem alten System fehl? Hast du eine Idee zu diesem Thema?
Vielen Dank. Ich weiß nicht warum, aber libc.a in ubuntu 16.04 enthält dieses Symbol nicht. – Hani
@Hani Wie der Funktionsname zeigt, wird diese Funktion verwendet, um die Argumente von memset zu überprüfen. Von gcc5.0, dem Standardcompiler unter Ubuntu16.04, wird diese Argumentprüfung in gcc implementiert, sodass es nicht mehr notwendig ist, eine Prüffunktion in libc.a einzubinden. Daher wird es in Ubuntu16.04 entfernt. – gzh