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