【compile theory】

写的代码的源程序都是以字节序列存储在文件中的,比如#include<iostream> #是35程序第一个整数值为35 每行结尾是以\n换行符结束代表ascll码10;.cpp .c的文件实际由ascll码构成的文本文件。

代码如何转化为可执行程序(编译转化成机器识别的二进制文件)运行?

gcc -o hello hello.cpp 

预处理:将头文件内容替换展开,宏替换注释去掉。

gcc -E server.c -o server.i

.i文件内容如下图:

编译阶段:编译器将文本文件hello.i转化为hello.s,汇编语言(低级机器语言指令

指令:gcc -S server.i -o server.s

汇编阶段:将低级机器语言转换为机器语言

指令:gcc -c server.s -o server.o

链接器:(将库函数的代码链接到程序中比printf如pintf.o链接到server.o中)变成了可执行程序

指令:gcc serer.o -o server

ld -o prog 

链接:将各种代码和数据片段收集组合成一个单一文件的过程。

链接可用于编译(源代码翻译成机器代码),也可用于加载(程序被加载器加载到内存并执行)。

ld命令(链接)需要指定所需的动态库,缺少一个都会连接出错。

正常编译程序一步gcc即可生成可执行程序,相当于里边把这些过程执行一遍。一步步来目的是为了详细描述过程。shell中有一个加载器的函数,将可执行文件prog的代码和数据复制到内存中,将控制转移到程序的开头

1.2系统硬件的组成

(1)总线(贯穿整个系统的电子管道),大多数机器字长要么是4字节,要么是8字节。

(2)I/O设备(系统与外部世界联系的通道),用户输入鼠标键盘,输出显示器长期存储数据的磁盘(可执行程序存在磁盘中)

I/O设备通过控制器或适配器I/O总线相连控制器是I/O设备本身或者系统主印制电路板上的芯片组(主板),适配器是插在主板卡槽上的卡。控制器适配器是为两者传递信息

(3)主存(动态随机存储器DRAM芯片组成

是临时存储设备,在处理器执行程序,来存放数据,逻辑上线行字节数组。也是常说的内存

(4)处理器CPU

是解释存储在主存指令的引擎,cpu的核心是程序计数器pc,任何时刻pc指向主存某条机器语言指令(含有该条指令地址

系统从通电的开始至结束一直都在执行着,pc指向的指令再更新程序技术器

输入一个可执行程序的流程:将用户输入的hello放到内存中

按下回车后:shell执行指令将可执行文件磁盘复制到主存中

内存复制完程序之后,cpu开始执行main程序的机器指令,将数据复制到寄存器上,在显示到最终屏幕上。

目标文件的三种形式:

可重定位目标文件。(目标代码和二进制文件)在编译时与其他可重定位文件结合起来。

可执行文件。包含二进制文件和代码。可直接复制到内存中并执行

共享目标文件。特殊类型的可重定位目标文件。(在加载时,或运行动态的加载进内存

链接分类:静态,动态

静态链接:由连接器在链接时将库内容加入到可执行程序中

优点:运行时对环境依赖较小,兼容性较好

缺点:生成的程序较大,需要更多的系统资源,装入内存消耗更多的时间

库函数更新,重新编译应用程序

静态库:目标代码的集合,可执行程序运行前就加入代码中,成为可执行程序的一部分

一般格式libXXX.a

制作静态库:(1)将源文件生成.o文件(二进制文件)g++ -c

(2)建立索引用打包工具

ar - rsc lib.shuai.a test.o 可以加多个.o文件

(3)静态库制作完成之后,需要将.a文件和头文件一起发布给用户

使用方法:g++ main.cpp -L ./ -I ./ -l test -o main

-L动态库所在目录 -I 头文件所在录 -l(小L) 动态库名(前去掉lib,后去掉.a

静态库缺点:容易造成空间浪费。(如果有多个比如500程序用到这个静态库,在内存中有多个浪费空间,造成内存不足)

动态库很好解决这个问题

(1)生成目标文件:加编译选项-fPIC(命令是为了在多个程序中共享

g++ -fPIC -c test.cpp 会自动生成test.o文件

(2) 生成共享库,此时要加链接器选项: -shared

g++ -shared test.o -o libtest.so

(3)nm 配合grep 查看相应函数

(4)编译cpp文件链接动态库 g++ main.cpp -L -I -I 和静态库使用方法一样 

(5)执行出错

ldd查看依赖动态库信息(需要添加动态库的绝对路径

系统加载可执行代码,执行通过动态载入器(dynamic linker)完成,elf格式程序通过ld-linux.so*来完成的

解决办法

(1)将动态库的绝对路径加入到 /etc/ld.so.conf 配置文件中

(2)执行sudo ldconfig -v 

在运行可执行程序就解决了

可定位目标文件ELF

ELF头16字节序列开始

(1)系统字的大小和字节顺序

(2)帮助链接器进行语法分析解释目标文件信息(ELF头大小,目标文件类型等)。

.text区域已编译程序机器代码。

.rodata 只读数据,printf的格式串,开关语句跳转表

.data 已初始化的全局变量区和静态C变量区。

.bss 未初始化全局变量和静态C变量区,以及所有未初始化为0的全局或静态变量区域。(在节中不占用实际空间,只是一个占位符)

.symtab 存放程序被定义引用的函数和全局变量信息

链接器上下文有三种不同符号:

模块定义并能被其他模块引用的全局符号。(非静态c函数,和全局变量)

其他模块定义并被模块m引用的全局符号。外部符号(非静态c函数,和全局变量

只被模块m定义引用的局部符号。对应带static属性的c函数,和全局变量。不能被其他模块引用

  • 8
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值