深入编译链接和运行

我们先看下面这份代码:
#include<stdio.h>
int gdata1=10;
int gdata2=0;
int gdata3;

static int gdata4=11;
static int gdata5=0;
static int gdata6;

int main()
{
        int a=12;
	int b=0;
	int c;
	static int d=13;
	static int e=0;
	static int f;
	return 0;
}
额,代码中有全局变量,静态全局变量,局部变量,静态局部变量
gdata1,gdata2,gdata3,gdata4,gdata5,gdata6的作用域都是从程序开始到结束,a,b,c,d,e,f的作用域是在代码块中,d,e,f一直占用内存,直到程序结束。

我们知道我们用C/C++写完一份代码后是要经过编译和链接才能生成可执行程序(.exe),这个可执行程序文件本身在磁盘中存储的。那么如果我们要运行它,就必须把它加载到内存中去运行。CPU访问内存的速度要比访问磁盘的速度快得多。
那么需要把什么东西加载到内存中去呢?
1、指令   2、数据
那么我们必须知道我们编写的程序中哪些是指令,哪些又是数据?
指令和数据又是怎么存储在内存中的呢?
计算机硬件CPU,内存,I/0都可以使用不同商家的硬件,操作系统为了屏蔽底层这些硬件的差异,使我们调用程序的时候能够使用统一的接口,如图:

为了屏蔽I/O的差异,使用VFS,屏蔽内存与I/O,使用虚拟地址空间,屏蔽CPU和I/0,使用了资源调度的最小单位,进程。

那么我们的程序加载到内存其实是在虚拟地址空间里,也就是虚拟内存里,操作系统提供给我们物理内存的管理方法,虚拟内存。

虚拟内存有多大呢?跟CPU的位数有关,如果是32位的,虚拟内存就是2^32,4G的大小
那么虚拟地址空间是怎么存放数据的呢?



.txt 放指令
.data 放数据 (初始化且不为0的数据)
.bss 放数据 (未初始化和初始化为0的数据)
那么我们上面写的程序哪个是指令,哪个是数据?

额,指令和数据为什么分开放?数据段为什么要分成.data和.bss?这样存放节省了谁的空间,虚拟地址空间还是文件空间


程序的编译过程是怎样的?


二进制可重定位目标文件的格式是什么呢?
我们在Linux下看一下:


.obj里面有段   .text    
                       .data    16进制下字节数为C ,程序中gdata1,gdata4,d都属于.data段,合起来12个字节
                       .bss     16进制下字节数为14,程序中按照我们之前说的,应该有6个数据,合起来是24个,可是.bss段只有20个字节,那么6个中哪个不是存储在.data块呢?
                       .comment 
                       .note.GUN-stack
                 .


我们读取.obj发现有一个文件头:里面包含了在哪种机器上运行,入口地址(entry point address)为0x0,我们说过0地址是不可访问的,那么.obj文件是不能执行的。

我么再看一下.obj文件的格式:



relocatable  是一个可重定位文件,并不是可执行文件。
我们再来看看:
size of this header:                 52(bytes)                                     文件头的大小是52字节
我们在段信息的那张图里知道:


VMA虚拟内存地址,LMA加载内存地址,都是0,那么说明在编译阶段是不会给程序分配内存的。

再来看File off 偏移量:

那么.data块下面根本不是.bss段,而是.comment段,那么.bss段是节省了文件的空间。

查看其他的段:


查看段的内容:


.data段是不是有10,11,13,.obj文件的格式就是这样了。


Start of section  headers:     204 bytes    16进制是CC


我们段表的第一条信息,就是starting at offset 0xcc,说明.obj文件先找文件头,在文件头里找到段头的偏移地址,就能找到.bss里面的数据了。




猜你喜欢

转载自blog.csdn.net/lyt15829797751/article/details/78446506