【问题标题】:conditional statements for linker command language LD链接器命令语言 LD 的条件语句
【发布时间】:2016-06-18 05:06:19
【问题描述】:

GNU LD 链接器命令语言是否有条件语句?

上下文:我正在为 arm cortex m0+ 开发固件,该固件由引导加载程序和应用程序组成。两者都在单独的项目中进行编译和闪存,但我使用了一个框架,其中包含指向驱动程序、makefile 和加载程序脚本的符号链接,这样我就可以为我制作的每个应用程序重用这些文件,而无需为每个应用程序复制这些文件。 目前我有两个加载器文件,用于引导加载器和应用程序(makefile 自动指定适当的一个),内存分配如下:

引导加载程序

MEMORY { 
  flash (rx)  : ORIGIN = 0x00000000, LENGTH = 16K
  ram   (rwx) : ORIGIN = 0x1FFFF000, LENGTH =  16K
}

应用程序

MEMORY { 
  flash (rx)  : ORIGIN = 0x00004000, LENGTH = 112K
  ram   (rwx) : ORIGIN = 0x1FFFF000, LENGTH =  16K
}

像 makefile 一样,我想将它们合并成这样的东西(使用 C 表达式来澄清)

MEMORY { 
#ifdef(bootloaderSymbol)
  flash (rx)  : ORIGIN = 0x00000000, LENGTH = 16K
#else
  flash (rx)  : ORIGIN = 0x00004000, LENGTH = 112K
#endif
  ram   (rwx) : ORIGIN = 0x1FFFF000, LENGTH =  16K
}

【问题讨论】:

  • 查看一些 Linux 内核链接器脚本。它们是高度宏观化的,并且始终是您可以使用 GCC 和 Binutils 做的各种疯狂事情的​​一个很好的例子。

标签: ld cortex-m linker-scripts


【解决方案1】:

虽然它不是它的主要目的,但您始终可以运行 C 预处理器 (cpp) 在您的链接器脚本上:

#if defined(MACHINE1)
#    define TARGET_ADDRESS 0x80000000
#    define SDRAM_START xxx
#    define SDRAM_SIZE yyy
#    define ROMFLAGS   rx
#elif defined(MACHINE2)
#    define TARGET_ADDRESS 0x40000000
#    define SDRAM_START zzz
#    define SDRAM_SIZE  aaa
#    define ROMFLAGS rwx
#else
#    error unknown machine
#endif

MEMORY
{
   rom (ROMFLAGS) : ORIGIN = TARGET_ADDRESS, LENGTH = 0x00100000
   ram (WX) : ORIGIN = SDRAM_START + SDRAM_SIZE - 0x00200000, LENGTH = 0x00100000
   driver_ram (WX) : ORIGIN = SDRAM_START + SDRAM_SIZE - 0x00100000, LENGTH = 0x00100000
}

...

您只需要确保您的宏不会与链接描述文件语法冲突。然后将您的链接器脚本保存为 xxx.lk.in(而不是 xxx.lk)并将配方添加到您的 Makefile:

xxx.lk: xxx.lk.in
        $(CPP) -P $(INCLUDE) -D$(MACHINE) $< $@

剩下要做的就是将 xxx.lk 作为依赖项添加到您的最终可执行文件构建配方中。我在我的许多项目中都成功地使用了类似的流程。

【讨论】:

  • 这个方法有效!我还采用了以下技巧: 1. 将 -P 添加到预处理器的调用中,以抑制行号输出。否则,我使用的链接器 (arm-none-eabi-ld) 不接受已处理的脚本。 2. 我将 FORCE 作为假依赖添加到依赖项中,因为您可以在不编辑 xxx.lk.in 的情况下更改 MACHINE,这不会触发对 xxx.lk 的重新处理。但是,显然,更改 MACHINE 正是您想要替换 xxx.lk 的原因。
  • @joop:我处理它的方式是使用包含文件。我没有直接在链接器脚本中定义宏,而是 #include 根据 MACHINE 单独定义文件。稍微谨慎一点,这些可以写成我也可以(重新)使用它们作为“真正的”C 包括只有一个地方来关心平台特价。忘了提到-P 开关,很高兴你自己找到了。
  • 还没有足够的声誉来支持这个答案,但也将所有内容都放在头文件中,正是我需要的!
【解决方案2】:

我以前也走过同样的路,后来发现有一个 ld 命令行参数来指定段原点,这减少了在链接描述文件中找出它的需要。从手册页:

   -Tbss=org
   -Tdata=org
   -Ttext=org
       Same as --section-start, with ".bss", ".data" or ".text" as the section name.

因此,在您的情况下,您将拥有 -Ttext=0(引导加载程序)或 -Ttext=0x00004000(应用程序)

【讨论】:

  • 所以如果我正确理解我现在所拥有的 MEMORY { flash (rx) : ORIGIN = FLASH_ORG, LENGTH = FLASH_LEN } SECTIONS { vectors : { *(.vectors) } &gt;flash 将成为 LD 的调用,没有链接器脚本,而是 -Tvectors=0x0
  • 是的。这也将起作用。但是,请注意它不是(完全)相同的东西。 MEMORY 允许您告诉链接器定义区域之外的内存在物理上不可用。如果您尝试在定义的区域之外生成代码,您将收到一条错误消息。使用段起始地址,您不会(仅当它们重叠时)。如果您的代码最终超出设备的限制,MEMORY 可以避免令人头疼的问题。
【解决方案3】:

我觉得你可以根据https://sourceware.org/binutils/docs/ld/Builtin-Functions.html试试“DEFINED(symbol)”

另外,请不要忘记将“--defsym=bootloaderSymbol=1”传递给 ld。

MEMORY {
    flash (rx)  : ORIGIN = DEFINED(bootloaderSymbol) ? 0x00000000 : 0x00004000, LENGTH = DEFINED(bootloaderSymbol) ? 112K : 16K
    ram   (rwx) : ORIGIN = 0x1FFFF000, LENGTH =  16K
}

【讨论】:

  • 我确认建议的解决方案至少适用于 GNU ld(用于 Arm 嵌入式处理器的 GNU 工具 7-2018-q2-update)2.30.0.20180329。
猜你喜欢
  • 2023-03-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-01-13
  • 1970-01-01
  • 2010-09-21
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多