程序内存空间分布与位置无关码

学习代码重定位时,对代码段、数据段、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寻找初始化数据以及使用全局变量都是可以正常完成的。

  所以,这其中①、④操作不是位置无关的。

 

posted @ 2020-10-13 13:39  星灯盏  阅读(243)  评论(0)    收藏  举报