《计算机组成原理/CSAPP》网课总结(二)——编译原理基础
这部分是四月份的安排,拖到五一放假了,主要是对源码编译过程的一次总结,总的来说,大致可分为预编译、编译、汇编和链接四部分。这里简单记录一下:

一 概述
1、预处理
或者说是预编译,指的是在编译前需要做的一些处理,如宏替换、include替换等等,这部分没什么东西
每一个.c或.cpp源代码文件会生成一个对应的.i文件;
2、编译
编译过程将预处理后的文件生成为.s的汇编文件,汇编文件可用文本编辑器打开查看,里面的汇编代码是直接对应CPU动作的;
3、汇编
汇编过程将.s汇编文件映射为可重定位目标文件, 一般为.o或.obj扩展名。
4、链接
链接阶段是通过链接器将不同的.o文件进行打包,可以理解为单纯的拼接操作,但操作的时候会检查各个实现是否存在。此外,链接可执行文件时还会导入c或cpp的启动相关的必要系统文件,如cruntime等
二 其他相关知识点
在shell中启动可执行文件后,shell会调用操作系统的加载器将可执行文件读入内存,然后将cpu的控制权交给可执行文件,然后开始执行。
可重定位目标文件的基本组成部分如下,链接过程是基于符号完成粘合的,比如a文件中调用了函数f,b文件中定义了函数f,那么链接过程就能正确完成;否则会出现找不到定义的链接错误,同样如果出现重复定义,也会报错。
至于最终生成可执行文件还是库文件,取决于程序员。如果是生成可执行文件,链接器还会链接调用main函数的相关系统文件,这些文件会调用main函数,所以如果源码里面没有实现,就会报“无法解析的外部符号main”,因为连接器找不到main函数的实现。
如果是生成库文件,比如静态库,我们在linxu下可以用命令
ar rcs libstatic.a *.o *.o,这样可以将可重定位目标粘合在一起,在使用的时候,我们只需要include静态库的头文件,使用其中的函数声明,然后再静态链接的时候链接之前生成的libstatic.lib即可,这个时候只有那些使用到的函数定义会被复制到可执行文件中,没有使用的不会复制,当然其他cruntime模块肯定会被链进来,这是默认的。如下图是一个可执行文件所包含的模块,主要分为代码段和数据段,以及其他部分,程序执行时前两部分会加载到内存中,然后跳转到系统函数
_start()处开始执行,_start()函数是C运行时库中定义的,然后_start()调用_libc_start_main(),然后再调用用户代码中的main()函数

- 如下图是可执行文件加载到内存中虚拟地址空间布局,我们在平时写代码的时候,需要理解其中的不同区域的意义:
在linux x86-64系统中,代码段总是从0x400000处开始,这部分是只读的;然后是数据段;接下来是堆内存段,堆内存是从低地址向高地址分配的;然后是一部分为共享库保留的内存区域;然后是栈空间,起始地址是248-1,这是最大合法用户地址,栈的开辟方向是从高到低;在往上,从248开始的地址是为操作系统的代码和数据保留的,对用户代码不可见。

在启动可执行文件后,操作系统会使用地址空间随机化的策略,栈、共享库和堆的运行时地址都会变化,以防止受到攻击。
动态链接库(动态库),一种特殊的可重定位目标文件。生成共享库的方式和静态库类似,linux下编译命令为
gcc -shared -fpic -o libshared.so A.c B.c,这样就可以生成位置无关的动态链接库文件,在使用时,通过命令gcc -o main main.c ./libshared.so完成动态链接,这个动作只会复制符号表和重定位信息。值得一提的是,在windows下,动态库的符号表和可重定位信息单独存放在一个.lib的动态库的导入库文件中,而真正的动态库实现在另一个同名的.dll中,所以在Windows下执行动态链接其实是静态链接导入库的过程。动态链接库的使用,在可执行文件启动时,可执行文件会检查一个名为.interp的section, 里面包含了动态链接器(ld-linux.so)的路径名,启动动态链接器来执行重定位代码和数据的工作,将动态链接的共享库加载到某个内存段,然后重定位可执行文件中由动态库定义的符号引用。完成重定位后再将控制权交还给可执行文件,至此完成动态库的加载和重定位工作,以后动态库的内存位置就固定了。这种动态库方式需要在编译时就链接动态库,在可执行文件开始执行前就要完成加载,这种方式称为动态库的静态加载。
动态库的动态加载,这种技术更加灵活,无需再编译期将动态库链接到应用中,在运行期间加载某个共享库进行使用。linux下可使用
void *dlopen(const char *filename, int flag)进行运行期加载动态库,示例:void* handle = dlopen("./libvector.so", RTLD_LAZY),信号RTLD_LAZY意思是推迟符号解析直到动态库中的代码被调用时。使用动态库的函数的方法:void *dlsym(void* handle, char* symbol),比如说我们蒂阿勇句柄handle指向的共享库中的add(int a, int b)函数,那么add = dlsym(handle, "add")将返回函数add(int a, int b)的地址供使用;最后,调用方法int dlclose(void* handle)可以将动态库关闭(卸载)。
以上做了一个简要总结,这些内容在我们写具体代码时可能不太重视,但是对构建知识体系,处理一些链接bug还是非常重要的。
《计算机组成原理/CSAPP》网课总结(二)——编译原理基础的更多相关文章
- 《计算机组成原理/CSAPP》网课总结(一)
现在是2022年4月17日晚10点,本月计划的网课<csapp讲解>视频课看到了第八章"异常"第三讲,视频讲的很好但更新很慢,暂时没有最新的讲解,所以先做一个简单总结. ...
- python网课自动刷课程序-------selenium+chromedriver
python的强大之处就在于有许多已经写好的功能库提供,这些库强大且易用,对于写一些有特定功能的小程序十分方便. 现在就用pyhton的selenium+谷歌游览器写一个可以自动刷课的程序,以智慧树上 ...
- linux的系统组成和计算机组成原理,linux常用操作
Linux入门 linux简介 学习目的:linux服务器操作系统稳定长期运行,python,pycharm装于linux上 linux系统组成 应用软件:调用系统软件接口 linux操作系统分两 ...
- Linux内核学习期末总结(网课)
标签(空格分隔): 20135321余佳源 余佳源(原创作品转载请注明出处) <Linux内核分析> MOOC课程http://mooc.study.163.com/course/USTC ...
- 计算机组成原理(电脑硬件&语言分类)
计算机组成原理 一.电脑硬件配置 CPU :中央处理器(人类的大脑) -飞机 内存:存放一些临时数据(人类的短暂记忆-右脑) -高铁 硬盘:存储永久数据(左脑-长期记忆) - 汽车 输入输出:键盘鼠标 ...
- Stanford公开课《编译原理》学习笔记(1~4课)
目录 一. 编译的基本流程 二. Lexical Analysis(词法分析阶段) 2.1 Lexical Specification(分词原则) 2.2 Finite Automata (典型分词算 ...
- 推荐书单(网课)-人生/编程/Python/机器学习-130本
目录 总计(130本) 一.在读 二.将读 三.已读 非专业书单(77本) 四.已读 专业书单(53本) 五.已看网课(8个) 六.在看网课 一个人如果抱着义务的意识去读书,便不了解读书的艺术.--林 ...
- 《数据结构》《C++程序设计》《计算机组成原理》中的英语名词
一.数据结构 data 数据data element 数据元素data item 数据项data object 数据对象data structure 数据结构ADT (Abstruct Date Ty ...
- 《计算机组成原理 》& 《计算机网络》& 《数据库》 Roadmap for self-taugh student
计算机组成原理: UCB的这门课绝对是不错的资源. Great Ideas in Computer Architecture (Machine Structures) B站:https://www.b ...
随机推荐
- 发现程序美----while+for冒泡实现的
思想记录: 每一轮回的冒泡都将产生一个最大值,其后每次循环次数都将少一次,因为每次都会确定一个最大值. private void method(){ int[] list = {10,7,8,4,7, ...
- 关于kafka客户端版本与服务端版本不一致导致的一次坑
上周开发了一个功能,需要使用kafka接上游数据并入库,本地开发时,自己安装了一个kafka服务,开发测试时使用本地的kafka服务给主题发消息,然后在自己本地的代码中进行调试.使用的kafka版本如 ...
- jQuery--属性和CSS
1.属性和CSS介绍 属性(重点掌握) attr(name) 获取指定属性名的值 attr(key,val) 给一个指定属性名设置值 attr(prop) 给多个属性名设置值.参数:prop json ...
- Mybatis框架基础入门(七)--关联查询
1.一对一查询 1.1 使用resultType接收查询结果 修改pojo类 public class OrderUser extends order { private String usernam ...
- linux-安装zookeeper及相关操作
下载两个安装包并解压: 配置jdk环境变量: [root@VM-0-10-centos zookeeper]# cat /root/.bash_profile # .bash_profile # Ge ...
- git-learningmeiy
什么是版本控制-版本迭代: 版本控制(Revision control)是一种在开发的过程中用于管理我们对文件.目录或工程等内容的修改历史,方便查看更改历史记录,备份以便恢复以前的版本的软件工程技术. ...
- 在多线程环境下,SimpleDateFormat 是线程安全的吗?
不是,非常不幸,DateFormat 的所有实现,包括 SimpleDateFormat 都不是 线程安全的,因此你不应该在多线程序中使用,除非是在对外线程安全的环境中 使用,如 将 SimpleDa ...
- 一个 Spring 的应用看起来象什么?
一个定义了一些功能的接口.这实现包括属性,它的 Setter , getter 方法和函数等.Spring AOP.Spring 的 XML 配置文件.使用以上功能的客户端程序.
- “a==b”和”a.equals(b)”有什么区别?
如果 a 和 b 都是对象,则 a==b 是比较两个对象的引用,只有当 a 和 b 指 向的是堆中的同一个对象才会返回 true,而 a.equals(b) 是进行逻辑比较,所以 通常需要重写该方法来 ...
- HTML 5中的本地存储概念?
很多时候,我们想在本地计算机存储有关用户的信息.例如,假设用户已经填满了一半的长表单,互联网却突然连接中断.此时,用户希望能在本地存储这些信息,然后当重新连接到互联网的时候,获取这些信息,并将其发送到 ...