开MMU的时候
CPU发出的地址是虚拟地址
PC寄存器中的值是虚拟地址
输出给主存的地址是物理地址
输出给cache 索引的地址是物理地址或虚拟地址
输出给MMU/TLB的地址 是虚拟地址
物理地址在 地址总线上有体现
物理地址在 内存实体上有体现
在没开MMU的时候
不存在虚拟地址
所有的运行地址都是物理地址
PC寄存器中的值是物理地址
1.链接过程中的体现
1.1
arm-linux-ld 的参数 -Ttext 定义链接地址,
arm-linux-ld -Ttext 0x3000000 -g -o led_on_elf crt0.o led_lighton.o
1.2
链接脚本里有体现
2.可执行文件中关于 链接地址的体现
1.
第一条汇编指令代码会有一个链接地址,就是0x3000000
第二条汇编指令代码会有一个链接地址,就是0x3000004
2.
如果有地址相关码,例如 ldr pc,=lable 的话,编译生成的汇编指令中会包含 连接地址
如果汇编指令指令代码的 链接地址 == 汇编指令代码的 运行地址(运行时的物理地址)
不会产生问题
如果汇编指令指令代码的 链接地址 != 汇编指令代码的 运行地址
1. 启动的时候,pc=代码的运行地址,然后按照 pc = pc + 4 运行下去
此时虽然 连接地址 != 运行地址 , 但是没问题
2. 一旦遇到 地址相关码,例如 ldr pc,=0x30000010, 且 连接地址 0x30000010 处 为 lable
就会将 物理地址 0x30000010 处的 内容(不知道是什么) 取值,译码,执行
此时 如果 运行地址 0x30000010 和 连接地址 0x30000010 一致
就没问题,因为运行地址 0x30000010 处的内容就是 标号 lable 的内容
此时 如果 运行地址 0x30000010 和 连接地址 0x30000010 一致
就会产生问题,就会产生问题,因为运行地址 0x30000010 处的内容不是 标号 lable 的内容
代码在运行时
代码的物理地址
数据的物理地址
PIC : position independent code
当运行地址不在链接地址时,必须用位置无关码,如果用位置相关码,会出问题.
bl lable . b lable 是位置无关码的体现.
运行完这一句后 pc = pc + 偏移值 ,而这个偏移值 是编译器算好的.
可以从汇编程序中看出来 , 汇编的到的数字中可以看出来这个偏移值
这个算出来的pc可能不予lable的连接地址相同.所以称为位置无关码
怎么用位置无关码
1/跳转用b 或者bl
2/C语言中不用全局 或者 静态
// 更详细的内容可以 搜索关键字 韦东山 位置无关码
//ldr pc , =lable
将pc赋值为 lable 的链接地址 ,就是反汇编 后 .dis中的第一列的地址.
这个pc是绝对地址
.align 2
.type LC0, #object
LC0: .word LC0 @ r1
.word __bss_start @ r2
.word _end @ r3
.word _edata @ r6
.word input_data_end - 4 @ r10 (inflated size location)
.word _got_start @ r11
.word _got_end @ ip
.word .L_user_stack_end @ sp
.size LC0, . - LC0
restart:
adr r0, LC0
// 将标号 LC0 的地址放入 r0
// r0 : LC0运行地址
ldmia r0, {r1, r2, r3, r6, r10, r11, r12}
// .word LC0 在运行前就已经分配好了LC0的大小和值,值是连接地址
// r1 : LC0链接地址
// r6 : _edata链接地址
ldr sp, [r0, #28]
/*
* We might be running at a different address. We need
* to fix up various pointers.
*/
sub r0, r0, r1 @ calculate the delta offset
// 获取 LC0运行地址 - LC0链接地址 的差值
add r6, r6, r0 @ _edata
// 计算出 _edata 的 运行地址
pc寄存器中的值-4
运行地址和链接地址不一致时,需要重定位
实现方式
1. 将代码从 当前物理地址 搬移到 链接地址
嵌入式Linux:物理地址、链接地址、虚拟地址的区别
物理地址,虚拟地址,链接地址的个人理解
PIC位置无关代码