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

Ara*_*ind 11 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定义的符号吗?
  • 你能不能在这里看看我做错了什么?

Ara*_*ind 16

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

首先,必须使用-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已由链接描述文件定义.它确实覆盖了它.但是不会使用overriden值,因为已经定义了部分,因为已经使用了链接描述文件.

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

解:

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

SYMBOL_RAM_START = DEFINED( SYMBOL_RAM_START )?SYMBOL_RAM_START :DEFAULT_VALUE;

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

此解决方案并未真正覆盖符号,但提供了一种可以定义符号以便可以覆盖它的方法.