77-C++编译链接过程

知识点:

1.磁盘:永久化存储,但是I/O速度慢

2.内存:支持程序执行所需要的真实空间

3.内存分为物理内存和虚拟内存

物理内存:内存条,I/O速度快

虚拟内存:虚拟就是假的,不是真正的内存,是磁盘上的一个交换空间,虚拟内存是在磁盘上提前划分了一块空间,当真实物理内存不够用时,将数据暂时存放到虚拟内存上

4.虚拟地址空间:逻辑上给到每个进程的执行空间

5.为什么真实物理内存会不够用?

6.程序执行时,会给每一个进程划分一个执行空间(虚拟地址空间),在32位系统上,大小是4G(2^32),注意:是逻辑上给了4G的空间,并不是真的给了4G的空间,如果当前进程用不到4G的空间,就会浪费,所以最大可以给到4G

7.虚拟地址如何产生?需要哪些步骤?

代码经过编译(预编译、编译、汇编的统称)生成二进制可重定位文件,然后经过链接生成二进制可执行文件,二进制可执行文件可以直接去执行,然后产生虚拟地址空间,虚拟地址空间通过地址映射,映射到真实的内存上面

8.虚拟地址空间的划分

在这里插入图片描述

0x0000 0000~0x0804 8000是预留空间, 不可以访问

一个进程会划分多个线程,每个线程默认分配10M的栈空间,如果没有划分多个线程就属于单一的执行线,默认分配10M的栈空间,如果多余10M,栈就崩了

一小块是存放环境变量、main函数的参数

***32位系统的虚拟地址空间为什么是4G?因为一共有32条地址总线,每一条线是0或者1,能标志的最小地址为0x0000 0000,能标志的最大地址为0xffff ffff,寻址范围就是从0x0000 0000~0xffff ffff,2^32=4G

9.什么是数据?什么是指令?判断一下下面哪些会生成数据?哪些会生成指令

框起来的都是数据,其他的都是指令

数据会存储在数据段(包括.bss段和.data段),指令会存储在指令段(代码段)

bss段存储没有初始化或者初始化为0的数据,data124578存储在bss段

data段存储有初始化且初始化值不为0的数据,data369存储在data段

其他都存储在指令段,包括main,大括号

在这里插入图片描述

并不是有了虚拟地址空间之后才划分了这些段,而是在二进制可执行文件中就已经划分了这些段,虚拟地址空间只是将二进制可执行文件中的对应段读取到虚拟地址空间中来使用

10.gcc -c main中的-c的意思是编译

C文件通过编译(预编译、编译、汇编)生成二进制可重定位文件,然后通过 链接生成二进制可执行文件

C文件到二进制可重定位文件是单文件进行,二进制可重定位文件到二进制可执行文件(链接的时候)是多文件进行

预编译:删除注释/* */ //等,处理#开头的预处理指令#include #define等,生成行号(如报错时提示的行号)和文件名索引

编译:生成符号,生成汇编码

汇编:将汇编码转成二进制,然后就生成了二进制可重定位文件

二进制可重定位文件(.o文件),Linux中 gcc -c生成.o文件 Linux中gcc -o 生成二进制可执行文件

编译是一个统称,包含了预编译,编译,汇编

链接:进行符号的重定位(单文件中很多的符号,多文件后有了更多的符号),然后生成二进制可执行文件,二进制可执行文件就可以直接执行了,然后放到虚拟地址空间中进行执行

###

二进制可重定位文件

1.二进制可重定位文件组成,在Linux系统,通过readelf -h main.o可以查看

在这里插入图片描述

Magic:前面四列(7f 45 4c 46)是魔数,用来标志一个文件

01:代表当前系统的位数 01:32为 10:64位 00:错误,有问题

01:大小端 01:大端 10:小端 00:错误

Class~Version:当前系统的信息

Entry point address:入口地址,如果显示0地址(0x0)说明这个文件执行的时候是从0地址执行,但是0地址到0x0804 8000是预留空间,是不可以访问的,所以说明当前文件是个不可以执行的文件,虽然是二进制文件,但是不可以执行

Start of program headers: program headers的开始位值 Start of program headers: 0(bytes into file)表示program headers的开始位值是从0x 00开始的

Start of section headers:section headers的开始位值 Start of section headers: 208(bytes into file)表示section headers的开始位值是从208(十六进制为0x d0)开始的

Size of this header: 52(bytes) 表示当前文件的头的大小为52字节(0x 34)

Size of section headers:40(bytes) 表示每块section headers的大小是40字节

Number of section headers: 9 表示section headers划分了9块

2.C文件经过编译生成二进制可重定位文件,然后经过链接生成二进制可执行文件,然后二进制可执行文件执行起来之后,会将数据放到虚拟地址空间中,然后经过地址映射,映射到内存中

3.off表示起始位置,size表示大小,al表示对齐方式

在这里插入图片描述

存储是按字节进行排列的,不可能出现重合的空间,但是为什么.bss段和.comment段的起始位置都是00005c(0x5c)呢?到底00005c(0x5c)是谁的起始地址呢?其实是.comment段的起始位置,而不是.bss段的,这是为什么呢?

.bss段只进行了标志,并没有给他真实的划分内存,.bss段存储的是没有初始化(没有初始化的值就是0)或者初始化为零的数据,就是说.bss段存储的都是零,不会产生数据值的修改,.bss段只用做到向下传递即可,当前文件并不是在执行空间里(不是二进制可执行文件而是二进制可重定位文件),只需要标志出来有这些东西就行

.symtab就是符号表,用来标记.bss段数据的存在

4. ①.bss段不进行真实的存储,那么如何标记这些数据的存在?

使用符号表进行标记

②.bss段大小为20字节,但是理论上存储在.bss段有六个int数据,应该是24字节,还有一个去哪里了?

还有一个并没有放在.bss段中,而是仅仅进行了一个COM标记,COM的含义是:弱符号,弱符号就是没有初始化的非静态数据,弱符号会在链接过程中被同名的强符号替代

5.什么是符号?所有的数据都会生成符号,函数名也会生成符号

在这里插入图片描述

6.指令一旦生成就不再改变了

7.为什么输出结果a为100,b为0?

因为fun中的a是一个弱符号,而右边文件中的a是一个强符号,在链接的时候,弱符号就会被同名的强符号替代,所以就会向右边文件的a的起始地址写入4个字节的100,因为右边文件a的大小为两个字节,所以又把b的值覆盖掉了,所以输出来的结果为0

这个程序在Linux系统中是可以执行的,在VS中有内存保护,写越界就会写入到保护的内存中去了,打印出来的b就还是20,在C++中同名会报错

在这里插入图片描述

二进制可执行文件

1.文件划分基本和二进制可重定位文件一样

在这里插入图片描述

2.在二进制可执行文件中,.bss段和.comment段的起始位置仍然是一样的

在这里插入图片描述

3.在二进制可执行文件中,data1现在在.bss段中存储(之前仅仅是COM标记),如果在链接过程中没有强符号的替换,那么就会把弱符号转换为强符号,链接之后就没有弱符号了,要么被强符号替代了,要么转换为强符号了

在这里插入图片描述

4.C文件仅仅编译后,fun函数和printf函数都属于未定义的状态,就是存在这个符号,但是具体引入到哪个地方还不知道,而main函数生成了指令,main函数所对应的位置在.text段中

在这里插入图片描述

5.在经过链接之后,fun函数所对应的位置在.text段中,但是为什么printf函数还是处在未定义的状态中呢?这是因为printf函数在动态库,只有执行的时候才会进行索引

在这里插入图片描述

6.动态库(.so或者.lib)

7.二进制可执行文件中各段的划分和大小

在这里插入图片描述

8.第一个load页是只读页,不可以修改的,常量;第二个load页是可读可写的

一个页是4K

在这里插入图片描述

9.虚拟地址空间:只是进行逻辑限定,执行起来后虚拟地址空间会映射到真实内存

10.真实存储:是在内存中

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值