【第 6 周】深入理解计算机系统共读心得体会

所在小组

第六组

组内昵称

蒋权

你的心得体会

一些重要的笔记和词汇

  • 链接是将各种代码和数据片段收集并组合成为一个单一文件的过程。
  • 静态链接:以一组可重定位目标文件和命令行参数作为输入,生成一个完全链接的、可以加载和运行的可执行目标文件作为输出。
  • 一共有两个主要任务:

符号解析:目标文件定义和引用的符号,每个符号对应于一个函数、一个全局变量或一个静态变量(注意,没有局部变量)。符号解析的目的是将每个符号引用正好和一个符号定义关联起来。

重定位:在完成符号解析后,就可以重定位这些节,修改所有对这些符号的引用,使得他们指向这个内存位置。

  • 目标文件的概念。

有三种形式,

可重定位目标文件:包含二进制代码和数据,在编译时与其他可重定位目标文件合并起来,创建一个可执行目标文件。

可执行目标文件:包含二进制代码和数据,其形式可以被直接复制到内存并执行。

共享目标文件:特殊的可重定位目标文件,可被动态地加载进内存并链接。

  • 目标文件的格式:ELF。

  • 目标文件都是按照特定的文件格式来组织的,Linux 和 Windows使用 可执行可链接格式(ELF)。

所在小组

第二组

组内昵称

陶鑫

心得体会

1、 静态链接是由在链接时将库的内容加入到可执行程序中的做法。链接器是一个独立程序,将一个或多个库或目标文件(先前由编译器或汇编器生成)链接到一块生成可执行程序。为了构造可执行文件,链接器必须完成两个主要任务: 符号解析和重定位;

2、静态库, 程序在编译阶段,会将引用到的库中的左右内容复制到程序中,然后在链接阶段,会将汇编生成的目标文件.o与引用到的库一起链接打包到可执行文件中。因此对应的链接方式称为静态链接。试想一下,静态库与汇编生成的目标文件一起链接为可执行文件,那么静态库必定跟.o文件格式相似。其实一个静态库可以简单看成是一组目标文件(.o/.obj文件)的集合 ,即很多目标文件经过压缩打包后形成的一个文件。

3、 重定位:两步组成:1) 重定位节和符号定义,链接器将所有想通类型的节合并为同一类型的新的聚合节、2) 重定位节中的符号引用,链接器修改代码节和数据节中对每个符号的引用,是的他们指向正确 的运行时地址。

4、链接器如何解析多重定义的全局符号,
规则1:不允许多个强符号;
规则2:如果有一个强符号和多个弱符号,那么选择强符号;
规则3:如果有多个弱符号,那么这些弱符号中任意选择一个。

5、动态链接, 他是使得不同的程序开发者和部门能够相对独立地开发和测试自己的程序模块,从某种意义上来讲大大促进了程序的开发效率,原先限制程序的规模也随之扩大。但是慢慢地静态链接的诸多缺点也逐步暴露出来,比如浪费内存和磁盘空间、模块更新困难等问题,使得人们不得不寻找一种更好的方式来组织程序的模块。

6、库打桩(library interpositioning),它允许你截获对共享库函数的调用,取而代之执行自己的代码。基本思想:给定一个需要打桩的目标函数,创建一个包装函数,它的原型与目标函数完全一样。使用某种特殊的打桩机制,你就可以欺骗系统调用包装函数而不是目标函数了。包装函数通常会执行它自己的逻辑,然后调用目标函数,再将日标函数的返回值传递给调用者。

所在小组

第六组

组内昵称

钟荣荣

你的心得体会

链接:理解链接器的作用:理解链接器如何解析引用,什么是库,链接器如何解析引用库可以在面对链接器错误是不会迷惑;了解语言的作用域是如何实现的;帮助理解加载,运行程序,虚拟内存,分页,内存映射等概念;链接器的两个主要任务:符号解析(将目标文件的每个全局符号都绑定到一个唯一的定义);重定位(确定每个符号的最终内存地址,并修改对目标的引用)
异常控制流:理解异常控制流的作用:帮助理解IO,进程,虚拟内存的实现机制;理解操作系统和应用程序如何交互;异常控制流是实现并发的基本机制,有助于理解并发;可以了解高级语言如何实现异常

名词解释

名词 解释
Linux LD 静态链接器(static linker)的一种. 以一组可重定位目标文件(relocatable object file/.o结尾)和命令行参数作为输入,生成一个完全链接的、可以加载和运行的可执行目标文件(executable object file)。
加载器(loader) shell 调用操作系统中一个叫做加载器的函数,将可执行文件中的代码和数据复制到内存,然后将控制转移到这个程序的开头
符号链接(symbol resolution) 目标文件定义和引用符号。每个符号对应于一个函数、一个全局变量或一个静态变量。符号解析的目的是将每个符号引用正好和一个符号定义关联起来
重定位(relocation) 编译器和汇编器生成从地址0开始的代码和数据节。链接器通过把每个符号定义与一个内存位置关联起来,从而重定位这些节,然后修改所有对这些符号的引用,使得它们指向对应的内存位置(即为每个符号分配运行时地址).

目标文件

  • 可重定位目标文件。 包含二进制代码和数据,其形式可以在编译时与其他可重定位目标文件合并起来,创建一个可执行目标文件。
  • 可执行目标文件。包含二进制代码和数据,其形式可以被直接复制到内存并执行
  • 共享目标文件。一个特殊类型的可重定位目标文件,可以在加载或者运行时被动态地加载进内存并链接

When in doubt, invoke the linker with a flag such as the gcc-fno-commonflag, which triggers an error if it encounters multiply-defined global symbols. Or use the -Werror option, which turns all warnings into errors.

当你怀疑有 变量的重复声明 时可以尝试开启

重定位

由两步组成

  • 重定位节和符号定义

    链接器将所有相同类型的节合并为同一类型的新的聚合节。例如: 来自所有输入模块的.data节被全部合并为一个节,这个节成为输出的可执行 目标文件的.data节。然后,链接器将运行时内存地址赋给新的聚合节,赋给输入模块定义的每个节,以及赋给输入模块定义的每个符号。

  • 重定位节中的符号引用

    链接器修改代码节和数据节中对每个符号的引用,使得它们指向正确的运行时地址。

静态库和动态库

为什么-lm或者引入的静态库要放到最后面?

关于库的一般准则时将它们放在命令行的结尾。如果各个库的成员时相互独立的(也就是说没有成员引用另一个成员定义的符号),那么这些库就可以以任何顺序放置在命令行的结尾处。如果库不是相互独立的,那么必须对它们排序,使得对于每个被存档文件的成员外部引用的符号s,在命令行中至少有一个s的定义是在对s的引用之后的。

异常控制流ECF

在任何情况下,当处理器检测到有时间发生时,他就会通过一张叫做一场表的跳转表,进行一个间接过程调用,到一个专门设计用来处理这类事件的操作系统子程序,当异常处理程序完成处理后,根据引起异常的事件的类型,会发生一下三种情况

  • 处理程序将控制返回给当前指令
  • 处理程序将控制返回给下一个指令
  • 中断程序
异常类别
类别 原因 同步异步 返回行为
中断 来自I/o设备的信号 异步 总是返回下一条指令
陷阱 有意的异常 同步 总是返回下一条指令
故障 潜在可恢复的错误 同步 可能返回当前指令
终止 不可恢复的错误 同步 不会返回

异常控制流的概念很宽,从处理器内置的异常(比如除0、段错误)、操作系统的(软件中断)、高级语言提供的(try/catch语句块)

陷阱最重要的作用就是提供了一个像过程一样的接口:syscall n

所在小组: 静默组
组内昵称:黄小黄
心得体会:

  • 链接:是将各种代码和数据片段收集并组合成一个单一文件的过程,这个文件可以被加载到内存并执行。链接可以执行于编译时,加载时或是运行时。

  • 静态链接:静态链接是像Linux LD程序这样的静态链接器以一组可重定位目标文件和命令行参数作为输入,生成一个完全链接的、可以加载和运行的可执行目标文件作为输出。

  • 目标文件三种形式:

– 可重定位目标文件:包含二进制代码和数据,其形式可以在编译时与其他可重定位目标文件合并起来,创建一个可执行目标文件。
可执行目标文件:包含二进制代码和数据,其形式可以直接拷贝到存储器并执行。
共享目标文件:一种特殊类型的可重定位目标文件,可以在加载或运行时被动态地加载到存储器并链接。

  • 典型的ELF 可重定位目标文件包含以下几个节:
    .text:已编译程序的机器代码
    .rodata:制度数据,比如 printf 语句中的格式串和开关语句的跳转表
    .data:已初始化的全局 C 变量。
    .bss:未初始化的全局 C 变量。
    .symtab:一个符号表,它存放在程序中定义和引用的函数和全局变量的信息。
    .rel.text:一个 .text 节中位置的列表,当链接器把这个目标文件和其它文件结合时,需要修改这些设置。
    .rel.data:被模块引用或定义的任何全局变量的重定位信息。
    .debug:一个调试符号表,其条目是程序中定义的局部变量和类型定义。
    .line:原始 C 源程序中的行号和 .text 节中机器指令之间的映射。
    .strtab:一个字符串表,其内容包括 .symtab 和 .debug 节中的符号表,以及节头部中的节名字。

所在小组:

     第二组

组内昵称:

心得体会

  1. 链接是将各种代码和数据片段收集并组合成成为一个单一文件的过程

    • 这个文件必须是可被加载(复制)到存储器中并执行
  2. 链接可执行的几个场景:编译时、加载时、运行时

  3. 静态链接,用一组可重定位的目标文件和命令行输入参数座位输入,生成一个完全链接、可加载和运行的可执行目标文件

  4. 目标文件的三种形式:可重定位文件、可执行目标文件、共享目标文件

  5. 静态库就是将所有相关目标模块打包成为一个单独可执行文件

  6. 异常就是控制流中的突变,来响应处理器状态的某些变化

所在小组

第三组

组内昵称

h0n9xu

你的心得体会

参见chapter_07chapter_08

所在小组

第三组

组内昵称

晴天

你的心得体会

  1. 链接是将各种代码和数据片段收集并组合成一个单一文件的过程,这个文件可被加载到内存并执行。
  2. 链接可以执行于编译期(源代码被翻译为机器代码时),也可以执行于加载时(程序被加载到内存并执行时)。链接器处理称为目标文件的二进制文件
  3. 目标文件有3种形式:可重定位目标文件,可执行目标文件,共享目标文件。编译器和汇编器生成可重定位目标文件(包括共享目标文件)。链接器生成可执行目标文件
  4. 可重定位目标模块m都有一个符号表,包含m定义和引用的符号信息,包括:
    1. 有模块m定义并能被其他模块引用的全局符号。
    2. 由其他模块定义并能被模块m引用的全局符号。
    3. 只被模块m定义和引用的局部符号。
  5. 链接器两个主要任务,符号解析和重定位。
    1. 符号解析:将目标文件中的每个全局符号都绑定到一个唯一的定义。
    2. 重定位:确定每个符号的最终内存地址,并修改对那些目标的引用。

所在小组

第七组

组内昵称

jinmiaoluo

你的心得体会

见: https://github.com/jinmiaoluo/blog/tree/main/example-8-reading-notes/csapp/chapter-7-and-chapter-8

Diff: https://github.com/jinmiaoluo/blog/pull/9/files

所在小组
第一组

组内昵称
成都-郝立鹏

心得体会

这里

所在小组

第二组

组内昵称

叶王

心得体会

  • 静态链接:不同的程序开发者和部门能够相对独立地开发和测试自己的程序模块,大大促进了程序开发效率。
    • 优点:代码装载速度快,执行速度略比动态链接库快;只需保证在开发者的计算机中有正确的.LIB 文件,在以二进制形式发布程序时不需考虑在用户的计算机上.LIB 文件是否存在及版本问题。
    • 缺点:浪费内存和磁盘空间、模块更新困难;会给对程序的更新、部署和发布带来很多麻烦。
  • 动态链接是把链接过程推迟到运行时再进行。
    • 优点:解决了共享目标文件多个副本浪费磁盘和内存空间的问题;使开发过程中各个模块更加独立,耦合度变小,便于不同的开发者和开发组织之间独立进行开发和测试。在内存中共享一个模块:节省内存,还可减少物理页面的换入换出,也可增加 CPU 缓存的命中率,因为不同进程间的数据和指令访问都集中在了同一个共享模块上。加强程序的兼容性,一个程序在不同平台运行时可以动态地链接到由操作系统提供的动态链接库。
    • 缺点:如果使用载入时动态链接,程序启动时发现 DLL 不存在,系统将终止程序并给出错误信息。而使用运行时动态链接,系统不会终止,但由于 DLL 中的导出函数不可用,程序会加载失败;速度比静态链接慢。当某个模块更新后,如果新模块与旧的模块不兼容,那么那些需要该模块才能运行的软件,则会出现错误。
  • 链接器把各个独立汇编的机器语言程序组合起来,并且解决所有未定义的标记,最后生成可执行文件。
    • 分 3 个步骤:1、将代码和数据模块象征性地放入内存;2、决定数据和指令标签的地址;3、修补内部和外部引用。
    • 目标文件是包括机器码和链接器可用信息的程序模块。链接器的工作就是解析未定义的符号引用,将目标文件中的占位符替换为符号的地址。链接器还要完成程序中各目标文件的地址空间的组织,这可能涉及重定位工作。

所在小组

第五组

组内昵称

chesongbin

心得体会

Subject: Linking 链接

Date: 2020-11-01

链接可以分为两个任务:

  • 符号解析:将目标文件中的每个全局变量都绑定到一个唯一的定义
  • 符号重定位:确定每个符号的最终内存地址,并修改目标文件中的地址

链接可以发生在:

  • 编译时静态链接
  • 加载时共享库动态链接
  • 运行时共享库动态链接

静态链接

image

gcc -c addvec.c multvec.c
ar rcs libvector.a addvec.o multvec.o # 创建静态库
gcc -c main2.c
gcc -static -o p2 main2.o ./libvector.a # 创建完全链接的可执行目标文件,使用libc.a 静态库不需要在命令行中指定

加载时共享库动态链接

  • 平时使用gcc时候,没有指定-static 参数,说明使用的是动态库,执行了动态链接
  • 生成的二进制可执行文件是一个部分链接的可执行文件
  • 基本过程:
    • 创建可执行文件时,静态执行部分链接
    • 在程序加载时候,调用动态链接器,完成链接

image

gcc -shared -fpic -o libvector.so addvec.c multvec.c
gcc -o p2 main2.c ./libvector.so # 使用libc.so 动态共享库不需要在命令行中指定

运行时共享库动态链接

Linux系统为动态链接器提供了一些接口

#include<dlfcn.h>
// 以调用我们自己构造的共享库libvector.so为例子
void * handler
void (* addvec)(int *, int *, int *, int)
// 打开共享库文件
handler = dlopen("./libvector.so", RTLD_LAZY)
// 符号解析,获得函数的地址
addvec = dlsym(handler, "addvec")
// 执行函数调用
addvec(x, y, z, 2)

Java本地接口(JNI):允许Java程序调用本地的C和C++函数,基本思想就是将相应的C、C++函数(eg:foo)编译到一个共享库(foo.so)。然后当Java程序在调用foo函数的时候,Java解释器就会利用到运行时共享库动态链接。

其他

这一章阅读比较吃力,有比较多的术语和概念,需要将其转化为自己的“存储模型”

  • 符号:全局变量、全局函数、static变量、static函数,也就是在生成.o文件时候,无法确定具体内存位置的,需要一个符号来表示
  • 链接:将多个.o文件合体,这里需要将.o文件中的符号,改为具体的内存地址

所在小组

第一组

组内昵称

SADAME

你的心得体会

  • 预处理器:将 C 语言代码(da.c)转化成 da.i 文件(gcc –E),对应于预处理命令 cpp
  • 编译器:C 语言代码(da.c, wang.c)经过编译器的处理(gcc -0g -S)成为汇编代码(da.s, wang.s)
  • 汇编器:汇编代码(da.s, wang.s)经过汇编器的处理(gccas)成为对象程序(da.o, wang.o)
  • 链接器:对象程序(da.o, wang.o)以及所需静态库(lib.a)经过链接器的处理(gccld)最终成为计算机可执行的程序
  • 加载器:将可执行程序加载到内存并进行执行,loaderld-linux.so

链接过程

链接器主要是将有关的目标文件彼此相连接生成可加载、可执行的目标文件。链接器的核心工作就是符号表解析和重定位。

所在小组
第二组
组内昵称
文弱书生

心得体会
链接:
是将各种程序和库组合成一个目标文件的过程,目标文件可以被加载到内存并执行。
链接执行时机:
编译时,加载时或运行时。
链接器:
负责链接的程序叫做链接器

静态链接:
用一组可重定位的目标文件和命令行输入参数作为输入,生成一个完全链接、可加载和运行的可执行目标文件
优点:代码加载速度快,执行速度快,在程序执行的时候不需要考虑运行环境
缺点:占用内存和空间,更新程序的时候比较麻烦,需要定期的维护和更新

动态链接:
运行时再进行链接
优点:不会浪费内存和空间,使各个模块更加独立,降低耦合。
缺点:载入时如果发现dll文件不存在会报错,速度比静态链接慢,有版本依赖

所在小组
第一组

组内昵称
深圳-李悦东

心得体会

这里

所在小组

第四组

组内昵称

张旭辉

你的心得体会

  • 静态链接,将代码和数据片段,生成完全链接的、可以加载到内存和可执行的文件。主要分为两步,符号解析和重定位
  • 静态库,被封装起来的一组独立的目标模块,链接时,链接器将只复制被程序引用的目标模块,例如常见的.a, .lib文件
  • Linux下目标文件采用ELF(可执行可链接)格式,包含:ELF头、节和节头部表 节头部表,记录节相关的信息
  • 异常控制流:有三个层次,硬件层:硬件监测到事件触发。操作系统层:内核从一个上下文切换到另一个上下文。 应用层: 一个进程发送信号到另一个进程
  • 上下文切换:1 保存当前进程上下文,2 恢复先前被抢占进程的上下文,3将控制传递给新恢复的进程。

所在小组

五组

组内昵称

张学广

心得体会

第六章 存储器层次结构
这一章介绍了计算机中的各种存储器,以及各自的优缺点和组合使用,之后介绍了如何编写缓存友好的代码,在这部分有很好的收货。
计算机中的存储是分层的,从最高速的cpu缓存,到 L1、L2、L3这些高速缓存,之后是主存以及最后的磁盘存储,规律是存储从小到大,速度从快到慢,造价从高到底,这样的组合利用了各种存储器的优劣势可以兼顾速度大小与造价。
之后是些高速缓存友好的代码,有以下几点

  1. 让常见的情况运行的更快
  2. 尽量增加缓存命中
    到实际中需要注意的两点:
  3. 对局部变量反复利用
  4. 步长为1的引用模式
    命中率主要看高速缓存的原理,一行一行的读取数据是要比一列一列读取快的多的。
    其次也要注意程序的切换,切换程序会导致缓存的刷新,导致命中率降低

所在小组

第三组

组内昵称

uucloud

心得体会

  • 静态链接:程序之所以可以分成多文件,是因为静态链接器会把他们合了起来。链接器主要完成两个任务:符号解析和重定位。
    • 符号解析:将符号引用和符号定义关联起来,比如c的函数定义和函数引用分别在两个文件中,符号解析会把他们关联起来。
    • 重定位:将符号定义和内存关联起来。
  • 静态链接的缺点:1. 当某个库更新时,用了它的程序更新需要重新链接。2. 重复调用的函数会浪费内存。
  • 共享库:在运行或加载时,可以加载到任意的内存地址,并和一个在内存中的程序链接起来。这个过程称为动态链接,由动态链接器执行。共享库也叫共享目标(shared object),linux中通常用.so后缀表示,windows中是DLL。

所在小组

第四组

组内昵称

zhilin

心得体会

  • 链接就是将代码和数据加载到内存中。可以执行于编译时,加载时,运行时。

  • 像Linux ld程序这样的静态链接器以一组可重定位目标文件和命令行参数作为输入,生成一个完全链接的可以加载和运行的可执行目标文件作为输出。

  • 输入的可重定位目标文件由各种不同的代码和数据节组成。

  • 指令在一个节中,初始化的全局变量在另一个节中,而未初始化的变量又在另外一个节中。
    链接器解析符号引用的方法是将每个引用与它输入的可重定位目标文件的符号表中的一个确定符号定义联系起来
    所有的编译系统都提供一种机制,将所有相关的目标模块打包成一个单独的文件,叫做静态库