c++ 编译链接运行原理及虚拟地址空间布局

当我们写好.c/.cpp文件时 此时文件还不能运行 因为他要经过以下的四步才可以运行

 

.c/.cpp(生成.i)     编译(生成.s)      汇编(生成.o)       链接(生成.exe)

1.#define宏替换      1.词法分析         指令翻译成二进制    1.合并段和符号表

2.#include 递归展开   2.语法分析                             2.符号解析

3.处理#if #endif等     3.语义分析                             3.分配地址空间

4.添加行号和文件表示 4.代码优化                             4.符号重定位

5.删除注释

6.保留#pragma

 

此时的文件已经成.exe的ELF格式了 然而现在文件还是不可以运行的 因为此时文件还在磁盘上 文件要加载到内存上才可执行 于是还有这以下三步文件才可以运行

 

运行.exe(./main)

1.建立虚拟地址空间到物理内存的映射(创建内核映射结构体)

2.加载指令和数据到内存中

3.程序的入口地址写入pc(保存下一行指令的地址)寄存器中

虚拟地址空间布局映射到真是物理内存如下图:

 

 

 

此时就算虚拟空地址(本身并不存在)被恶意修改 真实物理内存的大小是固定的 也不会影响到其他进程了

注意:数据一般都放在堆和栈 堆和栈都有随机的偏移 是因为防止被恶意修改 堆栈只有在运行的过程才有

DMA是不过寄存器的 直接通过数据总线得到数据

 

int * p = NULL;

*P = 20;

此段代码错误 因为NULL在保留区 保留区不允许访问 而解引用则访问了保留区

 

.data段放的是已初始化且初始化不为0的数据

.bss段放的是未初始化或初始化为0的数据

为什么两个段保留数据?节省的是哪块空间?

.bss为了节省空间 .bss节省的是文件空间(其实.bss段在文件中不存在) 只是从section header 把.bss信息保存了下来

 

符号表

l:本文件 g:全局

强符号:全局已初始化的变量

弱符号:全局未初始化的变量

强弱符号的规则:

  1. 两个强符号重定义错误
  2. 一强一弱 选强符号
  3. 两个弱符号 选数据较大的

.bss弱符号在汇编时 看不到本文件以外存放的强符号 所以先放在common块 链接完后当所有文件都看见后 若有强符号 则用强符号地址 此时弱符号也不再common块 在合理的位置了

 

引入外部符号放在und符号表中找不到 .test段对于外部变量用虚假的0地址代替真实地址针对函数用-4偏移 此时汇编完成 弱符号以及外部符号要在链接中处理

 

Ld链接器只关心全局符号g,80%错误发生在符号解析 main函数是默认入口地址 链接完后弱符号都放入.bss段

Call:近址相对偏移位移 所调用的函数入口地址为下一行指令地址+call所对应的偏移 运行过程中不需要common块 只需指令和数据段

猜你喜欢

转载自blog.csdn.net/xiaobaibai915/article/details/83758711