arm-none-eabi-ld 会重写 bl 指令吗?



我试图理解为什么某些 Cortex-M0 代码在链接和未链接时的行为不同。在这两种情况下,它都会加载到0x20000000.看起来尽管我尽最大努力通过将-fPIC传递给编译器来生成与位置无关的代码,但在代码通过链接器后,bl指令似乎有所不同。我是否正确阅读了这篇文章,这只是 ARM Thumb 中链接器工作的一部分,是否有更好的方法来生成与位置无关的函数调用?

联系:

20000000:
20000000:       0003            movs    r3, r0
20000002:       4852            ldr     r0, [pc, #328]
20000004:       4685            mov     sp, r0
20000006:       0018            movs    r0, r3
20000008:       f000 f802       bl      20000010
2000000c:       46c0            nop                     ; (mov r8, r8)
2000000e:       46c0            nop                     ; (mov r8, r8)

未链接:

00000000:
0:   0003            movs    r3, r0
2:   4852            ldr     r0, [pc, #328]
4:   4685            mov     sp, r0
6:   0018            movs    r0, r3
8:   f7ff fffe       bl      10
c:   46c0            nop                     ; (mov r8, r8)
e:   46c0            nop                     ; (mov r8, r8)

start.s

.globl _start
_start:
.word 0x20001000
.word reset
.word hang
.word hang
.thumb
.thumb_func
reset:
bl notmain
.thumb_func
hang:
b .

notmain.c

unsigned int x;
unsigned int fun ( unsigned int );
void notmain ( void )
{
x=fun(x+5);
}

趣味网

unsigned int y;
unsigned int fun ( unsigned int z )
{
return(y+z+1);
}

内存映射

MEMORY
{
ram : ORIGIN = 0x20000000, LENGTH = 0x1000
}
SECTIONS
{
.text : { *(.text*) } > ram
.bss : { *(.bss*) } > ram
}

arm-none-eabi-as start.s -o start.o
arm-none-eabi-gcc -fPIC -O2 -c -mthumb fun.c -o fun.o
arm-none-eabi-gcc -fPIC -O2 -c -mthumb notmain.c -o notmain.o
arm-none-eabi-ld -T memmap start.o notmain.o fun.o -o so.elf

生产

20000000 <_start>:
20000000:   20001000    andcs   r1, r0, r0
20000004:   20000011    andcs   r0, r0, r1, lsl r0
20000008:   20000015    andcs   r0, r0, r5, lsl r0
2000000c:   20000015    andcs   r0, r0, r5, lsl r0
20000010 <reset>:
20000010:   f000 f802   bl  20000018 <notmain>
20000014 <hang>:
20000014:   e7fe        b.n 20000014 <hang>
...
20000018 <notmain>:
20000018:   b510        push    {r4, lr}
2000001a:   4b06        ldr r3, [pc, #24]   ; (20000034 <notmain+0x1c>)
2000001c:   4a06        ldr r2, [pc, #24]   ; (20000038 <notmain+0x20>)
2000001e:   447b        add r3, pc
20000020:   589c        ldr r4, [r3, r2]
20000022:   6823        ldr r3, [r4, #0]
20000024:   1d58        adds    r0, r3, #5
20000026:   f000 f809   bl  2000003c <fun>
2000002a:   6020        str r0, [r4, #0]
2000002c:   bc10        pop {r4}
2000002e:   bc01        pop {r0}
20000030:   4700        bx  r0
20000032:   46c0        nop         ; (mov r8, r8)
20000034:   00000032    andeq   r0, r0, r2, lsr r0
20000038:   00000000    andeq   r0, r0, r0
2000003c <fun>:
2000003c:   4b03        ldr r3, [pc, #12]   ; (2000004c <fun+0x10>)
2000003e:   4a04        ldr r2, [pc, #16]   ; (20000050 <fun+0x14>)
20000040:   447b        add r3, pc
20000042:   589b        ldr r3, [r3, r2]
20000044:   681b        ldr r3, [r3, #0]
20000046:   3301        adds    r3, #1
20000048:   1818        adds    r0, r3, r0
2000004a:   4770        bx  lr
2000004c:   00000010    andeq   r0, r0, r0, lsl r0
20000050:   00000004    andeq   r0, r0, r4
Disassembly of section .got:
20000054 <.got>:
20000054:   20000068    andcs   r0, r0, r8, rrx
20000058:   2000006c    andcs   r0, r0, ip, rrx
Disassembly of section .got.plt:
2000005c <_GLOBAL_OFFSET_TABLE_>:
...
Disassembly of section .bss:
20000068 <x>:
20000068:   00000000    andeq   r0, r0, r0
2000006c <y>:
2000006c:   00000000    andeq   r0, r0, r0

当它想要查找全局变量 x 时,它似乎已经做了什么,它采用程序计数器和链接器提供/修改的偏移量0x32,并使用它来查找全局偏移量表中的条目。 然后从中取一个偏移量以找到 X。 Y也一样。 因此,当您重新定位时,您似乎需要在运行时或加载时修改全局偏移表,具体取决于。

如果我摆脱了这些全局变量,除了硬编码而不是 PIC 的向量表(无论如何都没有编译),这一切都与位置无关。

20000000 <_start>:
20000000:   20001000    andcs   r1, r0, r0
20000004:   20000011    andcs   r0, r0, r1, lsl r0
20000008:   20000015    andcs   r0, r0, r5, lsl r0
2000000c:   20000015    andcs   r0, r0, r5, lsl r0
20000010 <reset>:
20000010:   f000 f802   bl  20000018 <notmain>
20000014 <hang>:
20000014:   e7fe        b.n 20000014 <hang>
...
20000018 <notmain>:
20000018:   b508        push    {r3, lr}
2000001a:   2005        movs    r0, #5
2000001c:   f000 f804   bl  20000028 <fun>
20000020:   3006        adds    r0, #6
20000022:   bc08        pop {r3}
20000024:   bc02        pop {r1}
20000026:   4708        bx  r1
20000028 <fun>:
20000028:   3001        adds    r0, #1
2000002a:   4770        bx  lr

返回此版本

unsigned int y;
unsigned int fun ( unsigned int z )
{
return(y+z+1);
}

位置独立

00000000 <fun>:
0:   4b03        ldr r3, [pc, #12]   ; (10 <fun+0x10>)
2:   4a04        ldr r2, [pc, #16]   ; (14 <fun+0x14>)
4:   447b        add r3, pc
6:   589b        ldr r3, [r3, r2]
8:   681b        ldr r3, [r3, #0]
a:   3301        adds    r3, #1
c:   1818        adds    r0, r3, r0
e:   4770        bx  lr
10:   00000008    andeq   r0, r0, r8
14:   00000000    andeq   r0, r0, r0

不独立于位置

00000000 <fun>:
0:   4b02        ldr r3, [pc, #8]    ; (c <fun+0xc>)
2:   681b        ldr r3, [r3, #0]
4:   3301        adds    r3, #1
6:   1818        adds    r0, r3, r0
8:   4770        bx  lr
a:   46c0        nop         ; (mov r8, r8)
c:   00000000    andeq   r0, r0, r0

代码必须做更多的工作才能访问外部变量。 取决于位置,有些工作是因为它是外部的,但没有那么多。 链接器将填写所需的项以使其工作...链接它...

ELF 文件包含链接器知道执行此操作的信息。

Relocation section '.rel.text' at offset 0x1a4 contains 2 entries:
Offset     Info    Type            Sym.Value  Sym. Name
00000010  00000a19 R_ARM_BASE_PREL   00000000   _GLOBAL_OFFSET_TABLE_
00000014  00000b1a R_ARM_GOT_BREL    00000004   y

Relocation section '.rel.text' at offset 0x174 contains 1 entries:
Offset     Info    Type            Sym.Value  Sym. Name
0000000c  00000a02 R_ARM_ABS32       00000004   y

诺曼有这些 PIC

Relocation section '.rel.text' at offset 0x1cc contains 3 entries:
Offset     Info    Type            Sym.Value  Sym. Name
0000000e  00000a0a R_ARM_THM_CALL    00000000   fun
0000001c  00000b19 R_ARM_BASE_PREL   00000000   _GLOBAL_OFFSET_TABLE_
00000020  00000c1a R_ARM_GOT_BREL    00000004   x

没有。

Relocation section '.rel.text' at offset 0x198 contains 2 entries:
Offset     Info    Type            Sym.Value  Sym. Name
00000008  00000a0a R_ARM_THM_CALL    00000000   fun
00000014  00000b02 R_ARM_ABS32       00000004   x

简而言之,工具链正在完成它的工作,你不需要重新做它的工作。 请注意,这与手臂或拇指无关。每当使用对象和链接器模型并允许来自对象的外部项时,链接器都必须修补内容以将代码粘合在一起。 这就是它的工作原理。

最新更新