第三章 程序的机器级表示

程序的机器级表示

3.1历史观点

   8086—〉80286—〉i386—〉i486—〉Pentium—〉PentiumPro—〉Pentium—〉Pentium—〉Pentium4—〉Pentium4e—〉Core 2 Duo —〉Core i7

3.2程序编码

   1.gcc -01 –o p p1.c p2.c      使用第一级优化

   2.程序计数器(%eip)指示将要执行的下一条指令在存储器中的地址。

   3.寄存器文件

   4.-S:C语言编译器产生的汇编代码

        例:gcc -01 –S code.c 会产生一个汇编文件code.c

3.3数据格式  

char

字节

b

1

short

w

2

int

双字

1

4

long int

双字

1

4

long long int

4

char*

双字

1

4

float

单精度

s

4

Double

双精度

l

8

long double

扩展精度

t

10/12

3.4访问信息

   1.操作数指示符类型:立即数、寄存器、寄存器

   2.数据传送指令

指令

效果

描述

MOV      S,D

S<-D

传送

movb

movw

movl

传送字节

传送字

传送双字

MOVS     S,D

D<-符号扩展(S)

传送符号扩展的字节

MOVZ     S,D

D<-零扩展(S)

传送零扩展的字节

3.5算术和逻辑操作(20135315韩玉琪的博客)

   1.加载有效地址:leal实际上是movl的变形,为存储器引用产生指针

   2.一元操作和二院操作:1)++,- -;2)+=

  • 一元操作
  • - INC          加1
  • - DEC          减1
  • - NEG          取负

- NOT          取补

  • 只有一个操作数,既是源又是目的,可以是一个寄存器,或者存储器位置。
  • 二元操作
  • - ADD          加
  • - SUB          减
  • - IMUL         乘
  • - XOR          异或
  • - OR           或

- AND          与

  • 第一个操作数可以是立即数、寄存器或者存储器位置
  • 第二个操作数既是源也是又是目的。可以是寄存器或者存储器位置,但是不能同时是存储器位置。
  • 注意操作的顺序:

   第二个操作数 操作符 第一个操作数

   3.移位操作:>>,<<

  • 先给出移位量,第二项给出要移位的数值。
  • - SAL          左移
  • - SHL          左移(等同于SAL)
  • - SAR          算术右移     

- SHR          逻辑右移     

  • 源操作数(移位量):立即数或者放在单字节寄存器元素%cl中。
  • 目的操作数:一个寄存器或是一个存储器位置。

  

4.特殊算术操作

  • 乘法
  • 乘积截断
  •    imull 双操作数

   - 从两个32位操作数产生一个32位的乘积。

  • 乘积不截断
  •    mull  无符号数乘法
  •    imull 有符号数乘法
  •    - 要求一个参数必须在寄存器%eax中,另一个作为指令的源操作数给出。

   - 乘积的高32位在%edx中,低32位在%eax中。

  • 除法
  • 有符号除法
  •    idivl 操作数
  •    - 将DX:AX中的64位数作为被除数,操作数中为除数

   - 结果:商在AX中,余数在DX中。

  • 无符号除法
  •    divl指令

   - 通常会事先设定寄存器%edx为0.

3.6控制

   1.条件码:

   CF:进位标志   ZF:零标志    SF:符号标志  OF:溢出标志

   2.访问条件码 

  • SET指令:执行比较指令,根据计算t=a-b的结果设置条件码 

3.跳转指令及其编码:jmp *%eax

  • 无条件跳转
  • 直接跳转:跳转目标是作为指令的一部分编码的。
  • 间接跳转:跳转目标是从寄存器或存储器位置中读出的。

   4.条件传送指令(参考资料20135202闫佳歆博客)

  • 将条件表达式和语句从c语言翻译成机器语言,最常用的方式就是结合有条件和无条件跳转。
  • if-else 的汇编结构
  • 通用形式模板
  •    if(test-expr)
  •          then-statement
  •    else
  •          else-statement
  •  

   (注:test-expr     整数表达式[假/真])

  • 汇编实现形式
  •    t = test-expr;
  •    if (!t)
  •          goto false;
  •    then-statement
  •    goto done;
  •    false:
  •          else-statement

   done:

   5.switch语句

3.7过程

   1.栈帧结构:机器用栈帧来传递过程参数、存储返回信息、保存寄存器用于以后的回复以及本地存储。为单个过程分配的那部分栈称为栈帧

   2.帧指针:%ebp,栈指针:%%esp

   3.转移控制

      call  Label         过程调用

      call  *Operand      过程调用

      leave               为返回准备栈

      ret                 从过程调用中返回

   4.寄存器使用惯例

      1).%eax、%edx、%ecx  调用者保存

      2).%ebx、%esi、%edi  被调用者保存

   5.递归过程:递归调用一个函数本身与调用其他函数是一样的。相互调用更为复杂

问题:

1.比较指令cmp和减法指令sub有何不同?

 sub d,s   是d-s,结果送回d中,即送回目的操作数中。

 cmp d,s   也是d-s,但结果不送回目的操作数中,是利用减法进行两个数值的比较。

  作业

  • main.c:

  • 汇编代码:

  • 用vi查看编译器指令:

  • 删除gcc产生代码中以"."开头的编译器指令后:

  • 分析:
  • main函数保存%ebp,并设置新的帧指针。

    	pushl	%ebp
    	movl	%esp,%ebp
  • 分配4字节的栈空间

    	subl	$4,%esp
  • 设置 arg1=8

    	movl	$8,(%esp)
  • call调用fh
  • fh被调用,初始化帧指针,分配栈空间。
  • 将(%esp)中的8给 %eax,即存入栈中

    	movl	%eax,(%esp)
  • call调用gh
  • gh被调用,初始化栈指针,分配栈空间
  • 将 %eax 与立即数 3 相加

    	add		$3,%eax
  • 在gh结束前弹栈

    	popl	%ebp
  • ret返回fh中call的调用位置
  • fh也结束,return返回main中call调用的位置
  • main继续 %eax 加1的操作

    	addl	$1,%eax
  • leave为返回准备栈,相当于%ebp出栈,最后ret结束。

原文地址:https://www.cnblogs.com/20135207oneking/p/4869948.html