CSAPP学习笔记

深入理解计算机系统(C语言、数据结构、微嵌、编译原理、数电、模电)

第一章:计算机系统漫游

编译系统

hello.c->hello.i

gcc -E hello.c -o hello.i

hello.i->hello.s

gcc -S hello.i -o hello.s

hello.s->hello.o

gcc -c hello.s -o hello.o

hello.o->hello

gcc hello.o -o hello

第二章:信息的表示和处理

//数据在不同架构处理器下的表示
#include <stdio.h>

typedef unsigned char * byte_pointer;

void show_bytes(byte_pointer start, size_t led)
{
  size_t i;
  for (i = 0 ;i < led; i++)
  {
    printf("%.2x",start[i]);
  }
  printf("\n");
}

void show_int(int x)
{
  show_bytes((byte_pointer)&x,sizeof(int));
}

void show_float(float x)
{
  show_bytes((byte_pointer)&x,sizeof(float));
}

void show_pointer(void *x)
{
  show_bytes((byte_pointer)&x,sizeof(void *));
}

int main()
{
  int i =12345;
  show_int(i);
  return 0;
}

整数、浮点数在计算机内部的表示与运算

第三章:程序的机器级表示

while、do-while、for性能分析

三种都是通过条件测试和跳转指令实现的。

switch、if-else性能分析

switch通过一个跳转表实现,所以只需要执行一次跳转,而if-else需要多次跳转指令,代码效率相对低。

堆栈的分析对比

堆:一般由程序员申请控制,如C语言的malloc,地址由小到大增长,满足后入先出的原则。需要程序员自身控制内存的分配问题。一般栈的空间有限。

栈:一般由系统控制,如int a这种语句,地址由大到小递减,也满足后入先出的原则。我们C语言执行一个函数就是在栈中开辟空间执行,故函数执行完毕,会自动释放内存空间。堆的空间相对较大。

对抗缓冲区溢出攻击

  1. 栈随机化:每次程序运行时,程序栈位置随机,不容易被黑客进行漏洞发掘。

  2. 栈破坏检测:在缓冲区和栈保存的状态值之间存储一个特殊值,成为金丝雀值(随机产生

  3. 限制可执行代码区域:限制内存区域存放可执行代码范围

第四章:处理器体系结构

参考微嵌、数电、模电

第五章:优化程序性能

编写高效的程序

  1. 选择合适的算法和数据结构

    在某些情况下,减少函数调用的开销

  2. 了解编译器的能力和局限性

  3. 探索并行化

投机执行

指程序执行时,遇到分支结构,计算机会预测分支结果,甚至直接执行某个分支的代码。如果预测正确,则将执行结果送到寄存器中,失败则丢弃。此处由分支模块来控制。

第六章:存储器层次结构

存储技术

寄存器—缓存(cache)—主存—外存

  1. 缓存:可以存在多级缓存结构,为静态随机访问存储器(SRAM),用双稳态电路逻辑状态来存储信息。

  2. 主存:为动态随机访问存储器(DRAM),用电容充放电来存储信息,需要不断刷新来保持信息。SDRAM同步动态随机访问存储器速度优于DDRAM。

  3. 外存:

    • 磁盘(机械硬盘)

      磁片、磁面、磁道、521字节、扇区、读/写头

      磁盘取决于寻道时间+旋转时间(转速)+传送时间

    • 固态硬盘(flash)

      闪存芯片(plane、block、page)

      读、写、擦除,只能将1改为0,不能将0改为1

      写以page为单位,擦除以block为单位

局部性

  • 时间局部性,指同一变量在一段时间被多次访问

  • 空间局部性,指访问在一段连续的空间内,如数组的顺序访问

    合理利用局部性原理,可以提高程序执行速度

存储器层次结构

中心思想:速度更快、容量更小的存储设备作为速度更慢、容量更大的存储设备的缓存

相邻存储器层次结构之间块的大小通常一致。

几个概念:

  1. 缓存命中:需要使用k+1层数据时,需要先检索k层数据,如果在k层有缓存的数据,则为命中。

  2. cache的内部结构:内部为一个或多个set(组){S};每个set包含一个或多个cache line{E};每个cache由三部分组成,分别为有效位(1 bit,表示当前cache line的数据是否有效,1有效)、标记、数据块(内存数据的副本){B},数据块中前几位表示地址{m}。

直接映射高速缓存

当cache的每个组只有一个cache line时,称为直接映射。

读取数据的过程

  1. 组选择,根据组索引位,选择组

  2. 行匹配,对比cache line中的标记和地址中的标记是否一致,如果一致,表示数据一定在当前cache line中,如果有效位为0或标记不匹配,则目标数据不在次cache line中。

  3. 字抽取,块偏移决定目标数据在数据块中的位置。

组相联/高速缓存

第七章: 链接

链接

链接是指将可重定位目标文件以及所必要的系统文件组合起来,生成一个可执行目标文件的操作。

可重定位目标文件

每一个可重定位目标文件大致分为3部分:

  1. ELF header:(ELF是可执行可链接格式的缩写)

    gcc -c hello.c -o hello.o
    #查看hello.o的字节数
    wc -c hello.o
    #查看hello.o的EFL header信息
    readelf -h hello.o

    Magic字段解释:

    Type字段:REL表示为可重定位文件

  2. Section:

    • .text:存放已经编译好的机器代码

    • .data:存放已初始化的全局变量和静态变量的值

    • rodata:存放只读数据(printf的格式串和switch语句中的跳转表)

    • .bss:存放未初始化的全局变量和静态变量(被初始化为0的全局变量和静态变量)(并不占用实际空间,是一个占位符)

    • .comment:存放的是编译器的版本信息

    • .symtab:Symbol Table,符号表

      readelf -s hello.o
      
      • 全部符号:由该模块定义,同时能被其他模块引用

      • 外部符号:由其他模块定义,同时被该模块引用

      • 局部符号:只能在该模块定义、使用

    • .rel.text:Relocation Table,重定位表

    • .debug:调试信息

    • .line:原始C程序的行号和.text section中机器指令之间的映射

    • .strtab:String Table,字符串表

  3. 以及Section的表:

    readelf -S hello.o

符号解析

  • 强符号:函数和已经初始化的全局变量

  • 弱符号:未初始化的全局变量

强符号与弱符号,当有同名强符号时,链接时会报错;而同名强、弱共存时,可能会导致程序出现意想不到的错误。

静态库

archive文件是一组可重定位目标文件的集合,在Linux中以.a结尾

libc.a包含atoi、printf、scanf、strcpy、rand

构造静态库

ar rcs 库名.a ***.o ***.o

解包静态库

ar -x 库名.a

静态库的用法

  1. 将所需模块编译成.o文件

  2. 将编译成的.o文件通过ar命令打包成.a文件

  3. 编写模块函数的声明文件.h,并在主模块中include此文件,即可在主文件中调用此函数

  4. 使用gcc编译主模块时,在后面添加.a文件路径即可完成链接

静态库的解析过程

gcc -static main.o -o main ./test.a

链接器先处理main.o,然后处理test.a,最后处理libc.a,文件输入顺序非常重要,一般库放在命令结尾,如果库不是独立的,我们需要对其进行排序操作。(被调用的库在后,相互引用可多次写明静态库)

重定位

  1. 重定位节和符号定义

  2. 重定位节中的符号引用

可执行目标文件

与可重定位目标文件类似

代码运行时内存分布:

在Linux_x86_64位系统上,代码段从地址0x4000000开始,然后向上为数据段,堆在数据段之上,然后是共享区域,共享区域之上为栈(起始地址为248 -1),其上为操作系统保留。

动态链接共享库

静态库局限性

  1. 静态库需要定期维护和更新

  2. 几乎灭个C程序都需要使用标准的I/O函数

共享库

在Linux系统中以.so结尾表示,在Windows中以.dll结尾表示。

构造共享库
gcc -shared -fpic -o 共享库名.so   ***.o ***.o
应用
  1. 分发软件,因为共享库在链接过程中,不是真正与主程序链接在一起,所以只需要升级动态库,在重新执行程序时,就可以完成程序升级。

  2. 构建高性能Web服务器,无需关闭或重启服务就能实现升级

    #在C程序中动态加载共享库
    handle = dlopen("./***.so",RTLD_LAZY)

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇