12

我的用例如下:

  • 我正在使用基于 Makefile 的项目附带的典型 SDK
  • 我相信链接器已修补 gcc。gcc --version 给我 4.3.4
  • SDK 定义了链接器脚本(我们称之为 Linker.ld)
  • Linker.ld 包括 LinkerMemMap.cfg,它定义了链接的 ELF 映像中各个部分的绝对地址
  • SDK 提供基于 Makefiles (GNU Make 3.81) 的应用程序模板,并自行制作
  • 在 SDK 提供的 Makefile 模板中,当调用gcc时,Linker.ld 提供了 -T 命令行选项,如下所示:

gcc $(OBJS) -l$(Lib1) -l$(Lib2) -nostdlib -lgcc -L$(library_path) -g -msmall-mode -mconst-switch-tables -mas-mode -mno-initc -Wl,--start-group,--end-group,-T,$(PATH_TO_Linker.ld),--gc-sections -o$(OUTPUT).elf

我的要求如下:

  • 我想使用 Linker.ld 中定义的部分,并按照 LinkerMemMap.cfg 使用内存映射,但是调整 LinkerMemMap.cfg 中定义的特定符号(我们称之为 SYMBOL_RAM_START)

什么有效:

  • 我已经在makefile中尝试过,在链接最终的ELF映像之前,将LinkerMemMap.cfg(包含在Linker.ld中)复制到构建目录并对其进行修补以重新定义SYMBOL_RAM_START。这确实有效,因为链接器首先在当前文件夹中搜索链接器脚本和链接器脚本包含的文件。

什么不:

  • 不幸的是,我们的利益相关者认为上述方法风险太大且太复杂而无法理解。我想用以下内容覆盖链接器命令行上的符号值:

    1. gcc $(OBJS) -l$(Lib1) -l$(Lib2) -nostdlib -lgcc -L$(library_path) -g -msmall-mode -mconst-switch-tables -mas-mode -mno-initc -Wl,--start-group,--end-group,-T,$(PATH_TO_Linker.ld),--gc-sections,--defsym=SYMBOL_RAM_START=$(VALUE_TO_OVERRIDE) -o$(OUTPUT).elf

    2. gcc $(OBJS) -l$(Lib1) -l$(Lib2) -nostdlib -lgcc -L$(library_path) -g -msmall-mode -mconst-switch-tables -mas-mode -mno-initc -Wl,--start-group,--end-group,-T,$(PATH_TO_Linker.ld),--gc-sections --defsym=SYMBOL_RAM_START=$(VALUE_TO_OVERRIDE) -o$(OUTPUT).elf

    3. gcc $(OBJS) -l$(Lib1) -l$(Lib2) --defsym=SYMBOL_RAM_START=$(VALUE_TO_OVERRIDE) -nostdlib -lgcc -L$(library_path) -g -msmall-mode -mconst-switch-tables -mas-mode -mno-initc -Wl,--start-group,--end-group,-T,$(PATH_TO_Linker.ld),--gc-sections -o$(OUTPUT).elf

这些似乎都对链接器创建的链接图像没有任何影响。

  • --defsym 可以覆盖使用 -T 指定的链接描述文件定义的符号吗?
  • 你们中的任何人都可以看看我在这里做错了什么吗?
4

1 回答 1

18

在等待有人回复时,我确实解决了这个问题。这里的问题几乎没有问题,我想向可能犯同样错误的人解释我的发现。

首先,任何要传递给链接器的选项都必须用-Xlinker 或-Wl 指定。因此 2 和 3 在上述情况下都不起作用。修正后的 2 和 3 如下:

  1. 已经正确了

  2. gcc $(OBJS) -l$(Lib1) -l$(Lib2) -nostdlib -lgcc -L$(library_path) -g -msmall-mode -mconst-switch-tables -mas-mode -mno-initc -Wl,--start-group,--end-group,-T,$(PATH_TO_Linker.ld),--gc-sections -Xlinker --defsym=SYMBOL_RAM_START=$(VALUE_TO_OVERRIDE) -o$(OUTPUT).elf

  3. gcc $(OBJS) -l$(Lib1) -l$(Lib2) -Xlinker --defsym=SYMBOL_RAM_START=$(VALUE_TO_OVERRIDE) -nostdlib -lgcc -L$(library_path) -g -msmall-mode -mconst-switch-tables -mas-mode -mno-initc -Wl,--start-group,--end-group,-T,$(PATH_TO_Linker.ld),--gc-sections -o$(OUTPUT).elf

现在对于上面的选项 1 和 2, --defsym 出现在链接描述文件之后,并且SYMBOL_RAM_START已经由链接描述文件定义。它确实覆盖它。但是不会使用被覆盖的值,因为这些部分已经被定义为链接描述文件已经被使用。

对于上述选项 3 的情况,SYMBOL_RAM_START是在链接器读取链接器脚本之前定义的。因此,当解析链接描述文件时,脚本中指定的值会覆盖它。

解决方案:

为了使其工作,链接描述文件需要有条件地初始化符号SYMBOL_RAM_START,如下所示:

SYMBOL_RAM_START =定义( SYMBOL_RAM_START )?SYMBOL_RAM_START : DEFAULT_VALUE ;

鉴于链接描述文件中的上述内容,当包含链接描述文件之前定义了SYMBOL_RAM_START时(如上面的选项 3 所示),它确实有效。但最后我不得不修补链接描述文件。

这个解决方案并没有真正覆盖符号,而是提供了一种可以定义符号的方法,以便可以覆盖它。

于 2012-04-11T17:02:11.390 回答