汇编语言笔记

汇编语言笔记

本笔记由jzh整理《汇编语言(基于X86处理器》而成,未经允许不得转载

文章目录

0.前序

嗨,朋友。

也许长时间对于计算机的学习已经让你身心疲惫,不想继续阅读枯燥而没有感情的乏味书籍,特别是在面对汇编语言这些本身趣味性就不高的内容,更是无法提起学习的动力。

但这份笔记一定会带给你不一样的感受,他并不追求高大上的计算机理论知识,并不在一开始就用最难的知识来吓到你,而是从一个与你一样的计算机汇编语言的初学者的视角出发,一点点告诉你汇编语言的知识点。

他像一个和你一起学习的伙伴,而不是高高在上的老师。会和你说自己在学习汇编的时候的苦恼,在学习时候的“小聪明”,每一章的最后还有让人啼笑皆非的tips,让你有动力继续学下去。

也许这本书并不是最专业的书籍,但却绝对值得你一读。

​ 悟为

​ 为好友写于2021年


1.基本概念

1.1.欢迎来到汇编语言的世界

1.环境配置:Microsoft宏汇编器(MASM)或Microsoft visual studio

2.汇编器:将汇编语言转化为机器语言

3.链接器:将汇编器生成的单个文件组成为一个可执行文件

4.调试器:检查寄存器和内存状态

1.2.虚拟机概念

1.虚拟机概念是一种说明计算机硬件和软件关系的有效方法

2.虚拟机层次概念:

level4 : 高级语言
level3 :汇编语言
level2 : 指令集架构(IAS)
level1 :数字逻辑
1.3.数据表示

1.二进制整数:无符号二进制整数;二进制数与十进制数互转;二进制加法;整数存储大小

2.十六进制整数:无符号十六进制整数;无符号十六进制数与十进制数互转;十六进制加法

3.有符号二进制数:补码;加减法

4.字符储存:ASCII;UTF-8;UTF-16; UTF-32

1.4.布尔表达式

1.与或非:not; and; or

1.5.小结

1.汇编器:一种程序,用于把源程序从汇编语言转换为机器语言

2.链接器:将汇编器生成的单个文件组成为一个可执行文件

3.调试器:检查寄存器和内存状态

tips
  1. 汇编语言与机器语言一一对应

  2. 有一说一,我都不知道这本书作者第一章讲了些啥,计算机组成原理都加上了,搞得我都快劝退了,呜呜呜

  3. 下一章还不是汇编语言,我裂开了

  4. 我的建议是第一章和第二章先略过吧~~(误)~~


2.X86处理器架构

2.1:一般概念

1.X86处理器的型号:intel32; intel64;(大概率你用的电脑也是x86的吧)

2.寄存器:直接位于CPU内的高速储存位置的存储器,访问速度远高于传统存储器

p.s. CS:PC 指向代码的开头

2.时钟:对CPU内部操作与系统其他组件进行同步

3.控制单元(CU):协调参与机器指令执行的步骤序列

4.算术逻辑单元(ALU):执行算数运算

5.内存存储单元:用于在程序运行时保存指令和数据

6.总线:一组并行线,将数据从计算机一个部分传到另一个部分

​ 6.1数据总线:传指令和数据(双向)

​ 6.2控制总线:对设备进行同步,传送控制信号和状态信号(单向,但可能向外或者向内)

​ 6.3地址总线:保存指令和数据地址(译码器,与内存有关)

7.指令执行周期:其步骤主要分为取指,译码,执行
8.读取内存、加载、执行程序

2.2: 32位X86处理器

1.操作模式:保护模式,虚拟8086模式,实地址模式,系统管理模式

​ 1)保护模式:最安全

​ 2)虚拟8086模式:既安全又是实地址

​ 3)实地址模式:直接访问系统内存和硬盘

tips: 物理地址与逻辑地址(段基值,偏移量)

2.执行环境

​ 1)通用寄存器(球球了,这个记住吧,真的很重要)

32位16位8位(高)8位(低)
EAXAXAHAL
EBXBXBHBL
ECXCXCHCL
EDXDXDHDL

tips

​ 1)乘法默认EAX

​ 2)CPU默认用ECX做循环(参见后面的loop)

​ 3) ESP用于寻址堆栈数据

​ 4)ESI和EDI用于高速存储器传输指令

​ 5)EBP引用堆栈的函数参数和局部变量

​ 6) CS:IP 段基值和偏移量

​ 2)段寄存器

​ 3)指令指针

​ 4)EFLAGS寄存器:设置标志位,EFLAGS为1;清除标志位,EFLAGS为0

​ 5)控制标志位

​ 6)状态标志位

​ 1.进位(CF)

​ 2.溢出(OF)

​ 3.符号(SF)

​ 4.零(ZF)

​ 5.辅助进位(AC或AF)

​ 6.奇偶校验(PF)

​ 7.单步标志位(TF):触发单步中断,调试程序

​ 8.中断标志位(IF):是否处理可屏蔽中断

​ 9.方向标志位(DF):控制串操作指令存取数据的方向

3.MMX寄存器:单指令,多数据

4.XMM寄存器:浮点单元(FPU)

2.3 64位X86-64处理器

基本上和32位差不多

除了:

16个64位通用寄存器(32只有8个)

8个80位浮点寄存器

1个64位RFLAGS(但只能用低32位,好鸡肋啊

1个64位RIP

8个64位MMX

16个128位XMM(32位只有8个XMM)

操作数大小可用寄存器
8位AL;BL;CL;DL;DIL;SIL;BPL;SPL;R8L;R9L;R10L;R11L;R12L;R13L;R14L;R15L;
16位AX;BX;CX;DX;DI;SI;BP;SP;R8W;R9W;R10W;R11W;R12W;R13W;R14W;R15W
32位EAX;EBX;ECX;EDX;EDI;ESI;EBP;ESP;R8D;R9D;R10D;R11D;R12D;R13D;R14D;R15D
64位RAX;RBX;RCX;RDX;RDI;RSI;RBP;RSP;R8;R9;R10;R11;R12;R13;R14;R15
2.4 典型x86计算机组件

1.主板

2.内存

2.5 输入输出系统

1.I/O访问层次

2.6 小结

1.32位和64位寄存器,好好搞,本章就这个是重点,其他都是废话

2.寄存器:直接位于CPU内的高速储存位置的存储器,访问速度远高于传统存储器

2.时钟:对CPU内部操作与系统其他组件进行同步

3.控制单元(CU):协调参与机器指令执行的步骤序列

4.算术逻辑单元(ALU):执行算数运算

5.内存存储单元:用于在程序运行时保存指令和数据

6.总线:一组并行线,将数据从计算机一个部分传到另一个部分

​ 6.1数据总线:传指令和数据

​ 6.2控制总线:对设备进行同步

​ 6.3地址总线:保存指令和数据地址

tips

我现在严重怀疑作者想要劝退一些人,才这么写。前两章和汇编关系不是很大,但对我而言已经很劝退了,是不是我太菜了,,我裂开了。强烈建议跳过这俩,我吐了

第一章重点是配置一下环境

第二章重点是看看寄存器,稍微理解一下

没了。。。

对了,下章多看看,比前面硬核,真的开始了汇编之旅


3.汇编语言基础

3.1 基本语言元素

先来一个汇编语言代码

main PROC
	MOV eax,5
	add eax,6
	
	INVOKE ExitProcess,0
main ENDP

就是把5移动到 EAX 寄存器中,然后再把6加到 EAX 寄存器中,就结束了

(震惊!!!你的第一个汇编语言代码居然不是hello world)

接下来,我们添加一个变量吧

.data
sum DWORD 0
.code
main PROC
	mov eax,5
	add eax,6
	mov sum,eax
	
	INVOKE ExitProcess,0
main ENDP

就是sum = 5 + 6

啊啊啊啊,好累啊啊,我死了

和其他语言一样,我们先从常量和变量开始吧

1.整数常量

​ [{+|-}]数字[数制系统]

​ 垃圾总述,直接上例子

​ E.G.

​ 26 10

​ 26d 10

​ 1101001 10

​ 1101001b 2

​ 42q 8

​ 42o 8

​ 1Ah 16

​ 0A3h 16 注意:如果16进制开头是字母,要加前导0

2.整型常量表达式

运算符名称优先级
()圆括号1
+,-正负(+1,-4)2
*,/乘除3
MOD取mod*(泪目,回到高中VB)*3
+, -加减4

3.实数常量

​ [sign]integer.[integer][exponent]

​ 直接上例子吧

​ 2.

​ +3.0

​ -44.2E+05

​ 26.E5

小数点别忘了,不管怎么样都要有

4.字符(串)常量(学完这个就会hello world了)

​ ‘hello world’

​ “hello world”

​ “a ‘hello’ b”

​ ‘a “hello” b’

​ 这个和python好像啊,单双引号可以混用

5.保留字:别用就可以了

6.标识符:就是约等于变量,现在可以这么理解

7.伪指令:嵌入源代码中的命令,由汇编器识别和执行

不区分大小写

​ E.G.

​ .data .DATA .Data 是一样的

​ 定义段:.data,.code等等

8.指令

​ 标号(可选)

​ 指令助记符(必选)

​ 操作数(可选)

​ 注释(可选)

​ [label:] mnemonic [operands] [;comment]

​ L1: mov ax, bx ;move bx to ax

​ tips:NOP指令:空指令,用于对齐,对齐了,算起来快

3.2 示例
; AddTwo.asm - 两个32位整数相加
; 第三章示例

.386									;32位程序
.model flat, stacall					;flag内存模式, stdcall调用规范
.stack 4096								;堆栈4096,一个内存页大小
ExitProcess PROTO, dwExitCode:DWORD		;声明结束标准

.code
main PROC
	mov eax,5
	add eax,6
	
	INVOKE ExitProcess,0
main ENDP
END main
3.3 汇编、链接和运行程序

1.汇编-链接-执行周期

2.列表文件:包括程序源文件副本,行号,每条指令的数字地址,每条指令的机器代码字节和符号表

; AddTwo.asm - 两个32位整数相加
; 第三章示例

.386									;32位程序
.model flat, stacall					;flag内存模式, stdcall调用规范
.stack 4096								;堆栈4096,一个内存页大小
ExitProcess PROTO, dwExitCode:DWORD		;声明结束标准

00000000		.code
00000000		main PROC
00000000 B8 00000005	mov eax,5
00000005 83 C0 06		add eax,6
	
						INVOKE ExitProcess,0
00000008 6A 00			push	+00000000h
0000000A E8 00000000 E	call ExitProcess
0000000F				main ENDP
						END main

invoke伪指令使得汇编器生成PUSH和CALL语句

3.4 定义数据

1.内部数据类型:按数据大小(字节、字、双字)、是否有符号、是整数还是实数

[name] directive initializer [,initializer]…

类型用法
BYTE8位无符号
SBYTE8位有符号
WORD16位无符号
SWORD16位有符号
DWORD32位无符号
SDWORD32位有符号
FWORD48位
QWORD64位
TBYTE80位
REAL432位IEEE
REAL864位IEEE
REAL1080位IEEE

E.G.

count DWORD 12345	

就是count = 12345

2.伪指令

伪指令用法伪指令用法
DB8位整数DQ64位整数或实数
DW16位整数DT80位整数
DD32位整数或实数

3.初始化

sum DWORD 0	

就是把sum初始化为0

当然,如果你不愿意初始化的话,也可以用?去初始化

sum DWORD ?

所以,,我们加个变量吧

; AddTwo.asm - 两个32位整数相加
; 第三章示例

.386									;32位程序
.model flat, stacall					;flag内存模式, stdcall调用规范
.stack 4096								;堆栈4096,一个内存页大小
ExitProcess PROTO, dwExitCode:DWORD		;声明结束标准

.data
sum DWORD 0

.code
main PROC
	mov eax,5
	add eax,6
	mov sum,eax
	
	INVOKE ExitProcess,0
main ENDP
END main

4.定义BYTE和SBYTE

BYTE和SBYTE都是8位的,所以我们添加进的数据也都是8位的

E.G.

value1 BYTE 'a'
value2 BYTE 0
value3 BYTE 255
value4 SBYTE -128
value5 SBYTE 127

5.偏移量

即该元素(的首元素)的位置,记住这一点

6.多初始值

如果我们要用数组的话,我们可以用一个变量去代表数组

E.G.

list1 BYTE 10,20,30,40
list2 BYTE  10,20,30,40
		BYTE  50,60,70,80

这两种在现在是一样的,但记住,在未来,这俩还是有一点点区别的

当然,我们也可以使用不同的基数来定义

E.G.

list1 BYTE 10b,20,30o,40h

7.定义字符串

E.G.

greeting1 BYTE "Good afternoon",0

请记住这个0,0是字符串结尾标识符,真的很重要

8.DUP操作符:使用一个整数表达式,为多个数据项分配储存空间

E.G.

BYTE 20 DUP(0)		;20个字节,值都是0
BYTE 20 DUP(?)		;20个未定义的字节
BYTE 4 DUP("STACK")		;20个字节

9.定义WORD/SWORD

和BYTE/SBYTE一样,只不过BYTE是8位,WORD是16位的

所以直接上E.G.

word1 WORD 65535
word2 WORD -32768
myList WORD 1,2,3,4,5

10.定义DWORD/SDWORD

和BYTE/SBYTE一样,只不过BYTE是8位,DWORD是32位的

(略)

11.定义QWORD

(略)

12.定义浮点类型

直接上例子吧

rVal1	REAL4 -1.2
rVal2	REAL8 3.2E-260
rVal3	REAL10 4.6E+4096
shortArray REAL4 20 DUP(0.0)

13.加法程序

所以我们开始为上面那个加法程序加点料吧

.368
.model flat,stdcall
.stack 4096		;堆栈
ExitProcess PROTO, dwExitCode:DWORD

.data
firstval DWORD 20002000h
secondval DWORD 11111111h
thirdval DWORD 22222222h
sum DWORD 0

.code
main PROC
	mov eax, firstval
	add eax, secondval
	add eax, thirdval
	mov sum, eax
	
	INVOKE ExitProcess, 0
main ENDP
END main

14.小端顺序和大端顺序

12345678h

小端大端地址
78120000
56340001
34560002
12780003

15.未声明初始化的数据

用.data?

而不要放在.data里面,这样子可以减少编译程序的量

3.5 符号常量

1.等号伪指令:

COUNT = 500

2.当前地址计数器:

selfPtr DWORD $

$ 的作用就是不要自己数有几个数组

list BYTE 10,20,30,40
var = $-list

3.EQU伪指令:将不同文本连接起来

name EQU expression ;有效的整数表达式
name EQU symbol     ;已存在的符号
name EQU <text>		;文本或数字

就是将name = expression || symbol || text

4.TEXTEQU伪指令:类似于EQU,创建了文件宏

name TEXTEQU %constExpr 
name TEXTEQU textmarco     
name TEXTEQU <text>		
3.6 64位编程

我觉得约等于32位

除了:

.386									;32位程序
.model flat, stacall					;flag内存模式, stdcall调用规范
.stack 4096								;堆栈4096,一个内存页大小

以上,32位有,64位无

还有就是指令长度等等问题了

其他区别需要自己寻找了,此处省略

(但我怀疑我这里大写特写32位,然后考试和上课是64位,那不裂开)

3.7 小结

终于终于终于,汇编语言基础结束了,最基础的汇编语言的语法也结束了,你学废了么?

眼睛:我看完了;脑子:这啥?这又是啥?我是啥?(误)

需要了解的名字:

1.字符常量

2.保留字

3.标识符

4.伪指令

5.指令助记符

6.操作数

7.逻辑段

8.源文件

9.列表文件

10.链接器

11.符号常量

你学会了啥:

最基本的汇编语言指令怎么写,但你还是不会helloworld

tips

建议好好看此章,这个保证了以后课你能不能听懂,也保证了你能不能真正学会汇编语言,而不是混过去。

我所希望的大学生都能扎扎实实把每一门专业课学好,特别是计算机这种工科专业

吃饭的家伙总要学好,总不能现学现卖吧

虽然你可能觉得汇编语言没什么用,去看看最初我写的前言吧,或者想想看你的绩点吧。

好像扯远了,,回来回来

相信我,这章你肯定会回来看的,,(我也一样)

补充:寻址方式:寄存器寻址,立即数寻址,存储器寻址

直接寻址方式,寄存器间接寻址方式,变址寻址,基址寻址,基址变址寻址(具体见PPT)

4.数据传送、寻址和算术运算

4.1 数据传送指令

1.x86指令格式

[lebel:] mnemonic [operands][; comment]

指令包含的操作数一般是0、1、2、3个,包含超过三个

操作数是啥,不懂的记得回去看

操作数有三种:

​ 1.立即数——用

数字和文本的表达式

​ 2.寄存器操作数——cpu的寄存器

​ 3.内存操作数——引用内存位置

2.MOV指令(数据传输指令):将源操作数复制到目标操作数

MOV a,b

就是把b里的数复制到a里面去

a = b;

但它也有前提:

​ 1.a和b一样大

​ 2.a和b不能都是内存操作数

​ 3.指令指针寄存器不能做a

E.G.

.data
var1 WORD 0
.data?
var2 WORD ?
.code
mov ax, var1
mov var2, ax

就是

var2 = var1			//好累啊

2.1.覆盖值

.data
oneByte BYTE 78h
oneWord WORD 1234h
oneDWord DWORD 12345678h
.code
mov eax,0
mov al,oneByte		;eax = 00000078h
mov eax,oneWord		;eax = 00001234h
mov eax,oneDWord	;eax = 12345678h
mov ax,0			;eax = 12340000h

2.2.符号全零

因为mov不能将一个小的数复制到大的空间里面,所以我们可以先将大空间全部清理,然后传入大空间的低位

.data
count WORD 1
.code
mov ecx,0
mov cx,count

但如果我们有符号,负的就有bug了

所以我们想到了一个方法,也就是符号扩展

将最高位扩展到前面去即可

3.MOVZX指令:全零扩展传送

.data
byteVal BYTE 10001111b

.code
movezx ax,byteVal			;ax = 0000000010001111b

4.MOVESX:符号扩展传送

.data
byteVal BYTE 10001111b

.code
movesx ax,byteVal			;ax = 1111111110001111b

5.LAHF和SAHF

LAHF:将EFLAGS寄存器的低字节复制到AH

SAHF:将AH复制到EFLAGS寄存器的低字节

6.XCHG指令

交换a,b

mov指令是a = b

而XCHG是swap(a,b)

提醒一下,c++中algorithm(算法)的库里面有swap函数,可以直接用

xchg ax,bx

7.直接-偏移量操作

就和数组差不多,两个选择

[array+1]

或者

array[1]

4.2 加法和减法

1.INC和DEC指令

inc a	;a++
dec b	;b--

只能是寄存器和内存操作数

2.ADD指令(ADC)

add dest, sourse	;dest = dest + sourse

tips:标志位也会变

3.SUB指令(SBB)

sub dest,sourse	;dest = dest - sourse

tips:标志位也会变

4.NEG指令

neg a	;a的补码,也就是取反加一

tips:标志位也会变

所以我们可以通过以上完成加减的正常运算了

5.标志位

​ 1.进位标志位(CF):无符号整数溢出 11111111 + 00000001

​ 2.溢出标志位(OF):有符号整数溢出 01111111 + 00000001

​ 3.零标志位(ZF):结果为0 00000001 - 00000001

​ 4.符号标志位(SF):如果为负数,则符号标志位置1(0不是负号)

​ 5.奇偶标志位(PF):1的个数如果是偶数,则置1

​ 6.辅助进位标志位(AF):有进位或者借位

4.3 与数据相关的运算符和伪指令

1.OFFSET运算符

返回数据标号的偏移量(按字节计算)

.data?
bVal BYTE ?
wVal WORD ?
dVal DWORD ?
dVal2 DWORD ?
.code
mov esi, OFFSET bVal		;esi = 00404000h
mov esi, OFFSET wVal		;esi = 00404001h
mov esi, OFFSET dVal		;esi = 00404003h
mov esi, OFFSET dVal2		;esi = 00404007h

所以我们可以通过OFFSET运算符来解决数组问题

如取数组第几个

.data
myArray WORD 1,2,3,4,5
.code
mov esi, OFFSET myArray + 4

2.PTR运算符

PTR可以重写一个已经被声明的操作数的大小类型

.data
mydouble DWORD 12345678h
.code
mov ax,mydouble				;错误
mov ax,WORD PTR mydouble	;正确,把低位5678h放进来

因为X86是小端储存格式,所以是5678h

3.TYPE运算符

返回变量单个元素大小,以字节为单位计算的

.data?
var1 BYTE ?
var2 WORD ?
var3 DWORD ?
var4 QWORD ?
.code
TYPE var1			;1
TYPE var2			;2
TYPE var3			;4
TYPE var4			;8

4.LENGTHOF运算符

计算数组中元素的个数

.data
byte1 BYTE 1,2,3,4
	  BYTE 5,6,7
byte2 BYTE 1,2,3,4,
	  BYTE 5,6,7
.code
LENGTHOF byte1		;4
LENGTHOF byte2		;7

5.SIZEOF运算符

返回大小,即LENGTHOF和TYPE的乘积

.data
byte1 BYTE 1,2,3,4
.code
SIZEOF byte1		;4

6.ALIGN伪指令

ALIGN bound		;bound取1,2,4,8,16

将变量对齐到字节边界,字边界,双字边界,段落边界

可以让CPU更快的计算

7.LABEL伪指令

插入一个标号,定义大小属性,但不分配空间

4.4 间接寻址

1.任何一个寄存器加上[]就是一个间接操作数

​ 寄存器上存上地址,[寄存器]就是解地址

​ 数组也是同理

.data
array BYTE 10h,20h,30h
.code
mov esi,OFFSET arrayB
mov al,[esi]
inc esi
mov al,[esi]
inc esi
mov al,[esi]

2.变地址操作数

arr[i]
[arr+i]

两种形式

3.指针

一个变量包含另一个变量的地址

用OFFSET定义指针

4.TYPEDEF

创建用户定义类型

PBYTE TYPEDEF PTR BYTE
4.5 JMP和LOOP指令

1.无条件转移和条件转移

2.JMP指令

top:
	inc a
	jmp top	;不断的循环

3.LOOP指令

按照ECX计数器循环

	mov ax,0
	mov eax,5
L1:
	inc ax
	loop L1

每次循环eax都减1,直到为0

4.嵌套循环

.data
count DWORD ?
.code
	mov ecx,100
top1:
	mov count ecx
	mov ecx,20
top2:
	loop top2
	mov ecx,count
	loop top1
4.6 小结

我快要写死了,能不能给我点精神奖励呢?

当然能看到这里已经很不错了,值得鼓励

让我尊称你为巨巨

巨佬,ddw啊

我想放弃了。。。。

1.本章需要了解

MOV

MOVZX

MOVSX

XCHG

操作数类型

INC

DEC

ADD

SUB

NEG

状态标志

OFFSET

PTR

TYPE

LENGTHOF

SIZEOF

TYPEDEF

JMP

LOOP

tips

数据传送、寻址和算术运算结束了,接下来的学习会越来越有意思,加油啊

5.过程

5.1 堆栈操作

1.堆栈的数据结构:新值添加到栈顶,删除值也在栈顶移除(LIFO)

2.运行时堆栈

​ ESP:扩展堆栈指针

​ 使用CALL,RET,PUSH,POP等指令来间接进行修改

​ 2.1 入栈操作

​ ESP先向下移动一格(高地址向低地址扩展),然后数据入栈,

​ ESP指针总是指向最后压入堆栈的数据项

​ 2.2 出栈操作

​ 先删除ESP所指的数据,然后ESP向上移动一格

​ 或者直接ESP向上移动一格

​ 因为理论上ESP下面的值是多少其实是无所谓的

​ 2.3 堆栈的意义

​ 当寄存器用于多个目的时,我们可以用堆栈作为寄存器的一个保护区(临时储存区)

3.PUSH和POP指令

​ 3.1 PUSH是插入指令

PUSH eax		;将eax的值入栈

​ 3.2 POP是弹出指令

POP eax			;将栈顶的值放到eax中,并删除这个值

​ 3.3 PUSHFD和POPFD指令

​ PUSHFD将EFLAGS寄存器的值压入栈

​ POPFD将栈的值弹出到EFLAGS寄存器

PUSHFD
POPFD

​ 入栈必须要有一个出栈(确保push后面一定有个pop)

​ 4.PUSHAD,PUSHA,POPAD,POPA

​ PUSHAD和PUSHA按照EAX,ECX,EDX,EBX,ESP,EBP,ESI,EDI顺序压入

​ POPAD和POPA按照相反的顺序弹出

​ 只不过PUSHA,POPA是16位的,而PUSHAD,POPAD是32位的

5.2 定义并使用过程

1.PROC伪指令

;定义的过程
;前面最好有一串注释,这样子对程序猿友好一点
sample PROC
;
;
;
ret
sample ENDP

2.全局标号

jmp Destination ;因为标号只能在被定义的过程中可见,所以如果要jmp到其他地方,我们需要全局标号
;全局标号
Destination::

3.CALL和RET指令

CALL sth		;过程调用sth
;然后直接执行了sth,直到sth里面有RET出现,这样子就返回到原来的地方

4.过程调用嵌套

就是在一个过程中调用另外一个过程,不断套娃就出来了

main proc


call sub1
exit
main endp
;
sub1 proc


call sub2
ret
sub1 endp
;

sub1 proc


ret
sub1 endp

5.向过程中传递寄存器参数

在调用过程时,我们需要准备好过程中所需要的东西(放在寄存器里面)

然后输出的时候需要先push一个寄存器,组最后再pop回来,

先要保存,再变化,最后再变回来,万一这东西除了这里要用,其他地方也有用呢?

所以需要先push再pop回来

6.保存和恢复寄存器

一遍遍push,pop会不会太累啊,

所以聪明的计科人想到了模块化

也就推出了USES运算符

自动的push和pop,,但不能push和pop返回值,不然你啥也没干

arraysum proc uses esi ecx		;esi,ecx输入  eax输出 所以只要出现esi,ecx即可
	mov eax,0
L1:
	add eax,[esi]
	add esi,TYPE DWORD
	loop L1
	
	ret
arraysum endp

这个等同于

arraysum proc 			;esi,ecx输入  eax输出 所以只要出现esi,ecx即可
	push esi	;先esi后ecx
	push ecx
	mov eax,0
L1:
	add eax,[esi]
	add esi,TYPE DWORD
	loop L1
	pop ecx			;先ecx再esi
	pop esi
	ret
arraysum endp
5.3 链接到外部库

相当于c和c++里面的#include<>

相当于python里面的import

这样子方便一点点

5.4 Irvine32链接库

如何使用

include Irvine32.inc
.data
.code

能干啥

过程过程
closefilereadkey
clrscrreadstring
creatoutputfilesettextcolor
crlfstr_compare
delaystr_copy
dumpmemstr_length
dupregsstr_trim
getcommandtailstr_ucase
getdatetimewaitmsg
getmaxxywritebin
getmsecondwritebinb
gettextcolorwritechar
gotoxywritedec
isdigitwritehex
msgboxwritehexb
msgboxaskwriteint
openinputfilewritestackframe
parsedecimal32writestackframename
parseinteger32writestring
random32writetofile
randomizewritewindowsmsg
randomrange
readchar
readdec
readfromfile
readhex
readint

具体内容需要查表

5.5 小结

库是不需要背出来的,只需要记住一些常用的就可以了

本节需要了解什么是堆栈,如何操作,如何调用过程,如何调用库

tips

回想一下,前面的知识有没有学会,我到这已经快要打字打死了,可怜可怜我吧,www

6.条件处理

6.1 条件分支

条件分支:允许作决策的编程语句使程序猿可以改变控制流

6.2 布尔和比较指令
  1. 5种操作符:AND, OR, XOR, NOT, TEST

  2. CPU状态标志:零标志位,进位标志位,符号标志位,溢出标志位,奇偶标志位

  3. AND指令

    AND destination, source
    

    destination = destination & source

    AND指令可以将1转变为0

  4. OR指令

    OR destination, source
    

    destination = destination ^ source

    OR指令可以将0转化为1

  5. 位映射集:用位向量把一个二进制数中的位映射为数组的对象

    1.补集:用NOT

    2.交集:用AND

    3.并集:用OR

  6. XOR指令

    XOR destination, source
    

    异或运算可以检查奇偶性

  7. NOT指令

    NOT reg
    

    将操作数里面的所有位都取反

    NOT不影响标志符号

  8. TEST指令

    TEST指令在两个操作数的对应位之间进行AND操作

    但TEST指令不能修改目标操作数

    test al, 00001001
    
  9. CMP指令

    比较指令

    CMP destination,source
    
    CMP结果ZFCF
    destination<source01
    destination>source00
    destination=source10
    CMP结果标志位
    destination<sourceSF != OF
    destination>sourceSF = OF
    destination=sourceZF = 1

    其实CMP指令是从目的操作数中减去源操作数的隐含减法的操作,并且不修改任何操作数

  10. 置位和清除单个CPU标志位

    通过使用AND,OR,TEST等指令来修改,通过修改该数来修改该数的标志位

6.3 条件跳转

1.Jcond指令

Jcond destination

当条件为真时,我们就可以跳转到下一个地方

也就是高级语言里面的IF语句

;如何实现
cmp eax,5
je L1

2.条件跳转指令类型

JZ	;ZF = 1
JNZ	;ZF = 0
JC	;CF = 1
JNC	;CF = 0
JO	;OF = 1
JNO	;OF = 0
JS	;SF = 1
JNS	;SF = 0
JP	;PF = 1
JNP	;PF = 0
JE	;LEFT = RIGHT
JNE	;LEFT != RIGHT
JCXZ;CX = 0
JECXZ;ECX = 0
JRCXZ;RCX = 0(64bit)
;无符号
JA	;LEFT > RIGHT
JNBE;LEFT > RIGHT
JAE	;LEFT >= RIGHT
LNB	;LEFT >= RIGHT
JB	;LEFT < RIGHT
JNAE;LEFT < RIGHT
JBE	;LEFT <= RIGHT
JNA	;LEFT <= RIGHT
;有符号
JG	;LEFT > RIGHT
JNLE;LEFT > RIGHT
JGE	;LEFT >= RIGHT
LNL	;LEFT >= RIGHT
JL	;LEFT < RIGHT
JNGE;LEFT < RIGHT
JLE	;LEFT <= RIGHT
JNG	;LEFT <= RIGHT

3.给个例子吧

.data
V1 WORD ?
V2 WORD ?
V3 WORD ?
.code
	mov ax,V1
	cmp ax,V2
	JBE L1
	mov ax,V2
L1: cmp ax,V3
	jmb L2
	mov ax,V3
L2:
6.4 条件循环指令

1.LOOPZ和LOOPE指令

LOOPZ destination

LOOPZ是为零跳转,LOOPE是相等跳转

2.LOOPNZ和LOOPNE指令

使用方法同上

只不过

LOOPNZ是不为零跳转,LOOPNE是不相等跳转

6.5 条件结构

即通过使用多个if语句,for语句,while语句来实现每一个程序的选择与循环

其他就没啥。。。

6.6 有限状态机

即是一个根据输入改变状态的机器或程序

有兴趣可以用c++实现一下,但用汇编就多此一举了。

6.7 条件控制流的伪指令
.BREAK
.CONTINUE
.ELSE
.ELSEIF condition
.ENDIF
.ENFW
.IF condition
.REPEAT
.UNTIL condition
.UNTILCXZ
.WHILE condition

以上是那些简单的伪指令,这样子就不需要用前面那么累的东西了

当然等不等于也有逻辑运算符

==
!=
>
>=
<
<=
!
ab	;and a,b
||
&
carry ?
overflow ?
parity ?
sign ?
zero ?

这样子也太香了吧,基本上和写c语言差不多了

6.8 小结

本章需要了解那些选择结构,已经它们的细节,也需要了解条件判断语句的底层原理

知道AND,OR,XOR,NOT,TEST等语句的内容和意义

主要是背诵

tips

本章背诵的内容较多,需要多回去看看,多背背

如果来不及了,就直接看最后一部分,又好理解,又好背诵

啊啊啊啊,快了快了,第六章了,我已经停下写笔记写了好几天了,等写完就可以学新知识了

7.整数运算

7.1 移位和循环移位指令
SHL	;左移
SHR	;右移
SAL	;算术左移
SAR	;算术右移
ROL	;循环左移
ROR	;循环右移
RCL	;带进位的循环左移
RCR	;带进位的循环右移
SHLD;双精度左移
SHRD;双精度右移

0.左移和右移就不加以介绍了,不会的请回小学二年级学习

1.算术右移和逻辑右移有什么区别

也就是逻辑移动都是用0代替空缺的位置

而算术移动都是用最高位来填充(记住,只有算术右移才有,算术左移和逻辑左移是一个东西)

mov al,0F0h
sar dl,1

以上是代码实例,也就是往右移动一格

cf就是移出去的那一位,

如果移动了多位,应该是最后一位吧(我猜的)

3.左移右移的妙用

因为计算机是用二进制完成的,所以当你左移时是乘以2,当你右移时是除以2,这在快速的运算时很重要

4.循环移位也就是循环绕着转,然后CF就是和普通移位(没有循环)一样

5.双精度移位:就是两个字节进行正常的移位,自己脑补一下

(主要是这图太多了,我不想画了,就简略一点点)

7.2 移位和循环移位的应用

应用其实蛮多的,但需要你自己去想象

这里用书中的例子

1.多个双字的移位

2.二进制乘法

3.显示二进制位

4.提取文件日期字段

7.3 乘法和除法指令

1.MUL指令

MUL reg
被乘数乘数乘积
ALreg/mem8AX
AXreg/mem16DX:AX
EAXreg/mem32EDX:EAX

有没有发现MUL的乘积的比特数是乘数(被乘数)的两倍,所以完全不需要担心溢出的问题

代码举例

mov al,5h
mov bl,10h
mul bl

p.s. 我发现16位乘法也可以直接算诶。我好笨啊

2.IMUL指令

有符号的除法指令,和mul就相差一个符号

3.DIV指令

无符号除法

被除数除数余数
AXreg/mem8ALAH
DX:AXreg/mem16AXDX
EDX:EAXreg/mem32EAXEDX

4.IDIV指令

有符号的除法

mov dx,0
mov ax,009bh
mov bx,2
idiv bx

5.符号扩展指令

CBW:字节转字

CWD:字转双字

CDQ:双字转四字

7.4 扩展加减法

扩展精度加减法:对基本上没有大小限制的数进行加减法的技术、

1.ADC (带进位的加法)

2.SBB(带借位的减法)

adc a,b
sbb a,b
7.5 小结

本章主要是了解如何移位,如何乘除即可,其他书本上的细节本人认为意义不是很大,在以后的学习和使用中碰到的概率也是蛮小的,所以书上很多的内容在我的笔记中省略了,也是减轻大家复习的时间

tips

需要了解计算机如何使用移位和乘法的,所以需要更好的来回看,而且现在的你应该已经入门了,所以我所写的笔记是会越来越精简,甚至会只写它是什么,它要怎么用,以及它的原理。

8.高级过程

本章介绍如何使用函数,如何使用递归,如何传递参数等等问题

8.1 堆栈帧

1.实际参数与形式参数:自己上百度搜素

2.堆栈帧:一块堆栈保留区域,用于存放被传递的实际参数、子程序的返回值、局部变量等

3.普通的寄存器参数的方法耗时耗力,还极有可能是错误的,所以我们建议使用堆栈,我们只需要将所需要的参数压入栈即可

4.一般我们压入:值参数(不修改外部的数据)、引用参数(修改外部数据),想一想以前的swap函数

5.如何传递数组:我们只需要将数组的首地址传出去即可

6.堆栈帧的创建方法

​ 1.被传递的实际参数,若有,则压入堆栈(反向压入)

​ 2.被调用时,返回值压入

​ 3.执行时,EBP压入

​ 4.设置EBP等于ESP(作为基态)

​ 5.若有局部变量,就修改esp来预留空间

​ 6.若需要保存寄存器,就压入堆栈

7.寄存器参数的缺点:会导致代码混乱,消除性能优势。所以我们使用堆栈参数来实现。

值传递传递值,引用传递传递地址

;这个是值传递(通过数值去传递,不会改变原来的变量)
addtwo PROC
	push ebp
	mov ebp,esp
	mov eax,[ebp + 12] ;显式的基址偏移量寻址
	add eax,[ebp + 8]
	pop ebp
	ret
addtwo ENDP
int addtwo(int a, int b)
{
	return a + b;
}
push OFFSET val2
push OFFSET val1
call Swap
;调用swap函数,使用引用传参

当子程序返回,必须将参数从堆栈中删除,否则会导致内存泄漏

8.清除堆栈的方法:在call后紧跟一句在ESP上加上一个数,这个数是所占堆栈空间的总和或者在最后加上ret num(num是所占堆栈空间的总和)

9.保存和恢复寄存器:先push再pop,提示一下,要中心对称,先入后出

10.局部变量:

sub esp,8 ;创建局部变量
mov DWORD PTR [ebp-4],10	;第一个局部变量
mov DWORD PTR [ebp-8],20	;第二个局部变量


mov esp,ebp					;删除局部变量

;当然如果增加易读性,我们可以命名
X EQU DWORD PTR [ebp-4]
Y EQU DWORD PTR [ebp-8]
;然后就可以
mov X,10
mov Y,20

11.LEA指令:返回间接操作数的地址

lea eax		;	返回eax的地址

12.ENTER和LEAVE指令

ENTER:自动创建堆栈帧

enter 8,0		;为局部变量保留8个字节
;等价与
push ebp
mov  ebp, esp
sub esp,8

LEAVE:结束一个堆栈帧

enter 8,0

leave
;等价于
push ebp
mov  ebp, esp
sub esp,8

mov esp,ebp
pop ebp

13.LOCAL指令

在Microsoft里是enter的替补

local var1:BYTE
8.2 递归

也就是自己call自己

endless PROC
call endless
endless ENDP

加上普通的判断语句就可以实现递归计算

8.3 INVOKE,ADDR,PROC,PROTO

1.INVOKE

INVOKE DumpArray, OFFSET array, LENGTHOF array, TYPE array
;等价于
push TYPE array
push LENGTHOF array
push OFFSET array
call DumpArray

2.ADDR

ADDR在使用invoke调用时,可以传递指针参数

INVOKE FillArray, ADDR myArray

3.PROC

PROC就是一个声明

label PROC [attributes] [USES reglist], parameter_list

4.PROTO

PROTO指定程序外部过程

ExitProcess PROTO
8.4 新建多模块程序

可以使用INCLUDE和EXTERN

INCLUDE Irvine32.inc
EXTERN subl@0:PROC
8.5 小结

旧账重启,我停更了大半个月,发现我啥也没做,对不起

这一章需要了解的就是前面的一部分

了解堆栈帧,递归和外部引用

其他就粗浅知道即可

tips

啊啊啊,,快结束了,我也快死了,ddl也快到了,,gg了

大家加油啊,相信我,我会把欠的账都补补齐的。

9.字符串和数组

9.1 字符串基本指令

普通的指令可能只能执行一次或者一对数据,我们只需要使用重复前缀就可以了

REPECX>0时重复
REPZ,REPE零标志位为1且ECX>0时重复
PEPNZ,REPNE零标志位清零且ECX>0时重复

方位标志键:

CLD 方位标志位清零

STD 方位标志位置一

cld							;清除方位标志位
mov esi,OFFSET string1		;ESI指向源串
mov edi,OFFSET string2		;EDI指向目的串
mov ecx,10					;计数器赋值为10
rep movsb					;传送10个字节
9.1.1 MOVSB MOVSW MOVSD

功能:传送字符串:将ESI寻址的内存数据复制到EDI寻址的内存位置

MOVSB 传送(复制)字节 ESI或者EDI增加或减少1

MOVSW 传送(复制)字 ESI或者EDI增加或减少2

MOVSD 传送(复制)双字 ESI或者EDI增加或减少4

.data
sourse DWORD 20 DUP(0FFFFFFFh)
target DWORD 20 DUP(?)

.code
cld
mov ecx,LENGTHOF sourse
mov esi,OFFSET sourse
mov edi,OFFSET target
rep movsd
9.1.2 CMPSB CMPSW CMPSD

功能:比较字符串:比较分别由ESI和EDI寻址的内存数据

CMPSB 比较字节

CMPSW 比较字

CMPSD 比较双字

mov esi,OFFSET sourse
mov edi,OFFSET target
cmpsd
9.1.3 SCASB SCASW SCASD

功能:扫描字符串:比较累加器与EDI寻址的内存数据

SCASB 字节

SCASW 字

SCASD 双字

.data
alpha BYTE "ABCDEFGH",0
.code
mov edi,OFFSET alpha
mov al,'F'
mov ecx,LENGTHOF alpha
cld
repne scasb
jnz quit
dec edi
9.1.4 STOSB STOSW STOSD

功能:保存字符串:将累加器内容保存到EDI寻址的内存位置

.data
count = 100
string1 BYTE count DUP(?)
.code
mov al, 0FFh
mov edi,OFFSET string1
mov ecx,count
cld
rep stosb
9.1.5 LODSB LODSW LODSD

功能从字符串加载到累加器:将ESI寻址的内存数据加载到累加器

INCLUDE Irvine32.inc
.data
array DWORD 1,2,3,4,5,6,7,8,9,10
multilier DWORD 10
.code
main PROC
	cld
	mov esi,OFFSET array
	mov edi,esi
	mov ecx,LENGTHOF array
L1:lodsd
	mul multiplier
	stosd
	loop L1
	exit
main ENDP
END main
9.2 部分字符串过程
9.2.1 Str_compare

调用格式: INVOKE Str_compare,ADDR string1, ADDR string2

关系进位标志位零标志位为真则分支(指令)
string1 < string210JB
string1 = string201JE
string1 > string200JA
9.2.2 Str_length

调用格式:INVOKE Str_length, ADDR myString

9.2.3 Str_copy

调用格式:INVOKE Str_copy, ADDR source, ADDR target

9.2.4 Str_trim

从空字节结束字符串中移除所有与选定的尾部字符匹配的字符

调用格式:INVOKE Str_trim, ADDR string, char_to_trim

9.2.5 Str_ucase

把一个字符串全部转换为大写字母,无返回值

调用格式:INVOKE String_ucasn, ADDR myString

64位的话请使用Irivne64的库

9.3 二维数组

二维数组一般有两种,一种是行主序,一种是列主序

一般汇编语言有两种操作方式,即基址-变址基址-变址-位移量

基址-变址操作数

基址-变址操作就是将两个寄存器(一个是基址,一个是变址)相加,生成一个偏移地址

[base + index]

二维数组中可以把行偏移量放在基址寄存器中,列偏移量放在变址寄存器中

基址-变址-位移量

基址-变址-位移量操作数是用一个偏移量,一个基址寄存器,一个变址寄存器和一个可选比例因子来生成有效地址

[base + index + diaplacement]

diaplacement[base + index]

在二维数组中可以将偏移量作为数组名,基址操作数为行偏移量,变址操作数为列偏移量

当然,我觉得还不如使用一个一维数组,可能计算公式麻烦一点,但表达起来就简单了很多(误)

9.4 整数数组的检索和排序

冒泡排序和对分查找

其实后面还有很多排序和查找的方法,但在这里就不一一枚举了,本人的算法笔记和数据结构笔记都在编写中(本人拖延症比较严重)……

9.4 小结

本章需要了解字符串的一些基本操作和一些字符串函数的意义,其他就没什么再了解的意义了

是书编写的越来越没东西了,还是我看书越来越不认真了,

但我真觉得这些意义不是很大,会用就可以了

重点还是前面的部分

tips

没有tips的tips 😆

10.结构和宏

10.1 结构

结构:是一组逻辑相关变量的模板或模式

CORRD 结构
COORD STRUCT
X WORD ?
Y WORD ?
COORD ENDS
定义结构

使用struct和ends的伪指令

name STRUCT
...
name ENDS

无定义:?

字符串文本:用引号括起来

整数:常数或常数表达式

数组:DUP运算符号

对齐结构字段
ALIGN datatype		
;BYTE,SBYTE
;WORD,SWORD
;DWORD,SDWORD
;QWORD
;REAL4
;REAL8
;structure
;union

为什么需要对齐:为了更快的运算速度

声明结构变量
identifier structureType <initalizer-list>

;例子
COORD STRUCT
X WORD ?
Y WORD ?
COORD ENDS
.data
point1 COORD <5,10>
point2 COORD <5>
point3 COORD <,10>
point4 COORD <>		;随机值或者默认初始值
;当然<>可以改为{}
引用结构变量

1.引用成员

;e.g.
.data
worker employee <>
.code
mov dx,worker.years
mov worker.salaryhistory, 20000

使用.来调用内部成员,这点和c++差不多

当然,使用OFFSET运算符可以获得一个地址

mov eax,OFFSET worker.lastname

2.间接和变址操作数

引用间接操作需要指针

mov esi,OFFSET worker
mov ax,(employee PTR[esi]).years

变址操作数

.data
department Employee 5 DUP(<>)
.code
mov esi,TYPE Employee
mov department[esi].Years,4
结构套娃

当然,结构可以套着结构

和c++类似

不再赘述

A STRUCT
X WORD ?
Y WORD ?		;这个将要改变
A ENDS

B STRUCT
X WORD ?
Y WORD ?
B ENDS

C STRUCT
X A <>
Y B <>
C ENDS

.data
c C <>
.code
mov c.X.Y,10
声明和使用联合

前面是c++里面的struct,而我们将学习c++里面的union

unionname UNION
	union-fields
unionname ENDS
;提示,如果union在结构体里面,就是另外一个故事了
;下面是在结构体里面,而上面是在外面
name STRUCT
	...
	UNION unionname 
		union-fields
	ENDS 
name ENDS

其他的使用和c++差不多,所以我在这也不赘述了,以免浪费看官的时间

10.2 宏

宏是一个命名的汇编语句块,就是c++里面的define

在内部会自动展开,替换这个宏,也成为内联展开

宏的定义
macroname MACRO parameter1,parameter2...
	....
ENDM
;宏规定形参 REQ
;宏注释;;
;LOCAL 可以把两个相同名字换成唯一标识符号(汇编语言可能不允许重名)
print MACRO char:REQ
	push eax	;;我是注释
	mov al,char
	call WriteChar
	pop eax
ENDM
;E.G.
printx MACRO
	mov al,'x'
	call WriteChar
ENDM

print MACRO char
	push eax
	mov al,char
	call WriteChar
	pop eax
ENDM
调用宏

和C++一样,直接使用,并添加参数即可

但提醒一下,宏可能有一定的bug

宏也可以嵌套,就和函数嵌套一样,不浪费时间了

10.3 条件汇编伪指令

这个好像只适用于宏吧

IF expression

IFB<>

IFNB<>

IFIDN<>,<> 区分大小写比较

IFIDNI<>,<>不区分大小写比较

IFDIF<>,<>

IFDIFI<>,<>

IFDIF name

IFNDEF name

ENDIF

ELSE

ELSEIF expression

EXITM

默认参数 paramname : =

LT <

GT >

EQ =

NE !=

LE <=

GE >=

& 替换

<>文字文本运算符

!文字字符运算符

%展开运算符

10.4 定义重复语句块
WHILE

重复执行一个语句块,直到为真

WHILE constexpression

​ statements

ENDM

REPEAT

重复固定次数

REPEAT constexpression

​ statements

ENDM

FOR

C++里面的for循环

FOR parameter,<ARG1,ARG2,…>

​ statements

ENDM

FORC

为文本设计的for循环

FORC parameter,

​ statements

ENDM

10.5 小结

本章需要了解struct,union和宏,以及与宏相关的一系列的函数和伪代码,这个专题还是蛮重要的,希望大家能够好好复习,我写不动了,都快要放弃写作了

tips

还有最后一章了,加油啊

聪明的童鞋们会发现我少了两个单元,这两个单元我觉得无伤大雅,暂时对我的意义很小,如果有需要的童鞋们可以自行查看,我这就不去写了

11.浮点数处理与指令编码

11.1 浮点数二进制表达

浮点数包括符号,有效数字和阶码

单精度:32位,1位符号,8位阶码,23位有效数字的小数部分

双精度:64位,1位符号,11位阶码,52位有效数字的小数部分

扩展双精度:80位,1位符号,15位阶码,1位有效数字的整数部分,63位有效数字的小数部分

若有疑问请查阅《计算机概论》等书籍,本部分非重点,就此略过

11.2 浮点单元
FPU寄存器栈

FPU寄存器栈通过表达式的堆栈来完成计算的内容

FPU有8个独立的可寻址的80位数据寄存器,通过将寄存器中缀转后缀来完成运算

A+B -> AB+

(A+B)*(C+D) -> AB+CD+*

(A-B)/D->AB-D/

((A+B)/C)*(E-F)->AB+C/EF-*

专用寄存器

操作码寄存器:保存最后执行的非控制指令的操作码

控制寄存器:执行运算时,控制精度和FPU使用舍入方法

状态寄存器:包含栈顶指针、条件码和异常警告

标志寄存器:指明每个寄存器的内容

最后指令指针寄存器:保存指向最后执行的非控制指令的指针

最后数据(操作数)指针寄存器:保存指向数据操作数的指针

舍入

因为计算机的存储空间有限,所以不可能准确保存数据,可能需要进行舍入

四种舍入方式(FPU控制字)

舍入到最接近的偶数 00

向负无穷舍入 01

向正无穷舍入 10

向0舍入 11、

浮点数异常

#I无效操作

#Z除零

#D非规格化操作数

#O数字上溢

#U数字下溢

#P模糊精度

浮点数指令集

1.初始化FINIT

建议开始时就调用FINIT

2.浮点数类型

REAL4 32位

REAL8 64位

REAL10 80位

3.加载浮点数值(FLD)

将浮点操作数复制到栈顶

FLD m32fp

FLD m64fp

FLD m80fp

FLD ST(i)

加载常数

FLD1 1

FLDL2T log2 10

FLDL2E log2 e

FLDPI π

FLDLG2 log10 2

FLDLN2 loge 2

FLDZ 0.0

4.保存浮点数值

FST,FSTP

FST m32fp

FST m64fp

FST m80fp

FST ST(i)

FSTP dblThree

FSTP dblFour

5.算术运算指令

FCHS修改符号,无操作数

FABS绝对值,无操作数

FADD加法(若FADD ST(i)就是和ST(0)加,如果两个的话就两个相加存在第一个,和ADD类似)

FADDP相加并出栈

FIADD整数加法

FSUB和加法类似,但变成了减法

FSUBR源操作数减目标操作数

FSUBP相减并出栈

FOSUB整数减法

FMUL乘法

FMULP乘法并出栈

FIMUL整数乘法

FDIV除法

FDIVR源操作数除以目的操作数

FDIVP相除并出栈

FIDIV整数除法

6.FCOM比较浮点数

FCOM没有操作数就是ST(0)和ST(1)比较,有操作数就是操作数和ST(0)比较,,最多只能有一个操作数

FCOMP

FCOMPP

条件零标志位C3奇偶标志位C2进位标志位C0使用条件跳转指令
ST(0)>SPC000JA.JNBE
ST(0)>SPC001JB.JNAE
ST(0)>SPC100JE.JZ
无序111

7.读写浮点数值

ReadFloat

WriteFloat

ShowFPUStack

11.3 x86指令编码

了解一下汇编指令如何转变成机器语言的方法

1.指令格式

指令前缀:覆盖默认操作数大小

操作码:指定指令的特定变体

Mod R/M:字段指定寻址模式和操作数

伸缩引字节:用于计算数组索引偏移量

地址位移:字段保存了操作数的偏移量

立即数:字段保存了常量操作数

2.单字节指令

没有操作数的指令,我们只需找到对应的操作码即可

3.立即数送寄存器

按照小端顺序添加指令

4.寄存器模式指令

将指令分为mod,reg,r/m,然后一一转化即可

mov ax,dx 11 000 010

具体请查阅表格

11.4 小结

本章需要了解浮点数和指令编码,这两个是最重要的内容,需要好好学习

Tips

哦哦哦哦哦哦哦哦哦哦哦哦哦哦哦哦哦哦哦哦哦哦哦哦,终于学完了

我也终于写完了

完结撒花

泪目了

当然有很多没有做完,我就先记在这里

就不定期更新了

1.汇编语言是啥,能干啥

2.本笔记的结构

3.最后加个英语整理,学计算机还得学英语吧

4.最后在加个名词汇总,也方便我复习吧

12.后记

断断续续阅此书,絮絮叨叨记新知。

见者若获新玄机,不枉本人几多夜。

新手莫奉为圭臬,还需努力自苦读。

高手莫笑此记误,若知槽点望联系。

如有问题,请联系我,谢谢

当然,如果对您有帮助,可以进行打赏:happy:🤝

联系:1499765600@qq.com

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值