GNU LD:如何覆盖由-T指定的链接描述文件定义的符号值(地址)

时间:2012-04-05 16:43:21

标签: gcc ld linker-scripts

我的用例如下:

  • 我使用的是基于Makefile的项目附带的典型SDK
  • 我相信链接器是修补gcc的。 gcc --version给了我4.3.4
  • SDK定义链接器脚本(让我们称之为Linker.ld)
  • Linker.ld包含LinkerMemMap.cfg,它定义链接ELF图像中各个部分的绝对地址
  • SDK提供基于Makefile(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?
  • 指定的linkerscript定义的符号
  • 你们有没有人能看到我在这里做错了什么?

1 个答案:

答案 0 :(得分:15)

在等待某人回复时,我确实解决了这个问题。这里的问题很少,我想为可能犯同样错误的人解释我的发现。

首先必须使用-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

  4. 现在针对选项1&在上面的图2中,--defsym在链接器脚本之后, SYMBOL_RAM_START 已经由链接器脚本定义。它确实覆盖了它。但是不会使用overriden值,因为已经定义了部分,因为已经使用了链接器脚本。

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

    解决方案:

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

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

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

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