GCC - 如何告诉链接器不要跳过未使用的部分

大维派

我的问题如下:

我正在尝试编写嵌入式应用程序,它必须提供自己的链接器脚本(使用 arm-none-eabi-gcc 编译器/链接器)。

嵌入式引导加载程序加载二进制文件并从 0x8000 地址开始,这就是为什么我需要一个专用的链接器脚本,它允许我将所需的启动功能放入该地址。脚本代码如下:

MEMORY
{
    ram : ORIGIN = 0x8000, LENGTH = 0x1000
}

SECTIONS
{
    .start : { *(.start) } > ram
    .text : { *(.text*) } > ram
    .bss : { *(.bss*) } > ram
}

有了这个,我现在想做的是有一个函数,它将插入到 .start 部分,使其位于 0x8000 的开头。为此,在我的库中,我使用以下函数:

__attribute__((section(".start"))) void notmain() {
    main();
}

这似乎工作正常,但后来我将这个库与函数notmain与定义main()函数的项目链接起来在链接过程中,我可以看到.start部分不再存在并且notmain符号完全丢失。当我将 notmain 函数移出库(移入项目)时,一切正常。

我的理解是,链接器看到,在我的应用程序中根本没有使用 .start 部分,这使得它跳过所有部分。我已经尝试向函数 notmain 添加几个属性,例如 ( __attribute__((used)) __attribute__((externally_visible))) 但它也不起作用(最终二进制文件中仍然缺少 notmain )。

CMake源代码如下:

** 项目 **

project(AutomaticsControlExample)

enable_language(ASM)

set(CMAKE_CXX_STANDARD 14)

set(SOURCES main.cpp PID.hpp)
set(DEPENDENCIES RPIRuntime PiOS)

add_executable(${PROJECT_NAME} ${SOURCES})
target_link_libraries(${PROJECT_NAME} ${DEPENDENCIES})
add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
        COMMAND ${CMAKE_OBJDUMP} -D ${PROJECT_NAME}
        COMMAND ${CMAKE_OBJDUMP} -D ${PROJECT_NAME} > ${PROJECT_NAME}.list
        COMMAND ${CMAKE_OBJCOPY} ${PROJECT_NAME} -O binary ${PROJECT_NAME}.bin
        COMMAND ${CMAKE_OBJCOPY} ${PROJECT_NAME} -O ihex ${PROJECT_NAME}.hex)

** 图书馆 **

project(RPIRuntime)

enable_language(ASM)

set(CMAKE_CXX_STANDARD 14)

set(LINKER_SCRIPT memmap)
set(LINKER_FLAGS "-T ${CMAKE_CURRENT_SOURCE_DIR}/${LINKER_SCRIPT}")


set(SOURCES
        notmain.cpp
        assert.cpp)

add_library(${PROJECT_NAME} STATIC ${SOURCES})
target_link_libraries(${PROJECT_NAME} ${LINKER_FLAGS})

我的问题是:有什么办法可以防止链接器省略链接 .start 部分?

迈克·金汉

如您所知,静态库是ar目标文件存档。

假设libfoobar.a只包含foo.obar.o一个联动:

g++ -o prog a.o foo.o bar.o     # A

一样的联动:

g++ -o prog a.o -lfoobar.   # B

链接器无条件地使用链接序列中的每个目标文件,因此在情况下A,它链接a.o, foo.o, bar.oin prog

链接器不会无条件地使用作为链接序列中静态库成员的每个目标文件。静态库是一种向链接器提供一堆目标文件的方法,从中可以选择需要的文件。

假设a.o调用了foo在 中定义的函数foo.o并且没有a.o引用 中定义的任何内容bar.o

在这种情况下,链接器无条件地链接a.oprog,之后prog包含对 的未定义引用foo,链接器需要对其进行定义。接下来它到达libfoobar.a并检查档案(通常通过其索引)以查看档案的任何成员是否定义了foo. 它发现foo.o确实如此。所以它foo.o从档案中提取并链接它。它不需要对 中定义的任何符号进行定义bar.o,因此bar.o不会添加到链接中。链接B完全相同:

g++ -o prog a.o foo.o

另一方面,假设在中定义的a.o调用并且没有引用 中定义的任何内容在这种情况下,链接与以下内容完全相同:barbar.ofoo.oB

g++ -o prog a.o bar.o

因此,默认情况下,您插入静态库以与可执行文件链接的目标文件将永远不会被链接,除非它为至少一个已引用但未定义的目标文件中的符号提供定义链接。

您的函数notmain未在main.o您在程序中显式链接的唯一目标文件中引用因此,当main.o被链接到您的程序时,该程序不包含对 的未定义引用notmain:链接器不需要定义notmain- 它从未听说过notmain- 并且不会从静态库中链接任何目标文件来获取notmain. 这与链接部分无关。

将普通程序与静态库链接时,您当然可以这样做:

g++ -o prog main.o x.o ... -ly -lz ....

其中一个*.o文件 - 比如说main.o- 是定义main函数的目标文件您永远不会放入main.o静态库之一。这是因为,在普通程序中,main不会在您显式链接的任何其他目标文件中调用,因此如果main.o在您的库之一中,则链接:

g++ -o prog x.o ... -ly -lz ...

不需要main在 中的任何一个找到 的-ly -lz ...定义,main也不会链接 的定义

情况与您的notmain. 如果您希望将其链接,您可以执行以下操作之一:-

  1. 添加-Wl,--undefined=notmain到您的链接选项(替换为 C++notmain的损坏名称notmain)。这将使链接器假定它有一个未定义的引用,notmain即使它没有看到任何引用

  2. 将命令添加EXTERN(notmain)到您的链接器脚本中(再次使用 C++ 的 mangling)。这相当于1

  3. 显式链接定义了notmain. 不要把它放在静态库中。

3是您在发现以下内容时所做的有效操作:

当我将 notmain 函数移出库(移入项目)时,一切正常。

对于3,但是,你没有需要编译notmain.cpp你的项目和其他项目的需求notmain.o您可以独立构建、安装它/usr/local/lib并明确添加/usr/local/lib/notmain.o到项目的链接中。这将遵循 GCC 本身的例子,它crt*.o通过将它们的绝对名称附加到链接中来显式链接普通程序启动文件,例如

/usr/lib/gcc/x86_64-linux-gnu/6/../../../x86_64-linux-gnu/crti.o
...
/usr/lib/gcc/x86_64-linux-gnu/6/../../../x86_64-linux-gnu/crtn.o

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

如何告诉CMake向GCC指定多个链接描述文件?

来自分类Dev

如何使gcc跳过预处理?

来自分类Dev

如何强制 gcc 编译器/链接器从可执行文件中删除未使用的静态数组

来自分类Dev

GCC:如何告诉GCC将“主要”功能放在.text部分的开头?

来自分类Dev

GCC - 如何阻止 malloc 被链接?

来自分类Dev

GCC链接目录

来自分类Dev

链接期间的GCC标志

来自分类Dev

Linux gcc链接问题

来自分类Dev

链接期间的GCC标志

来自分类Dev

GCC链接静态库

来自分类Dev

GCC:未使用的退货警告

来自分类Dev

如何告诉GCC映射包含目录?

来自分类Dev

告诉autoconf使用不同版本的gcc

来自分类Dev

如何使gcc ftrapv工作?

来自分类Dev

如何使msys识别gcc?

来自分类Dev

如何安装gcc 4.7?

来自分类Dev

如何安装gcc 4.7?

来自分类常见问题

使用-(存档-)gcc命令

来自分类Dev

GCC不使用inc

来自分类Dev

使用gcc的文件格式

来自分类Dev

使用-(存档-)gcc命令

来自分类Dev

使用gcc的文件格式

来自分类Dev

使用旧版GCC

来自分类Dev

跳过不兼容的目录 - gcc

来自分类Dev

GCC链接器:传递多个--wrap = <function>

来自分类Dev

gcc链接器:使用了哪些输入库?

来自分类Dev

尝试使用GetProcessImageFileName时,GCC(MinGW)链接器失败

来自分类Dev

GCC:在链接器中使用-O3优化标志

来自分类Dev

使用sqrt函数(C,gcc)时的链接器问题