【计算机组成原理】四、指令系统:3.汇编语言

5.汇编语言


高级语言与机器级代码之间的对应:

汇编语言和机器语言都是机器级代码,是一一对应的。

在这里插入图片描述

5.1考试要求(408)

  • 只需关注x86汇编语言;若考察其他汇编语言题目会详细注释。
  • 题目给出某段简单程序的c语言、汇编语言、机器语言表示。能结合c语言看懂汇编语言的关键语句(看懂常见指令、选择结构、循环结构、函数调用)。
  • 汇编语言、机器语言一一对应,要能结合汇编语言分析机器语言指令的格式、寻址方式。

不会考:将c语言人工翻译为汇编语言或机器语言。

x86汇编语言

mov为例子:

mov 要移动到的位置destination, 被移动的内容/位置source;

mov eax, ebx				#寄存器→寄存器
mov eax, dword ptr [af996h]	#主存→寄存器
mov eax, 5 					#立即数→寄存器

#将ebx所指主存地址的32bit复制到eax寄存器中(寄存器间接寻址)
mov eax, dword ptr [ebx]	
mov eax,[ebx]				#若未指明主存读写长度,默认32 bit

#将eax的内容复制到af996h所指的地址
mov [af996h], eax			#未指明长度默认32bit

#将eax的内容复制到ebx所指主存地址的32bit
mov dword ptr [ebx], eax

#将ebx所指的主存地址的8bit复制到eax
mov eax, byte ptr [ebx]

#将ebx+8所指主存地址的32bit 复制到eax寄存器中
mov eax, dword ptr [ebx+8]
#将af996-12所指主存地址的 32bit复制到eax寄存器中
mov eax, dword ptr [af996-12h]

在这里插入图片描述

5.2地址码

x86架构CPU,有哪些寄存器?

每个寄存器都是32bit,32bit = Extended = E

都是E开头的,包含32bit数据。

  1. 通用寄存器 X

    • EAX
    • EBX
    • ECX
    • EDX
  2. 变址寄存器 I = index

    变址寄存器可用于线性表字符串的处理。

    • ESI: source index(被移动的)
    • EDI: destination index(要移动到的目的)
  3. 堆栈寄存器 P = pointer

    用于函数调用

    • EBP: 堆栈指针base pointer
    • ESP: 堆栈指针stack pointer

在这里插入图片描述

  • 通用寄存器还可以使用一半寄存器(低16位)

AX, BX, CX, DX:16bit

在这里插入图片描述

两个变址寄存器只能固定使用32bit;
两个堆栈寄存器只能固定使用32bit。

  • 甚至还可以使用1/4=8bit:

AL, AH
BL, BH

在这里插入图片描述

总结

在这里插入图片描述

5.3操作码

操作码 地址码
操作码 d, s

#王道书中:
add <reg>/<mem>, <reg>/<mem>/<con>
#要注意,一般不建议同时访问两个主存:
add <mem>, <mem>	# ×,访存太多是不可以的
  • destination:目的地(d 目的操作数)
  • source:来源地(s 源操作数)

目的操作数d不可以是常量,因为进行完操作之后还要把数据放到d的位置。

还有:

  • reg:寄存器register
  • mem:内存memory
  • con:常数constant
5.3.1算术运算
功能英文汇编指令注释
addadd d, s#计算d+s,结果存入d
subtractsub d, s#计算d-s,结果存入d
multiplymul d, s
imul d, s
#无符号数d*s,乘积存入d
#有符号数d*s,乘积存入d
dividediv s
idiv s
#无符号数除法:edx:eax/s,商存入eax,余数存入edx
#有符号数除法:edx:eax/s,商存入eax,余数存入edx
取负数negativeneg d#将d取负数,结果存入d
自增 ++increaseinc d#将d++,结果存入d
自减 - -decreasedec d#将d–,结果存入d

【注意】除法(被除数/除数)用到了隐含寻址,s是除数,而被除数提前放到了edx和eax。

【注意!】add d, s在这里是(d)+(s)→(d),

但是有的是写add s, d就是(d)+(s)→(d)

5.3.2逻辑运算
功能英文汇编指令注释
andand d, s#将d、s逐位相与,结果放回d
oror d, s#将d、s 逐位相或,结果放回d
notnot d#将d逐位取反,结果放回d
异或exclusive orxor d, s#将d、s逐位异或,结果放回d
左移shift leftshl d, s#将d逻辑左移s位,结果放回d(通常s是常量)
右移shift rightshr d, s#将d逻辑右移s位,结果放回d(通常s是常量)
5.3.3其他
  1. 用于实现分支结构、循环结构的指令:
    • cmp:比较。
    • test
    • jmp:直接跳转。
    • jxxx:条件跳转。
    • loop:封装循环。
  2. 用于实现函数调用的指令:
    • push:放入函数调用栈。
    • pop:从函数调用栈出栈。
    • call:函数调用。
      • ①将IP旧值压栈保存(保存在函数的栈帧顶部);
      • ②设置IP新值,无条件转移至被调用函数的第一条指令。
    • ret:函数返回。
      • 从函数的栈帧顶部找到IP旧值,将其出栈并恢复IP寄存器。
  3. 用于实现数据转移的指令:mov

【注意】Intel x86处理器中,程序计数器PC ( Program Counter)通常被称为IP(Instruction Pointer)。


5.4循环分支

5.4.1 jmp直接跳转指令

jmp(jump)

jmp <address>

jmp 124
jmp eax
jmp [985]

#其中:
exa = 124
[985] = 124

这个地址可以是直接一个数字,也可以是寄存器或者主存

但是其实程序员其实是不知道指令在内存的位置,所以使用**NEXT:标号**来锚定位置。

标号,有冒号就是,NEXT是名字,可以自己改)。

例如:

mov eax, 1
mov ebx, 2
jmp BIAOHAO
add ebx, 2
BIAOHAO:
add ebx, exa
5.4.2 jxxx条件跳转指令

先**比较cmp**两个数:

cmp本质上是进行a-b减法运算,并生成标志位OF、ZF、CF、SF,放入PSW程序状态字寄存器(Intel称其为“标志寄存器”)。

cmp d, s

然后紧跟跳转指令:

#jump when equal,若a==b则跳转
je <地址>

#jump when not equal,若a != b则跳转
jne <地址>

#jump when greater than,若a>b则跳转
jg <地址>

#jump when greater than or equal to,若a>=b则跳转
jge <地址>

#jump when less than,若a<b则跳转
jl <地址>

#jump when less than or equal to,若a<=b则跳转
jle <地址>
  • e:等于equal
  • n:不not
  • g:大于greater
  • l:小于less

例如:

cmp eax, ebx
je NEXT
分支C→汇编

那么就可以把c语言的代码翻译为汇编代码(机器级表示)

C:

int a=7;
int b=6;

if(a>b){
	c=a;
}else{
	c=b;
}

assembly:

mov eax,7		#假设变量a=7,存入eax
mov ebx,6		#假设变量b=6,存入ebx

cmp eax,ebx		#比较变量a和b
jg NEXT			#若a>b,转移到NEXT:

# 如果没有跳转,那么顺序执行,就是else

mov ecx ,ebx	#假设用ecx存储变量c,令c=b
jmp END			#无条件转移到END:
NEXT:
mov ecx ,eax	#假设用ecx存储变量c,令c=a
END:
循环C→汇编

用条件转移指令实现循环,需要4个部分构成:

①循环前的初始化

②是否直接跳过循环?

③循环主体

④是否继续循环?

在这里插入图片描述

用loop指令实现循环

【注意】loop默认使用ECX作为循环计数器(只能是ECX)。

在这里插入图片描述

5.5函数调用

函数的栈帧( Stack Frame):保存函数大括号内定义的局部变量、保存函数调用相关的信息。

在这里插入图片描述

5.5.1函数调用栈在内存中的位置

在这里插入图片描述

地址码中的堆栈寄存器(P,pointer)用于函数调用

  • EBP: 堆栈指针base pointer,指向栈的底部
  • ESP: 堆栈指针stack pointer ,指向栈的顶部(下面是“顶”,开口的)
5.5.2两种方式访问栈帧数据

pushpop指令实现入栈、出栈操作,x86默认以4字节为单位。指令格式如:

在这里插入图片描述

在这里插入图片描述

5.5.3函数调用时,如何切换栈帧

在每一个函数加上“例行处理”

push ebp		#保存上一层函数的栈帧基址(ebp旧值)
mov ebp, esp	#设置当前函数的栈帧基址(ebp新值)

#等价于:
enter			#零地址指令,进入

在函数结束的时候,就移除函数栈,例行处理:

mov esp, ebp	#让esp指向当前栈帧的底部
pop ebp			#将esp所指元素出栈,写入寄存器ebp

#等价于:
leave

在这里插入图片描述

5.5.4一个栈帧内可能包含哪些内容?

一个函数栈:

0xFFFF FFFF

栈底

EBP

向上(栈底)是加

向下(栈顶)是减

ESP

栈顶

0x0000 0000


  1. 上一层栈帧基址:栈帧最部一定是上一层栈帧基址(ebp旧值)。
  2. 返回地址:栈帧最部一定是返回地址(当前函数的栈帧除外)。
  3. 局部变量:保存在栈底,如果出现[ebp-4](最后一个定义的变量)或ebp-8这种,一般是局部变量。
  4. 调用参数:保存在栈顶[ebp+8](第一个调用参数),ebp+12(第二个调用参数)…。
    为什么是+8,因为+4保存了IP(PC)返回地址。这里的ebp不是上面的ebp,而是调用参数的ebp,属于上面函数的esp。
  5. 空闲:gcc编译器将每个栈帧大小设置为16B的整数倍(当前函数的栈帧除外),因此栈帧内可能出现空闲未使用的区域。

在这里插入图片描述

具体:

在这里插入图片描述

5.5.5如何传递参数和返回值

4.3_6_4_如何传递参数和返回值(函数调用的机器级表示)_哔哩哔哩_bilibili

相加之后,最终的结果存储在EAX,那么leave之后,caller函数只需要从EAX种就可以取到返回值。

在这里插入图片描述

总结

除了main函数,其他所有函数的汇编代码结构都一样!

在这里插入图片描述

5.6汇编格式

AT&T 格式:Unix、Linux的常用格式。

intel 格式:Windows的常用格式。(408常考,也是我们这里讲的

在这里插入图片描述

  • 16
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值