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的测试程序(通过eCos图形配置工具菜单Build >> Tests),当编译cxxsupp测试程序时出现未解析符号“__sprintf_chk”。
 

错误输出:

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] 错误 1
make: *** [tests] 错误 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,以及其它最近发行的Linux版本默认开启了GCC的堆栈保护特性,因此sprintf函数调用将会被替换为__sprintf_chk函数调用,__sprintf_chk除了实现sprintf的功能外还将检查堆栈是否溢出。
2、new操作符的实现是由编译器提供的(libsupc++.a),编译eCos Synthetic Target时使用的是Linux下的本地编译器,因此libsupc++.a是在打开堆栈保护特性的情况下编译的,也就是说如果new操作符引用或者间接引用了sprintf函数,那么实际引用的将是__sprintf_chk。
3、new操作符在分配内存失败时需要抛出异常,异常机制经过一系列的函数调用,最终会调用cp-demangle.o文件内的__cxa_demangle函数逆向解析C++名称包装,例如将_Znwj解析为operator new(unsigned int),__cxa_demangle引用了sprintf进行字符串格式化,而在开启GCC堆栈保护特性的情况下,sprintf自动被替换为__sprintf_chk,在Xubuntu中,__sprintf_chk函数由glibc提供,而eCos Synthetic Target虽然编译成Linux下的一个进程,但是使用的仍然是eCos自带的C库,而不是Linux中的C库,而eCos中的C库并没有实现__sprintf_chk函数,因此在链接过程中产生无法解析的符号“__sprintf_chk”,解决办法是实现该函数。

 

 

 

深入解析:

编译器将new和delete操作符的相关代码打包到libsupc++.a静态库(new_op.o和del_op.o),因此使用了new和delete操作符的程序将引用该静态库内的相关代码,根据C++标准要求,new操作符在内存分配失败是将抛出异常,从底层实现角度就是将会调用__cxa_throw函数,而__cxa_throw函数引用了__cxxabiv1::__terminate_handler,这是一个函数指针,该函数指针指向__gnu_cxx::__verbose_terminate_handler函数,该函数引用了cp-demangle.o文件内的__cxa_demangle函数,__cxa_demangle函数引用了__sprintf_chk,使用nm工具输出.o文件符号可以非常清楚地看到函数间可能的调用关系,下面是nm工具的输出,已删除无关的符号,T字母标识的是该.o文件定义的符号,U字母标识的是该.o文件引用的符号。

 

 

 

new_op.o:
00000000 T _Znwj(operator new(unsigned int))
         U __cxa_throw
         
eh_throw.o:
         U _ZN10__cxxabiv119__terminate_handlerE(__cxxabiv1::__terminate_handler)
00000000 T __cxa_throw


eh_term_handler.o:
00000000 D _ZN10__cxxabiv119__terminate_handlerE
         U _ZN9__gnu_cxx27__verbose_terminate_handlerEv(__gnu_cxx::__verbose_terminate_handler())


vterminate.o:
00000000 T _ZN9__gnu_cxx27__verbose_terminate_handlerEv
         U __cxa_demangle


cp-demangle.o:
00006e20 T __cxa_demangle
         U __sprintf_chk

具体的实现以及调用层次关系可以阅读libsupc++的源代码,位于gcc源代码的libstdc++-v3\libsupc++目录下。

 

补充说明:

cxxsupp是eCos用来测试C++支持的测试程序,其中使用了new和delete操作符,如果这个测试通不过意味着在应用中不能够使用new和delete操作符。默认情况下new和delete操作符的实现代码由编译器提供,即使是eCos也是如此,除非进行显式地重定义覆盖编译器的默认实现。
除了libsupc++.a之外,根据需要还将链接libgcc.a、libgcc_eh.a,这两个静态包同样是由编译器提供的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值