CSAPP学习笔记 -- 第三章 程序的机器级表示(上)

3.1 历史观点

    IA32是x86-64的32位前身
    每个处理器的设计都是向后兼容的
    
3.2 程序编码

    编译选项 -0g告诉编译器使用会生成符合原始C代码整体结构的机器代码的优化级别。
    机器级编程的两种抽象
        第一种抽象:ISA定义了机器级程序的格式和行为——处理器状态,指令的格式,以及每条指令对状态的影响。
        第二种抽象:机器级程序使用的内存地址是虚拟地址,提供的内存模型看上去是一个非常大的字节数组。
    程序计数器 - PC - %rip - 将要执行的下一条指令在内存中的地址
    整数寄存器文件 - 16个 - 存储地址或者整数数据
    条件码寄存器 - 保存最近执行的算术或逻辑指令的状态信息
    一组向量寄存器可以存放一个或多个整数或浮点数值
    程序内存包含:程序的可执行机器代码、操作系统需要的一些信息、用来管理过程调用和返回的运行时栈、以及用户分配的内存块(比如说用malloc库函数分配)
    一条机器指令只执行一个非常基本的操作
    值得注意的关于机器代码和他的反汇表示的特性值得注意:
        x86-64的执行长度从1到15个字节不等,常用指令以及操作数少的指令所需要的字节数少,而那些不太常用或操作数较多的指令所需字节数多
        设计指令格式的方式是,从某个给定位置开始,可以将字节唯一的解码成机器指令
        反汇编器只是基于机器代码文件中的字节序列来确定汇编代码,他不需要访问该程序的源代码或汇编代码
        反汇编器使用的指令命名规则与GCC生成的汇编代码使用的有写席位的差别。
    汇编代码中,所有以‘.’开头的行都是知道汇编器和链接器工作的伪指令。
    在C语言中插入汇编代码的方法有两种:
        1. 编写完整的函数放进一个独立的汇编代码文件中,让汇编器和链接器把它和用C语言书写的代码合并起来
        2. 使用GCC的内联汇编他行,用asm伪指令可以在C程序中包含简短的汇编代码,这种方法的好处是减少了与机器相关的代码量
 
 
3.3 数据格式

Intel用术语“字word”表示16位数据类型
 
大多数GCC生成的汇编代码指令都有一个字符的后缀,表明操作数的大小
 
 
 
3.4 访问信息

一个x86-64的CPU包含一组16个存储64位值的通用目的寄存器,用来存储整数数据和指针
  • %rax  返回值
  • %rbx  被调用者保存
  • %rcx  第4个参数
  • %rdx  第3个参数
  • %rsi  第2个参数
  • %rdi  第1个参数
  • %rbp  被调用者保存
  • %rsp  栈指针
  • %r8  第5个参数
  • %r9  第6个参数
  • %r10  调用者保存
  • %r11  调用者保存
  • %r12  被调用者保存
  • %r13  被调用者保存
  • %r14  被调用者保存
  • %r15  被调用者保存
 
当这些指令以寄存器作为目标时,对于生成小于8字节结果的指令,寄存器处理剩下字节遵循两个原则
  • 生成1/2字节数字的指令会保持剩下的字节不变
  • 生成4字节数字的指令会把高四位字节置0
 
大多数指令有一个或多个操作数,指示出执行一个操作中要使用的源数据值,以及放置结果的目的位置。操作数分为三类
  • 立即数
    • 在AT&T格式的汇编代码中,立即数的书写代码是‘$’后面跟一个用标准C表示法表示的整数
    • 不同的指令允许的立即数范围不同
  • 寄存器
    • 用符号 ra 来表示任意寄存器a
    • 用引用 R[ra] 来表示他的值
  • 内存引用
    • 根据计算出来的地址(通常称为有效地址)访问某个内存位置
    • 用符号 Mb[Addr] 表示对存储在内存中从地址Addr开始的b字节的引用,为了简便通常省去下标b
 
寻址模式
 
最简单形式的数据传送指令——MOV类
  • MOV类由四条指令组成:movb、movw、movl、movq
  • 这些指令把数据从源位置复制到目的位置,不作任何变化
  • x86-64有一条限制,传送指令的两个操作数不能都是指向内存位置
  • 寄存器部分的大小(两者取小)必须与最后一个字符指定的大小匹配
  • MOV指令只会更新目的操作数指定的那些寄存器字节或内存位置,除了movl指令的目的寄存器的高位四字节置0
  • movabsq能够以任意64位立即数值作为源操作数,并且只能以寄存器作为目的
  •  
  • 拓展——P123 - MOVZ类、MOVS类
    • MOVZ 零扩展
    • MOVS 符号扩展
 
  • 按照惯例,栈是倒过来画的
  • 栈顶元素的地址是所有栈中元素地址中最低的
  • 栈指针%rsp保存着栈顶元素的地址
 
3.5 算术和逻辑运算

操作指令分为四组
 
加载有效地址指令
  • 加载有效地址指令实际上是mov指令的变形
  • 他的指令形式是从内存读取数据到寄存器,但实际上它根本没有引用内存,而是将有效地址写入到目的操作数,C语言的取址符可以解释这种运算
  • 这条指令可以为后面的内存引用产生指针
  • 另外还可以简洁的描述普通的算术操作
 
一元操作
  • 只有一个操作数,既是源操作数,又是目的操作数
  • 这个操作数可以是寄存器或者内存位置
 
二元操作
  • 第一个操作数是源,可以是立即数、寄存器和内存位置
  • 第二个操作数既是源操作数,又是目的操作数,可以是寄存器或者内存位置
  • 当第二个操作数是内存位置时,处理器必须从内存位置读出值,执行操作,再把结果写回内存
 
移位操作
  • 第一操作数是移位量,可以是立即数或者单字节寄存器%cl中的值(特定寄存器)
  • 第二操作数是目的操作数,可以是寄存器或内存位置
  • SAL是算术左移,右边补0
  • SHL是逻辑左移,右边补0
  • SAR是算术右移,左边补符号位
  • SHR是逻辑左移,左边补0
 
特殊的算术操作
  • Intel把16字节的数称为 八字
  • 理解--除法
 
posted @ 2020-08-11 19:39  Yoke_cc  阅读(403)  评论(0)    收藏  举报