【问题标题】:Problems with static local variables with relocatable code带有可重定位代码的静态局部变量的问题
【发布时间】:2011-07-02 21:44:08
【问题描述】:

我正在构建一个在裸机上具有可重定位代码的项目。它是一个 Cortex M3 嵌入式应用程序。我没有动态链接器,并且在我的启动代码中实现了所有重定位。

大部分情况下它都在工作,但我的本地静态变量似乎定位不正确。它们的地址被我的可执行文件在内存中的偏移量所抵消——即我编译我的代码,就好像它被加载在内存位置 0 但我实际上将它加载到位于 0x8000 的内存中一样。静态局部变量的内存地址偏移量为 0x8000,这是不好的。

GOT 正确定位了我的全局变量,但静态局部变量根本不在 GOT 中(至少在我运行 readelf -r 时它们不会出现)。我正在使用-fpic 编译我的代码,并且链接器指定了-fpic-pie。我认为我必须缺少一个编译和/或链接选项来指示gcc 将 GOT 用于静态局部变量或指示它对它们使用绝对寻址。

目前看来代码将PC添加到静态局部变量的位置。

【问题讨论】:

    标签: arm static-variables relocation fpic


    【解决方案1】:

    我想我已经重复了你所看到的:

    statloc.c 无符号整数全局; unsigned int fun ( unsigned int a ) { 静态无符号整数 loc; 如果(a==0) 位置=7; 返回(a+glob+loc); } arm-none-linux-gnueabi-gcc -mcpu=cortex-m3 -Wall -Werror -O2 -nostdlib -nostartfiles -ffreestanding -mthumb -fpic -pie -S statloc.c

    这给出了:

        .cpu cortex-m3
        .fpu softvfp
        .thumb
        .text
        .align  2
        .global fun
        .thumb
        .thumb_func
    fun:
        ldr r3, .L6
    .LPIC2:
        add r3, pc
        cbnz    r0, .L5
        ldr r1, .L6+4
        movs    r2, #7
    .LPIC1:
        add r1, pc
        ldr ip, .L6+8
        str r2, [r1, #0]
        ldr r1, [r3, ip]
        ldr r3, [r1, #0]
        adds    r0, r0, r3
        adds    r0, r0, r2
        bx  lr
    .L5:
        ldr ip, .L6+8
        ldr r2, .L6+12
        ldr r1, [r3, ip]
    .LPIC0:
        add r2, pc
        ldr r2, [r2]
        ldr r3, [r1, #0]
        adds    r0, r0, r3
        adds    r0, r0, r2
        bx  lr
    .L7:
        .align  2
    .L6:
        .word   _GLOBAL_OFFSET_TABLE_-(.LPIC2+4)
        .word   .LANCHOR0-(.LPIC1+4)
        .word   glob(GOT)
        .word   .LANCHOR0-(.LPIC0+4)
        .size   fun, .-fun
        .comm   glob,4,4
        .bss
        .align  2
    .LANCHOR0 = . + 0
        .type   loc.823, %object
        .size   loc.823, 4
    loc.823:
        .space  4
    

    我还添加了启动代码并编译了二进制文件并进行了反汇编,以进一步了解/验证正在发生的事情。

    这是从 pc 到 .got 的偏移量 ldr r3, .L6 添加 pc 以使 r3 保持与 .got 的位置无关的偏移量 添加 r3, 电脑 获取 glob 地址的偏移量 ldr ip, .L6+8 从 got 中读取全局变量的绝对地址 ldr r1, [r3, ip] 最后将全局变量读入r3 ldr r3, [r1, #0] 这是从 pc 到 .bss 中静态本地的偏移量 ldr r2, .L6+12 添加 pc 以使 r2 保持与静态本地的位置无关的偏移量 在.bss 添加 r2, 电脑 读取 .bss 中的静态本地 ldr r2, [r2]

    因此,如果您要更改 .text 的加载位置,并且要更改 .got 和 .bss 相对于 .text 的加载位置,就是这样,那么 .got 的内容将是错误的,全局变量将是从错误的地方加载。

    如果您要更改 .text 的加载位置,请将 .bss 保留在链接器放置的位置并相对于 .text 移动 .got。那么全局会从正确的地方拉出来,而本地不会

    如果您要更改 .text 的加载位置,更改 .got 和 .bss 相对于 .text 的加载位置并修改 .got 内容以反映 .text 的加载位置,则本地和全局变量都将是从正确的位置访问。

    所以加载器和 gcc/ld 需要全部同步。我的直接建议是不要使用静态本地,而只使用全局。那或者不用担心位置无关的代码,它毕竟是一个 cortex-m3 并且有些资源有限,只需预先定义内存映射。我假设问题是我如何让 gcc 将 .got 用于本地全局,而我不知道答案,但是举一个像上面这样的简单示例,您可以使用许多命令行选项,直到找到改变输出的一种。

    【讨论】:

    • 不幸的是,对于这个应用程序,我需要让位置独立工作。很高兴看到您能够重现我迄今为止发现的内容。以下工作是否可行:
    • 在链接描述文件中将 GOT 设置在 SRAM 中。将 .dynamic 保留在 flash 中,以便可以找到符号表。使用符号表定位文本、数据、数据等。从 Flash 复制 GOT 并修改内容?
    • 正如我在这里所做的那样,我将举一个像上面这样的简单示例,制作一个超级简单的启动文件,其中仅包含一个 _Start: 和 bl fun 并使用各种链接器脚本进行构建,以查看工具链的确切功能.就我个人而言,我采用 KISS 方法,所有内容都在不可重定位的 .text 段中,而 .bss init 无关紧要,因为我在第一次写作之前从未阅读过。基本上我不是 gnu 链接器专业人士,也许其他人在听谁可能知道如何操作这些段而无需在加载器中解决它。
    • 代码如何定位GOT?它是否希望在内存中找到它的绝对地址,还是它也是 PC 的相对位置?从示例的前两行来看,它看起来像是基于 PC - 这可能是一个问题。
    • 看来 gcc 已经使其与 PC 相关。所以如果你移动 .text 那么你需要移动 .got 。多远与链接描述文件有关,因此如果将 .text 移动 x 个字节,然后将 .got 移动 x 个字节。至少 gcc 使用命令行选项编译它的方式。
    【解决方案2】:

    这里也讨论了这个问题:https://answers.launchpad.net/gcc-arm-embedded/+question/236744

    从 gcc 4.8 (ARM) 开始,有一个名为 -mpic-data-is-text-relative 的命令行开关,它也可以通过 GOT 寻址静态变量。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-10-04
      • 1970-01-01
      • 2017-06-17
      • 2018-04-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-08-02
      相关资源
      最近更新 更多