计算机组成原理与汇编语言(二)

计算机组成原理与汇编语言(二)

文章目录

  • 计算机组成原理与汇编语言(二)
    • 第三章 程序的机器级表示
      • --- 汇编语言
          • 通过汇编语言 ,可以做到
      • 对比C语言、汇编语言、机器语言
        • 程序编码
      • 不同类型数据的区分
        • 数据格式
      • 数据如何访问
          • 数据的传送指令
          • 栈操作
      • 算术和逻辑运算 +,-, &,|
      • 控制结构 if,for,switch
        • 程序的基本结构形式
        • 控制--实现分支、循环
          • 条件码
          • 设置条件码的典型指令
          • 分支程序设计
          • 循环结构
      • 过程,函数(敲重点)
        • 栈和栈的操作:push, pop
        • 指令指针寄存器 eip(指令指针)
        • 过程调用和返回: call, ret
        • 过程调用中寄存器使用惯例
        • 栈帧(stack frame)
      • 数组和指针
        • 数组分配和访问:
        • 综合:理解指针

承接上文:计算机组成原理与汇编语言(一)

第三章 程序的机器级表示

— 汇编语言

计算机组成原理与汇编语言(二)_第1张图片

通过汇编语言 ,可以做到
  • 分析程序隐含的低效率,例如,访问数组元素的顺序的不同a[i][j],a[j][i]

  • 了解程序运行时的行为

  • 了解程序漏洞的产生


主要是分析Inter-IA32 ,32位操作系统,在X86架构下的体系指令 (课程学习只学到32位的,还没学X86-64即64位的

  • IA:指令体系结构,即机器语言的语法规则

对比C语言、汇编语言、机器语言

计算机组成原理与汇编语言(二)_第2张图片

程序编码
  • 高级语言程序:不关心CPU,也极少直接访问硬件资源

  • 汇编语言程序:更关心CPU,看到更多

    ​ –整数寄存器:8个,eax, ebx, ecx, edx, …

    ​ –程序计数器:1个,PC

    ​ –条件码寄存器:1个

不同类型数据的区分

数据格式
  • 不同整数数据类型,汇编代码的区分,以add传送指令为例:

    ​ – addb (b:byte,8位)

    ​ – addw (w:word,16位)

    ​ – addl (l:long word,32位)

  • 整数与浮点数的区分:不同指令,不同代码

数据如何访问

信息,即数据,放在存储器,CPU中的寄存器

计算机组成原理与汇编语言(二)_第3张图片
计算机组成原理与汇编语言(二)_第4张图片

​ x可以是:常数寄存器存储器引用

​ y可以是:常数寄存器存储器引用

​ –常数:直接给出数本身,如“z = $77 + x”

​ –寄存器:给出寄存器名字,如指令z = %eax + $44

​ –存储器引用

			给出能计算存储器地址的形式:`Imm(Eb, Ei, s)`,

			地址计算:`Imm+Eb+Ei*s`

​ 例如指令z = %ecx + 9(%eax,%edx,4),后一个操作数地址的计算形式是:Imm+Eb+Ei*s=9+eax+edx*4

  • 操作数指令符
1.立即数 2.寄存器 3.存储器
(immediate) (register) (memory)

寻址模式:Imm(Eb , Ej , s)

由四部分组成立即数偏移Imm,基址寄存器Eb , 变址寄存器 Ej , 比例因子s(值只能为1,2,4,8其中一个,也可以没有)

存储器地址的计算形式:Imm+Eb+Ei*s

数据的传送指令

mov S,D 相当于 D(目的操作数)=S(源操作数)

mov:传送

​ 例如:movl %eax, %ebx

​ 要求:两操作数长度一致

movs:符号扩展传送

​ 例如:movswl %ax, %eax

​ 要求:两操作数前短后长

movz:零扩展传送

​ 例如:movzwl %bx, %ebx

​ 要求:两操作数前短后长

两个操作数不能都指向存储器

  • 例如:

​ 有定义如下:

​ int A;

​ char c=‘a’;

​ unsigned char d=‘a’;

​ 则

​ d=c; 相当于 movb c, d

​ A=c; 相当于 movsbl c, A

​ A=d; 相当于 movzbl d, A

栈操作
  • push、pop:栈操作

  • push功能:将数据进栈

    其操作相当于:

    subl $4, %esp

    movl 要进栈的数据, (%esp)

  • pop功能:将栈顶数据弹出

    其操作相当于:

    movl %esp, 数据弹出的存储位置

    addl $4, %esp

  • 例子

    C语言代码:

 int exchange(int *xp, int y)

{
    	int x = *xp;
 	*xp = y;
   	return x;
}

汇编代码

movl   8(%ebp), %edx       

movl   (%edx), %eax           

movl  12(%ebp), %ecx        

movl  %ecx, (%edx)      

出栈操作,先把8(%ebp)的数据出栈,传给%edx,就得到*xp

(%edx)-> %eax*xp的值赋给x

12(%ebp)->%ecx 然后到12(%ebp)的数据出栈,传给%ecx ,就得到y

%ecx-> (%edx)*xp赋给y

算术和逻辑运算 +,-, &,|

  • 1.一元指令(只有一个操作数):xxx D

    inc D,dec D,not D

    increase , decrease

    例:

    inc %eax ;加一
    
    dec %ebx ;减一
    
    not %ecx ;非
    

    若:已知执行上述三条指令前eax=1,ebx=10,ecx= -1

    则,执行上述指令后,eax=?ebx=?ecx=?

    2,9,1

  1. 二元指令(有两个操作数):xxx S,D

add,sub,xor,or,and

add,subtract

例:

add %eax, %ebx ;加

 sub %eax, %ecx ;减

 xor %eax, %edx ;异或

 or %eax, %edi ;或

 and %eax, %esi ;与

若:已知执行上述五条指令前eax=1,ebx=10,ecx=20,edx=1,edi=0,esi=1

则,执行上述指令后, ebx=?ecx=?edx=?edi=?esi=

11,19, 0,1, 1

  1. 移位指令:xxx k,D(k是移位次数)是在二进制的基础上进行移位

sal,sar,shl,shr (其中sal和shl功能完全等价)

在计算机中只能以二进制的形式进行移位,向左移动 |n| 位,就相当于乘于2n ,其中n也分正负值,向左为正值,向右为负值。

算术左移,操作数左移,最低位补0,逻辑左移,操作数左移,最低位补0。

算术右移,操作数右移,最高位不变,逻辑右移,操作数右移,最高位补0。

左移操作相当于乘法操作,它是会让操作数变大的,也就是说,它随时存在着溢出的风险若左移操作保留符号位的话,那么左移会出现越来越小的情况,但是你的本意是让这个数变大最后却发现左移后的数变小了,为了规避这种溢出带来的问题,统一了左移操作,也就是说,在左移操作中,寄存器只负责储存这个数(不管是否合乎人意,它只要是个数就行),若没有溢出的时候,则原样存储。所以说左移操作是会改变符号位的。

我们知道右移操作的算术操作是除法,那么在计算机中是肯定让这个数变小的,所以不存在溢出的风险,那么设计者就把是否保留符号位的权力交给了程序编写人员,所以 SARSHR 是两个不同的操作

维基百科中有介绍:

Logical shifts are best used with unsigned numbers
逻辑移位最好用于无符号数

In an arithmetic shift, the spaces are filled in such a way to preserve the sign of the number being slid. For this reason, arithmetic shifts are better suited for signed numbers in two’s complement format
在算术移位中,移位空间被补0或者保留高位(即符号位)的方式处理,因此,算术移位操作更适用于两个有符号数的补码操作

计算机组成原理与汇编语言(二)_第5张图片

字母代表的意思:

s/sh:shift

a:arithmetic

l:left

r:right

例:

sal 1,%eax ;算数左移

sar 3,%eax ;算数右移(前面补符号)最高位不变

shl 4,%eax  ;逻辑左移

shr 2,%eax ;逻辑右移(前面补零)

若:已知执行上述三条指令前eax=16,则单独执行上述各指令后,eax各是多少?

100000,11110,100000000,00100

  1. 加载有效地址(Load Effective Address Long word):

leal S,D ;功能:D <- &S,类似C中的取地址操作

例:leal (%eax), %ebx

指令 效果 描述
leal S, D D <-&S 加载有效地址
INC D D <- D+1 加1
DEC D D <- D-1 减1
NEG D D <- -D 取负
NOT D D <- ~D 取补
ADD S, D D <- D + S
SUB S, D D <- D - S
IMUL S, D D <- D * S
XOR S, D D <- D ^ S 异或
OR S, D D <- D | S
AND S, D D <- D & S
SAL k, D D <- D< 左移
SHL k, D D <- D< 左移(等同于SAL)
SAL k, D D <- D>>L k 算术右移
SHL k, D D <- D>>L k 逻辑右移

">>A “和”>>L "分别表示算术右移和逻辑右移

SHLSAL两者对应操作的机器码是完全相同的,因此 SHLSAL是不同名的同种操作

SARSHR是两个的操作对应的机器码是不同的,所以 SARSHR是两个不同的操作


补充:(忘了的偷瞄一下)

计算机组成原理与汇编语言(二)_第6张图片

控制结构 if,for,switch

程序的基本结构形式
  • 顺序结构

计算机组成原理与汇编语言(二)_第7张图片

  • 分支结构

计算机组成原理与汇编语言(二)_第8张图片

分支、循环都涉及转移地址

  • 循环结构

计算机组成原理与汇编语言(二)_第9张图片

控制–实现分支、循环

•实现C语言中的

​ if

​ for

​ while

​ switch

条件码

除了整数寄存器,CPU还维护着一组单个位的条件码(condition code)寄存器,它们描述了最近的算术或逻辑操作的属性。可以检测这些寄存器来执行条件分支指令。

  • 一个条件码 <–> 一位二进制数,其值为:1或0,即真或假
条件值 进位 - CF 零 - ZF 溢出 - OF 负 - SF
Carry Flag Zero Flag Overflow Flag Sign Flag
1 有进位 为零 溢出 为负
0 无进位 非零 未溢出 非负

举个栗子

计算机组成原理与汇编语言(二)_第10张图片

附:无特殊说明,统一按有符号数计算

设置条件码的典型指令
  • 比较指令

    • cmp S,D ; D-S (比较)

      类似于sub SD,设置条件码,但不存减的结果

      例如,若S=0 0001110,D=0 0001111,则该指令后各条件值是:无进位,不为零,无溢出,非负。即:CF=0,ZF=0,OF=0,SF=0

    • test S,D ; D&S (测试)

      类似于and SD,设置条件码,但不存与的结果

  • 跳转指令

    • 无条件转移指令 jmp 地址

      • 无条件转移到目标地址去执行指令
    • 格式:jmp 目标地址

    • 条件转移指令jX地址

      • 根据条件码的状态判断是否转移
          1. 单个条件码判断
          2. 无符号数判断
          3. 有符号数判断

j / jmp :jump


  1. 单个条件码判断的转移指令

    jz:若结果为零,即zf=1,则转移

    jnz:若zf=0,则转移

    js:若结果为负,即sf=1 ,则转移

    jns:若sf=0,则转移

    j/jmp:jump

    z: zero

    s: signed

    n: not

    举个栗子:

    设(ax)=0x8000, (bx)=0x8000

    cmp bx, ax 因为ax-bx是等于0, 所以zf为真

    jz L2 程序将转到语句2

    L1: 语句1

    L2: 语句2

    e和z的区别

    e: equal 判断是否相等

    比较结果为零,说明两数相等,所以

    jz=je,jnz=jne

  2. 无符号数比较的转移指令

    ja:高于则转移(a > b)

    jna:不高于则转移(a <= b)

    jb:低于则转移(a < b)

    jnb:不低于则转移(a >= b)

    j/jmp:jump

    a: above

    b: below

    n: not

    举个栗子:

    设(al)=1111 1111b, (bl)=0000 0000b,

    分别为255,0

    cmp al, bl 0低于255,即bl低于al,

    jb L2 将转去语句2的位置

    L1: 语句1

    L2: 语句2

  3. 带符号数比较转移指令

    jg:大于则转移(a>b)

    jng:不大于则转移(a <= b)

    jl:小于则转移(a < b)

    jnl:不小于则转移a >= b)

    j/jmp:jump

    g: greater

    l: less

    n: not

    举个栗子:

    设(al)=1111 1111b, (bl)=0000 0000b,

    分别为-1,0

    cmp al, bl 0大于-1,即bl大于al

    jg L2 将转去语句2的位置

    L1: 语句1

    L2: 语句2

分支程序设计
  • 利用比较指令和转移指令实现分支:
    • 比较指令:CMP
    • 转移指令:无条件jmp、条件转移jX
循环结构

三种循环:

  • do while 先执行后判断

  • for 相当于 if + do while

  • while 相当于 if + do while

do-while while for
do while (条件) for(初始化表达式;条件;更新表达式)
body body body
while(条件)

计算机组成原理与汇编语言(二)_第11张图片


过程,函数(敲重点)

栈和栈的操作:push, pop
  • 栈:一片内存区域,按栈的操作规则使用

    ​ 只能从栈顶进行操作

    ​ 栈的增长方向:低地址方向

  • esp(extended stack pointer 栈指针):栈顶指针寄存器,指示栈顶位置.

  • ebp(extended base pointer 帧指针): 栈底指针寄存器, 指示栈底位置

  • 当程序执行的时候,栈指针可以移动,因为大多数信息的访问都是相对于帧指针的.

  • 栈的操作:push,pop

    push S:进栈指令

    esp - 4 -> p

    S ->(esp)

    pop D:出栈指令

    (esp)-> D

    esp + 4 -> esp

指令指针寄存器 eip(指令指针)
  • eip: extended instruction pointer

  • “eip指哪里,CPU打哪里”

    • eip指哪里,CPU就执行哪里的指令,CPU总是跟着eip走的
过程调用和返回: call, ret
  • call 子过程:过程调用指令

    保存返回地址

    ​ 转入子过程

    相当于:

    ​ push 返回地址

    ​ jmp 子过程

  • ret:过程返回指令

    ​ 从子过程返回

    相当于:pop eip

计算机组成原理与汇编语言(二)_第12张图片

过程调用中寄存器使用惯例
  • 寄存器:共享资源,需要保护

  • 保护寄存器:保护惯例

    调用者保护:eax, ecx, edx

    被调用者保护:ebx, edi, esi

栈帧(stack frame)
  • 每个过程需要存储自己的一些信息:

    存储返回信息

    保存寄存器

    存储本地变量

    传递过程参数

  • 栈帧(stack frame):为每个过程分配的栈

    esp:栈顶

    ebp:栈底

计算机组成原理与汇编语言(二)_第13张图片

  • 栈帧内容(被调用者的):

    调用者的ebp

    保存的寄存器

    局部变量

    参数区

计算机组成原理与汇编语言(二)_第14张图片

  • 每个过程有三部分:

    建立栈帧

    程序主体

    结束

计算机组成原理与汇编语言(二)_第15张图片


补充:

数组和指针

数组分配和访问:
  • 计算机组成原理与汇编语言(二)_第16张图片

计算机组成原理与汇编语言(二)_第17张图片

综合:理解指针
  • int *p;

    ​ p是地址,其指向的存储单元存放的须是个int型数据

  • int **cp;

    ​ cp是地址,其指向的存储单元存放的须是一个int*型数据(即整型指针,其指向的存储单元存放的是一个int型数据)

  • 指针类型的强制转换:

    设char *p;则p+7 计算为 p+7,

    而(int *)p+7则相当于(int *)p+7 ,所以计算为p+28

  • 地址运算符:

    • 取内容:“*”
    • 取地址:“&”

未完待续。。。。。。。

计算机组成原理与汇编语言(三)

你可能感兴趣的:(计算机组成原理与汇编语言,笔记,反汇编,其他)