【问题标题】:What is __aeabi_unwind_cpp_pr1' and how can I avoid it?什么是 __aeabi_unwind_cpp_pr1',我该如何避免?
【发布时间】:2017-05-26 22:16:29
【问题描述】:

我有一堆 arm 程序集、C 和 C++ 文件。 gcc 正在尝试链接它们,但这些是针对嵌入式项目的。

我没有使用任何外部库,所有正在使用的代码都是由我编写的。似乎发生了错误,因为我在main.c 中定义了一个名为int kernel_main(void) 的函数,它试图调用mailbox.cpp 中定义的set_LED(int value),其中包括标题mailbox.h(我确实在main.c 中包含了标题文件)。

确切的错误是:

undefined reference to `__aeabi_unwind_cpp_pr1'

我制作项目的方式是: - 将所有源文件(.s、.c、.cpp)编译为目标文件(.o)而不使用链接(-c),然后使用自定义链接器脚本将它们链接在一起。

编辑:我将添加一些信息以使事情更清楚。

首先更改所有文件,使它们都是 C 文件(无 cpp 扩展名):

undefined reference to `set_LED'

问题本身不太可能是名称混淆,它可能与 CPP 和 C 的差异无关。

问题很可能是链接器问题

这是构建过程:

编译c文件,示例:

arm-none-eabi-g++ -O0 -march=armv8-a source/MainFiles/mailbox.cpp -nostartfiles -c -o objects/MainFiles/mailbox.o

(编译一个 C++ 文件将是相同的,除了使用 g++ 而不是 gcc)

链接一切:

arm-none-eabi-ld object1 object2... -o build/kernel.elf -T ./source/kernel.ld -I include_directory_1 -I include_directory_2 -L include_directory_1 -L indlude_directory_2

包含目录是当前目录下的所有目录

编辑: 错误又回来了。忽略此问题中与名称修改相关的部分。我需要修复的错误是:

./objects/Hardware/mailbox.o:(.ARM.exidx+0x18): undefined reference to `__aeabi_unwind_cpp_pr1'

到目前为止,我所知道的是,这与展开堆栈和异常有关。似乎该函数是在 libgcc 中定义的。但是我使用了-nostdlib,我省略了它,并且在这两种情况下错误仍然存​​在。我已尝试尽可能将文件扩展名更改为 .c 并尽可能更改为 .cpp,可惜错误始终存在。

只要我有 1 个 cpp 文件并且我的其余文件是 C 文件,它就得到了修复(这不再是真的,我试过了)。再次触发错误的是我正在重构代码,并且我想将几个函数移动到新文件中。

换句话说,在不删除单个文件的情况下,在mailbox.cpp 中声明一个名为wait(uint32_t time) 的函数可以工作,在名为time.c(或cpp)的文件中声明它,并使用其各自的标头声明并在邮箱中包含标头.cpp 打破了一切。注意我在移动函数时不会删除文件我只是删除每个文件中的函数声明。

像这样添加存根:

void __aeabi_unwind_cpp_pr1()
{

}

解决了问题并且代码有效。但我不喜欢这个解决方案。我不希望在我的代码中神秘地调用无用的存根。我在当前的实现中不需要也不想要这个函数,我怎么能告诉编译器或链接器他们要忽略他们正在做的任何需要这个函数的事情?

【问题讨论】:

  • 只是猜测,但unwind 部分听起来像是异常实现的一部分。
  • 我向编码之神发誓我并没有明确地使用异常
  • 你看过这篇stackoverflow.com/questions/27831735/…的帖子了吗?
  • 是的,并添加 -lgcc_eh。似乎对我没有任何作用
  • 我不知道 gcc 是否仍然支持-fno-exceptions,但如果支持,您可以尝试使用它进行编译,这样它就不会放入展开代码以防万一。构造函数抛出异常。

标签: c++ c gcc


【解决方案1】:

解决方案非常简单。事实证明,默认情况下会启用异常(这是生成调用__eabi_unwind_cpp_pr1 的代码的原因)。要禁用它们,只需通过: -fno-exceptions 作为 gcc/g++ 编译器的参数,问题就解决了。

【讨论】:

    【解决方案2】:

    您有一个属于 GCC 的 C++ 运行时的函数的引用。这是异常处理的一部分。不管你在做什么,听起来有点疯狂,但无论如何,如果你真的知道你在做什么,你就可以做到这一点。您必须链接 C++ 运行时库。就是这样。链接到“libstdc++”。

    关于 set_LED 我也相信这只是关于 C++ 修改,正如 Justin J 在另一个答案中提到的那样。

    【讨论】:

    • 这是一个“编译器定义”的库,还是一个实际的库?问题是,这是一个嵌入式项目,所以没有操作系统,如果这与异常处理有关,听起来它需要一个操作系统
    • 不,它不需要操作系统的任何东西来处理异常......您正在使用一些肯定会调用异常处理的代码。在幕后throw 只不过是一个启动堆栈展开过程的函数。顾名思义,这个函数与展开过程有关。一旦它是 GCC 特定的,就很难准确地说出来。我建议你看看这个链接:monoinfinito.wordpress.com/series/exception-handling-in-c
    【解决方案3】:

    我在混合 C 和 C++ 时看到了这一点。由于名称修改,符号在内部将根据源文件的类型具有不同的名称。

    如果 'set_LED' 的来源是 c 文件,请在原型周围的标题中使用以下内容,看看是否有帮助。

    #ifdef __cplusplus
    extern "C" {
    #endif
    
    // function prototypes here
    
    #ifdef __cplusplus
    }
    #endif
    

    【讨论】:

    • set_LED 的来源是一个 cpp 文件
    【解决方案4】:

    还请在 -fno-exceptions 中添加不带引号的前缀“-shared”。我使用的是 ARM GCC 版本

    【讨论】:

    • 它有什么作用,为什么要添加它?
    猜你喜欢
    • 1970-01-01
    • 2011-07-10
    • 2020-08-27
    • 2012-04-08
    • 2014-10-28
    • 2012-07-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多