这部分是四月份的安排,拖到五一放假了,主要是对源码编译过程的一次总结,总的来说,大致可分为预编译、编译、汇编和链接四部分。这里简单记录一下:

一 概述
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》网课总结(二)——编译原理基础的更多相关文章

  1. 《计算机组成原理/CSAPP》网课总结(一)

    现在是2022年4月17日晚10点,本月计划的网课<csapp讲解>视频课看到了第八章"异常"第三讲,视频讲的很好但更新很慢,暂时没有最新的讲解,所以先做一个简单总结. ...

  2. python网课自动刷课程序-------selenium+chromedriver

    python的强大之处就在于有许多已经写好的功能库提供,这些库强大且易用,对于写一些有特定功能的小程序十分方便. 现在就用pyhton的selenium+谷歌游览器写一个可以自动刷课的程序,以智慧树上 ...

  3. linux的系统组成和计算机组成原理,linux常用操作

    Linux入门 linux简介   学习目的:linux服务器操作系统稳定长期运行,python,pycharm装于linux上 linux系统组成 应用软件:调用系统软件接口 linux操作系统分两 ...

  4. Linux内核学习期末总结(网课)

    标签(空格分隔): 20135321余佳源 余佳源(原创作品转载请注明出处) <Linux内核分析> MOOC课程http://mooc.study.163.com/course/USTC ...

  5. 计算机组成原理(电脑硬件&语言分类)

    计算机组成原理 一.电脑硬件配置 CPU :中央处理器(人类的大脑) -飞机 内存:存放一些临时数据(人类的短暂记忆-右脑) -高铁 硬盘:存储永久数据(左脑-长期记忆) - 汽车 输入输出:键盘鼠标 ...

  6. Stanford公开课《编译原理》学习笔记(1~4课)

    目录 一. 编译的基本流程 二. Lexical Analysis(词法分析阶段) 2.1 Lexical Specification(分词原则) 2.2 Finite Automata (典型分词算 ...

  7. 推荐书单(网课)-人生/编程/Python/机器学习-130本

    目录 总计(130本) 一.在读 二.将读 三.已读 非专业书单(77本) 四.已读 专业书单(53本) 五.已看网课(8个) 六.在看网课 一个人如果抱着义务的意识去读书,便不了解读书的艺术.--林 ...

  8. 《数据结构》《C++程序设计》《计算机组成原理》中的英语名词

    一.数据结构 data 数据data element 数据元素data item 数据项data object 数据对象data structure 数据结构ADT (Abstruct Date Ty ...

  9. 《计算机组成原理 》& 《计算机网络》& 《数据库》 Roadmap for self-taugh student

    计算机组成原理: UCB的这门课绝对是不错的资源. Great Ideas in Computer Architecture (Machine Structures) B站:https://www.b ...

随机推荐

  1. Spring Boot 的核心配置文件有哪几个?它们的区别是什么?

    Spring Boot 的核心配置文件是 application 和 bootstrap 配置文件.application 配置文件这个容易理解,主要用于 Spring Boot 项目的自动化配置.b ...

  2. Java并发机制(9)--Callable、Future、FutureTask的使用

    Java并发编程:Callable.Future.FutureTask的使用 整理自:博客园-海子-http://www.cnblogs.com/dolphin0520/p/3949310.html ...

  3. WEB架构深度优化之PHP

    一.PHP引擎缓存加速优化(4种) 1.eAccelerator 2.XCache 3.APC 4.Zend 二.使用tmpfs作为缓存加速缓存的目录(可用rc.local或fstab来自动挂载) m ...

  4. .NET面试题整理

    .NET..NET Framework..NET Core和C#的解释各是什么? ASP.NET MVC和ASP.NET Web API的区别是什么? C#中的委托是什么?事件是不是一种委托? 简述P ...

  5. 前端性能优化(JavaScript篇)

    正巧看到在送书,于是乎找了找自己博客上记录过的一些东西来及其无耻的蹭书了~~~ 小广告:更多内容可以看我的博客 优化循环 如果现在有个一个data[]数组,需要对其进行遍历,应当怎么做?最简单的代码是 ...

  6. Java/C++实现装饰模式---模拟手机功能的升级过程

    用装饰模式模拟手机功能的升级过程:简单的手机(SimplePhone)在接收来电时,会发出声音提醒主人:而JarPhone除了声音还能振动:更高级的手机(ComplexPhone)除了声音.振动外,还 ...

  7. 【Android开发】Android 颜色透明度换算

    透明度 透明度分为256阶(0-255),计算机上用16进制表示为(00-ff). 透明就是0阶,不透明就是255阶,如果50%透明就是127阶(256的一半当然是128,但因为是从0开始,所以实际上 ...

  8. 【Android开发】Android6.0请求权限方式

    记录一下最普通的动态请求权限的方法: private int requestCode == 123; //判断当前系统的版本 if(Build.VERSION.SDK_INT >= 23){ i ...

  9. ansble通过脚本定时清理k8s日志

    环境:环境k8s1.17,ansble通过脚本定时清理k8s日志 [root@tidb-21 delete-k8s-logs]# lsansib-delete.sh delete-logs.sh [r ...

  10. 帝国CMS随机调用栏目

    [e:loop={'select * from [!db.pre!]enewsclass where bclassid in(1) order by rand() desc limit 10',10, ...