如何防止 C++ 名称解构函数包含在二进制文件中

Posted

技术标签:

【中文标题】如何防止 C++ 名称解构函数包含在二进制文件中【英文标题】:How to prevent C++ name demangling functions from being included in binary 【发布时间】:2019-05-02 21:58:30 【问题描述】:

我正在使用 C++14 模式下的 GCC 7.3.1 为 ARM Cortex-M 上的 C++ 嵌入式应用程序开发固件。只有 64k 的闪存可用,而且我的二进制文件不适合。查看映射文件,我发现二进制文件中有一个名为__gcclibcxx_demangle_callback 的函数,它占用了 27k 闪存空间。我知道这与 C++ 名称拆解有关。链接器不会丢弃此符号,尽管我绝对没有在我的代码中进行任何名称解构。我在这里和那里使用 STL。如何消除此功能以获得一些闪存空间?

我尝试将-ffreestanding -fno-exceptions -nostartfiles -fno-rtti 传递给编译器和链接器。传递-nostdlib 会导致链接失败,即使我传递-lc -lg -lgcc -lstdc++

【问题讨论】:

只在发布模式下编译你的代码而不是调试? 你在编译什么优化级别? 尝试用-fdata-sections -ffunction-sections编译你的对象并用-Wl,--gc-sections链接,最后通过strip运行生成的二进制文件 这可能与 STL 库中内置的异常有关。 (可能有些人在 STL 深处捕捉到了一些东西)。在打开交叉引用的情况下进行构建,这样您就可以看到哪个符号需要它,然后找出它在哪里,等等。最后,您可能需要重新编译 STL 而没有例外(为什么这不是嵌入式中的默认设置)世界工具链,我不知道) @J.AntonioPerez 我在 -O0(没有优化),但我认为这不会影响链接。 【参考方案1】:

更多选项:

-Os -flto  -fno-fat-lto-objects -fuse-ld=gold -fuse-linker-plugin \
-Wl,--icf=all -Wl,--icf-iterations=4 -Wl,--gc-sections -Wl,--as-needed \
-Wl,--strip-all -Wl,-O3 -Wl,--orphan-handling=discard -Wl,--no-eh-frame-hdr \
-Wl,--no-ld-generated-unwind-info -fno-unwind-tables

错误更正--icf 专用于“黄金”)

我自己只是在学习,但如果不这样做,您可以开始修改链接器脚本...您可以通过在链接行上传递一个“隐式”链接器脚本到常设默认值( ld 尝试将任何看起来不像目标代码的东西作为脚本读取)。我最好的猜测是您需要将问题库分配给它自己的部分,然后丢弃它: >

链接器将忽略地址分配(*note Output Section 地址::) 在丢弃的输出节上,除非链接描述文件 在输出部分定义符号。在这种情况下,链接器将 遵守地址分配,即使 部分被丢弃。

特殊的输出节名称“/DISCARD/”可用于丢弃 输入部分。分配给输出的任何输入部分 名为“/DISCARD/”的部分不包含在输出文件中。

我觉得这真的不应该是这样,但也有--no-demangle...

编辑:如果您尝试使用-nostdlib 进行编译,您可能需要-lgcc_s -lsupc++ -lm-B `your/compiler/dir` 等的某种组合

【讨论】:

-fuse-linker=gold 不被链接器理解,它建议-fuse-ld=gold。传递所有这些标志会得到collect2: fatal error: cannot find 'ld',这是正确的,因为链接器应该是arm-none-eabi-ld。我不知道这是从哪里来的。乍一看,它可以通过一些 shell 别名技巧来解决,但我在这里停了下来,因为我找到了一个更通用的解决方案。非常感谢! nod -fuse-linker 是个脑残。不知道黄金不适用于 arm 编译,抱歉【参考方案2】:

@Russ Schultz 的评论让我思考。很可能确实是一些 STL 代码使用了名称解构,如果没有其他更适合嵌入式系统的 libstdc++,那将是令人惊讶的。显然,GNU Arm Embedded Toolchain 提供了 libstdc++ 的替代版本。一种是“nano”版本,可以通过将-specs=nano.specs 传递给链接器来轻松使用。这大大减少了生成的二进制文件的大小(115k 到 45k),并且粗略地看一下内容,它实际上只包含必要的符号。除了一些很小的 C++ vtable 之外,几乎没有代码膨胀。

【讨论】:

以上是关于如何防止 C++ 名称解构函数包含在二进制文件中的主要内容,如果未能解决你的问题,请参考以下文章

从二进制文件中删除 protobuf c++ 编译的路径字符串

如何防止 libtorrent 创建带有名称的文件夹?

C++:如何防止私有名称污染派生类型?

如何告诉 gcc 不要内联函数?

如何获取包含函数的名称[重复]

C++程序文件链接