3

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

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

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

似乎当前代码将 PC 添加到静态局部变量的位置。

4

2 回答 2

3

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

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 用于本地全局,而我不知道答案,但是举一个像上面这样的简单示例,您可以使用许多命令行选项,直到找到改变输出的一种。

于 2011-02-23T23:57:38.107 回答
3

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

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

于 2014-06-25T12:25:36.260 回答