美文网首页
第三章、程序的

第三章、程序的

作者: 饭扭圆 | 来源:发表于2020-03-01 00:10 被阅读0次

程序的机器级表示:

程序编码:

C语言 ---【预处理器--->扩展后的C ---【编译器】---> 汇编语言 ---【汇编器】---> 二进制目标文件  ---【链接器】---> 可执行文件

对于机器级编程的两种抽象:

[if !supportLists]1、[endif]指令集架构将程序的行为抽象成每条指令按顺序执行

[if !supportLists]2、[endif]内存模型抽象成非常大的字节数组

机器代码可见的处理器状态:

程序计数器:

整数寄存器:

条件码寄存器

向量寄存器

数据格式:

字表示16位,32位双字,64位四子,不同数据类型大小不同,汇编后缀也不同

64位机器里面一个指针8个字节

访问信息

寄存器

一个X86-64的cpu包含一组16个存储64位值的通用目的寄存器:

[if !supportLists]l [endif]部分指令会在寄存器中生成小于8个字节的指令,生成1个字节、2个字节的指令会保持剩下的字节不变,生成4字节数字的指令会把高位4个字节置为0。

操作数:

一个指令有>=1个操作数.

三种类型:立即数、寄存器、内存引用

[if !supportLists]l [endif]寄存器用类似数组的R[r]来表示,寄存器名就是索引,R[r]表示寄存器存储的值

[if !supportLists]l [endif]%rax是表示寄存器里存的值0x100,(%rax)表示内存里0x100位置处的值。

[if !supportLists]l [endif]64位机器里不能用32位寄存器来寻址:(%ebx)非法

数据传送指令:

MOV  S,D

前面是源操作数:立即数,寄存器里的值,内存里的值

源操作数表示的是如果源操作数为%rax,表示寄存器里的值,如果源操作数为(%rax),表示间接寻址内存里的值

后面是目标操作数:寄存器、内存地址

后面是存储数据的位置,如果目标操作数为%rax,表示放到寄存器里,如果源操作数为(%rax),表示放到间接寻址后的内存地址里。

[if !supportLists]1. [endif]Movb, movw, movl, movq表示对于操作数大小不同

[if !supportLists]2. [endif]不能将内存里的值直接传送到内存:mov (%rax),(%rbx)(非法)

[if !supportLists]3. [endif]一般情况下只会更新目的操作数指定的寄存器,唯一例外是movl,会把高位四字节记成0。见寄存器部分

[if !supportLists]4. [endif]movq和movabsq区别,前者只能移动32位补码数字,然后符号扩展到64位的值,后者可以以任意64位立即数作为源操作数,并且目标只能是寄存器

MOVZ S,R

小移动到大时,零扩展

按照b,w,l,q应该有四个,为啥没有movlq,因为movlq的含义和movl的含义是一样的。

MOVS S,R

小移动到大时,符号扩展,高位由源操作数第一位复制得到

cltq的含义: movslq %eax, %rax

为啥都只考虑小移动到大,大会不会移动到小呢?

如果目标是内存地址,应该会以此地址为起始,往后存储,所以不存在源操作数过大

如果目前是寄存器呢,64位操作数移动到32位寄存器会发生什么?应该是低32位存储

数据传送示例

这段从C到汇编的转换,帮助我们理解了指针是什么:

[if !supportLists]1、[endif]指针在64位机器中,占8个字节,指针其实就是地址。

[if !supportLists]2、[endif]指针变量在右边时,意思是指针指向的内存里的,->对应于MOV指令中的源操作数,我们对(%rax)的理解

[if !supportLists]3、[endif]指针变量在右边时。意思是指针指向的内存。->对应于MOV指令中的目标操作数,我们对(%rax)的理解

[if !supportLists]4、[endif]在上图汇编中,把指针存在寄存器rdi里,2,3两点可以解释c语言和翻译成汇编后的含义是一致的

5、局部变量通常放在寄存器中,而不是内存,访问寄存器比内存快得多

 

再通过这个例子,我们可以认识一下&取址操作。&a的含义是取值为4的a变量他在内存中的地址。

导入和弹出栈数据:

栈是什么?栈不是什么神奇的东西,也就是内存中的某个区域。

栈指针,始终指向栈顶位置,入栈时地址减小:

1、pushq和popq都是可以用mov指令+计算指令替代的。区别在于前两个指令大小只有1个字节。

2、栈可以同样当做内存来处理:movq 8(%rsp), %rdx会将第二个四字从栈中复制到寄存器rdx,为什么是第二个四字?8(%rsp)操作数值为M[R[%rsp] + 8], 取的是栈顶上方8-15个字节,即第二个四字。

算术和逻辑操作:

加载有效地址(leaq):

[if !supportLists]1、[endif]源是内存地址(看上去是),目标是寄存器

[if !supportLists]2、[endif]和movq的区别:

Movq (%rdx) %rax将M[R[rdx]]的值赋给rax

Leaq (%rdx) %rax将R[rdx]的值赋给rax

[if !supportLists]3、[endif]由于这种特性,往往用于普通的算术操作:long t = x + 4y +12z

一元和二元操作:

[if !supportLists]l [endif]一元操作:

只有一个操作数,这个操作数必须是寄存器或者内存(也就是必须是个地址

表示的含义是:把这个寄存器或者内存的值中,再放入这个寄存器或者内存中

[if !supportLists]l [endif]二元操作:两个操作数,第一个操作数是源,可以是寄存器或者内存、立即数,这个操作数必须是寄存器或者内存(也就是必须是个地址

表示的含义是:把这个寄存器或者内存的中取出,和源操作数做计算,放入这个寄存器或者内存中

移位操作:

[if !supportLists]l [endif]第一个数是移位量,第二个是目标操作数

表示的含义是:目标操作数的值经过移位处理后,放回目标操作数位置

[if !supportLists]l [endif]移位量时立即数或者单字节寄存器cl

[if !supportLists]l [endif]当移位量为cl时的移位规则是:对w位长的数据值进行操作,移位量由cl寄存器的低m位组成,2^m-1=w

[if !supportLists]l [endif]左移指令SAL和SHL相同,右边补0

[if !supportLists]l [endif]右移质量SAR执行算术右移(填符号位),SLR执行逻辑右移(填0)

特殊的算术操作:

此图的idivq和divq的寄存器有误,看原书第三版:

imulq的两种形式:

[if !supportLists]一、[endif]二元操作:将两个64位相乘得到一个64位数,此时,仅用imulq一个操作可以同时实现有符号数和无符号数的乘法:截断后的补码的位级行为是一样的

[if !supportLists]二、[endif]如上图中,只有一个操作数,将两个64位相乘得到一个128位数,分别放在两个寄存器中

控制:

除了整数寄存器,CPU还维护着一组单个位的访问条件码寄存器:他们记录了算术或逻辑操作的属性,我们检测这些寄存器的值,就可以判断条件的真假,就是这么神奇

举例而言,当我们执行一个ADD指令完成 t = a + b这个C表达式时,各个条件码寄存器都会发生变化:

ZF和SF很好理解,但是CF、OF是什么意思呢,我们可以举例说明:

CF可以使用反证法:如果没有无符号溢出,t必然大于a,反之亦然

OF:有符号数加法溢出,a和b必然符号不同,所以有(a<0 == b<0), 同时如果没有溢出,t必然和a、b符号相同。

相关文章

网友评论

      本文标题:第三章、程序的

      本文链接:https://www.haomeiwen.com/subject/cernhhtx.html