最近我把我的項目從ubuntu 14.04移到了ubuntu 16.04。當我使用從os倉庫安裝的gcc 4.8.5編譯我的項目時,遇到了一個錯誤「undefined __warn_memset_zero_len」。我從來沒有見過與GNU 4.8.4的Ubuntu 14.04錯誤。string3.h中__warn_memset_zero_len的定義在哪裏
__warn_memset_zero_len,它在mem3set中被聲明,以警告程序員的錯誤。要重現錯誤我做了下面的示例代碼,並與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;
}
此代碼也與GCC 4.8.4編譯僅在Ubuntu 14.04編譯它。所以,首先,我認爲新的libc可能缺少__warn_memset_zero_len的定義。爲了找出這個定義,我比較了ubuntu 14.04的舊libc和ubuntu 16.04的舊libc。這兩個版本都沒有,只有string3.h中的函數聲明。我錯了。 :<
作爲下一步,我認爲gcc可能會在編譯期間刪除對該函數的引用,因爲它是一個特殊的警告函數。但是,由這兩個系統創建的對象文件仍然有參考,由nm檢查。然後,源代碼仍然需要__warn_memset_zero_len的定義。我的想法轉向與測試代碼鏈接的共享對象。
/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
這是gcc用來鏈接ubuntu 14.04測試代碼的鏈接命令。我查找了鏈接對象和庫的所有符號,但找不到__warn_memset_zero_len。神祕感正在變得嚴重。
作爲最後的嘗試,我認爲屬性「警告」__warn_memset_zero_len的聲明使用可能允許舊的gcc編譯一個沒有定義的代碼。所以我做了以下測試代碼。
extern void __warning_test (void) __attribute__((__warning__ ("test_warning")));
int main(){
__warning_test();
return 0;
}
現在,我可以在兩個系統上得到未定義的符號錯誤。
/tmp/ccN1UbZh.o: In function `main':
test.c:(.text+0x5): undefined reference to `__warning_test'
collect2: error: ld returned 1 exit status
我不知道爲什麼編譯在舊系統中,而不__warn_memset_zero_len的定義,以及爲什麼它無法在新的一個成功。另外,即使在舊系統上,爲什麼與__warn_memset_zero_len看起來完全相同的自定義函數失敗?你對這個問題有什麼想法嗎?
非常感謝。我不知道爲什麼,但在Ubuntu 16.04中的libc.a不包含那個符號。 – Hani
@Hani如函數名所示,該函數用於檢查memset的參數。從gcc5.0(這是Ubuntu16.04上的默認編譯器),這個參數檢查是在gcc中實現的,因此在libc.a中包含一個檢查函數變得沒有必要。因此它在Ubuntu16.04中被刪除。 – gzh