问题标签 [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 投票
1 回答
1946 浏览

c - 是否可以将命令行参数传递给 GNU LD 以创建一个部分、定义大小并将其放置在特定的内存中?

我想在 RAM 中创建一个部分,分配一个特定的大小并将其放置一个地址?是否可以在不传递链接描述文件“文件”或不修改现有链接描述文件的情况下完成所有这些操作?

是否可以使用 GNU LD/GCC 在命令行中执行链接器脚本完成的所有操作?

0 投票
1 回答
1213 浏览

c - gcc:你能把函数指针指向不同的部分(不是.data)吗?

为了在主机上对嵌入式项目进行单元测试,我开始使用函数指针来在函数的“真实”实现和运行时的模拟之间进行切换。所以,我的函数 'foo' 在 .c 文件中看起来像这样:

结果表明,目标处理器(Blackfin)产生了异常,因为函数指针驻留在内部 L1 数据存储器中,不允许携带代码,只能携带数据。

一种可行的解决方案是为每个函数指针分配一个属性,以便将其放入不驻留在 L1 数据存储器中的不同部分,例如:

但这使代码有点难以阅读并且容易出错(如果您忘记分配属性,单元测试将运行良好,但代码将在目标上调用该函数时立即生成异常)。

所以我的问题是,是否有某种方法可以告诉 gcc 默认将所有函数指针指向不同的部分。

0 投票
1 回答
1354 浏览

linker - 使用 sprintf() 时出现链接错误

在我的 cortex-m3 上,我试图将一个浮点变量输出到我的 UART 端口。所以我需要将其float DATA转换为char outputstr[].

为此,我使用了 libc.a 中的 sprintf

  1. 如果我注释掉 sprintf(),我可以编译和链接。
  2. 如果我使用sprintf(outputstr, "t"),我可以编译和链接。
  3. 如果我使用sprintf(outputstr, "The value is %f", DATA),我会得到链接错误,例如:没有为可加载部分指定内存区域`.rodata','.bss','.text','.data'

但我已经在我的链接器脚本中添加了 *(.rodata)、*(.bss) 等...,如下所示:

另外,我确实在我的makefile中包含了lib路径和包含路径,如下所示:

另一方面,我也在使用libc.a 和 libgcc.a 中的和,这些函数可以编译、链接并正常工作strlen()other float division operations

  1. 有人可以建议吗?

  2. 另外,如果我遇到链接错误消息,例如:没有为可加载部分“.rodata”指定内存区域...我如何知道哪个对象的(.o).rodata 部分被排除在我的链接器脚本之外?


更新:我意识到如果在 main() 中调用了 sprintf() 函数,程序可以编译和链接成功.. 但是如果我在其他函数中调用 sprintf() 函数,我会得到上面的链接错误(没有内存区域指定为可加载部分 .bss),即使我使用 *(.bss) 作为输出部分的输入部分。

0 投票
1 回答
830 浏览

c - 使用cmake编译和链接两个文件?

我的项目中有两个文件。
一个是“.c”文件,一个是“.asm”文件。首先,我将这两个文件编译成两个“.o”目标文件,然后使用自定义链接器脚本链接在一起。
目前,我正在使用带有手动命令的简单 bash 脚本来构建项目,但随着项目规模的增加,我正在考虑将项目转移到使用 cmake 作为其主要构建系统。

我已经搜索了 cmake 的文档并在 Google 上搜索了很多时间,尽管我已经将 cmake 中的一些变量列入了候选名单,这些变量在这种情况下可能被证明是有用的,但我找不到任何解释如何实现这一点的示例。

任何人都可以为我提供一个简短的示例代码,说明我应该如何实现这一目标?

0 投票
0 回答
117 浏览

c++ - 在 RAM 中锁定 Linux 进程的选择性代码和数据页

当我使用 mlockall 将所有进程锁定在内存中时,我有一个运行内存占用约为 150MB 的多线程 Linux 应用程序。这样做是为了避免一些具有低延迟要求的高优先级线程的页面错误。但是,只有选择执行流/上下文具有这样的要求,我试图仅为这些流锁定代码和数据,以便我可以减少进程的锁定内存占用。这个想法是将所有这些功能收集在一个单独的文本部分中,然后锁定页面。该想法的蓝图如下

这种方法的灵感来自嵌入式系统上采用的方法,其中一部分代码需要重新定位在 RAM 中,而其余部分则留在 ROM 中。我有以下疑问
1.这可以通过动态(gnu)链接器/加载器实现吗?
2.如何为动态加载的共享库指定页面锁定。
3.是否有更好的方法或工具来仅锁定已识别的代码和数据部分。

0 投票
1 回答
785 浏览

c - 链接描述文件不起作用?

我有一个非常简单的程序(simple.c):

我正在尝试使用以下链接器脚本(MEMORY):

我正在使用以下命令进行编译和链接:

gcc -c 简单的.c

ld -T MEMORY -o simple -dynamic-linker /lib64/ld-linux-x86-64.so.2 /usr/lib/x86_64-linux-gnu/crt1.o /usr/lib/x86_64-linux-gnu/ crti.o /usr/lib/x86_64-linux-gnu/crtn.o simple.o

我收到以下错误:

如果我尝试使用:

ld -T MEMORY4 -o simple -dynamic-linker /lib64/ld-linux-x86-64.so.2 /usr/lib/x86_64-linux-gnu/crt1.o /usr/lib/x86_64-linux-gnu/ crti.o /usr/lib/x86_64-linux-gnu/crtn.o simple.o -lc

它给出了错误

ld:找不到-lc

有什么建议么?我要做的就是将我的 simple.c 放入一些不同的内存区域,然后默认。

0 投票
1 回答
770 浏览

linker - 如何在 CCSv5 中为整个项目设置对齐方式?

我需要在 TI Code Composer Studio 5.5(TI ARM 编译器 5.1.1)中为整个项目设置链接器对齐方式。

这是我的链接器 .cmd 文件:

.align 8没有做这项工作。在生成的映射文件中,我可以看到许多地址以 4 或 C 结尾的符号。如果所有符号都对齐为 8 的倍数,我应该得到仅以 0 或 8 结尾的地址。

将链接器对齐设置为 64 位的正确命令是什么?

0 投票
1 回答
104 浏览

gcc - 如果引用了某个符号,则导致链接失败

如果代码引用库中的某个符号,有没有办法使链接失败?

我似乎依稀记得链接器脚本语言中有这样的指令,但显然它不是 GNU LD(也许是错误的记忆)。

我需要它来防止第三方库的某些部分意外链接到应用程序。如果它确实链接,它会添加一些在运行时造成严重破坏的静态初始化程序(它是一个嵌入式项目,因此环境有点古怪)。我无法更改有问题的第三方库。我想在构建时检测错误。我想我可以编写一个构建后脚本来解析映射文件并在找到有问题的部分时发出错误,但是上面提到的 [false?] 内存提示我确定它不能单独使用链接器来完成。

我正在使用 GNU GCC 工具链。

0 投票
1 回答
819 浏览

attributes - 为什么使用 __attribute__ (section) 进行一些内存分配?

我有foo[NUMBYTES] __attribute__((section(".bar")));

为什么使用这个属性 .bar 部分?因为 foo[] 已经提供了一些内存空间。这是为了方便内存管理吗?

0 投票
1 回答
844 浏览

c - 将 memcpy 移动到另一个代码部分

我正在构建一个旨在在 ARM Cortex-M0+ 微控制器上运行的软件。它包括一个 USB 引导加载程序,在调用函数时作为辅助程序运行。我memcpy在编译期间插入函数时遇到问题。

背景

链接描述文件是一切开始的地方。其中大部分都非常简单和标准。该程序也存储在.text其中并从那里执行。里面的所有东西都.text存储在芯片的闪存部分。

奇怪的是引导加载程序运行的部分。为了能够在不覆盖引导加载程序代码的情况下写入所有闪存,我的引导加载程序入口点将引导加载程序程序的副本启动到微控制器的 SRAM 部分,然后从那里执行它。这样,引导加载程序可以安全地擦除设备上的所有闪存,而不会无意中删除自身。

这是通过在链接器脚本中做一个伪造的“覆盖”来实现的(真实的OVERLAY与我的用例不太匹配):

_end_flash是对上一节末尾的引用,它将所有数据存储在闪存中(.text基本上.rodata所有.init只读的东西都会卡在那里)。

这样做的结果是.dataand.bss部分通常位于 RAM 中。但是,这些.bootloader部分也位于 RAM 中的相同位置。编译时,这两个部分都按顺序存储到闪存中。在我的crt0例程中,该.data部分从闪存复制到 RAM 中的相应地址(由 指定_start_data),并且该.bss部分被归零。我在该部分.text中存储了一个附加部分,该部分通过将其数据从闪存复制到 RAM 来启动引导加载程序,覆盖.data和中的任何内容.bss。引导加载程序的唯一退出是系统重置,因此它可以破坏正在运行的程序的数据。将引导加载程序复制到 RAM 后,它会执行它。

问题

显然,编译覆盖程序并确保所有引用都对齐可能存在一些问题。为了减轻从普通程序访问引导加载程序代码或从普通程序或引导加载程序访问的问题.data.bss我在链接器脚本中有以下三行:

现在,每当我在.text(可能被引导加载程序擦除)、.data(引导加载程序位于其之上)或.bss(再次,引导加载程序位于其之上)和该.bootloader部分之间存在交叉时,编译器错误将是发布。

在我真正开始编写代码之前,这很有效。我的部分代码包括一些结构复制和其他类似的东西。显然,编译器决定这样做(bootloader_函数位于该.bootloader部分中):

在我的芯片架构中,0x20000000直到大约的地址0xE000000都位于 SRAM 中(设备上实际上只有 4Kb)。下面的任何地址0x1fffffc00都位于闪存部分。

问题是这样的:在位于我的.bootloader部分 ( ) 的函数中,插入了对( 、和)bootloader_usb_endp0_handler的引用,因为我正在执行结构复制等操作。它所引用的地址是地址,它存在于闪存中……可以被擦除。memcpy2000039c200005622000056cmemcpy0x00000869

具体代码是:

where setup_tis a two-word struct and bdt->addris avoid*我知道指向看起来像 a 的数据setup_t。此行生成对 的调用memcpy

我的问题是:我真的很想保留我的结构复制。这很方便。有没有办法指定编译器将 memcpy 放入默认部分以外的特定部分?我希望仅针对引导加载程序模块发生这种情况。所有其他代码都可以memcpy...我只想为我的引导加载程序模块提供一份特殊的.bootloader副本

如果这根本不可能,我将要么在汇编中编写整个引导加载程序(不是那么有趣),要么走单独编译引导加载程序的路线,将它作为一个相当长的十六进制字符串包含在最终程序中,然后执行将其复制到 RAM 后的字符串。字符串路线对我的吸引力不是很好,因为它易碎且难以实施......所以任何其他建议也将不胜感激。

该模块的编译行是:

通常优化会是-Os,但我试图摆脱memcpy......它没有用。

另外,我看过这个问题,但没有解决问题。