2017-03-24 6 views
2

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?

Antwort

1

__warn_memset_zero_len() ist in /usr/lib/x86_64-linux-gnu/libc.a deklariert, was eine implizite Bibliothek für gcc ist. Sie können den Befehl nm verwenden, um dies zu bestätigen.

+0

Vielen Dank. Ich weiß nicht warum, aber libc.a in ubuntu 16.04 enthält dieses Symbol nicht. – Hani

+1

@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

0

Ich vermute, dass dies ein absichtlicher Fehler ist, durch diese Linie verursacht wird:

memset (str, 1, 0); 

Die Erklärung für memset ist:

void *memset(void *s, int c, size_t n); 

Beachten Sie, dass Ihre Größe/Länge Wert Null ist. Was Sie wirklich wollen, ist vielleicht so etwas wie folgt aus:

char str[] = "almost every programmer should know memset!"; 
memset (str, 0, sizeof str); 

Edit: rereading Ihre Post, merke ich, Sie könnten absichtlich diesen Fehler zu schaffen sein? Aber vielleicht versuchst du zu viel hineinzulesen. Es könnte sein, dass gcc zu einem späteren Zeitpunkt in der Compiler-Optimierung das Problem sieht, aber zu spät, um einen spezifischen Fehler zu erhalten, sodass ein Link-Fehler einen Stopp erzwingt.

Und noch ein Gedanke: Es gibt eine geringe Chance, dass der Compiler str in den schreibgeschützten Speicher setzen könnte, weil er denkt, dass dies eine Zeichenfolge ist. Wenn das passiert, wird Ihr memset sowieso sterben. I denke, Sie sind okay, obwohl str auf dem Stapel gespeichert ist (d. H. Innerhalb einer Funktion deklariert und nicht statisch).

Verwandte Themen