第二章 信息的表示和处理

  • 信息存储
  • 整数表示
  • 整数运算
  • 浮点
  • 小结

信息存储

第三章 程序的机械级表示

  • gcc编译器的使用
  • 汇编语言
  • boom

gcc

gcc编译器是通过命令行来实现的,在mac下需要单独安装,在linux下是自带

在启动的时候会安排优化级别,二级优化是性能优化和使用方便的一种折中

在启动gcc编译器的时候会首先调用将插入所有用#include命令指定的文件,并且扩展宏

其次编译器将.c文件转换为汇编语言的.s文件

最后汇编器将汇编代码转换为二进制目标代码文件.o

1
2
3
4
gcc -O2 -S code.c
gcc -O2 -C code.c
objdump -d code.o
movl $0x4050,%eax Immediate-Register

image-20200517173220188

  • 跳转指令:跳转到另一行指令(指令一般是一行一行的执行)

image-20200517170403399

  • 条件码:描述了最近的算数或逻辑操作的属性,

逻辑操作

  • leal是指将存储器读数据到寄存器,没有引用存储器。将有效地址写入目的操作数(寄存器)

    在这里我们需要熟练的掌握寻址方式,上面我写的表有,可以看看

  • image-20200517162016418

  • 右移:右边填上0 左移:左边填上0 x>>=2代表将x右移2位

算数操作

  • 操作分为二元操作和一元操作,二元操作有两个操作数,一元只有一个操作数。
  • 与mov一样,很多操作都有l,w,b的后缀

算数和逻辑操作

以上为3.4节的内容

  • 定义指针,就是分配一个内存地址,如果这个指针指向一个变量,我们将读取这个指针的值,这个操作叫做指针的间接引用。但不仅仅包括读,写也是一种间接引用
  • C中的&称为取址符,是创建一个指针。指针可以表示为一个寄存器的引用(),这样就很好的表示出了它的意义

C中指针的间接引用

  • 栈:向下增长,FILO(first in last out),栈顶元素的地址是栈中最低的

  • 我们一般说的栈是程序栈,存放在存储器中的某个区域

  • 程序栈是用来保存数据的,栈指针是%esp就是%rsp,用来保存着栈顶元素(栈顶元素的地址是最低的(栈是向下增长的))

  • 举例:我们想将一个双字压入堆栈中,首先将栈指针减去4,然后将值写到新的栈顶地址。所以

    1
    2
    3
    4
    pushl %ebp
    等价于
    subl $4,%esp
    movl %esp,(%esp)
  • 弹出一个双字就是popl指令,它也等价于先将值写到栈顶指针里,再将指针加4

推入和推出栈

b则是不改变其他的,仅仅传输低位

而sbl是将其他三个字节设置为全1或者全0

zbl将低位2位设置为dh寄存器(edx)的值,其他三个字节为全0

  • mov有很多形式,movl,movw,movb,movsbl,movzbl

    l代表是传送的是双字,vw传送的是字,b传送的是字节,sbl传送的是符号拓展字节,zbl传送零扩展的字节

    image-20200513154035105

  • 原则:在IA32中传输指令的两个操作数不能都指向存储器的位置

    也就是说将一个值从一个存储器的位置放到另一个存储器的位置需要两条指令,一条负责加载到寄存器中,第二条将寄存器写入目的位置

  • 指令规则:除开操作指令,第一个是源操作数,第二个是目的操作数,边角我们采用的是注释的写法

数据传送指令

练习题对照图3.3来操作

1)%eax,%dx就是寄存器的名字 2)(%rax)。只要是有括号的了,那就是内存引用。注意x86-64中的内存引用总是用四字长寄存器给出的,即寄存器名字开头都是r开头的。(%rax)意思是取寄存器%rax中的存的地址中的存的值,相当于解引用两次,先解引用寄存器,再解引用这地址(我用“解引用”这个词只是为了方便理解)。 3)mov命令中,两个操作数只允许有一个内存引用,即只能有一个带括号的。 4)关于mov命令的后缀,肯定与内存引用中的寄存器的长度无关,而是与另一个寄存器的长度有关 5)b代表1个字节;w代表1个字,2个字节;l代表2个字,4个字节;q代表4个字,8个字节。

汇编命令总结

image-20200513124559271

伸缩化的变址寻址

比例寻址

有立即数寻址,寄存器寻址,绝对寻址,间接寻址,(基址+偏移量)寻址

  • 寻址模式

存储器访问要比寄存器访问要慢

根据计算出来的地址(有效地址)访问某个存储器的位置。

  • 存储器引用

image-20200513150705333

用Ea来表示任意寄存器a,通过引用R[Ea]来表示他的值,将寄存器集合看成一个数组,用寄存器标识符作为索引

  • 寄存器

例如:$-577和$0x1F 任何32位的字都可以用作立即数

$+整数是它的表示方法

一种操作数的类型,是常数值,采用标准C的表示方法

  • 立即数

操作数指令符

至此,前三节结束

16位CPU的对应图

大多数汇编指令操作对字节或者双字

字(Word):不同计算机系统中占据一个单独的地址(内存单元的编号)并作为一个单元(由一个或多个字节组合而成)处理的一组二进制数。8位的CPU字长为8位,一个字等于一个字节,一次只能处理一个字节,而32位的CPU字长为32位,一个字等于4个字节,一次就能处理4个字节,同理字长为64位的CPU一次可以处理8个字节,一个字等于8个字节。

字长:电脑技术中对CPU在单位时间内(同一时间)能一次处理的二进制数的位数

字节(Byte) :8个二进制位构成1个字节(B),1个字节可以储存1个英文字母或半个汉字。字节是存储空间的基本计量单位,计算机杨的内存和磁盘的容量都是以字节表示的。八位二进制数最小为00000000,最大为11111111;

位(Bit)::在计算机中,数据的最小单位是位,表示一个二进制数码0或1

Intel将字表示为16位数据,所以称32位为双字,64位为四字

数据格式

在了解汇编语言之前,我们先了解一下数据格式

  • 程序计数器:存放指令的地址(%eip)表示
  • 整数寄存器:存储32位的值,存储整数或者地址
  • 条形码寄存器:存储算数指令的状态信息(if while语句)
  • 浮点寄存器:包含8个位置,存放浮点数据
  • 程序存储器:管理程序调用和返回的堆栈(合法地址较少,虚拟地址较多)

汇编语言

  1. 反汇编器不需要访问程序的源代码或汇编代码

-d 代表生成汇编代码格式

我们可以利用反汇编器来确定程序的字节表示

  • 反汇编器

这时便会产生 .o二进制文件

-C代表编译并汇编该语言

-S 代表查看C编译器产生的汇编代码