汇编语言
2021-07-11 12:01:10 0 举报
AI智能生成
汇编语言整理
作者其他创作
大纲/内容
汇编指令(8086)
mov(赋值)
mov ax, 1234H
mov ax, ds:[0]
(段前缀访问模式,不加段前缀,默认ds段)
mov ds:[0], ax
mov ax, [200+bx] = mov ax, 200[bx] = mov ax, [bx].200
mov ax, [bx+si] = mov ax, [bx][si]
mov ax, [bx+si+di] = mov ax, [bx][si][di]
(偏移地址的多种访问方式)
mov byte ptr....,如mov byte ptr [bx],1
mov word ptr....,如mov byte word [bx],1
(操作内存的时候,可以指定ptr值名操作内存的大小)
(段前缀访问模式,不加段前缀,默认ds段)
mov ds:[0], ax
mov ax, [200+bx] = mov ax, 200[bx] = mov ax, [bx].200
mov ax, [bx+si] = mov ax, [bx][si]
mov ax, [bx+si+di] = mov ax, [bx][si][di]
(偏移地址的多种访问方式)
mov byte ptr....,如mov byte ptr [bx],1
mov word ptr....,如mov byte word [bx],1
(操作内存的时候,可以指定ptr值名操作内存的大小)
add(加法)
add ax, bx(结果存到ax)
sub(减法)
sub ax, bx(结果存到ax)
mul(乘法)
mul bl(用al与bl相乘,结果放在ax中)
mul bx (用ax与bx相乘,高位放在dx中,低位放在ax中)
mul byte ptr [bx]
mul word ptr [bx]
loop(循环)
s: 代码段
loop s
loop s
int(中断)
int 21H
jmp(指令跳转)
jmp 2AE3:3 (将CS设置2AE3,IP设置为3)
jmp ax (将IP设置为ax中的值)
jmp dword ptr ds:[0]
(ds[0]-ds[1]是偏移地址,ds[2]-ds[3]是段地址)
(ds[0]-ds[1]是偏移地址,ds[2]-ds[3]是段地址)
jmp far prt [标号]
(将cs设置为标号的cs,将ip设置为标号的ip)
(将cs设置为标号的cs,将ip设置为标号的ip)
jmp word ptr [bx]
jmp word ptr ds:[0]
(将IP中的值设置为内存中的值)
jmp word ptr ds:[0]
(将IP中的值设置为内存中的值)
jmp short [标号]
(s为某段代码,汇编会根据jmp的目的地址,修改IP的值,即ip = ip + 需要跳转代码的字节数)
(只支持8位位移,即-128~127)
(s为某段代码,汇编会根据jmp的目的地址,修改IP的值,即ip = ip + 需要跳转代码的字节数)
(只支持8位位移,即-128~127)
jmp near ptr [标号]
(支持16位转移,即-32768~23767)
(支持16位转移,即-32768~23767)
jcxz(指令有条件位移)
jcxz [标号] (当cx寄存器为0的时候,相当于jmp short [标号])
ret(指令跳转)
出栈第一个数据,修改IP的内容
retf(指令跳转)
先出栈第一个数据先修改CS的内容,在出栈第二个数据修改IP的内容
iret(指令跳转)
先出栈第一个数据修改IP的内容,在出栈一个数据出栈CS的内容
call(指令跳转+位移)
call [标号] (将当前的IP入栈,在位移到标号处,相当于jmp near ptr [标号])
call far ptr [标号](将当前CS入栈,再将IP入栈,在将cs与ip设置为标号处的值)
call ax (先将当前IP入栈,然后自将IP的值设置为ax的值)
call word ptr [bx](先将当前IP入栈,在将IP设置为bx内存处的值)
call dword ptr [bx](先将当前cs入栈,在将ip入栈,在跳转至内存bx指向的cs与ip,相当于先做两次push,在jmp dword ptr [bx] )
push(入栈)
push ax
push [100]
push [100]
pop(出栈)
pop ax
inc(自增)
inc ax
dec(自减)
dec ax
and(逻辑与)
两个2进制数,将两数字同为位为1的位置,设置为1,否则设置为0
or(逻辑或)
两个2进制数,将两数字任意位为1的位置,设置为1,否则设置为0
xor(异或)
如果两个位的值相同,设置为1,否则设置为0
div(除法)
如果被除数大于16位,则高16位用DX,低16位用AX
abc(带进位加发)
sbb(带借位减法)
cmp(比较)
cmp ax, bx
无符号
结果:目的操作数 < 源操作数 ZF=0 CF=1
结果:目的操作数 > 源操作数 ZF=0 CF=0
结果:目的操作数 = 源操作数 ZF=1 CF=0
结果:目的操作数 < 源操作数 ZF=0 CF=1
结果:目的操作数 > 源操作数 ZF=0 CF=0
结果:目的操作数 = 源操作数 ZF=1 CF=0
有符号
结果:目的操作数 < 源操作数 SF ≠ OF
结果:目的操作数 > 源操作数 SF=OF
结果:目的操作数 = 源操作数 ZF=1
结果:目的操作数 < 源操作数 SF ≠ OF
结果:目的操作数 > 源操作数 SF=OF
结果:目的操作数 = 源操作数 ZF=1
je(等于则转移)
zf = 1
jne(不等于则转移)
zf = 0
jb(低于则转移)
cf = 1
jnb(不低于则转移)
cf = 0
ja(高于则转移)
cf = 0 && zf = 0
jna(不高于则转移)
cf = 1 || zf = 1
rep(重复指令)
rep xx(根据cx的值,重复执行后面的指令)
movsb(串传送指令)
movsw(串传送指令,传送一个字)
rep
iret
将栈中的前16位放入CS中,再讲接下来16位放入IP中,在将接下来16位放入flag中
cld(将标志寄存器的df位置设为0)
std(将标志寄存器的df位置设为1)
sti(将标志寄存器的if位置设为1)
打开中断
cli(将标志寄存器的if位置设为0)
关闭中断
pushf(将标志寄存器的值压栈)
prof(将标志寄存器的值出栈)
in(端口读)
out(端口写)
shl(逻辑左移)
shr(逻辑右移)
hlt(cpu睡眠)
nop(空指令)
xchg(交换)
lock(锁前缀)
lock add ax, 1(只对当前指令生效)
汇编指令(80386)
lgdt(加载GDT的地址进入GDTR寄存器)
sgdt(保存GDTR寄存器中的内容)
pushfd(32为eflag寄存机入栈)
popfd(32为eflag寄存机出栈)
伪汇编指令(masm6.11)
assume(定义有用途的段和相关寄存器的联系)
申明代码段 assume cs:[code]
申明数据段 assume ds:[data]
申明栈段 assume ss:[stack]
segmen(段定义)
定义代码段([code] segment)
定义数据段([data] segment,mov ds data)
定义栈段([stack] segment,mov ss, stack)
ends(定义的代码段结束的标记)
end(汇编代码结束的标记)
通知程序结束
通知程序入口在哪,即加载汇编程序后,设置IP:end start
dw(定义字类型数据)
dw 0123h,0456h
db(定义字节类型数据)
db 'linux'
dd(定义双字数据)
dd 100001h
dup(数据重复定义)
db 3 dup (0) = db 0 0 0
offset(获取标号偏移地址)
mov ax, offset start
获取start的偏移地址
获取start的偏移地址
+ - * / mod (四则运算符号)
org(设置程序起始地址)
org 2000H(将代码开始的偏移指令放在2000H)
汇编语言源程序中若没有ORG伪指令,则程序执行时,指令代码被放到自由内存空间的CS:0处;
若有ORG伪指令,编译器则把其后的指令代码放到ORG伪指令指定的偏移地址。
若有ORG伪指令,编译器则把其后的指令代码放到ORG伪指令指定的偏移地址。
两个ORG伪指令之间,除了指令代码,若有自由空间,则用0填充。
数字表示
2进制
11011011b(字母B结尾)
16进制
9fh(字母h结尾,如果第一位是字母,需要0开头)
10进制
9(不需要结尾标注)
伪汇编指令(nasm2.15)
equ(定义常量)
test db 'hello world'
db
db
dd
dq
dt
db
dd
dq
dt
times(汇编指令被汇编多次)
有效的地址引用
wordvar dw 123
mov ax, [wordvar]
mov ax, [wordvar + 1]
mov ax, [wordvar + 1 + di]
mov as, [es:wordvar+bx]
mov ax, [wordvar]
mov ax, [wordvar + 1]
mov ax, [wordvar + 1 + di]
mov as, [es:wordvar+bx]
mav ax, wordvar(将wordvar的偏移地址赋值ax)
mov ax, [wordvar](将wordvar的值123赋值给ax)
mov ax, [wordvar](将wordvar的值123赋值给ax)
$
当前代码开始处的位置,不包含当前行
$$
当前段开始处的地址,通过$-$$可以计算出当前段内的偏移
常数
数值常数
mov ax, 0a2h
mov ax, 100
mov ax, 100
字符常数
mov ax, 'ab'
字符串常数
db 'abcdefg'
浮点常数
dd 1.2
运算符号
| 或运算
^ 异或
& 与运算
<< 左位移预算
>> 右位移运算
+ 加法
- 减法
* 乘法
/ 除法,无符号
// 除法,有符号
% 模运算,无符号
%% 模运算,有符号
^ 异或
& 与运算
<< 左位移预算
>> 右位移运算
+ 加法
- 减法
* 乘法
/ 除法,无符号
// 除法,有符号
% 模运算,无符号
%% 模运算,有符号
seg()
wrt()
临界表达式
NASM 的一个限制是它是一个两遍的汇编器,它总是只做两遍汇编。
第一遍汇编是用于确定所有的代码与数据的尺寸大小,这样的话,
在第二遍产生代码的时候,就可以知道代码引用的所有符号地址。
所以,有一件事NASM 不能处理,那就是一段代码的尺寸依赖于另一个符号值,
而这个符号又在这段代码的后面被声明。比如:
times (label-$) db 0
label: db 'Where am I?'
第一遍的时候,无法确认label的值,导致无法计算,因为label的值需要看times重复几次
第一遍汇编是用于确定所有的代码与数据的尺寸大小,这样的话,
在第二遍产生代码的时候,就可以知道代码引用的所有符号地址。
所以,有一件事NASM 不能处理,那就是一段代码的尺寸依赖于另一个符号值,
而这个符号又在这段代码的后面被声明。比如:
times (label-$) db 0
label: db 'Where am I?'
第一遍的时候,无法确认label的值,导致无法计算,因为label的值需要看times重复几次
本地labels
section
1.组织代码与存储的方式
2.支持标准的.data, .text和.bss,编译后的程序文件中的内存地址顺序是.text, .data,用户自定义section
3.同名的section,编译后会放在同一块连续的内存上
4.每个SECTION默认都是按4字节对齐的
2.支持标准的.data, .text和.bss,编译后的程序文件中的内存地址顺序是.text, .data,用户自定义section
3.同名的section,编译后会放在同一块连续的内存上
4.每个SECTION默认都是按4字节对齐的
bits
[bits 16]以下代码编译成16位
[bits 32]以下代码编译成32位
[bits 32]以下代码编译成32位
宏定义
模板
%macro macro_name number_of_params
<macro body>
%endmacro
示例
%macro Descriptor 3
dw %2 & 0FFFFh
dw %1 & 0FFFFh
db (%1>>16) & 0FFh
dw ((%2 >> 8) & 0F00h) | (%3 & 0F0FFh)
db (%1 >> 24) & 0FFh
%endmacro
%1第一个参数,%2第二个参数,%3第三个参数
%macro macro_name number_of_params
<macro body>
%endmacro
示例
%macro Descriptor 3
dw %2 & 0FFFFh
dw %1 & 0FFFFh
db (%1>>16) & 0FFh
dw ((%2 >> 8) & 0F00h) | (%3 & 0F0FFh)
db (%1 >> 24) & 0FFh
%endmacro
%1第一个参数,%2第二个参数,%3第三个参数
align
align num,num 必须是2的幂,如:2、4、8和16等
本伪指令下面的内存变量必须从下一个能被Num整除的地址开始分配。
如果下一个地址正好能被Num整除,那么,该伪指令不起作用,否则,汇编程序将空出若干个字节,直到下一个地址能被Num整除为止。
本伪指令下面的内存变量必须从下一个能被Num整除的地址开始分配。
如果下一个地址正好能被Num整除,那么,该伪指令不起作用,否则,汇编程序将空出若干个字节,直到下一个地址能被Num整除为止。
寄存器(8086)
ax(通用寄存器)
乘法结果的低16位
端口的读写中间寄存器
bx(通用寄存器)
ds的端的偏移地址
cx(通用寄存器)
loop遍历计数器
jcxz条件跳转指令
dx(通用寄存器)
被除数的高位;结果的余数
乘法结果的高16位
si(通用寄存器,不能拆分为2个8位,支持[si + 偏移地址],ds段的偏移地址)
di(通用寄存器,不能拆分为2个8位,支持[di + 偏移地址],ds段的偏移地址)
cs(指令段地址)
ds(数据段地址)
ss(栈段地址)
es(附加段寄存器)
ip(指令偏移地址,cs段的偏移地址)
sp(栈偏移地址)
入栈,SP会减,出栈,SP会增加,永远指向栈顶
bp(基址寄存器)
一般在函数中用来保存进入函数时的sp的栈顶基址
flag(标志寄存器)
zf(零标志位,记录相关指令执行后,其结果是否为0,1=是,0=否。如add,sub,or,and等)
debug中:ZR=1 NZ=0
pf(奇偶标志位,记录相关指令执行后,其结果的所有bit位中1的个数是偶数是偶数,1=是,0=否)
debug中:PE=1 PO=0
sf(符号标志位,记录相关指令执行后,其结果是否是为负数,1=是,0=否)
debug中:NG=1 PL=0
cf(进位标志位,它记录无符号运算结果的最高有效位是否向更高位进位或者借位,1=是,0=否)
debug中: CY=1 NC=0
通常用来比较,比较大小时,如果小于,则等于减法借位,导致cf = 1
of(溢出标志位,它记录有符号符号运算是否发生了溢出,1=是,0=否)
debug中:OV=1 NV = 0
df(方向标志位)
debug中:DN=1 UP=0
if(是否响应可屏蔽中断标志位,1=是,0=否)
寄存器(80836)
cr0
GDTR
eflag
debug工具
R (查看CPU中的信息)
D (查看内存中的信息,D 2000:0)
E(修改内存中的信息,E 2000:0 1 2 3……)
U(查看CS与IP最近10条的汇编指令,多次执行,等于翻页 -U -U 1000:10)
A(用汇编指令的模式,编写)
T(执行当前IP指向的汇编指令)
P(执行完当前循环,将IP执行下一个指令)
G(将IP跳到指定的编译地址,如G 00FF)
常用编译器
masm 编译
masa(masa 汇编源码文件,生成obj文件)
link(link obj文件,生成可执行文件)
nasm 编译
nasm.exe -f bin test.asm
masm与nasm区别
其他
字节(8bit)
CPU访问的最小单位是一个字节,即一个物理地址对应一个字节
字(2个字节)
16进制表示法,16进制1位=2进制4位
段寄存器需要用寄存器赋值,无法直接赋值
寄存器中,操作偏移量都是字节,如:偏移1=一个字节(比较难以理解,容易陷入其中)
立即数: idata,编码写在汇编指令的数字
同一个汇编指令,对应的立即数位数不一致,其指令也不一致
jmp 4e00(这里的jmp的机器码 = e9)
jmp 4f(这里的jmp的机器码 = eb)
代码转移
短转移只支持8位计算偏移地址
长转移支持16位计算偏移地址
转移可以理解为相对路径跳转
代码跳转可以理解为绝对路径跳转
补码
最高位为1,表示负数
正数的补码取反加1后,为其对应的负数的补码
负数的补码取反加1后,为其绝对值
正数的补码与其二进制一样
汇编中补码
mov al, 0F0H,表示有符号数-16的补码
中断程序
一个中断向量里面,可以有多个子程序
bios(基本输入输出系统)
硬件系统的检测与初始化程序
外部中断和内部中断的中断程序
用于对硬件设备进行I/P操作的中断程序
其他和硬件系统相关的中断程序
与输入输出设备交互,通过设置寄存器的值,通知io设备,完成操作
bios与dos中断程序安装
开机后,CPU通电后,初始化CS=FFFFH,IP=0,自动从FFFF:0单元开始执行程序。FFFF:0处有一条跳转指令,CPU执行该指令后,转去执行BIOS中的硬件系统检测与初始化程序
初始化程序将建立BIOS所支持的中断向量,即将BIOS提供的中断程序的入口地址登录在中断向量表中。注意,对于BIOS所提供的的中断程序,只需将入口地址登记在中断向量表中即可,以为它们是固话到ROM中的程序,一直在内存中存在
硬件系统检测和初始化程序完成后,调用int 19h进行操作系统的引导,从此将计算机交给操作系统控制
操作系统启动后,除完成其他工作外,还将它自己所提供的的中断程序装入内存,并存入中断向量表中
中断类型
中断方式
内中断
除法错误
单步执行
执行info指令
执行int指令
外中断
外部设备的中断
中断类型
可屏蔽中断
几乎所有的外设都是可屏蔽中断
不可屏蔽中断
中断向量表
一共有256中断,每个中断占用4个字节,用来存放cs与ip,中断类型号码 * 4 = IP,中断类型号码 * 4 + 2 = CS
其内存地址:0000:0000 ~ 0000:03FF,一共1024个字节
中断过程
获取中断码
标志寄存器的值入栈,再讲第8位TF与第9位IF的值设置为0
将CP入栈,再将IP入栈
获取中断程序的cs与ip,并设置
CPU工作模式
实模式
通过段地址+偏移地址,直接访问物理地址
保护模式
通过段选择器定位GDT或者LDT中的段描述符,找到其中的基地址+偏移,访问物理地址
虚拟8086模式
.com tiny
masm6编译出来的文件,前面有256字节的内容,代码都放在其后面,这里存放的是文件头,代码段,初始化数据段三部分
0 条评论
下一页