我的问题如下:
我正在尝试编写嵌入式应用程序,它必须提供自己的链接描述文件(使用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
符号
完全失踪了。当我将非主要功能从库中移出(进入项目)时,一切都很好。
我的理解是,链接器看到,我的应用程序中根本没有使用.start部分,这使得它跳过所有部分。我已经尝试添加几个属性来运行notmain,例如(__attribute__((used)) __attribute__((externally_visible))
),但它也不起作用(从最终的二进制文件中仍然没有遗漏)。
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部分?
答案 0 :(得分:3)
如您所知,静态库是目标文件的ar
存档。
假设libfoobar.a
仅包含foo.o
和bar.o
。联系:
g++ -o prog a.o foo.o bar.o # A
与链接相同:
g++ -o prog a.o -lfoobar. # B
链接器无条件地消耗链接序列中的每个目标文件,
所以在A
的情况下,它会在a.o
中链接foo.o
,bar.o
,prog
。
链接器不无条件地使用作为其成员的每个目标文件 链接序列中的静态库。静态库是一种提供的方式 链接器是一堆目标文件,可以从中选择所需的文件。
假设a.o
调用foo
中定义的函数foo.o
,并且
a.o
引用bar.o
中未定义的任何内容。
在这种情况下,链接器无条件地将a.o
链接到prog
,之后
prog
包含对foo
的未定义引用,链接器需要该引用
定义。接下来它到达libfoobar.a
并检查存档(通过其索引,
通常)查看档案的任何成员是否定义foo
。它发现foo.o
有
所以。因此,它从存档中提取foo.o
并链接它。它不需要定义
对于bar.o
中定义的任何符号,因此bar.o
不会添加到链接中。该
链接B
与:
g++ -o prog a.o foo.o
另一方面,假设a.o
调用了bar
bar.o
,foo.o
,
和引用B
中没有定义任何内容。在这种情况下,链接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
的链接将被链接。
案例与您的-Wl,--undefined=notmain
相同。如果您想要链接,您可以执行以下操作之一: -
将notmain
添加到您的关联选项中(将notmain
替换为
对于C ++,错误的notmain
名称。这将使链接器假设它具有
对EXTERN(notmain)
的未定义引用,即使它没有看到任何内容。
将命令notmain
添加到链接描述文件中(再次进行修改
对于C ++)。这相当于 1 。
显式链接定义notmain.cpp
的目标文件。不要把它放在静态库中。
3 实际上是您在发现:
时所做的当我将非主要功能移出图书馆(进入项目)时,它会很好。
对于 3 ,您不需要 来编译项目中的notmain.o
和其他任何内容
需要/usr/local/lib
的项目。您可以单独构建它,安装它
在/usr/local/lib/notmain.o
中明确添加crt*.o
你的项目的联系。那将明确遵循GCC本身的例子
通过附加它们来链接普通程序的/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
启动文件
链接的绝对名称,例如
<%
while (rs.next()) {
%>
<%=StringUtils.defaultString(rs.getString("program"), "")%><br />
<input type="hidden" class="program" name="program" value="<%=StringUtils.defaultString(rs.getString("program"), "")%>" />
<%
}
%>