长话短说.我希望学习如何创建一个好的链接器脚本,这样我就可以更改平台/架构/供应商,我不会再知道该做什么而再次停留在零点.我并不关心任务的难度,而是关心它.
我已经开始了一个项目,就是为STM的32位Cortex-M3芯片编程和开发创建基础或骨架.在jsiei97的帮助下,从STM32F103RB开始(我还有TI Stellaris LM3S828,但这是另一个问题),无需经过许可的IDE.由于我是学生,而且大多数学生都买不起这样的东西.
我知道有ODev,Eclipse插件和什么不是,并且已经阅读了各种博客,wiki,docs/man页面,大多数项目为您提供了一个链接器脚本,几乎无法解释为什么以及在哪里定义了事物.
我已经为STM32编译了一个arm-none-eabi工具链,但我挂起的是链接器脚本.CodeSourcery也需要一个.我有一个基本的概念,如何在阅读gnu手册页后创建它们和它们的语法,但我根本没有线索从哪个开始添加除了显而易见的.text,.bss和.data之外的各种额外部分.
我创建了一个基本版本,但是我得到链接错误,要求分区定义,这就是我遇到的问题.我知道如何定义它们,但知道我正在做的事情是否接近正确就是问题所在.
您好我有一个链接器脚本,我在其中找到了这个代码" __exidx_start = .;",它将标签值设置为位置计数器" ." 的值.此标签不在同一链接描述文件中的任何位置使用.
在第一个下方有一个类似的标签定义了几行,它的定义方式与" __exidx_end = .;" 相同.
这两个标签是边界.text和.rodata部分,但我不知道为什么有人会定义这两个,如果他们没有在链接器脚本中使用?
我想得到我的程序结束的地址,并在编译/链接器时检查我是否有足够的空间,在代码之后,在执行时间放置一些随机数据.
但是由于PROVIDE关键字提供的符号与C代码中的常规变量一样,我无法在编译时验证它.
在链接器脚本中我有符号:
PROVIDE (__data_end_rom = _etext + SIZEOF (.data));
Run Code Online (Sandbox Code Playgroud)
所以我可以用这个符号来获取代码结尾的地址:
extern u16 __data_end_rom;
Run Code Online (Sandbox Code Playgroud)
如果我认为结束地址是0xffff,我可以计算可用内存:
#define AVAILABLE_MEM (0Xffff - &__data_end_rom)
Run Code Online (Sandbox Code Playgroud)
我正在考虑使用gcc 4.6中提供的_Static_assert(cond,message)检查可用内存
_Static_assert(SIZE_I_WANT_TO_ASSURE <= AVAILABLE_MEM, "NOT ENOUGH MEMORY!!!");
Run Code Online (Sandbox Code Playgroud)
我的问题是:宏AVAILABLE_MEM不是在编译时计算的,所以我收到错误:
error: expression in static assertion is not constant
Run Code Online (Sandbox Code Playgroud)
有没有办法直接在标签中或以其他方式提供__data_end_rom地址?
我知道我无法在编译时得到它,因为符号只会在链接器时间内链接,所以有一些方法可以使链接器失败?
我可以直接在链接器脚本中检查这个,但我不喜欢这样做,因为SIZE_I_WANT_TO_ASSURE是从配置头中的其他宏计算的另一个宏.
链接库时,使用-rpath 将动态库的地址传递给ld。我的问题是,如果我在 LD_LIBRARY_PATH 中设置了地址,我的链接过程中还需要 -rpath 标志吗?
我在链接文件中创建了一些特殊部分,我希望它们位于不同的段中以具有不同的页面权限。
在链接描述文件中,PHDRS 命令可以指定链接文件中的段。但是,正如文档所说,除了命令中指定的之外,PHDRS 不会创建任何默认定义的段。我在ld --verbose输出中没有发现 PHDRS 命令。
有没有办法保留默认值?或者段的默认规范是什么,以便我可以在自己的链接器脚本中编写它们?
我知道最新的 STM32 微控制器中的 RAM 存储器包含几个具有显着速度差异的部分。这就是为什么我试图围绕这些设备的链接描述文件(注意:arm-none-eabi-gcc工具链)。不幸的是,CubeMX 为 STM32F767ZI 生成的链接描述文件只是忽略了 RAM 中的不同部分:
/* Specify the memory areas */
MEMORY
{
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 512K
FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 2048K
}
Run Code Online (Sandbox Code Playgroud)
STMicroelectronics 似乎已经做了一些努力,使其最新的STM32H743ZI的链接描述文件更加复杂:
/* Specify the memory areas */
MEMORY
{
DTCMRAM (xrw) : ORIGIN = 0x20000000, LENGTH = 128K
RAM_D1 (xrw) : ORIGIN = 0x24000000, LENGTH = 512K
RAM_D2 (xrw) : ORIGIN = 0x30000000, LENGTH = 288K …Run Code Online (Sandbox Code Playgroud) 我正在修改现有的.ld代码,并且我有两个闪存部分。这两个 Flash 部分并不连续,因此我不能仅仅扩展其中一个部分的定义以包含另一个部分。
目前所有代码都可以放入sec1,但如果我关闭空间优化,它就不适合。
问题
我该如何编写.ld才能说放置尽可能多的代码sec1,然后放置尽可能多的代码sec2,然后……sec3等等?
我知道如何将特定内容放在.obj特定部分中,但这不是我想要的,因为我需要.ld随着代码的变化不断修改。
我试图弄清楚如何访问链接器在运行时生成的构建 ID。
从该页面,https://linux.die.net/man/1/ld
当我构建一个测试程序时,例如:
% gcc test.c -o test -Wl,--build-id=sha1
Run Code Online (Sandbox Code Playgroud)
我可以看到二进制文件中存在构建 ID:
% readelf -n test
Displaying notes found in: .note.gnu.build-id
Owner Data size Description
GNU 0x00000014 NT_GNU_BUILD_ID (unique build ID bitstring)
Build ID: 85aa97bd52ddc4dc2a704949c2545a3a9c69c6db
Run Code Online (Sandbox Code Playgroud)
我想在运行时打印它。
编辑:假设您无法访问加载正在运行的进程的 elf 文件(权限、嵌入式/无文件系统等)。
编辑:接受的答案有效,但链接器不一定必须将变量放在该部分的末尾。如果有一种方法可以获取指向该部分开头的指针,那就更可靠了。
我正在从文本“Operating Systems from 0 to 1”中学习如何链接脚本,并且在文本中他们展示了一个使用关键字 PHDRS 的示例;
ENTRY(main);
PHDRS
{
headers PT_PHDR FILEHDR PHDRS;
code PT_LOAD FILEHDR;
}
SECTIONS /*top level command that declares a list of custom program sections, ld provides set of such instructions.*/
{
. = 0x10000; /* set location counter to address 0x10000, base address for subsequent commands */
.text : { *(.text) } :code /* final .text section begins at address 0x1000, combines all .text sections from obj files into one final*/
. = …Run Code Online (Sandbox Code Playgroud) linker-scripts ×10
c ×4
gcc ×4
linker ×3
arm ×2
elf ×2
stm32 ×2
bare-metal ×1
c++ ×1
compilation ×1
cortex-m3 ×1
embedded ×1
g++ ×1
gnu ×1