程序内存空间分布与位置无关码
学习代码重定位时,对代码段、数据段、BSS段等分别存储的内容以及指令读取时的内存操作感觉很模糊,先做个小测试做初步的探讨:
一、测试在Linux系统下用arm-linux-gcc编译test文件
test测试代码:
Start.S:
.text .global _start _start: ldr sp, =0x34000000 bl main
main.c:
在测试代码main.c文件中:①全局变量(已初始化和未初始化)
②局部变量(已初始化和未初始化)
③向固定地址的写操作
④初始化数组
int b1; int b2 = 100; void main (){ int a1; int a2 = 100; unsigned long *p = (unsigned long *)0x32000000; p[0] = 0x1111111; p[1] = 0x2222222; p[3] = 0x333333; unsigned int arr[] = { 0x444, 0x555, 0x666, }; }
makefile:
all: arm-linux-gcc -c -o main.o main.c arm-linux-gcc -c -o start.o start.S arm-linux-ld -T test.lds start.o main.o -o test.elf arm-linux-objcopy -O binary -S test.elf test.bin arm-linux-objdump -D test.elf > test.dis
链接脚本:
SECTIONS { . = 0x30000000; __code_start = .; . = ALIGN(4); .text : { *(.text) } . = ALIGN(4); .rodata : { *(.rodata) } . = ALIGN(4); .data : { *(.data) } . = ALIGN(4); __bss_start = .; .bss : { *(.bss) *(.COMMON) } _end = .; }
查看生成的.dis文件:
test.elf: file format elf32-littlearm Disassembly of section .text: 30000000 <_start>: 30000000: e3a0d30d mov sp, #872415232 ; 0x34000000 30000004: ebffffff bl 30000008 <main> 30000008 <main>: 30000008: e1a0c00d mov ip, sp 3000000c: e92dd800 stmdb sp!, {fp, ip, lr, pc} 30000010: e24cb004 sub fp, ip, #4 ; 0x4 30000014: e24dd018 sub sp, sp, #24 ; 0x18 30000018: e3a03064 mov r3, #100 ; 0x64 3000001c: e50b3014 str r3, [fp, #-20] 30000020: e3a03432 mov r3, #838860800 ; 0x32000000 30000024: e50b3018 str r3, [fp, #-24] 30000028: e51b2018 ldr r2, [fp, #-24] 3000002c: e3a03c11 mov r3, #4352 ; 0x1100 30000030: e2833011 add r3, r3, #17 ; 0x11 30000034: e1833603 orr r3, r3, r3, lsl #12 30000038: e5823000 str r3, [r2] 3000003c: e3a02004 mov r2, #4 ; 0x4 30000040: e51b3018 ldr r3, [fp, #-24] 30000044: e0822003 add r2, r2, r3 30000048: e3a03c22 mov r3, #8704 ; 0x2200 3000004c: e2833022 add r3, r3, #34 ; 0x22 30000050: e1833603 orr r3, r3, r3, lsl #12 30000054: e5823000 str r3, [r2] 30000058: e3a0200c mov r2, #12 ; 0xc 3000005c: e51b3018 ldr r3, [fp, #-24] 30000060: e0822003 add r2, r2, r3 30000064: e3a03833 mov r3, #3342336 ; 0x330000 30000068: e2833c33 add r3, r3, #13056 ; 0x3300 3000006c: e2833033 add r3, r3, #51 ; 0x33 30000070: e5823000 str r3, [r2] 30000074: e59f3010 ldr r3, [pc, #16] ; 3000008c <.text+0x8c> 30000078: e24bc024 sub ip, fp, #36 ; 0x24 3000007c: e8930007 ldmia r3, {r0, r1, r2} 30000080: e88c0007 stmia ip, {r0, r1, r2} 30000084: e24bd00c sub sp, fp, #12 ; 0xc 30000088: e89da800 ldmia sp, {fp, sp, pc} 3000008c: 30000090 mulcc r0, r0, r0 Disassembly of section .rodata: 30000090 <.rodata>: 30000090: 00000444 andeq r0, r0, r4, asr #8 30000094: 00000555 andeq r0, r0, r5, asr r5 30000098: 00000666 andeq r0, r0, r6, ror #12 Disassembly of section .data: 3000009c <b2>: 3000009c: 00000064 andeq r0, r0, r4, rrx Disassembly of section .bss: 300000a0 <b1>: 300000a0: 00000000 andeq r0, r0, r0 Disassembly of section .comment: 00000000 <.comment>: 0: 43434700 cmpmi r3, #0 ; 0x0 4: 4728203a undefined 8: 2029554e eorcs r5, r9, lr, asr #10 c: 2e342e33 mrccs 14, 1, r2, cr4, cr3, {1} 10: Address 0x10 is out of bounds.
二、分析.dis文件分析各段的对应内容
①全局变量(已初始化和未初始化):
未初始化的全局变量被放在BSS段,已经初始化的会把初始化数据放在.data段。
②局部变量(已初始化和未初始化):
局部变量存储在栈中,关于局部变量的定义、赋值等操作都在.text段中,由CPU执行相应的指令将他们入栈和出栈。对应:
30000018: e3a03064 mov r3, #100 ; 0x64 3000001c: e50b3014 str r3, [fp, #-20]
③向固定地址的写操作
跟局部变量的操作方法类似,他们都属于代码的执行部分,在.text段中。
④初始化数组
首先观察.dis文件,初始化数组时所用的初始值0x444,0x555,0x666都存储在.rodata段,在.text段执行到初始化数组这一部分时,命令会去.rodata段取得对应的值。
.text
......
30000074: e59f3010 ldr r3, [pc, #16] ; 3000008c <.text+0x8c> //找到.rodata段的指引指令位置 30000078: e24bc024 sub ip, fp, #36 ; 0x24 3000007c: e8930007 ldmia r3, {r0, r1, r2} 30000080: e88c0007 stmia ip, {r0, r1, r2} 30000084: e24bd00c sub sp, fp, #12 ; 0xc 30000088: e89da800 ldmia sp, {fp, sp, pc} 3000008c: 30000090 mulcc r0, r0, r0 //通过该指令找到.rodata段的位置 Disassembly of section .rodata: 30000090 <.rodata>: 30000090: 00000444 andeq r0, r0, r4, asr #8 30000094: 00000555 andeq r0, r0, r5, asr r5 30000098: 00000666 andeq r0, r0, r6, ror #12
三、分析位置无关性
位置无关码是执行该代码段时依赖本身被存储的物理地址,例如该代码,如果未按照链接脚本要求,将其直接烧录在0地址,其②、③可以正常完成,但因为.text中对.data和.rodata的引用依然是以0x30000000为基地址的,将无法找到对应的值,如果按照链接脚本规定将其烧录在0x30000000起始的位置,那么当运行到初始化数组时,去0x30000090寻找初始化数据以及使用全局变量都是可以正常完成的。
所以,这其中①、④操作不是位置无关的。

浙公网安备 33010602011771号