[CSAPP][深入理解计算机][03]程序的机器级表示

本文深入探讨了Intel处理器的发展历程,从8086到现代的i9,讲解了从16位到64位的扩展。文章详细阐述了汇编语言的生成及反汇编过程,并介绍了寄存器的使用策略。通过实例解析了数据传送、算术逻辑运算、条件码、跳转指令和循环在汇编中的实现。此外,还讨论了函数调用、栈操作、数组和结构体的处理,以及缓冲区溢出的安全问题和防护机制。
摘要由CSDN通过智能技术生成

视频教程:b站九曲阑干【合集】CSAPP

程序的机器级表示

  1. intel处理器的发展历史,从1978年的8086到现在的i9,从16位扩展到64位
  2. 生成汇编文件x.s,汇编文件里面包括以.开头的指导汇编器和链接器的指令,以及与代码相关的汇编代码
  3. intel中把16位看作一个字,所以32位称为双字,64位称为四字,汇编码中指令后缀的字母可以代表数据类型,例如movb,movw分别代表复制字节,复制字
  4. gcc中-s参数表示从c文件生成汇编文件s,改成-c参数则是从c文件生成机器代码o
  5. 利用反汇编工具objdump可以从机器代码o生成汇编代码s

寄存器与数据传送指令

  1. intelx86-64处理器有16个通用寄存器,名字都以%r开头。
  2. 使用寄存器时包括调用者保存和被调用者保存两种策略,16个寄存器分别被定义成不同的策略。
  3. 通过一些编程规范,寄存器在不同程序中扮演了不同角色,例如rax用来保存程序返回值,rsp用来保存程序栈的结束位置,还有6个寄存器用来传递函数参数。
  4. 寄存器带小括号表示内存引用。
  5. mov指令复制时有源操作数和目的操作数 。
  6. 源操作数可以是立即数、内存引用、寄存器地址,目的操作数不可以是立即数。
  7. 源操作数和目的操作数也不可以同时是内存地址,即一个数在内存中进行复制时,需要两条mov指令,只能先复制到寄存器,再从寄存器复制到内存。

栈与数据传送指令

  1. 内存中有一个区域称为程序栈,用来程序执行时寄存器不够用时来保存指令和数据的。
  2. 栈的增长方向是从高地址向低地址,栈顶就是最低地址,所以修改栈顶地址就可以实现pop操作。

算数和逻辑运算指令

  1. 在进行乘法时,移位是生成汇编语言时会自动选择的更高效的指令,由于比例因子是1、2、4、8,所以会用一些分解的指令来组合。

指令与条件码

  1. 条件码寄存器由cpu维护,只有1个bit。
  2. 常用的条件码寄存器有进位标志、零标志、符号标志、溢出标志,当ALU在执行计算和逻辑运算时会更新条件寄存器的值。
  3. 判断a=b就看零标志的值。
  4. 判断a<b就看a-b的符号位和溢出位异或的值。

跳转指令与循环

  1. 在if-else情况下,汇编语言更高效的方式是同时执行两条路径,再根据条件选择返回某个结果,即根据条件执行比跳转指令更高效,原因是因为现在处理器采用的流水线技术不喜欢卡住。
  2. 循环语句是通过条件测试与跳转结合实现。
  3. switch语句通过跳转表实现,因此不需要多次判断,比if-else-else高效。

过程(函数调用)

  1. 当函数执行时需要的存储空间大于寄存器空间时,就会借用栈上的存储空间。
  2. main函数在调用子函数时,要把返回地址存到栈中,子函数调用结束后,就接着把栈中的返回地址弹出来,接着运行main函数。
  3. 当一个函数的参数多于6个时,多余的参数要通过栈来传递。
  4. 用栈来传递参数时,存储数据的大小都是以8个字节的倍数分配空间。
  5. 用栈来保存局部变量时,局部变量不需要8字节对齐。

数组的分配和访问

  1. 指针进行加减运算时会根据指针类型选择加的基数。
  2. 当(定长)二维数组A的某行和(定长)二维数组B的某列进行内积运算时,c语言的实验是一个循环,汇编语言的优化指令就是条件加跳转,首先记录下A行的首地址,B列的首地址和尾地址,相乘之后放到一个寄存器中,再移动到下一个要相乘的数,直到B列地址与尾地址相同。

结构体与联合体

  1. 结构体分配地址空间时,对不同类型的值的起始地址有固定的要求,例如占8个字节的数据类型,起始地址必须是8的倍数,因此如果按顺序排列不满足,就会在前面或者后面插空(为了满足结构体数组,也即是末尾地址要满足下一个结构体首元素的起始地址)直到满足起始地址要求。
  2. 联合体可以不同的类型共享同样的空间,一般很少用,但例如强制类型转换时,就可以定义联合体以一种类型存储,另一种类型访问。

缓冲区溢出

  1. gets函数有一个问题就是不知道返回的数据大小是否超过缓冲区的栈空间,如果溢出的话会导致返回地址错误,程序会跳转到意想不到的地方。
  2. 保护机制一:地址空间布局随机化,程序的不同部分会被加载到内存的不同区域
  3. 保护机制二:栈破坏检测,在缓冲区与栈保护中间加一个金丝雀值,在函数返回时判断金丝雀值是否变化来判断是否有错误
  4. 保护机制三:栈中的页可以被设置属性为可读、可写、不可执行,通过限制可执行代码区域来放置缓冲区溢出攻击
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值