本文大致提點這個問題,有哪些可行的解決方案。
這是常見 C/C++ 的一類連接器錯誤,我們需要知道它一般是怎么產生的,才能知道如何正確的解決它。
例如:(當發生這類問題時,連接器通常會輸出這樣的信息)
[build] /usr/mips64el-linux-gnuabi64/include/c++/7/mips64el-linux-gnuabi64/bits/gthr-default.h:251:(.text+0x1c): relocation truncated to fit: R_MIPS_GOT_DISP against `__pthread_key_create@@GLIBC_2.0'
[build] CMakeFiles/xxx.dir/xxx/net/asio/websocket.cpp.o: In function `__gthread_mutex_lock(pthread_mutex_t*)':
[build] /usr/mips64el-linux-gnuabi64/include/c++/7/mips64el-linux-gnuabi64/bits/gthr-default.h:748:(.text+0x90): relocation truncated to fit: R_MIPS_CALL16 against `pthread_mutex_lock@@GLIBC_2.0'
[build] CMakeFiles/xxx.dir/xxx/net/asio/websocket.cpp.o: In function `__gthread_mutex_unlock(pthread_mutex_t*)': [build] /usr/mips64el-linux-gnuabi64/include/c++/7/mips64el-linux-gnuabi64/bits/gthr-default.h:778:(.text+0x114): relocation truncated to fit: R_MIPS_CALL16 against `pthread_mutex_unlock@@GLIBC_2.0'
通常出現這類連接器問題,多數是C++編譯器編譯CC/CPP源文件出來的 .obj(*.o)文件太大了,導致超出了一些平臺CPU可以短鏈接重定向的范圍。
注意:這個問題可能會在 MIPS、MIPS64 CPU架構上面較容易出現。
以下是可以采納的解決方案(逐個試)
1、拆分引起連接器暴這個錯誤的 cpp 文件(XXX.o 對應那個CPP文件)把這個源文件自己分析,按著拆分到多個 cpp 文件之中在編譯
2、按需配置C語言、C++ 語言的編譯器選項,增加編譯器選項?-mlong-calls
? ? ?-mlong-calls 編譯器選項是指:要求編譯器適用VA絕對地址(長地址)來調用跳轉,這樣呢,可以顯著解決因為 XXX.o 編譯出來的二進制太大,導致連接器無法連接上的問題。
? ? 但是缺點肯定是有的,那就是效率肯定沒有RVA相對地址(短地址)跳轉速度塊,因為絕對地址都是需要先放在寄存器之中的,在按照寄存器的值跳轉,不能直接JMP到絕對地址上面的,相當于每次都要多走一些流程,并且在CPU之中相對尋址本來就比隨機的絕對尋址要快的。
3、配置連接器選項,增加選項
1、嘗試使用 -Wl,--no-relax 選項來禁用鏈接器的放松(relocation relaxation)功能,這可能有助于解決一些符號重定位(truncated relocation)的問題。
2、使用 -Wl,--no-merge-exidx-entries 選項來禁止合并 .ARM.exidx 表條目,這可能有助于解決某些鏈接問題。
這條會有限制,C++ 17 直接沒法用了,而且 C++ 11 的一些模板展開特性也會受到限制,基本不是很推薦通過這條指令來解決,但如果真的必須要,無可避免、退無可退的情況下,您或許可以考慮設置它到連接器上面試試看,的確是有效的。
4、調整編譯器選項,增加選項
1、考慮添加 -fPIC 選項以生成位置無關代碼(Position Independent Code),這有助于減少一些鏈接時的問題。
2、也可以嘗試添加 -ffunction-sections -fdata-sections 選項來將函數和數據放置到單獨的段(section)中,這有助于優化鏈接器的處理。
在這些解決方案之中,相對更親民靠譜的解決方案還是編譯器增加選項:?-mlong-calls,另外就是手動拆分C/CPP源文件到多個之中了,畢竟平臺及編譯器限制也是沒有辦法不是。