问题标签 [linker-scripts]

For questions regarding programming in ECMAScript (JavaScript/JS) and its various dialects/implementations (excluding ActionScript). Note JavaScript is NOT the same as Java! Please include all relevant tags on your question; e.g., [node.js], [jquery], [json], [reactjs], [angular], [ember.js], [vue.js], [typescript], [svelte], etc.

0 投票
3 回答
10470 浏览

linker - 了解 GNU 链接描述文件的位置计数器

我正在从事一个大学项目,我正在从头开始为 Atmel SAM7S256 微控制器编写软件。这比我以前使用过的其他 MCU 更深入,因为这次需要了解链接器脚本和汇编语言。

我一直在仔细研究 SAM7S 芯片的示例项目,以便完全了解如何从头开始启动 SAM7/ARM 项目。一个值得注意的例子是 Miro Samek 的“使用 GNU 构建裸机 ARM 系统”教程,可在此处找到(此问题中的代码来自哪里)。我还花了很多时间阅读 sourceware.org 上的链接器和汇编器文档。

我很高兴我在很大程度上理解了以下链接器脚本。只有一件事涉及位置计数器,这对我来说没有意义。以下是上述教程提供的链接器脚本:

在整个示例中(例如在 .ramvect、.fastcode 和 .stack 部分中)都有符号定义,例如__ram_start = .;. 启动汇编代码和初始化 C 代码使用这些地址来初始化 MCU RAM 中的正确位置。

我有一个问题理解是这些符号定义如何导致分配正确的值。这确实发生了,脚本是正确的,我只是不明白如何。

按照我的理解,当您在一个部分中使用位置计数器时,它只包含与该部分本身的虚拟内存地址 (VMA) 的相对偏移量。

因此,例如,在该行__ram_start = .;中,我希望 __ram_start 被分配一个值 0x0 - 因为它在 .ramvect 部分的最开头被分配了位置计数器的值。但是,为了使初始化代码正常工作(确实如此),必须将 __ram_start 分配为 0x00200000(RAM 开头的地址)。

我原以为这只会按预期工作,如果该行改为__ram_start = ABSOLUTE(.);__ram_start = ADDR(.ramvect);.

__fastcode_start和也是如此__stack_start__。它们不能都被定义为地址 0x0,否则程序将无法运行。但是此处链接的文档似乎表明这就是应该发生的事情。这是文档中的引用:

笔记: 。实际上是指从当前包含对象开始的字节偏移量。通常这是 SECTIONS 语句,其起始地址为 0,因此 . 可以用作绝对地址。如果 。但是,在节描述中使用,它指的是从该节开始的字节偏移量,而不是绝对地址。

因此,在这些符号分配期间的位置计数器值应该从相应的部分 VMA 偏移。所以那些“_start”符号应该设置为0x0。这会破坏程序。

所以很明显我错过了一些东西。我想这可能只是将位置计数器值分配给一个符号(在一个部分内)导致 ABSOLUTE() 默认使用。但我无法在任何地方找到明确的解释来证实这一点。

如果有人可以解决这个问题,请提前感谢。

0 投票
1 回答
1542 浏览

linker - 是否有允许我移动堆栈起始地址的链接器脚本指令?

我正在尝试使用 x86_64 上的链接器脚本更改堆栈的起始位置。我可以使用以下方法移动我的可执行文件起始地址:

我像这样改变了我的全局变量:

我尝试使用以下内容来移动堆栈区域:

但这并没有让我到任何地方。

这是我用来测试堆栈位置的测试程序:

这是我从 gcc 的默认链接器脚本的输出(没有修改):

这是我的链接器脚本的输出:

由于 nm 输出新位置,我真的很困惑:

虽然我什至不确定 stack_start 和 stack_end 在 x86_64 上是否有效,因为我从 arm online 的链接器脚本教程中得到了那部分。我的链接器脚本没有收到任何错误或警告,所以我不确定发生了什么。

如果您想知道为什么有人会这样做 - 它对安全研究有影响。

有没有办法使用链接器脚本做我想做的事?我简直不敢相信我可以移动我的 .text、.bss 和 .data 部分,但不能移动堆栈。


更新:这是从http://www.lurklurk.org/linkers/linkers.html#os获取的解释,说明为什么使用链接器无法做到这一点:

“你可能已经注意到,到目前为止所有关于目标文件和链接器的讨论都只讨论了全局变量;没有提到前面提到的局部变量和动态分配的内存。这些数据不需要任何链接器参与,因为它们的生命周期只发生在程序运行时——在链接器完成其业务很久之后。”

0 投票
2 回答
1556 浏览

c - 在链接描述文件中提取存档文件

我正在尝试处理如下问题:

假设我有一个库 libxyz.a 创建自:

编译和存档:

我如何编写链接描述文件才能将 abc.o 准确地放在预期的位置?

我试图以这种方式处理它:

但运行后:

我得到:

我在论坛的链接器文件中找不到任何提取档案的示例。我唯一找到的是链接器的文档,它只包含有关archive:file构造的信息。

0 投票
8 回答
899 浏览

c++ - 通过函数指针定义“main”

在 C++ 中,main 是否可以由函数指针定义?例如:

此代码可以正确编译和链接,但在运行时会触发分段错误。我相信这可能是因为它试图将函数指针的值作为代码执行。

此外,如果在纯 C++ 中不可能,那么可以通过 gcc 的非标准功能来实现(可能以某种方式更改导出符号的类型)。

最后,如果使用 gcc 指令无法实现,是否可以使用自定义链接器脚本来完成?

0 投票
1 回答
286 浏览

cortex-m3 - 当两个固件使用相同的链接描述文件链接时,为什么复位向量的地址会不同?

我有一个 Cortex-M3 芯片,我正在运行一个使用 eCos 的引导加载程序。引导加载程序在检查固件更新等后,跳转到实际应用程序所在的 ROM 上的另一个位置(BASE_ADDRESS_OF_APP + 0x19)(也使用 eCos 编译)。

现在,我不想运行普通固件,而是想运行为 Cortex-M3 目标编译的 CppUTests。因此,我能够使用 ecos glibc 编译和链接目标平台的测试,而不是实际的操作系统。但是当我使用 JTAG 将它加载到我的板上时,它不会运行。

在使用 arm-eabi-objdump 进行一些调查后,我发现 CppUTest 固件的重置向量位于 0x490 的偏移量处,而普通固件的偏移量为 0x18。我怀疑这就是为什么永远不会执行测试的原因。这个对吗?

当我将它们与相同的链接描述文件链接时,这两个固件怎么可能有不同的起始地址?

如何确保测试程序的起点与应用程序的起点相同?

0 投票
1 回答
1287 浏览

c - 如何防止隐式链接描述文件更改部分的 LMA

我正在为软件使用模块化构建系统,而不是在 ARM 嵌入式目标以及普通 X86 (linux) 机器上运行。我正在使用 GNU 工具链进行编译,因此使用ld.

其中一个模块使用链接脚本技巧来组装一组“已注册”对象。这些对象是使用这样的宏创建的:

该模块还向链接步骤添加了一个隐式链接器脚本,如下所示:

代码使用regobj_table_startregobj_table_end符号来查找已注册的对象。此解决方案适用于本机 (Linux) 编译目标。

但是,这不适用于 ARM 目标。原因是我有一个用于目标的自定义默认链接器脚本(它是一个微型微控制器,在没有操作系统的情况下运行),它定义了该.data部分的加载内存地址。这是因为该部分存储在闪存中,但是一旦微控制器启动,它就会被复制到 RAM。链接描述文件的相关部分如下所示:

这会将.data部分的 VMA 设置为 0x4000000 范围内的某个位置,并将 LMA 设置为 0x00000000 范围内的某个位置。

问题是,当隐式链接器脚本被添加到命令行时ld,它只是忘记了 LMA,它再次变得等于 VMA。我正在拼命寻找一种方法来告诉ld在加载隐式链接器脚本时不要触摸 LMA。

0 投票
1 回答
731 浏览

c - 如何编译和链接示例代码以获取二进制文件?

我正在使用 TI Stellaris LM3S1968。该 MCU 具有 ARM Cortex-M3。

我在装有 Windows 7 的笔记本电脑上安装了一个 VM,并在那里安装了GNU Tools for ARM Embedded Processors。然后我安装了Stellaris Flash Programmer、GUI 和命令行。我还安装了Stellaris FTDI 驱动程序

最后,我下载并解压了EK-LM3S1968 固件开发包

在提取的文件夹中,有一些示例。其中之一是眨眼的。如果我去 /StellarisWare/board/ek-lm3s1968/blinky/gcc/ 有一个名为 blinky.bin 的文件。使用 Stellaris Flash Programmer,我可以将它连接到我的计算机并对其进行闪存,它会工作的。我尝试了各种示例,它们都有效。

现在我的目标是编译 /StellarisWare/board/ek-lm3s1968/blinky/ 中提供的示例代码,并将其烧写。但是,我运气不佳,因为我对 C 或微控制器编程不是很有经验。

我将 LM3S1968 库从 StellarisWare 文件夹复制到编译器的包含文件夹。然后我按照我在网上找到的一些例子,但我没有成功。这是我尝试过的:

当我刷新这个 .bin 文件时,它什么也没做,LED 一直亮着。

我认为这是因为有一个 startup_gcc.c 文件,它处理在运行程序之前启动 MCU。但我不确定如何捆绑它。

有很多文件适用于不同的 IDE,但它们不是免费的,所以我想使用 GNU 工具。

我尝试在 StackOverflow 和谷歌搜索中搜索,但我无法找到答案。

0 投票
4 回答
35963 浏览

gcc - 了解 __libc_init_array

我从http://newlib.sourcearchive.com/documentation/1.18.0/init_8c-source.html查看了 __libc_init_array 的源代码。
但我不太明白这个函数的作用。

我知道这些符号

在链接描述文件中定义。
部分链接描述文件可能如下所示:

然后我在 ELF-v1.1、gcc 4.7.2、ld 和 codesourcery(我正在使用 codesourcery g++ lite)的文档中使用键“init_array”进行搜索,但一无所获。

我在哪里可以找到这些符号的规格?

0 投票
3 回答
3529 浏览

ld - ld 链接器脚本产生巨大的二进制文件

我正在使用binutils-2.21.53.0.1-6.fc16.x86_64.

我有一个小目标文件,hello.o只有足够的“东西”来包含所有部分的内容:

如果我使用-pie并且没有链接器脚本,则结果与预期一致:

但是,如果我包含任何类型的链接器脚本,输出大小会爆炸:

如您所见,这个文件变得很大。

请注意,这似乎是因为该.text部分坚持从文件中的偏移量 0x200000 开始:

无论我的链接描述文件的内容如何,​​这种情况一直在发生。有什么想法吗?

0 投票
1 回答
1459 浏览

gcc - 将 gcc libs .data 放在特定部分?

我正在尝试为我们的嵌入式系统切换到 GNU GCC 编译器,但是由于我们芯片的内存布局被拆分,我无法链接项目:

我们项目中的数据可以放在第 1 节中,但从 gcc 库链接的数据不适合。地图文件提取:

是否可以将库中的 .data 部分放在第二部分?我尝试了不同的事情但没有成功......链接器脚本提取: