问题标签 [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.
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() 默认使用。但我无法在任何地方找到明确的解释来证实这一点。
如果有人可以解决这个问题,请提前感谢。
linker - 是否有允许我移动堆栈起始地址的链接器脚本指令?
我正在尝试使用 x86_64 上的链接器脚本更改堆栈的起始位置。我可以使用以下方法移动我的可执行文件起始地址:
我像这样改变了我的全局变量:
我尝试使用以下内容来移动堆栈区域:
但这并没有让我到任何地方。
这是我用来测试堆栈位置的测试程序:
这是我从 gcc 的默认链接器脚本的输出(没有修改):
这是我的链接器脚本的输出:
由于 nm 输出新位置,我真的很困惑:
虽然我什至不确定 stack_start 和 stack_end 在 x86_64 上是否有效,因为我从 arm online 的链接器脚本教程中得到了那部分。我的链接器脚本没有收到任何错误或警告,所以我不确定发生了什么。
如果您想知道为什么有人会这样做 - 它对安全研究有影响。
有没有办法使用链接器脚本做我想做的事?我简直不敢相信我可以移动我的 .text、.bss 和 .data 部分,但不能移动堆栈。
更新:这是从http://www.lurklurk.org/linkers/linkers.html#os获取的解释,说明为什么使用链接器无法做到这一点:
“你可能已经注意到,到目前为止所有关于目标文件和链接器的讨论都只讨论了全局变量;没有提到前面提到的局部变量和动态分配的内存。这些数据不需要任何链接器参与,因为它们的生命周期只发生在程序运行时——在链接器完成其业务很久之后。”
c - 在链接描述文件中提取存档文件
我正在尝试处理如下问题:
假设我有一个库 libxyz.a 创建自:
编译和存档:
我如何编写链接描述文件才能将 abc.o 准确地放在预期的位置?
我试图以这种方式处理它:
但运行后:
我得到:
我在论坛的链接器文件中找不到任何提取档案的示例。我唯一找到的是链接器的文档,它只包含有关archive:file
构造的信息。
c++ - 通过函数指针定义“main”
在 C++ 中,main 是否可以由函数指针定义?例如:
此代码可以正确编译和链接,但在运行时会触发分段错误。我相信这可能是因为它试图将函数指针的值作为代码执行。
此外,如果在纯 C++ 中不可能,那么可以通过 gcc 的非标准功能来实现(可能以某种方式更改导出符号的类型)。
最后,如果使用 gcc 指令无法实现,是否可以使用自定义链接器脚本来完成?
cortex-m3 - 当两个固件使用相同的链接描述文件链接时,为什么复位向量的地址会不同?
我有一个 Cortex-M3 芯片,我正在运行一个使用 eCos 的引导加载程序。引导加载程序在检查固件更新等后,跳转到实际应用程序所在的 ROM 上的另一个位置(BASE_ADDRESS_OF_APP + 0x19)(也使用 eCos 编译)。
现在,我不想运行普通固件,而是想运行为 Cortex-M3 目标编译的 CppUTests。因此,我能够使用 ecos glibc 编译和链接目标平台的测试,而不是实际的操作系统。但是当我使用 JTAG 将它加载到我的板上时,它不会运行。
在使用 arm-eabi-objdump 进行一些调查后,我发现 CppUTest 固件的重置向量位于 0x490 的偏移量处,而普通固件的偏移量为 0x18。我怀疑这就是为什么永远不会执行测试的原因。这个对吗?
当我将它们与相同的链接描述文件链接时,这两个固件怎么可能有不同的起始地址?
如何确保测试程序的起点与应用程序的起点相同?
c - 如何防止隐式链接描述文件更改部分的 LMA
我正在为软件使用模块化构建系统,而不是在 ARM 嵌入式目标以及普通 X86 (linux) 机器上运行。我正在使用 GNU 工具链进行编译,因此使用ld
.
其中一个模块使用链接脚本技巧来组装一组“已注册”对象。这些对象是使用这样的宏创建的:
该模块还向链接步骤添加了一个隐式链接器脚本,如下所示:
代码使用regobj_table_start
和regobj_table_end
符号来查找已注册的对象。此解决方案适用于本机 (Linux) 编译目标。
但是,这不适用于 ARM 目标。原因是我有一个用于目标的自定义默认链接器脚本(它是一个微型微控制器,在没有操作系统的情况下运行),它定义了该.data
部分的加载内存地址。这是因为该部分存储在闪存中,但是一旦微控制器启动,它就会被复制到 RAM。链接描述文件的相关部分如下所示:
这会将.data
部分的 VMA 设置为 0x4000000 范围内的某个位置,并将 LMA 设置为 0x00000000 范围内的某个位置。
问题是,当隐式链接器脚本被添加到命令行时ld
,它只是忘记了 LMA,它再次变得等于 VMA。我正在拼命寻找一种方法来告诉ld
在加载隐式链接器脚本时不要触摸 LMA。
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 和谷歌搜索中搜索,但我无法找到答案。
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”进行搜索,但一无所获。
我在哪里可以找到这些符号的规格?
ld - ld 链接器脚本产生巨大的二进制文件
我正在使用binutils-2.21.53.0.1-6.fc16.x86_64
.
我有一个小目标文件,hello.o
只有足够的“东西”来包含所有部分的内容:
如果我使用-pie
并且没有链接器脚本,则结果与预期一致:
但是,如果我包含任何类型的链接器脚本,输出大小会爆炸:
如您所见,这个文件变得很大。
请注意,这似乎是因为该.text
部分坚持从文件中的偏移量 0x200000 开始:
无论我的链接描述文件的内容如何,这种情况一直在发生。有什么想法吗?
gcc - 将 gcc libs .data 放在特定部分?
我正在尝试为我们的嵌入式系统切换到 GNU GCC 编译器,但是由于我们芯片的内存布局被拆分,我无法链接项目:
我们项目中的数据可以放在第 1 节中,但从 gcc 库链接的数据不适合。地图文件提取:
是否可以将库中的 .data 部分放在第二部分?我尝试了不同的事情但没有成功......链接器脚本提取: