【问题标题】:How do I specify manual relocation for GCC code?如何为 GCC 代码指定手动重定位?
【发布时间】:2016-09-04 14:41:04
【问题描述】:

我在嵌入式系统(xtensa 处理器)中处于需要手动覆盖符号的情况,但该符号恰好位于另一个符号的中间。当我尝试使用-Wl,--wrap=symbol 时,它不起作用,因为符号不是它自己的东西。

我需要做的是指定(最好在 GCC .S 中,尽管 .c 也可以)代码将在哪里结束。虽然实际的符号会被编译器随机放置在某个地方,但我会memcpy将代码放到正确的位置。

40101388 <replacement_user_vect>: 40101388: 13d100 wsr.excsave1 a0 4010138b: 002020 esync 4010138e: 011fc5 call0 4010258c <_UserExceptionVector_1>

我的问题是 GCC 使用相对跳转创建程序集,假设代码将位于闪存中的位置,而最终位置将固定在中断向量中。我如何告诉 GCC / GNU “将代码放在任何你想要的地方,但是,相信我它实际上会从 {这里} 执行”

虽然我的代码位于 0x40101388(GCC 决定),但它最终会驻留在 0x40100050 并执行。我如何通过告诉它“将代码放在这里”来欺骗 GCC,但假装它位于“这里”

编辑:我能够解决这个问题,事实证明,我需要修改的函数单独保存在链接描述文件中。我能够在链接器脚本中将其切换出来。虽然我仍然很想知道答案,但我现在有一个变通办法。

【问题讨论】:

  • gcc 或 gas 不会重定位任何代码。它们不是链接器。而 relative 跳转根据定义是与位置无关的。不清楚你的问题是什么(以及“在另一个符号中间”是什么意思)。请参阅How to Ask,提供足够的信息。
  • 您可以在as 中定义一个特定的符号,即出现在代码中的某处。链接器无法重新定位,但我不知道为什么。在我的测试中,您似乎可以重新定位完全独立的符号,例如函数,但如果它在函数中间看到某些东西,它就不会重新定位。不知道为什么。
  • 您的第一段没有意义,但是如果我忽略了这一点,那么您可以通过将要复制的代码放在它自己的部分中,然后使用链接器脚本告诉它将被复制到的链接器。看来 Linux 内核确实可以看到lxr.free-electrons.com/source/arch/xtensa/kernel/vmlinux.lds.S 中的SECTION_VECTOR
  • 你不能修改向量表以指向你的符号吗?我觉得很奇怪,你可以在0x40100050 复制一些东西而不会造成某种损害,但你不能直接在可执行文件中指定它的内容。或者0x40100050 是否有系统/默认代码,您的代码稍后会在其他地方加载?由于 jmp/call 是相对的,只要将所需的所有代码复制到 0x40100050,它就应该可以正常工作。在旧的汇编器中,有 org 指令来生成为特定地址设计的机器代码,但在 as 中,.org 更复杂(我认为它对你没有帮助)。
  • 我还是没抓住重点,你的问题是什么。 1)由于您的所有代码都是相对的,您可以将其全部复制到0x40100050(除非它太长而无法放在那里)。 2)0x40100050 来自哪里?不是来自某个向量处理程序表吗?那么你为什么不修改表在你的地址设置新的处理程序,忘记0x40100050? 3) 如果您将该处理程序放入单独的.section 并修改链接脚本以将该部分放在0x40100050 中,可以吗?那部分代码也是从闪存中获取的吗?等等......你的问题是call0 4010258c吗?然后也复制该代码。

标签: c gcc assembly relocation


【解决方案1】:

在链接描述文件中,每个输出部分都有两个相关的地址:VMA 和 LMA——链接代码的地址和加载代码的地址。

将需要重定位的代码放入单独的部分,将输出部分添加到具有所需 VMA 和 LMA 的链接描述文件中,并将与代码部分名称匹配的输入部分放入其中。

例如以下C代码

void f(void) __attribute__((section(".relocatable1.text")))
{
    ...
}

extern char _relocatable1_lma[];
extern char _relocatable1_vma_start[];
extern char _relocatable1_vma_end[];

void relocatable1_copy(void)
{
        memcpy(_relocatable1_vma_start, _relocatable1_lma,
               _relocatable1_vma_end - _relocatable1_vma_start);
}

连同下面一段 ld 脚本,用所需的目标代码位置替换 VMA

SECTIONS {
  ...
  .some_section : { ... }
  .relocatable1 VMA : AT(LOADADDR(.some_section) + SIZEOF(.some_section)) {
    _relocatable1_vma_start = . ;
    *(.relocatable1.literal .relocatable1.text) ;
    _relocatable1_vma_end = . ;
  }
  _relocatable1_lma = LOADADDR(.relocatable1) ;
  ...
}

应该做你想做的。

【讨论】:

    猜你喜欢
    • 2021-11-12
    • 1970-01-01
    • 1970-01-01
    • 2016-09-15
    • 2013-06-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多