NASM入门教程(part2)

本文介绍了NASM汇编语言的基础指令集,包括数据移动、算术运算、逻辑运算及条件跳转等指令的语法和使用示例。还探讨了如何将常见的C/C++控制结构转换为NASM代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

NASM入门第二发-~~~~~~~~~

---------------------------Basic Instruction Set[基础指令集]

这一节,我们将会讨论NASM基本指令集的语法、语义,看到一些例子。

1.MOV-Move/Copy

将一个寄存器或者内存单元里面的内容拷贝到另一个寄存器或者内存单元中,或者将内存单元中的值、寄存器中的变量赋值为立即数。

sy: 

mov  dest, src

~~src是源操作数,应该是一个寄存器或者内存操作数

~~源操作数和目的操作数不能同时是取自内存的操作数

2.MOVZX-Move and Extend

拷贝并扩展一个lower spaced(提供较低地址空间--位数少的)内存/寄存器的值到一个可以提供较大地址空间的内存/寄存器单元

sy: 

mov zx  src, dec

~~目的操作数的位数>=源操作数的位数

~~src应该是一个寄存器/内存操作数

~~源操作数和目的操作数不能同时是取自内存的操作数

~~只能用户无符号数

Eg:

movzx eax,ah

movzx cx , al

--为扩展有符号数,我们使用向CBW(convert byte to word)、CWD(convert word to double)这样的指令

--CBW扩展AL寄存器至AX

--CWD扩展AX到DX:AX寄存器对

3.ADD--Addition

sy:

add dest, src

dest=dest+src

用于计算两个寄存器/内存变量的和,将结果存进源操作数的位置。

~~源操作数应该是一个寄存器/内存操作数

~~源操作数和目的操作数不能同时是取自内存的操作数

~~源操作数和目的操作数的位数应该是一致的

Eg: 

add eax, ecx ; eax=eax+ecx;

add al, ah ; al=al+ah

add ax, 5 ;ax=ax+5

add edx, 31h

4.SUB--Subtraction

sy: 

sub dest, src

dest=dest-src;

用于计算两个寄存器/内存变量的差,将结果存进源操作数的位置。

~~源操作数应该是一个寄存器/内存操作数

~~源操作数和目的操作数不能同时是取自内存的操作数

~~源操作数和目的操作数的位数应该是一致的


Eg: 

sub eax, ecx ; eax=eax-ecx

sub al, ah;

sub ax, 5

sub  edx, 31h

5.INC--Increment Operation

用于将一个寄存器/内存变量增量1,类似于高级语言中的++

Eg:

INC eax, eax++

INC byte[var]

INC a1

6.DEC--Decrement Operation

用于将一个寄存器/内存变量减少一

Eg: 

DEC eax; eax--

DEC byte[var]

DEC al

7,MUL--Multiplication

Sy: 

mul src

用于将一个寄存器/内存变量和EAX/AX/AL寄存器相乘。MUL依据以下规则进行运算

~~如果src是1Byte,那么AX=AL*src

~~如果src是一个字长(16Byte),那么DX:AX=AX*src(结果的高16位将会进入DX,低16位将会进入AX)

~~如果Src是两个字长的(32Byte),那么EDX:EAX=EAX*src(结果的高32位将会进入EDX,低32位进入EAX)

8.IMUL--Multiplication of signed numbers

IMUL指令用于有符号数的相乘,主要有以下三种不同的用法:

Sy: 

(i) imul src

(ii) imul dest, src

(iii) imul dest, src1, src2

~~如果按照(i)中的方法使用,其语义和MUL一致

~~如果按照(ii)中的方法使用,dest=dest*src

~~如果按照(iii)中的方法使用,dest=src1*src2

9.DIV--Division

Sy: 

div src

用于将EAX/AX/AL寄存器和一个寄存器/内存变量相除。DIV依据以下规则进行运算

~~如果src是一个字长(16Byte),AX将会被src除,余数将会进入AH,商数进入AL

~~如果src是一个字长(16Byte),那么DX:AX将会被src除,余数进入DX,商数进入AX

~~如果Src是两个字长的(32Byte),那么EDX:EAX将会被src除,余数进入EDX,商数进入EAX

10.NEG--Negation of signed numbers

Sy: 

NEG opl

NEG 指令将给出的寄存器/内存变量取反

11.CLC--Clear Carry

此指令用于将CPU FLAGS中的进位标志位[carry flag]清空为0

12.ADC--Add with Carry

Sy:

ADC dest, src

ADC用于较大数字的相加。假如我们想将两个64bit的数字相加,我们将第一个数字放在EDX:EAX(将最有意义起决定性作用的32bits放在EDX中,其他在EAX中),将第二个数字放在EBX:ECX中,而后像如下这样做加法。

Eg: 

clc ; 清空进位

add eax, ecx ; eax和ecx之间正常的加法

adc edx, ebx;对于高位使用带进位加

13.SBB--Subtract with Borrow

Sy: 

SBB dest, src

SBB和ADC是相似的。

NASM中的分支指令:

14.JMP--Uncoditionally Jump to label

JMP 与C/C++中的goto比较相似,用于实现将控制流跳转到程序中的任意地方而不做任何条件判断

Eg:

label: _______________

_______________

JMP label

_______________

_______________

JMP exit

_______________

_______________

exit:

15:CMP--Compares the Operands

Sy: 

CMP op1, op2

当对两个操作数op1,op2使用CMP时候,将会执行op1-op2,但不会存储结果,反之,他将会影响CPU FLAGS。这就像是不存储结果的减法指令一样。比如若是op1==op2,那么ZERO FLAGS(ZF)将会被置为1,。

NB:对于nasm中的条件跳转,首先用CMP指令将ZF置位,然后用以下指令实现对ZF的检查和跳转

Condition Jump Instructions:


Eg: 将if 语句转化为nasm 代码

if(cax>=ebx)
	eax++;
else
	ebx++;
/*转化后的代码*/
cmp	eax, ebx
JNC	if
	INC  ebx	;ELSE part
	JMP	 L1
if:				;If Part
	INC	 eax	
L1:
	........

Advanced conditional Jump Instructions[高级条件跳转指令]:


Eg:
CMP	ax,	bx	;比较
JA	L1		;跳转
	INC	ax	;Else Part
	JMP	L2	
L1:			;If Part
	INC	bx
L2:
	......

16,Loop Instruction循环指令

Sy: 

loop label

当我们使用loop指令的时候,ecx用做循环计数器,Loop指令开始时自减ecx的值,而后检查ecx的新值,是不是ecx!=0的情形,如果是的话,那么将跳转至label所标记的位置,否则控制流将会跳向下一条指令。

Eg:

mov	ecx, 10
mov eax, 0
add:
	add	eax,	ecx
loop	add

Converting Standard C/C++ Control Structures to NASM:

//**************** (i) ******************
//if-else
if(eax>5)
	eax=eax+ebx;
else
	ecx=ecx+ebx;

//nasm statement
CMP	eax,5;
JA	IF	
ELSE:
	ADD	ecx,ebx
	JMP L2
IF:
	add	eax,ebx
L2:
//**************** (i) ******************

//**************** (ii) ******************
//For loop
eax=0;
for(ebx=1 to 10)
	eax=eax+ebx;

//nasm statement
MOV	eax,0
MOV ebx,1
FOR:
	ADD	eax,ebx
	CMP	ebx,10
JBE	FOR
//**************** (ii) ******************

//**************** (iii) ******************
//While-loop
sum=0;
ecx=n;
while(ecx>0)
	sum=sum+ecx;

//nasm statement
MOV	dword[sum],0
MOV	ecx, dword[n]

ADD:
	ADD [sum],ecx
loop ADD
//**************** (iii) ******************
Boolean Operations:

17.AND--bitwise Logical AND

sy: 

AND op1, op2

执行按位与操作,结果被放入op1的位置。

18.OR--bitwise logical OR

sy:

OR op1, op2

执行按位或操作,结果被存入op2的位置

19.XOR--bitwise Logical Exclusive OR

Sy:

XOR op1,op2

执行按位异或,结果存入op1的位置

20.NOT--Bitwise Logical Negation

sy:

NOT op1

按位取反,结果进入Op1

21.TEST--Logical AND, affects only CPU FLAGS

sy: TEST op1

~~和CMP的用法类似,按位与运算的结果不会被保存,而是依据结果对CPU FLAGS进行置位。

22.SHL--shift Left

sy:

SHL op1,op2

op1=op1<<op2;//等价的C语句

~~执行按位左移,op1是寄存器/内存变量,op2 必须是立即数,或者是常量值

~~将会把op1左移op2位,末位补0

23.SHR--shift right

sy:

SHR op1,op2

op1=op1>>op2;//等价的C语句

~~执行按位右移,op1是寄存器/内存变量,op2必须是立即数或者常量

~~op1左移op2位,高位补0

24.ROL--Rotate Left

sy:

ROL op1,op2

~~ROL执行按位的循环左移,op1是寄存器/内存变量,op2是立即数。

Eg:

rol eax,5

25.ROR --Rotate right

sy:

ROR op1,op2

~~ROR执行按位的循环右移,op1是寄存器/内存变量,op2是立即数。

26.RCL--Rotate Left with Carry

sy:

RCL op1,op2

27.RCR--Rotate Right with Carry

sy:

RCR op1,op2

Stack Operations:

28.PUSH--Pushes a value into system stack

减少ESP的值,将寄存器或者是常量的值压入系统栈

Eg:

PUSH ax; ESP=ESP-2 and copies value of ax to [EBP]

PUSH eax; ESP=ESP-4 and copies value of ax to [EBP]

PUSH ebx;

PUSH  dword 5

PUSH word 256

29.POP--pop off a value from the system stack

将栈顶的值存至寄存器,并且增加ESP的值

Eg:

POP bx; ESP=ESP+2;

POP ebx; ESP=ESP+4;

POP eax

这篇就到这里~~Thx!微笑

目录 前言i 第1章简介1 1.1 数制. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 1.1.1 十进制. . . . . . . . . . . . . . . . . . . . . . . . . . . 1 1.1.2 二进制. . . . . . . . . . . . . . . . . . . . . . . . . . . 1 1.1.3 十六进制. . . . . . . . . . . . . . . . . . . . . . . . . 2 1.2 计算机结构. . . . . . . . . . . . . . . . . . . . . . . . . . . . 4 1.2.1 内存. . . . . . . . . . . . . . . . . . . . . . . . . . . . 4 1.2.2 CPU . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5 1.2.3 CPU 80x86系列. . . . . . . . . . . . . . . . . . . . . 5 1.2.4 8086 16位寄存器. . . . . . . . . . . . . . . . . . . . . 6 1.2.5 80386 32位寄存器. . . . . . . . . . . . . . . . . . . . 7 1.2.6 实模式. . . . . . . . . . . . . . . . . . . . . . . . . . . 7 1.2.7 16位保护模式. . . . . . . . . . . . . . . . . . . . . . . 8 1.2.8 32位保护模式. . . . . . . . . . . . . . . . . . . . . . . 8 1.2.9 中断. . . . . . . . . . . . . . . . . . . . . . . . . . . . 9 1.3 汇编语言. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9 1.3.1 机器语言. . . . . . . . . . . . . . . . . . . . . . . . . 9 1.3.2 汇编语言. . . . . . . . . . . . . . . . . . . . . . . . . 9 1.3.3 指令操作数. . . . . . . . . . . . . . . . . . . . . . . . 10 1.3.4 基本指令. . . . . . . . . . . . . . . . . . . . . . . . . 10 1.3.5 指示符. . . . . . . . . . . . . . . . . . . . . . . . . . . 11 1.3.6 输入和输出. . . . . . . . . . . . . . . . . . . . . . . . 14 1.3.7 调试. . . . . . . . . . . . . . . . . . . . . . . . . . . . 14 1.4 创建一个程序. . . . . . . . . . . . . . . . . . . . . . . . . . . 15 1.4.1 第一个程序. . . . . . . . . . . . . . . . . . . . . . . . 16 1.4.2 编译器依赖. . . . . . . . . . . . . . . . . . . . . . . . 18 1.4.3 汇编代码. . . . . . . . . . . . . . . . . . . . . . . . . 19 1.4.4 编译C代码. . . . . . . . . . . . . . . . . . . . . . . . 19 1.4.5 连接目标文件. . . . . . . . . . . . . . . . . . . . . . . 20 1.4.6 理解一个汇编列表文件. . . . . . . . . . . . . . . . . . 20 3 4 目录 1.5 骨架文件. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21 第2章基本汇编语言23 2.1 整形工作方式. . . . . . . . . . . . . . . . . . . . . . . . . . . 23 2.1.1 整形表示法. . . . . . . . . . . . . . . . . . . . . . . . 23 2.1.2 正负号延伸. . . . . . . . . . . . . . . . . . . . . . . . 25 2.1.3 补码运算. . . . . . . . . . . . . . . . . . . . . . . . . 28 2.1.4 程序例子. . . . . . . . . . . . . . . . . . . . . . . . . 29 2.1.5 扩充精度运算. . . . . . . . . . . . . . . . . . . . . . . 31 2.2 控制结构. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32 2.2.1 比较. . . . . . . . . . . . . . . . . . . . . . . . . . . . 32 2.2.2 分支指令. . . . . . . . . . . . . . . . . . . . . . . . . 33 2.2.3 循环指令. . . . . . . . . . . . . . . . . . . . . . . . . 36 2.3 翻译标准的控制结构. . . . . . . . . . . . . . . . . . . . . . . 36 2.3.1 If语句. . . . . . . . . . . . . . . . . . . . . . . . . . . 36 2.3.2 While循环. . . . . . . . . . . . . . . . . . . . . . . . . 37 2.3.3 Do while循环. . . . . . . . . . . . . . . . . . . . . . . 37 2.4 例子:查找素数. . . . . . . . . . . . . . . . . . . . . . . . . . . 37 第3章位操作41 3.1 移位操作. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41 3.1.1 逻辑移位. . . . . . . . . . . . . . . . . . . . . . . . . 41 3.1.2 移位的应用. . . . . . . . . . . . . . . . . . . . . . . . 42 3.1.3 算术移位. . . . . . . . . . . . . . . . . . . . . . . . . 42 3.1.4 循环移位. . . . . . . . . . . . . . . . . . . . . . . . . 42 3.1.5 简单应用. . . . . . . . . . . . . . . . . . . . . . . . . 43 3.2 布尔型按位运算. . . . . . . . . . . . . . . . . . . . . . . . . . 43 3.2.1 AND运算符. . . . . . . . . . . . . . . . . . . . . . . . 44 3.2.2 OR运算符. . . . . . . . . . . . . . . . . . . . . . . . . 44 3.2.3 XOR运算. . . . . . . . . . . . . . . . . . . . . . . . . 44 3.2.4 NOT运算. . . . . . . . . . . . . . . . . . . . . . . . . 45 3.2.5 TEST指令. . . . . . . . . . . . . . . . . . . . . . . . . 45 3.2.6 位操作的应用. . . . . . . . . . . . . . . . . . . . . . . 45 3.3 避免使用条件分支. . . . . . . . . . . . . . . . . . . . . . . . 47 3.4 在C中进行位操作. . . . . . . . . . . . . . . . . . . . . . . . . 49 3.4.1 C中的按位运算. . . . . . . . . . . . . . . . . . . . . . 49 3.4.2 在C中使用按位运算. . . . . . . . . . . . . . . . . . . 50 3.5 Big和Little Endian表示法. . . . . . . . . . . . . . . . . . . . 51 3.5.1 什么时候需要在乎Little和Big Endian . . . . . . . . . 52 3.6 计算位数. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53 3.6.1 方法一. . . . . . . . . . . . . . . . . . . . . . . . . . . 53 3.6.2 方法二. . . . . . . . . . . . . . . . . . . . . . . . . . . 53 3.6.3 方法三. . . . . . . . . . . . . . . . . . . . . . . . . . . 55 目录5 第4章子程序57 4.1 间接寻址. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57 4.2 子程序的简单例子. . . . . . . . . . . . . . . . . . . . . . . . 57 4.3 堆栈. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60 4.4 CALL和RET指令. . . . . . . . . . . . . . . . . . . . . . . . . 60 4.5 调用约定. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61 4.5.1 在堆栈上传递参数. . . . . . . . . . . . . . . . . . . . 62 4.5.2 堆栈上的局部变量. . . . . . . . . . . . . . . . . . . . 66 4.6 多模块程序. . . . . . . . . . . . . . . . . . . . . . . . . . . . 67 4.7 C与汇编的接口技术. . . . . . . . . . . . . . . . . . . . . . . 71 4.7.1 保存寄存器. . . . . . . . . . . . . . . . . . . . . . . . 71 4.7.2 函数名. . . . . . . . . . . . . . . . . . . . . . . . . . . 72 4.7.3 传递参数. . . . . . . . . . . . . . . . . . . . . . . . . 72 4.7.4 计算局部变量的地址. . . . . . . . . . . . . . . . . . . 73 4.7.5 返回值. . . . . . . . . . . . . . . . . . . . . . . . . . . 73 4.7.6 其它调用约定. . . . . . . . . . . . . . . . . . . . . . . 73 4.7.7 样例. . . . . . . . . . . . . . . . . . . . . . . . . . . . 74 4.7.8 在汇编程序中调用C函数. . . . . . . . . . . . . . . . . 78 4.8 可重入和递归子程序. . . . . . . . . . . . . . . . . . . . . . . 78 4.8.1 递归子程序. . . . . . . . . . . . . . . . . . . . . . . . 79 4.8.2 回顾一下C变量的储存类型. . . . . . . . . . . . . . . 79 第5章数组83 5.1 介绍. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83 5.1.1 定义数组. . . . . . . . . . . . . . . . . . . . . . . . . 83 5.1.2 访问数组中的元素. . . . . . . . . . . . . . . . . . . . 84 5.1.3 更高级的间接寻址. . . . . . . . . . . . . . . . . . . . 86 5.1.4 例子. . . . . . . . . . . . . . . . . . . . . . . . . . . . 87 5.1.5 多维数组. . . . . . . . . . . . . . . . . . . . . . . . . 91 5.2 数组/串处理指令. . . . . . . . . . . . . . . . . . . . . . . . . 93 5.2.1 读写内存. . . . . . . . . . . . . . . . . . . . . . . . . 94 5.2.2 REP前缀指令. . . . . . . . . . . . . . . . . . . . . . . 95 5.2.3 串比较指令. . . . . . . . . . . . . . . . . . . . . . . . 96 5.2.4 REPx前缀指令. . . . . . . . . . . . . . . . . . . . . . . 96 5.2.5 样例. . . . . . . . . . . . . . . . . . . . . . . . . . . . 97 第6章浮点103 6.1 浮点表示法. . . . . . . . . . . . . . . . . . . . . . . . . . . . 103 6.1.1 非整形的二进制数. . . . . . . . . . . . . . . . . . . . 103 6.1.2 IEEE浮点表示法. . . . . . . . . . . . . . . . . . . . . 105 6.2 浮点运算. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 107 6.2.1 加法. . . . . . . . . . . . . . . . . . . . . . . . . . . . 108 6.2.2 减法. . . . . . . . . . . . . . . . . . . . . . . . . . . . 108 6 目录 6.2.3 乘法和除法. . . . . . . . . . . . . . . . . . . . . . . . 109 6.2.4 分支程序设计. . . . . . . . . . . . . . . . . . . . . . . 109 6.3 数字协处理器. . . . . . . . . . . . . . . . . . . . . . . . . . . 109 6.3.1 硬件. . . . . . . . . . . . . . . . . . . . . . . . . . . . 109 6.3.2 指令. . . . . . . . . . . . . . . . . . . . . . . . . . . . 110 6.3.3 样例. . . . . . . . . . . . . . . . . . . . . . . . . . . . 115 6.3.4 二次方程求根公式. . . . . . . . . . . . . . . . . . . . 115 6.3.5 从文件中读数组. . . . . . . . . . . . . . . . . . . . . 118 6.3.6 查找素数. . . . . . . . . . . . . . . . . . . . . . . . . 120 第7章结构体与C++ 127 7.1 结构体. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 127 7.1.1 简介. . . . . . . . . . . . . . . . . . . . . . . . . . . . 127 7.1.2 内存地址对齐. . . . . . . . . . . . . . . . . . . . . . . 128 7.1.3 位域s . . . . . . . . . . . . . . . . . . . . . . . . . . . 130 7.1.4 在汇编语言中使用结构体. . . . . . . . . . . . . . . . 132 7.2 汇编语言和C++ . . . . . . . . . . . . . . . . . . . . . . . . . 134 7.2.1 重载函数和名字改编. . . . . . . . . . . . . . . . . . . 134 7.2.2 引用. . . . . . . . . . . . . . . . . . . . . . . . . . . . 136 7.2.3 内联函数. . . . . . . . . . . . . . . . . . . . . . . . . 137 7.2.4 类. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 139 7.2.5 继承和多态. . . . . . . . . . . . . . . . . . . . . . . . 147 7.2.6 C++的其它特性. . . . . . . . . . . . . . . . . . . . . 153 附录A 80x86指令155 A.1 非浮点指令. . . . . . . . . . . . . . . . . . . . . . . . . . . . 155 A.2 浮点数指令. . . . . . . . . . . . . . . . . . . . . . . . . . . . 161 索引163
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值