C++02(编译链接运行原理)


0x12345678 ,1的权重高

在这里插入图片描述
在这里插入图片描述

1.如何将源文件变成一个进程

.c/.cpp—>进程
由于操作系统只能识别机器码(0 1),因此将源文件变成进程,需要五个步骤:

1.预编译:(.cpp—>.i)

1.删除#define,然后进行文本替换

//不建议使用宏定义,不安全,宏处理就是简单的问题替换  没有类型检查和安全检查
//因此在C++中尽量不要用宏定义
#define MUT(a,b) a*b
int main()
{
	int rt = MUT(5+5,5+5);   //替换会变成5+5*5+5  --》答案会变成35
	printf(“rt:%d\n”,rt);
	return 0;
}

2.处理以#include的头文件,以递归的形式展开(因为头文件中可能还会包含头文件)
3.处理#if #endif等预编译指令
4.删除注释
5.添加行号和文件标识(便于定位错误的位置)
6.保留#pragma ,留给编译器处理

2.编译:(.i----->.s)

.i是高级语言
词法命名规则:字母数字下划线,数字不能做首字母
1.词法分析
2.语法分析:一行表达式是否正确
3.语义分析:结合上下文,分析是否正确
4.代码优化(可以提高运行效率)
5.生成汇编指令
.s 汇编语言:低级语言

//编译过程生成了汇编语言
int main()
{
	int abc=10;
	//mov dword ptr[abc],0ah   //16进制的10  dword=double word (一个字两个字节dword占四个字节)
	//意思就是将10放进abc所代表的内存块中,占4个字节
	return 0;
}

操作系统也看不懂低级语言

3.汇编:(.s---->.o)

翻译指令:把低级语言翻译成机器语言,生成了.o目标文件/可重入的二进制文件
.o文件仍然不能运行

3.1 变量存放在哪里

数据段分为:
.data--->已初始化且初始化不为0的数据
.bss---->未初始化或初始化为0的数据

全局变量、静态全局变量、静态局部变量都是数据。
局部变量是指令

int gdata1=10;//.data
int gdata2=0;//.bss
int gdata3;//.bss

static int gdata4=20;//.data
static int gdata5=0;//.bss
static int gdata6;//.bss

char* p="hello";  
//字符串包含六个字符,指针大小为4个字节,所以指针中存放的是字符串的地址
//而字符串本身存放在.rodata--->read-only data只读数据段
int main()                  //函数名生成的是指令  .text段
{
	static int ldata1=30;    //.data
	static int ldata2=0;//.bss
	static int ldata3;//.bss
	int ldata4=40;//.text
	int ldata5=0;//.text
	int ldata6;//.text
	return 0;
}

关于之前说过的局部变量存储在栈区,为什么现在存储在.text指令段?
答:是两个不同的过程。
在指令段:汇编过程,在运行之前,所有东西都在文件中(文件中是没有栈区和堆区)
在栈区:运行后,程序才在内存中,栈是内存区域,运行指令,才会在栈上给局部变量开辟内存区域。

3.2汇编后生成的.o文件中存在什么内容?(提及了强弱符号)

汇编后生成的.o文件中存在什么内容?
可重入的二进制文件:
ELF格式文件
.text指令段–.data数据段–.bss数据段–.comment注释信息段—.nte.GUN-stack堆栈提示段
File off --起始偏移量 Algn–字节偏移
在这里插入图片描述
问题:

    • 汇编阶段 bss少了4个字节,一个数据,少了哪个数据?为什么?
      答:少了gdata3,在comment块
      gdata3是一个弱符号,不能直接确定地址,因此不能存在bss中,当链接完成后,如果没有gdata3强符号,则会将gdata3放入bss 段
      为什么gdata6和ldata3不放在comment块?
      答:强弱符号不确定,是因为存在两个文件中,而静态变量的特点是,只能在本文件中可见。
      只有c语言有强弱符号,在c++中,程序会报错
//原因与C语言中的强弱符号有关
强符号:全局的已初始化的符号
弱符号:全局的未初始化的符号 
规则:
1.两强符号--》报错
2.一强一弱--》选强
3.两弱------》编译器决定

预编译、编译、汇编三个过程是独立的,一个完成另一个才开始,处理的是同一个源文件

编译main.c的时候是看不到test.c文件的,编译test.c是看不到main.c
//main.c
#include<stdio.h>
short a=10; //强符号
short b=20;

int main()
{
	func();
	printf("a:%d\n",a);
	printf("b:%d\n",b);
}
//test.c
int a; 
 //弱符号,编译器不能确定其他的源文件中是否存在强符号,因此不能放在bss段,只能先放在comment块
void func()
{
	a=30;
}
//编译完成后生成了汇编指令:mov dword ptr[a] 1E

//运行时,a,b分配的内存空间,a和b均只有两个字节,要将汇编指令1E(四字节)放入两字节a中会产生溢出,但此时溢出刚好覆盖了内存b中的值,将b变为0000 0000
    • 通过计算,bss段不存在,为什么?信息是从哪里来的?
      section headers
      在这里插入图片描述

3.3 ELF文件格式与布局

文件的格式(Class)相同的话,文件的布局就是相同的
Data:文件的存放格式(little endian小端存放)
OS/ABI:操作系统UNIX-System V
Type:格式REL(Relocatable file)可重入的文件
Entry point address:0x0 整个程序的入口地址,一般就是main函数的地址
在这里插入图片描述
在这里插入图片描述
可执行文件最后要和虚拟地址空间做映射,布局比较像就是为了方便映射

3.4指令数据生成的符号存放的位置和属性

文件名称(main.c)、指令段、数据段、数据和指令会生成符号
注意:(所有数据都能生成符号,指令只有函数名可以生成符号,普通局部变量不会生成符号,只会存放在指令段)

3.5外部引入变量的问题(在UND区域存放)

int gdata1=10;//.data
int gdata2=0;//.bss
int gdata3;//.bss

static int gdata4=20;//.data
static int gdata5=0;//.bss
static int gdata6;//.bss

extern int gdata;  //声明gdata的定义在外部
extern int Sum(int,int);
int main()                  //函数名生成的是指令  .text段
{
	static int ldata1=30;    //.data
	static int ldata2=0;//.bss
	static int ldata3;//.bss
	int ldata4=40;//.text
	int ldata5=0;//.text
	int ldata6=Sum(ldata4,ldata5);//.text
	return 0;
}

test.c

int gdata=1000;
int Sum(int a,int b)
{
	return a+b;
}

外部引入的变量都放在UND未定义区
在这里插入图片描述

3.6虚假地址、虚假位移问题

在这里插入图片描述

4.链接:(.o—>.exe)

在这里插入图片描述1.合并段和符号表
2.符号解析
3.分配地址和空间(程序和虚拟地址空间的映射)
4.符号的重定位

5.运行:(程序变成进程)

1.建立虚拟地址空间和物理内存的映射(创建内核映射结构体),创建页目录页表
2.加载指令和数据
3.把入口地址放到下一行指令寄存器中

6.附上笔记

在这里插入图片描述

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值