Arm 带有可重定位代码的静态局部变量的问题

Arm 带有可重定位代码的静态局部变量的问题,arm,static-variables,relocation,fpic,Arm,Static Variables,Relocation,Fpic,我正在构建一个在裸机上有可重定位代码的项目。这是一个Cortex M3嵌入式应用程序。我没有动态链接器,并且在启动代码中实现了所有重定位 大多数情况下,它是工作的,但我的局部静态变量似乎被错误地定位。它们的地址被我的可执行文件在内存中的偏移量所偏移——即我编译代码时,就好像它是在内存位置0加载的,但我实际上是在0x8000的内存中加载的。静态局部变量的内存地址偏移量为0x8000,这是不好的 我的全局变量由GOT正确定位,但静态局部变量根本不在GOT中(至少在我运行readelf-r时它们不会出

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

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

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


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

我想我已经重复了您看到的内容:

statloc.c unsigned int glob; unsigned int fun ( unsigned int a ) { static unsigned int loc; if(a==0) loc=7; return(a+glob+loc); } 我还添加了启动代码,编译了一个二进制文件并进行了反汇编,以进一步了解/验证正在发生的事情

this is the offset from the pc to the .got ldr r3, .L6 add pc so r3 holds a position independent offset to the .got add r3, pc offset in the got for the address of the glob ldr ip, .L6+8 read the absolute address for the global variable from the got ldr r1, [r3, ip] finally read the global variable into r3 ldr r3, [r1, #0] this is the offset from the pc to the static local in .bss ldr r2, .L6+12 add pc so that r2 holds a position independent offset to the static local in .bss add r2, pc read the static local in .bss ldr r2, [r2] 这是从pc到.get的偏移量 ldr r3、.L6 添加pc,使r3保持与.got的位置无关的偏移量 添加r3,pc 全局地址的got中的偏移量 ldr ip,.L6+8 从got中读取全局变量的绝对地址 ldr r1,[r3,ip] 最后将全局变量读入r3 ldr r3,[r1,#0] 这是从pc到.bss中静态本地的偏移量 ldr r2、.L6+12 添加pc,使r2保持与静态局部位置无关的偏移 in.bss 添加r2,pc 读取.bss中的静态本地 ldr r2,[r2] 因此,如果要更改.text的加载位置以及.get和.bss相对于.text的加载位置,那么.get的内容将是错误的,全局变量将从错误的位置加载

如果要更改.text的加载位置,请将.bss保留在链接器放置它的位置,然后相对于.text移动.get。然后,全球将被从正确的地方拉出来,而本地将不会

如果要更改.text的加载位置,请更改.get和.bss相对于.text的加载位置,并修改.get内容以反映.text的加载位置,则可以从正确的位置访问局部变量和全局变量


因此,加载程序和gcc/ld都需要同步。我的直接建议是不要使用静态局部变量,而只使用全局变量。或者不用担心位置无关的代码,毕竟它是一个cortex-m3,资源有限,只需预先定义内存映射即可。我想问题是如何让gcc使用.get来表示本地全局,我不知道答案,但举一个简单的例子,比如上面的一个,您可以使用许多命令行选项,直到找到一个可以更改输出的选项。

这里还讨论了这个问题:


从GCC4.8(ARM)开始,有一个名为
的命令行开关-mpic数据是文本相关的
,这会导致静态变量也通过GOT寻址。

不幸的是,对于这个应用程序,我需要使位置独立性工作。很高兴看到你能重现我目前的发现。以下工作是否有效:在链接器脚本中,将GOT设置为在SRAM中。在flash中动态显示,以便可以定位符号表。使用符号表查找文本、数据、edata等。复制从flash获得的内容并修改内容?正如我在这里所做的那样,我将举一个类似上面的简单示例,制作一个超级简单的启动文件,只需一个_Start:和bl fun,并使用各种链接器脚本进行构建,以查看工具链的具体功能。就我个人而言,我采用KISS方法,所有内容都在一个不可重新定位的.text段中,.bss init并不重要,因为我在第一次写作之前从未阅读过。基本上,我不是gnu链接器专业人士,也许其他正在听的人可能知道如何操作这些段,而不必在加载程序中解决它。代码如何定位GOT?它希望在内存中找到一个绝对地址,还是它也是电脑的一个相对位置?从示例的前两行看,它似乎是基于PC的-这可能是一个问题。gcc似乎使它与PC相对。因此,如果移动.text,则需要移动.get。距离有多远与链接器脚本有关,所以如果移动.text x字节,则移动.get x字节。至少是gcc用命令行选项编译它的方式。
    .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
this is the offset from the pc to the .got ldr r3, .L6 add pc so r3 holds a position independent offset to the .got add r3, pc offset in the got for the address of the glob ldr ip, .L6+8 read the absolute address for the global variable from the got ldr r1, [r3, ip] finally read the global variable into r3 ldr r3, [r1, #0] this is the offset from the pc to the static local in .bss ldr r2, .L6+12 add pc so that r2 holds a position independent offset to the static local in .bss add r2, pc read the static local in .bss ldr r2, [r2]