qemu-基础篇——ARM 链接过程分析(六)

ARM 链接过程分析

源文件

这里新建五个文件

  • global_bss_file.c:定义了两个未初始化的全局变量
  • global_bss_file.c:定义了两个初始化的全局变量
  • global_function_file.c:定义了一个函数,函数实现传入的两个参数相加功能
  • global_rodata_file.c:定义了两个只读常量,并初始化
  • main.c:使用上述定义的变量和函数

根据上述自定义的链接脚本将这五个. c 文件链接为一个输出文件。编译环境为 arm-none-linux-gnueabihf-

global_bss_file.c

int bss_data1;
int bss_data2;

global_data_fle.c

int test_data1 = 1;
int test_data2 = 2;

global_function_file.c

int test_func(int a, int b)
{
    
    
    return a + b;
}

global_rodata_file.c

const int rodata_1 = 3;
const int rodata_2 = 4;

main.c

/* rodata */
extern const int rodata_1;
extern const int rodata_2;

/* data */
extern int test_data1;
extern int test_data2;

/* bss data(no init) */
extern int bss_data1;
extern int bss_data2;

/* code */
extern int test_func(int a, int b);

int main (int argc, int *argv[])
{
    
    
    bss_data1 = test_func(test_data1, test_data2);
    bss_data2 = test_func(rodata_1, rodata_2);

    return 0;
}

链接文件 link.lds

SECTIONS
{
    
    
    . = 0x00900000;
    .text :
    {
    
    
        *(.text)
    }

    .rodata :
    {
    
    
        *(.rodata)
    }

    . = 0x80000000;
    .data :
    {
    
    
        *(.data)
    }

    .bss :
    {
    
    
        *(.bss)
    }
}

编译命令及反汇编命令

命令示例

arm-none-linux-gnueabihf-gcc -c global_bss_file.c
arm-none-linux-gnueabihf-objdump -h global_bss_file.o > global_bss_file.sec
arm-none-linux-gnueabihf-objdump -s -d global_bss_file.o > global_bss_file.info

使用上述命令编译源文件之后会生成 global_bss_file.o/sec/infoglobal_data_fle.o/sec/infoglobal_function_file.o/sec/infoglobal_rodata_file.o/sec/info, 和 main.o/sec/info 等文件。

解析 .o 文件

global_bss_file.o

命令

arm-none-linux-gnueabihf-objdump -h global_bss_file.o >global_bss_file.sec

section,以及对应的 VMA 和 LMA

global_bss_file.o:     file format elf32-littlearm

Sections:
Idx Name          Size      VMA       LMA       File off  Algn
  0 .text         00000000  00000000  00000000  00000034  2**0
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
  1 .data         00000000  00000000  00000000  00000034  2**0
                  CONTENTS, ALLOC, LOAD, DATA
  2 .bss          00000008  00000000  00000000  00000034  2**2
                  ALLOC
  3 .comment      0000005e  00000000  00000000  00000034  2**0
                  CONTENTS, READONLY
  4 .note.GNU-stack 00000000  00000000  00000000  00000092  2**0
                  CONTENTS, READONLY
  5 .ARM.attributes 00000035  00000000  00000000  00000092  2**0
                  CONTENTS, READONLY

global_bss_file.o 有六个 sections 分别是

  • .text:代码段,没有包含任何有用的代码信息,所以 .text 段为 0
  • .data:数据段,没有已经初始化的数据,所以 .data 段是 0
  • .bss:未初始化变量段 8,源码总定义了两个 int 数据,所以 .bss 段的长度为 8
  • .comment:存放一些 GNU 的通用信息
  • .note.GNU-stack:GNU 的注释信息
  • .ARM.attributes:编译器相关信息

使用下面命令查看详细信息

arm-none-linux-gnueabihf-objdump -s -d global_bss_file.o >global_bss_file.info

命令返回结果如下

global_bss_file.o:     file format elf32-littlearm

Contents of section .comment:
 0000 00474343 3a202847 4e552054 6f6f6c63  .GCC: (GNU Toolc
 0010 6861696e 20666f72 20746865 20412d70  hain for the A-p
 0020 726f6669 6c652041 72636869 74656374  rofile Architect
 0030 75726520 31302e33 2d323032 312e3037  ure 10.3-2021.07
 0040 20286172 6d2d3130 2e323929 29203130   (arm-10.29)) 10
 0050 2e332e31 20323032 31303632 3100      .3.1 20210621.
Contents of section .ARM.attributes:
 0000 41340000 00616561 62690001 2a000000  A4...aeabi..*...
 0010 05372d41 00060a07 41080109 020a030c  .7-A....A.......
 0020 01120414 01150117 03180119 011a021c  ................
 0030 011e0622 01                          ...".
  • 由于还未链接,没有 .bss 段的相关信息

global_data_fle.o

命令

arm-none-linux-gnueabihf-objdump -h global_data_fle.o >global_data_fle.sec

section,以及对应的 VMA 和 LMA

global_data_fle.o:     file format elf32-littlearm

Sections:
Idx Name          Size      VMA       LMA       File off  Algn
  0 .text         00000000  00000000  00000000  00000034  2**0
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
  1 .data         00000008  00000000  00000000  00000034  2**2
                  CONTENTS, ALLOC, LOAD, DATA
  2 .bss          00000000  00000000  00000000  0000003c  2**0
                  ALLOC
  3 .comment      0000005e  00000000  00000000  0000003c  2**0
                  CONTENTS, READONLY
  4 .note.GNU-stack 00000000  00000000  00000000  0000009a  2**0
                  CONTENTS, READONLY
  5 .ARM.attributes 00000035  00000000  00000000  0000009a  2**0
                  CONTENTS, READONLY

global_data_fle.o 同样有六个 sections 分别是

  • .text:代码段,没有包含任何有用的代码信息,所以 .text 段为 0
  • .data:数据段长度为 8,定义了两个 int 型全局变量并初始化,int 的长度是 4 个字节,两个 int 于是占用了 8 个字节,所以 .data 段的长度为 8
  • .bss:没有未初始化的变量,所以 .bss 段为 0
  • .comment:存放一些 GNU 的通用信息
  • .note.GNU-stack:GNU 的注释信息
  • .ARM.attributes:编译器相关信息

使用下面命令查看详细信息

arm-none-linux-gnueabihf-objdump -s -d global_data_fle.o >global_data_fle.info

命令结果如下

global_data_fle.o:     file format elf32-littlearm

Contents of section .data:
 0000 01000000 02000000                    ........
Contents of section .comment:
 0000 00474343 3a202847 4e552054 6f6f6c63  .GCC: (GNU Toolc
 0010 6861696e 20666f72 20746865 20412d70  hain for the A-p
 0020 726f6669 6c652041 72636869 74656374  rofile Architect
 0030 75726520 31302e33 2d323032 312e3037  ure 10.3-2021.07
 0040 20286172 6d2d3130 2e323929 29203130   (arm-10.29)) 10
 0050 2e332e31 20323032 31303632 3100      .3.1 20210621.
Contents of section .ARM.attributes:
 0000 41340000 00616561 62690001 2a000000  A4...aeabi..*...
 0010 05372d41 00060a07 41080109 020a030c  .7-A....A.......
 0020 01120414 01150117 03180119 011a021c  ................
 0030 011e0622 01                          ...".
  • 由于还未链接,所以 .data 段的数据起始地址为 0

  • data.o 里面只有 .data 段的数据,并且长度为 8 个字节,小端模式,的确包含了 01000000 以及 02000000 两个全局变量的数据。

global_function_file.o

命令

arm-none-linux-gnueabihf-objdump -h global_function_file.o >global_function_file.sec

section,以及对应的 VMA 和 LMA

global_function_file.o:     file format elf32-littlearm

Sections:
Idx Name          Size      VMA       LMA       File off  Algn
  0 .text         0000001c  00000000  00000000  00000034  2**1
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
  1 .data         00000000  00000000  00000000  00000050  2**0
                  CONTENTS, ALLOC, LOAD, DATA
  2 .bss          00000000  00000000  00000000  00000050  2**0
                  ALLOC
  3 .comment      0000005e  00000000  00000000  00000050  2**0
                  CONTENTS, READONLY
  4 .note.GNU-stack 00000000  00000000  00000000  000000ae  2**0
                  CONTENTS, READONLY
  5 .ARM.attributes 00000035  00000000  00000000  000000ae  2**0
                  CONTENTS, READONLY

global_function_file.o 同样有六个 sections 分别是

  • .text:代码段,文件中定义了一个函数,所以 .text 的数据长度不为 0
  • .data:数据段,未定义任何数据,所以为 .data 段的长度为 0
  • .bss:没有未初始化的变量,所以 .bss 段的长度为 0
  • .comment:存放一些 GNU 的通用信息
  • .note.GNU-stack:GNU 的注释信息
  • .ARM.attributes:编译器相关信息

使用下面命令查看详细信息

arm-none-linux-gnueabihf-objdump -s -d global_function_file.o >global_function_file.info

命令结果如下

global_function_file.o:     file format elf32-littlearm

Contents of section .text:
 0000 80b483b0 00af7860 39607a68 3b681344  ......x`9`zh;h.D
 0010 18460c37 bd465df8 047b7047           .F.7.F]..{
    
    pG
Contents of section .comment:
 0000 00474343 3a202847 4e552054 6f6f6c63  .GCC: (GNU Toolc
 0010 6861696e 20666f72 20746865 20412d70  hain for the A-p
 0020 726f6669 6c652041 72636869 74656374  rofile Architect
 0030 75726520 31302e33 2d323032 312e3037  ure 10.3-2021.07
 0040 20286172 6d2d3130 2e323929 29203130   (arm-10.29)) 10
 0050 2e332e31 20323032 31303632 3100      .3.1 20210621.
Contents of section .ARM.attributes:
 0000 41340000 00616561 62690001 2a000000  A4...aeabi..*...
 0010 05372d41 00060a07 41080109 020a030c  .7-A....A.......
 0020 01120414 01150117 03180119 011a021c  ................
 0030 011e0622 01                          ...".

Disassembly of section .text:

00000000 <test_func>:
   0:	b480      	push	{
    
    r7}
   2:	b083      	sub	sp, #12
   4:	af00      	add	r7, sp, #0
   6:	6078      	str	r0, [r7, #4]
   8:	6039      	str	r1, [r7, #0]
   a:	687a      	ldr	r2, [r7, #4]
   c:	683b      	ldr	r3, [r7, #0]
   e:	4413      	add	r3, r2
  10:	4618      	mov	r0, r3
  12:	370c      	adds	r7, #12
  14:	46bd      	mov	sp, r7
  16:	f85d 7b04 	ldr.w	r7, [sp], #4
  1a:	4770      	bx	lr

  • 由于还未链接,所以代码段 .text 的起始地址为 0

  • global_function_file.o 里面只有 .text 段的数据,其代码实现数据相加功能。

global_rodata_file.o

objdump 解析命令

arm-none-linux-gnueabihf-objdump -h global_rodata_file.o >global_rodata_file.sec

objdump 解析结果:section,以及对应的 VMA 和 LMA

global_rodata_file.o:     file format elf32-littlearm

Sections:
Idx Name          Size      VMA       LMA       File off  Algn
  0 .text         00000000  00000000  00000000  00000034  2**0
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
  1 .data         00000000  00000000  00000000  00000034  2**0
                  CONTENTS, ALLOC, LOAD, DATA
  2 .bss          00000000  00000000  00000000  00000034  2**0
                  ALLOC
  3 .rodata       00000008  00000000  00000000  00000034  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  4 .comment      0000005e  00000000  00000000  0000003c  2**0
                  CONTENTS, READONLY
  5 .note.GNU-stack 00000000  00000000  00000000  0000009a  2**0
                  CONTENTS, READONLY
  6 .ARM.attributes 00000035  00000000  00000000  0000009a  2**0
                  CONTENTS, READONLY

global_rodata_file.o 有七个 sections 分别是

  • .text:代码段,由于没有代码,所以 .text 段的长度为 0
  • .data:没有全局初始化的数据,所以 .data 段的长度为 0
  • .bss:没有未初始化的全局数据,所以 .bss 段的长度为 0
  • .rodata:数据段长度为 8,定义了两个 int 型全局只读常量并初始化,int 的长度是 4 个字节,两个 int 于是占用了 8 个字节,所以 .data 段的长度为 8。
  • .comment:存放一些 GNU 的通用信息
  • .note.GNU-stack:GNU 的注释信息
  • .ARM.attributes:编译器相关信息

使用下面命令查看详细信息

arm-none-linux-gnueabihf-objdump -s -d global_rodata_file.o >global_rodata_file.info

命令结果如下

global_rodata_file.o:     file format elf32-littlearm

Contents of section .rodata:
 0000 03000000 04000000                    ........
Contents of section .comment:
 0000 00474343 3a202847 4e552054 6f6f6c63  .GCC: (GNU Toolc
 0010 6861696e 20666f72 20746865 20412d70  hain for the A-p
 0020 726f6669 6c652041 72636869 74656374  rofile Architect
 0030 75726520 31302e33 2d323032 312e3037  ure 10.3-2021.07
 0040 20286172 6d2d3130 2e323929 29203130   (arm-10.29)) 10
 0050 2e332e31 20323032 31303632 3100      .3.1 20210621.
Contents of section .ARM.attributes:
 0000 41340000 00616561 62690001 2a000000  A4...aeabi..*...
 0010 05372d41 00060a07 41080109 020a030c  .7-A....A.......
 0020 01120414 01150117 03180119 011a021c  ................
 0030 011e0622 01                          ...".
  • 由于还未链接,所以 .rodata 段的起始地址为 0。

main.o

objdump 解析命令

arm-none-linux-gnueabihf-objdump -h main.o >main.sec

objdump 解析结果:section,以及对应的 VMA 和 LMA

main.o:     file format elf32-littlearm

Sections:
Idx Name          Size      VMA       LMA       File off  Algn
  0 .text         00000064  00000000  00000000  00000034  2**1
                  CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE
  1 .data         00000000  00000000  00000000  00000098  2**0
                  CONTENTS, ALLOC, LOAD, DATA
  2 .bss          00000000  00000000  00000000  00000098  2**0
                  ALLOC
  3 .comment      0000005e  00000000  00000000  00000098  2**0
                  CONTENTS, READONLY
  4 .note.GNU-stack 00000000  00000000  00000000  000000f6  2**0
                  CONTENTS, READONLY
  5 .ARM.attributes 00000035  00000000  00000000  000000f6  2**0
                  CONTENTS, READONLY

main.o 有六个 sections 分别是

  • .text:代码段,文件中定义了几个函数,所以 .text 的数据长度不为 0
  • .data:没有全局初始化的数据,所以 .data 段的长度为 0
  • .bss:没有未初始化的全局数据,所以 .bss 段的长度为 0
  • .comment:存放一些 GNU 的通用信息
  • .note.GNU-stack:GNU 的注释信息
  • .ARM.attributes:编译器相关信息

使用下面命令查看详细信息

arm-none-linux-gnueabihf-objdump -s -d main.o >main.info

命令结果如下

main.o:     file format elf32-littlearm

Contents of section .text:
 0000 80b582b0 00af7860 396040f2 0003c0f2  ......x`9`@.....
 0010 00031a68 40f20003 c0f20003 1b681946  ...h@........h.F
 0020 1046fff7 feff0246 40f20003 c0f20003  .F.....F@.......
 0030 1a6040f2 0003c0f2 00031a68 40f20003  .`@........h@...
 0040 c0f20003 1b681946 1046fff7 feff0246  .....h.F.F.....F
 0050 40f20003 c0f20003 1a600023 18460837  @........`.#.F.7
 0060 bd4680bd                             .F..
Contents of section .comment:
 0000 00474343 3a202847 4e552054 6f6f6c63  .GCC: (GNU Toolc
 0010 6861696e 20666f72 20746865 20412d70  hain for the A-p
 0020 726f6669 6c652041 72636869 74656374  rofile Architect
 0030 75726520 31302e33 2d323032 312e3037  ure 10.3-2021.07
 0040 20286172 6d2d3130 2e323929 29203130   (arm-10.29)) 10
 0050 2e332e31 20323032 31303632 3100      .3.1 20210621.
Contents of section .ARM.attributes:
 0000 41340000 00616561 62690001 2a000000  A4...aeabi..*...
 0010 05372d41 00060a07 41080109 020a030c  .7-A....A.......
 0020 01120414 01150117 03180119 011a021c  ................
 0030 011e0622 01                          ...".

Disassembly of section .text:

00000000 <main>:
   0:	b580      	push	{
    
    r7, lr}
   2:	b082      	sub	sp, #8
   4:	af00      	add	r7, sp, #0
   6:	6078      	str	r0, [r7, #4]
   8:	6039      	str	r1, [r7, #0]
   a:	f240 0300 	movw	r3, #0
   e:	f2c0 0300 	movt	r3, #0
  12:	681a      	ldr	r2, [r3, #0]
  14:	f240 0300 	movw	r3, #0
  18:	f2c0 0300 	movt	r3, #0
  1c:	681b      	ldr	r3, [r3, #0]
  1e:	4619      	mov	r1, r3
  20:	4610      	mov	r0, r2
  22:	f7ff fffe 	bl	0 <test_func>
  26:	4602      	mov	r2, r0
  28:	f240 0300 	movw	r3, #0
  2c:	f2c0 0300 	movt	r3, #0
  30:	601a      	str	r2, [r3, #0]
  32:	f240 0300 	movw	r3, #0
  36:	f2c0 0300 	movt	r3, #0
  3a:	681a      	ldr	r2, [r3, #0]
  3c:	f240 0300 	movw	r3, #0
  40:	f2c0 0300 	movt	r3, #0
  44:	681b      	ldr	r3, [r3, #0]
  46:	4619      	mov	r1, r3
  48:	4610      	mov	r0, r2
  4a:	f7ff fffe 	bl	0 <test_func>
  4e:	4602      	mov	r2, r0
  50:	f240 0300 	movw	r3, #0
  54:	f2c0 0300 	movt	r3, #0
  58:	601a      	str	r2, [r3, #0]
  5a:	2300      	movs	r3, #0
  5c:	4618      	mov	r0, r3
  5e:	3708      	adds	r7, #8
  60:	46bd      	mov	sp, r7
  62:	bd80      	pop	{
    
    r7, pc}
  • 由于还未链接,所以代码起始地址为 0

  • 第 22 行可以看到一个跳转指令,表示需要链接的位置

    f7ff fffe 	bl	0 <test_func>
    

    有一个标签 <test_func>,bl 目前跳转的地方是 0 地址,后期连接器会把这个值改回来

  • 变量的赋值时通过如下汇编语句实现,可以看到变量的值都是 0,后期链接器会将这两个值改为真正的 test_data1test_data2 等数据。
    test_data1:

    a:	f240 0300 	movw	r3, #0
    e:	f2c0 0300 	movt	r3, #0
    12:	681a      	ldr	r2, [r3, #0]
    20:	4610      	mov	r0, r2
    
    • movw 将一个 16 位数据移动到寄存器的低 16 位,并把高 16 位清零。
    • movt 将一个 16 位数据移动到寄存器的高 16 位,低 16 位不处理。
    • 所以此时 r3 寄存器的值为 0,接着将 r3 寄存器的值解引用的值,加载到 r2
    • 函数调用时,将 r2 寄存器的值放到 r0 寄存器中,r0 在函数调用时,传递的是第一个参数

    test_data2:

    14:	f240 0300 	movw	r3, #0
    18:	f2c0 0300 	movt	r3, #0
    1c:	681b      	ldr	r3, [r3, #0]
    1e:	4619      	mov	r1, r3
    
    • movw 将一个 16 位数据移动到寄存器的低 16 位,并把高 16 位清零。
    • movt 将一个 16 位数据移动到寄存器的高 16 位,低 16 位不处理。
    • 所以此时 r3 寄存器的值为 0,接着将 r3 寄存器的值解引用的值,加载到 r3
    • 函数调用时,将 r3 寄存器的值放到 r1 寄存器中,r1 在函数调用时,传递的是第二个参数

链接

上面描述中有五个 .o 文件,分别是

  • global_bss_file.o 定义了 2 个未初始化的全局变量
  • global_data_fle.o 定义了 2 个初始化的全局变量
  • global_function_file.o 定义了一个函数
  • global_rodata_file.o 定义了 2 个只读常量
  • main.o 使用上面定义的函数和变量

在链接之前并不知道数据的具体数值,也不知道调用函数的函数位置,因此事先会把不知道的信息空出来,等到链接的时候再合并。因此接下来要观察链接的结果。

使用链接命令

arm-none-linux-gnueabihf-ld global_bss_file.o global_data_fle.o global_function_file.o global_rodata_file.o main.o -T link.lds -o test

得到输出文件 test

使用

arm-none-linux-gnueabihf-objdump -h test > test.sec

命令返回结果如下

test:     file format elf32-littlearm

Sections:
Idx Name          Size      VMA       LMA       File off  Algn
  0 .text         00000080  00900000  00900000  00010000  2**1
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
  1 .rodata       00000008  00900080  00900080  00010080  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  2 .data         00000008  80000000  80000000  00020000  2**2
                  CONTENTS, ALLOC, LOAD, DATA
  3 .bss          00000008  80000008  80000008  00020008  2**2
                  ALLOC
  4 .comment      0000005d  00000000  00000000  00020008  2**0
                  CONTENTS, READONLY
  5 .ARM.attributes 00000035  00000000  00000000  00020065  2**0
                  CONTENTS, READONLY

test 有六个 sections 分别是

  • .text
  • .rodata
  • .data
  • .bss
  • .comment
  • .ARM.attributes。

可以看到链接后的 test 文件的 .text,.data,.rodata,和 .bss 等段的 size 是多个 .o 文件的和。

使用下面命令查看详细信息

arm-none-linux-gnueabihf-objdump -s -d test >test.info

命令结果如下

test:     file format elf32-littlearm

Contents of section .text:
 900000 80b483b0 00af7860 39607a68 3b681344  ......x`9`zh;h.D
 900010 18460c37 bd465df8 047b7047 80b582b0  .F.7.F]..{
    
    pG....
 900020 00af7860 396040f2 0003c8f2 00031a68  ..x`9`@........h
 900030 40f20403 c8f20003 1b681946 1046fff7  @........h.F.F..
 900040 dfff0246 40f20803 c8f20003 1a6040f2  ...F@........`@.
 900050 8003c0f2 90031a68 40f28403 c0f29003  .......h@.......
 900060 1b681946 1046fff7 cbff0246 40f20c03  .h.F.F.....F@...
 900070 c8f20003 1a600023 18460837 bd4680bd  .....`.#.F.7.F..
Contents of section .rodata:
 900080 03000000 04000000                    ........
Contents of section .data:
 80000000 01000000 02000000                    ........
Contents of section .comment:
 0000 4743433a 2028474e 5520546f 6f6c6368  GCC: (GNU Toolch
 0010 61696e20 666f7220 74686520 412d7072  ain for the A-pr
 0020 6f66696c 65204172 63686974 65637475  ofile Architectu
 0030 72652031 302e332d 32303231 2e303720  re 10.3-2021.07
 0040 2861726d 2d31302e 32392929 2031302e  (arm-10.29)) 10.
 0050 332e3120 32303231 30363231 00        3.1 20210621.
Contents of section .ARM.attributes:
 0000 41340000 00616561 62690001 2a000000  A4...aeabi..*...
 0010 05372d41 00060a07 41080109 020a030c  .7-A....A.......
 0020 01120414 01150117 03180119 011a021c  ................
 0030 011e0622 01                          ...".

Disassembly of section .text:

00900000 <test_func>:
  900000:	b480      	push	{
    
    r7}
  900002:	b083      	sub	sp, #12
  900004:	af00      	add	r7, sp, #0
  900006:	6078      	str	r0, [r7, #4]
  900008:	6039      	str	r1, [r7, #0]
  90000a:	687a      	ldr	r2, [r7, #4]
  90000c:	683b      	ldr	r3, [r7, #0]
  90000e:	4413      	add	r3, r2
  900010:	4618      	mov	r0, r3
  900012:	370c      	adds	r7, #12
  900014:	46bd      	mov	sp, r7
  900016:	f85d 7b04 	ldr.w	r7, [sp], #4
  90001a:	4770      	bx	lr

0090001c <main>:
  90001c:	b580      	push	{
    
    r7, lr}
  90001e:	b082      	sub	sp, #8
  900020:	af00      	add	r7, sp, #0
  900022:	6078      	str	r0, [r7, #4]
  900024:	6039      	str	r1, [r7, #0]
  900026:	f240 0300 	movw	r3, #0
  90002a:	f2c8 0300 	movt	r3, #32768	; 0x8000
  90002e:	681a      	ldr	r2, [r3, #0]
  900030:	f240 0304 	movw	r3, #4
  900034:	f2c8 0300 	movt	r3, #32768	; 0x8000
  900038:	681b      	ldr	r3, [r3, #0]
  90003a:	4619      	mov	r1, r3
  90003c:	4610      	mov	r0, r2
  90003e:	f7ff ffdf 	bl	900000 <test_func>
  900042:	4602      	mov	r2, r0
  900044:	f240 0308 	movw	r3, #8
  900048:	f2c8 0300 	movt	r3, #32768	; 0x8000
  90004c:	601a      	str	r2, [r3, #0]
  90004e:	f240 0380 	movw	r3, #128	; 0x80
  900052:	f2c0 0390 	movt	r3, #144	; 0x90
  900056:	681a      	ldr	r2, [r3, #0]
  900058:	f240 0384 	movw	r3, #132	; 0x84
  90005c:	f2c0 0390 	movt	r3, #144	; 0x90
  900060:	681b      	ldr	r3, [r3, #0]
  900062:	4619      	mov	r1, r3
  900064:	4610      	mov	r0, r2
  900066:	f7ff ffcb 	bl	900000 <test_func>
  90006a:	4602      	mov	r2, r0
  90006c:	f240 030c 	movw	r3, #12
  900070:	f2c8 0300 	movt	r3, #32768	; 0x8000
  900074:	601a      	str	r2, [r3, #0]
  900076:	2300      	movs	r3, #0
  900078:	4618      	mov	r0, r3
  90007a:	3708      	adds	r7, #8
  90007c:	46bd      	mov	sp, r7
  90007e:	bd80      	pop	{
    
    r7, pc}

观察链接前后的差异

地址变化

  • 链接之后,代码起始地址为:0x00900000
  • 链接之后,数据起始地址为:0x80000000

main.o

  • 原先 bl 0 位置被连接器替换为了 bl 900000。而 900000 刚好是 test_func 的代码地址
    90003e:	f7ff ffdf 	bl	900000 <test_func>
    
  • 全局变量的地址
    900026:	f240 0300 	movw	r3, #0
    90002a:	f2c8 0300 	movt	r3, #32768	; 0x8000
    90002e:	681a      	ldr	r2, [r3, #0]
    90003c:	4610      	mov	r0, r2
    
    • movw 将一个 16 位数据移动到寄存器的低 16 位,并把高 16 位清零。
    • movt 将一个 16 位数据移动到寄存器的高 16 位,低 16 位不处理。
    • 所以此时 r3 寄存器的值为 0x80000000
    • 将 r3 寄存器的值解引用后放到 r2 寄存器中,所以此时 r2 寄存器的值为 0x01
    • 函数调用时,将 r2 寄存器的值给到 r0,所以 r0 的值为 0x01 表示第一个参数
    900030:	f240 0304 	movw	r3, #4
    900034:	f2c8 0300 	movt	r3, #32768	; 0x8000
    900038:	681b      	ldr	r3, [r3, #0]
    90003a:	4619      	mov	r1, r3
    
    • movw 将一个 16 位数据移动到寄存器的低 16 位,并把高 16 位清零。
    • movt 将一个 16 位数据移动到寄存器的高 16 位,低 16 位不处理。
    • 所以此时 r3 寄存器的值为 0x80000004
    • 将 r3 寄存器的值解引用后放到 r3 寄存器中,所以此时 r3 寄存器的值为 0x02
    • 函数调用时,将 r3 寄存器的值给到 r1,所以 r1 的值为 0x02 表示第二个参数

猜你喜欢

转载自blog.csdn.net/tyustli/article/details/130588634