eCos编译Synthethic Target程序时无法解析__sprintf_chk的解决办法
mingdu.zheng <at> gmail <dot> com
http://blog.csdn.net/zoomdy/article/details/10615853
?
官方已解決此問題:
詳見:http://hg-pub.ecoscentric.com/ecos/rev/a1df75458e13
問題描述:
在Xubuntu 12.04下編譯eCos Synthetic Target的測(cè)試程序(通過eCos圖形配置工具菜單Build >> Tests),當(dāng)編譯cxxsupp測(cè)試程序時(shí)出現(xiàn)未解析符號(hào)“__sprintf_chk”。
?
錯(cuò)誤輸出:
gcc -L/home/pangu/ecos/conf/synth_default_install/lib -Ttarget.ld -o /home/pangu/ecos/conf/synth_default_install/tests/infra/current/tests/cxxsupp tests/cxxsupp.o -g -nostdlib -Wl,-static -Wl,--fatal-warnings make[1]:正在離開目錄 `/home/pangu/ecos/conf/synth_default_build/infra/current' /usr/lib/gcc/i686-linux-gnu/4.6/libsupc++.a(cp-demangle.o): In function `.L741': make:離開目錄“/home/pangu/ecos/conf/synth_default_build” (.text+0x4088): undefined reference to `__sprintf_chk' /usr/lib/gcc/i686-linux-gnu/4.6/libsupc++.a(cp-demangle.o): In function `.L747': (.text+0x45c3): undefined reference to `__sprintf_chk' /usr/lib/gcc/i686-linux-gnu/4.6/libsupc++.a(cp-demangle.o): In function `.L747': (.text+0x473b): undefined reference to `__sprintf_chk' /usr/lib/gcc/i686-linux-gnu/4.6/libsupc++.a(cp-demangle.o): In function `.L747': (.text+0x4833): undefined reference to `__sprintf_chk' /usr/lib/gcc/i686-linux-gnu/4.6/libsupc++.a(cp-demangle.o): In function `d_print_mod_list': (.text+0x62e9): undefined reference to `__sprintf_chk' collect2: ld 返回 1 make[1]: *** [/home/pangu/ecos/conf/synth_default_install/tests/infra/current/tests/cxxsupp] 錯(cuò)誤 1 make: *** [tests] 錯(cuò)誤 2?
解決辦法:
在packages\hal\synth\arch\<version>\src\synth_entry.c文件中追加以下代碼。
?
?
#include <stdarg.h> #include <limits.h> #include <stdio.h>// __chk_fail -- terminate a function in case of buffer overflow // copy from gcc-4.8.1/libssp/ssp.c void __chk_fail (void) {CYG_FAIL("Buffer overflow detected, aborting");diag_printf("Application error: buffer overflow detected.\n");cyg_hal_sys_exit(1);for(;;); }// __sprintf_chk -- convert formatted output, with stack checking // copy from gcc-4.8.1/libssp/sprintf-chk.c int __sprintf_chk (char *s, int flags __attribute__((unused)),size_t slen, const char *format, ...) {va_list arg;int done;va_start (arg, format);if (slen > (size_t) INT_MAX)done = vsprintf (s, format, arg);else{done = vsnprintf (s, slen, format, arg);if (done >= 0 && (size_t) done >= slen)__chk_fail ();}va_end (arg);return done; }?
問題原因:
1、Xubuntu 12.04,以及其它最近發(fā)行的Linux版本默認(rèn)開啟了GCC的堆棧保護(hù)特性,因此sprintf函數(shù)調(diào)用將會(huì)被替換為__sprintf_chk函數(shù)調(diào)用,__sprintf_chk除了實(shí)現(xiàn)sprintf的功能外還將檢查堆棧是否溢出。
2、new操作符的實(shí)現(xiàn)是由編譯器提供的(libsupc++.a),編譯eCos Synthetic Target時(shí)使用的是Linux下的本地編譯器,因此libsupc++.a是在打開堆棧保護(hù)特性的情況下編譯的,也就是說如果new操作符引用或者間接引用了sprintf函數(shù),那么實(shí)際引用的將是__sprintf_chk。
3、new操作符在分配內(nèi)存失敗時(shí)需要拋出異常,異常機(jī)制經(jīng)過一系列的函數(shù)調(diào)用,最終會(huì)調(diào)用cp-demangle.o文件內(nèi)的__cxa_demangle函數(shù)逆向解析C++名稱包裝,例如將_Znwj解析為operator new(unsigned int),__cxa_demangle引用了sprintf進(jìn)行字符串格式化,而在開啟GCC堆棧保護(hù)特性的情況下,sprintf自動(dòng)被替換為__sprintf_chk,在Xubuntu中,__sprintf_chk函數(shù)由glibc提供,而eCos Synthetic Target雖然編譯成Linux下的一個(gè)進(jìn)程,但是使用的仍然是eCos自帶的C庫,而不是Linux中的C庫,而eCos中的C庫并沒有實(shí)現(xiàn)__sprintf_chk函數(shù),因此在鏈接過程中產(chǎn)生無法解析的符號(hào)“__sprintf_chk”,解決辦法是實(shí)現(xiàn)該函數(shù)。
?
?
?
深入解析:
編譯器將new和delete操作符的相關(guān)代碼打包到libsupc++.a靜態(tài)庫(new_op.o和del_op.o),因此使用了new和delete操作符的程序?qū)⒁迷撿o態(tài)庫內(nèi)的相關(guān)代碼,根據(jù)C++標(biāo)準(zhǔn)要求,new操作符在內(nèi)存分配失敗是將拋出異常,從底層實(shí)現(xiàn)角度就是將會(huì)調(diào)用__cxa_throw函數(shù),而__cxa_throw函數(shù)引用了__cxxabiv1::__terminate_handler,這是一個(gè)函數(shù)指針,該函數(shù)指針指向__gnu_cxx::__verbose_terminate_handler函數(shù),該函數(shù)引用了cp-demangle.o文件內(nèi)的__cxa_demangle函數(shù),__cxa_demangle函數(shù)引用了__sprintf_chk,使用nm工具輸出.o文件符號(hào)可以非常清楚地看到函數(shù)間可能的調(diào)用關(guān)系,下面是nm工具的輸出,已刪除無關(guān)的符號(hào),T字母標(biāo)識(shí)的是該.o文件定義的符號(hào),U字母標(biāo)識(shí)的是該.o文件引用的符號(hào)。
?
?
?
new_op.o: 00000000 T _Znwj(operator new(unsigned int))U __cxa_throweh_throw.o:U _ZN10__cxxabiv119__terminate_handlerE(__cxxabiv1::__terminate_handler) 00000000 T __cxa_throweh_term_handler.o: 00000000 D _ZN10__cxxabiv119__terminate_handlerEU _ZN9__gnu_cxx27__verbose_terminate_handlerEv(__gnu_cxx::__verbose_terminate_handler())vterminate.o: 00000000 T _ZN9__gnu_cxx27__verbose_terminate_handlerEvU __cxa_demanglecp-demangle.o: 00006e20 T __cxa_demangleU __sprintf_chk具體的實(shí)現(xiàn)以及調(diào)用層次關(guān)系可以閱讀libsupc++的源代碼,位于gcc源代碼的libstdc++-v3\libsupc++目錄下。
?
補(bǔ)充說明:
cxxsupp是eCos用來測(cè)試C++支持的測(cè)試程序,其中使用了new和delete操作符,如果這個(gè)測(cè)試通不過意味著在應(yīng)用中不能夠使用new和delete操作符。默認(rèn)情況下new和delete操作符的實(shí)現(xiàn)代碼由編譯器提供,即使是eCos也是如此,除非進(jìn)行顯式地重定義覆蓋編譯器的默認(rèn)實(shí)現(xiàn)。
除了libsupc++.a之外,根據(jù)需要還將鏈接libgcc.a、libgcc_eh.a,這兩個(gè)靜態(tài)包同樣是由編譯器提供的。
總結(jié)
以上是生活随笔為你收集整理的eCos编译Synthethic Target程序时无法解析__sprintf_chk的解决办法的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: @click.stop作用(阻止点击事件
- 下一篇: VXLAN配置示例