汇编的零碎知识点
复习提纲
汇编语言的特性和应用场景(与机器语言、高级语言的比较)
机器语言
是机器指令的集合。机器指令是0和1构成的二进制信息。
直接面向机器,与机器的硬件操作一一对应。计算机可以直接识别、执行,使用机器语言可以充分发挥计算机的硬件功能。
缺点: 依赖机器硬件,机器指令很难记忆,直接使用机器语言编制程序极易出错,并且难以调试。
汇编语言
汇编语言的主体是汇编指令。汇编语言的核心是汇编指令,它决定了汇编语言的特性。
汇编指令和机器指令的差别在于指令的表示方法上。汇编指令是机器指令的助记符,便于人类记忆和使用。
不同的CPU有不同的汇编指令。
汇编语言改善了机器语言的不直观性。
从目标代码的长度和程序运行时间的角度上看,汇编语言程序与机器语言程序是等效的。
汇编语言的用途:有助于从软件角度理解计算机的工作原理,汇编语言具有能够直接有效控制硬件的能力,能够编写出运行速度快、代码量小的高效程序,在许多场合具有不可替代的作用。
应用场合:操作系统的核心程序段、实时控制系统的软件、智能仪器仪表的控制程序、频繁调用的子程序或动态链接库、加密解密软件、分析和防治计算机病毒
高级语言
面向程序设计人员,接近于自然语言,易学易记,便于阅读和掌握,使用方便,通用性强,不依赖具体计算机。
高级语言对计算机操作步骤进行描述有一整套标记符号、表达格式、结构及其使用的语法规则。
高级语言程序所对应的目标代码往往比机器语言程序要长,运行所需时间也更多。
冯诺依曼体系结构
(1)采用存储程序方式,指令和数据不加区别混合存储在同一个存储器中,数据和程序在内存中是没有区别的,它们都是内存中的数据,当EIP指针指向哪 CPU就加载那段内存中的数据,如果是不正确的指令格式,CPU就会发生错误中断. 在现在CPU的保护模式中,每个内存段都有其描述符,这个描述符记录着这个内存段的访问权限(可读,可写,可执行).这就变相的指定了哪些内存中存储的是指令哪些是数据)
指令和数据都可以送到运算器进行运算,即由指令组成的程序是可以修改的。
(2)存储器是按地址访问的线性编址的一维结构,每个单元的位数是固定的。
(3)指令由操作码和地址码组成。操作码指明本指令的操作类型,地址码指明操作数和地址。操作数本身无数据类型的标志,它的数据类型由操作码确定。
(4)通过执行指令直接发出控制信号控制计算机的操作。指令在存储器中按其执行顺序存放,由指令计数器指明要执行的指令所在的单元地址。指令计数器只有一个,一般按顺序递增,但执行顺序可按运算结果或当时的外界条件而改变。
(5)以运算器为中心,I/O设备与存储器间的数据传送都要经过运算器。
(6)数据以二进制表示。
将指令和数据同时存放在存储器中,是冯·诺伊曼计算机方案的特点之一。
计算机由控制器、运算器、存储器、输入设备、输出设备五部分组成。
冯·诺伊曼提出的计算机体系结构,奠定了现代计算机的结构理念。
计算机硬件系统的基本组成及工作原理
⑴ 计算机硬件由五个基本部分组成:运算器、控制器、存储器、输入设备和输出设备。
⑵ 计算机内部采用二进制来表示程序和数据。
⑶ 采用“存储程序”的方式,将程序和数据放入同一个存储器中(内存储器),计算机能够自动高速地从存储器中取出指令加以执行。
可以说计算机硬件的五大部件中每一个部件都有相对独立的功能,分别完成各自不同的工作。五大部件实际上是在控制器的控制下协调统一地工作。首先,把表示计算步骤的程序和计算中需要的原始数据,在控制器输入命令的控制下,通过输入设备送入计算机的存储器存储。其次当计算开始时,在取指令作用下把程序指令逐条送入控制器。控制器对指令进行译码,并根据指令的操作要求向存储器和运算器发出存储、取数命令和运算命令,经过运算器计算并把结果存放在存储器内。在控制器的取数和输出命令作用下,通过输出设备输出计算结果。
原码、反码、补码及其与计算机真值的转换
将带符号位的机器数对应的真正数值称为机器数的真值。例:0000 0001的真值 = +000 0001 = +1,1000 0001的真值 = –000 0001 = –1
反码:
正数的反码是其本身
负数的反码是在其原码的基础上, 符号位不变,其余各个位取反.
补码:
正数的补码就是其本身
负数的补码是在其原码的基础上, 符号位不变, 其余各位取反, 最后+1. (即在反码的基础上+1)
大小写的转换,数字到字符
大写转小写:add dl, 32(ASCII码加上32)或or dl, 00100000B ; or dl, 20H
小写转大写sub dl, 32或and dl, 11011111B ; and dl, 0dfH
数字到字符(ASCII码加上48):
内存地址空间
对于CPU来讲,系统中的所有存储器中的存储单元都处于一个统一的逻辑存储器中,他的容量受CPU存之能力的限制,这个逻辑存储器就是内存地址空间。基础地址+偏移地址=物理地址
段地址 ×16+偏移地址 = 物理地址
CPU在操控这些独立的物理存储器时,把它们统一当作一个逻辑存储器看待。这个逻辑存储器即内存地址空间。
每个物理存储器在这个逻辑存储器中占有一段地址空间;CPU在这段地址空间中读写数据,实际上就是在相对应的物理存储器中读写数据。
不同的计算机系统的内存地址空间分配情况是不同的。
内存地址空间是逻辑上的概念;
内存地址空间,即CPU寻址空间,与CPU地址总线宽度直接相关;
内存地址空间的容量与平时所讲的内存条的容量不是一回事;
不同的计算机系统内存地址空间如何使用有不同的分配方案。
db,dw,dd
db定义字节类型变量,一个字节数据占1个字节单元,读完一个,偏移量加1
dw定义字类型变量,一个字数据占2个字节单元,读完一个,偏移量加2
dd定义双字类型变量,一个双字数据占4个字节单元,读完一个,偏移量加4
byte ptr [bx];word ptr [bx];dword ptr [bx];
小端法,小的地址单元存放低位,大的存放高位。
栈段的ss sp的设置
而对于栈顶的段地址,其是存放在段寄存器 SS 中的,而对于栈顶的偏移地址,其则是存放在 SP 寄存器中的 。记住,在任何时刻,SS:SP 都是指向栈顶元素 。push和pop处理的都是ss:sp栈顶的地址
当栈为空时,sp在栈顶的基础上再加x(x的值视情况而定)正常是2
入栈sp=sp-x,将对应的内容存入栈顶指向的内存单元;出栈先将内容取出,再sp=sp+x
8086汇编中约定「栈」空间的入栈和出栈均以字为单位。但是,其他有些CPU汇编指令支持以字节、字、双字等作为入栈和出栈操作的单位。
call,ret,int对栈的使用
ret时,执行ip=ss*16+sp,sp=sp+2,执行ret相当于pop ip,执行retf相当于执行pop ip pop cs
call时将当前的ip或者cs和ip(call far ptr s)存入栈中,再转移到对应的地址
软中断指令int① 取中断类型码n;② FR入栈,IF、TF清零;③ CS, IP依次入栈;④ 根据中断类型码计算中断向量,设置CS=n*4和IP=n*4+2,
寄存器
要知道哪些可以作为独立的8位寄存器使用
答:ax,bx,cx,dx。
知道字数据在寄存器中如何存放
答:一个字的高位字节高8位寄存器,低位存在低8位,一个16位的寄存器,前8位为高8位。
在8086CPU中,哪些寄存器可以用作寄存器间接寻址
答:bx,si,di。形如:[bx+idata]可以写作[bx]idata或idata[bx],[bx+di+idata],[bx+si+idata],[bx+si]
可以写成[bx][si]
(均是间接寻址)
直接寻址:[idata];
CS和IP, SS和SP组合使用的特殊用途
答:俺也不知道
理解9个标志位中一些常用标志位的用途
答:状态标志位:CF, PF, AF, ZF, SF, OF;控制标志位:IF, TF, DF.
cf:进位标志位,运算时最高二进制位产生进位或者错位,cf置1.与指令adc相关
pf:奇偶标志位,运算结果低8位中1的个数为偶数,pf置1
af:辅助进位标志位,运算时半字节产生进位或者错位,af置1.
zf:0标志位,运算结果为0,zf置1.
sf:符号标志位,符号1时sf置1.
of:溢出标志位,有符号数运算结果超出系统所表示范围,of置1
tf:跟踪标志位,TF=1,控制单步执行。CPU单步执行;TF=0,CPU连续执行。
if:中断允许标志位,IF=1,控制CPU是否允许响应可屏蔽中断的中断请求。响应可屏蔽中断;IF=0,不响应可屏蔽中断。
df:方向标志位,DF=1,控制串操作时指令的处理方向,反向(高地址→低地址);DF=0,正向(低地址→高地址)。
指令add/sub的执行会影响到CF, PF, AF, ZF, SF, OF。
指令je (等于0时跳转)依赖于ZF(零标志位)的值。
mov, push, pop, inc, dec不影响标志位。
初步了解x86系列中32位/64位CPU对寄存器做的扩展、新增和用途变化
8086是Intel系列中16位微处理器,地址总线20位。
在Intel 32位CPU中,寄存器EAX, EBX, ECX, EDX不仅仅是从原先16位寄存器扩展到了32位,而且,在用途上也更加通用。比如,16位CPU中,寄存器AX, BX, CX, DX只能用来保存运算的操作数和中间结果,不能用来存放地址。而32位CPU中,EAX,EBX, ECX,EDX功能更加通用,也可以用来保存地址。类似地,在64位CPU中RAX, RBX, RCX, RDX也是如此。
中断
8086CPU的中断过程,1)从中断信息中取得中断类型码;2)标志寄存器的值入栈(因为在中断过程中要改变标志寄存器的值,所以将其保存);3)设置标志寄存器的第8位TF和第九位IF为0();4)CS,ip依次入栈;5)设置CS=n*4和IP=n*4+2。
内部中断都是不可屏蔽中断;如:int软中断,异常处理,单步中断
几乎所有由外设引发的中断,都是可屏蔽中断。
中断的作用主要体现在五个方面:实现CPU和外设之间的数据传送,实现分时操作,实现实时处理,实现故障处理,调试及检查程序。
中断、中断源、中断信息、中断类型码、中断向量、中断向量 表、中断过程、中断例程
软中断指令及其执行过程
软中断指令int① 取中断类型码n;② FR入栈,IF、TF清零;③ CS, IP依次入栈;④ 根据中断类型码计算中断向量,设置CS=n*4和IP=n*4+2。
汇编源程序
汇编程序的组成:指令、伪指令、标号注释。
程序调试的注意事项:
汇编时默认是十进制,debug工具中默认的是十六进制,且不支持2进制写法;
在.asm中写的代码默认是十进制,支持2进制,支持16进制
debug调试的是可执行文件,带扩展名
在debug中:
a命令中不支持诸如'a'这样的写法
e命令中支持诸如'a'这样的写法,也支持ASCII码形式的写法
首次进入调试界面,cx(16进制)中存放的是可执行文件的长度,cs:ip
存放的是指令的首地址,单步调试是调试到int 21h要用p命令。
汇编源程序的框架由一些段构成,这些段存放代码、数据,或者将某一个段当作栈控件,段的大小是以16B为倍数。(原因16位程序中的寻址方式是段寄存器地址(16位)和偏移地址(4位)拼成的20位线性地址空间(共计1MB)。程序加载到内存后,为了确保下一个段的第1个字节在那个段偏移0的位置上,所以要将下一个段放在下一个16字节倍数上。)
每个段的最大长度不能超过64KB。(因为寄存器是16位的,能表示的地址范围只能是0000HFFFFH**,即**0216-1)
指令
mov, add, sub等汇编指令中,访问内存单元时,默认情况下,指的是数据段。即:[1]=ds:[1]
mov的注意事项:
常数作源操作数时,如果最高位是十六进制的a~f或A~F,前面要加零! 典型的就是:mov ax 0b800h;如果没有这个约定,那么b800h是由字母、数字组成的合法标识符,可能是段的名称、标号的名称、子程序的名称,等等。设定了这样一条规则后,就可以有效表示以a~f开头的十六进制表示的立即数了
两个内存单元之间不可以直接传送数据。
不可以用mov指令修改cs和ip
不能把常数送到段寄存器中;两个段寄存器直接不能直接传送。
add和sub的注意事项操作数不能同时是内存地址单元,操作数不能是段寄存器;第一个操作数是 内存地址一定要指定大小(如:sub bype ptr[bx], 32 或 sub [bx] bype ptr 32
栈
栈为空时,栈顶指向栈底+2
push和pop的注意事项:入栈出栈均以字为单位;操作对象不能是常数;pop段寄存器,这个段寄存器不可以是cs和ss; (栈顶越界有两种情况,栈满入栈和栈空出栈) 8086CPU不会自动考虑栈顶超界,需要程序员在编程设计时自己考虑。栈区长度不同,栈顶超界的具体情形也不同。
push、pop等指令在执行的时候只修改sp,所以栈顶的变化范围0000H~FFFFH,栈空sp=0,栈满sp=0,所以一个栈最大为64kB。
ret时,执行ip=ss*16+sp,sp=sp+2,执行ret相当于pop ip,执行retf相当于执行pop ip pop cs
call时将当前的ip或者cs和ip(call far ptr s)存入栈中,再转移到对应的地址
adc ax, 3==ax<-ax+3+(cf);adc指令语法形式与add相同。 区别在于使用adc做加法时,还要加进位标志位的值。
sbb指令语法形式与sub相同。区别在于使用sbb做减法时,还要减去进位标志位CF的值。
adc和sbb使用之前可以先用sub ax,ax将cf位置为0,以免对后面的运算有影响。
cmp指令语法形式如同sub,将两个操作数相减,但是只运算,不保存结果,运算结果运算结果会影响标志位CF, ZF, SF, OF, PF,配合转移指令使用。
jz | zf=1 |
---|---|
jnz | zf=0 |
je | zf=1 |
jne | zf=0 |
jc | cf=1 |
注: 大于、小于等的判断综合依赖于标志位ZF, CF, OF, SF,详细可参考教材p225。
所有的条件跳转指令位移都是[-128,127]
rep movsb实现字节单元的重复传送
rep movsw实现内存字单元的重复传送
pushf将标志寄存器的值入栈
popf从栈中弹出数据到标志寄存器中
上述两条指令提供了标志寄存器的内容访问方式
jcxz检测cx中的数值,cx=0就修改ip,否则什么也不做。
loop比jcxz要多一个cx=cx-1的操作,单步执行到loop得用p,应该是遇到跳转指令都用p指令调试
inc可以对内存单元进行操作,但是一i的那个要在前面指定大小
段前缀会对反汇编的结果有影响
and和or的主要用法见上面的数字到字符,英文字母大小写转换。
div无符号数除法指令
除数有8位或16位
被除数放在ax或者dx和ax中,除数为8位(0255),被除数就是16位(065535),在ax中,结果的商在al中,余数在ah中,除数位32位时,在dx和ax中存放,dx存高16位,ax存低16位,结果的商在ax中,余数在dx中。
mul无符号乘法,8*8,被乘数al,积在ax中
16*16,被乘数为ax,积在dx:ax
伪指令db
db 1,2,3,1,2,3,1,2,3与下面的效果一样
db 3 dup(1,2,3)就是预留9个字节单元
伪指令segement使用多个段,使得程序结构清晰,解决了长度超过64kB的限制
end除了通知编译器程序结束外,还可以通知编译器程序的入口在什么地方。
伪指令end 描述了程序的结束和程序的入口。在编译、连接后,"end start" 指明的程序入口,被转化为一个入口地址,存储在可执行文件的描述信息中。
使用assume仅仅表示将某个逻辑段和某个段寄存器关联起来;真正当作特定的段使用,需要在代码段中设置相应的段寄存器值,如ds, ss。
$指下一个数据项的偏移地址
debug工具
r命令:查看各个寄存器的情况
a命令:以汇编格式在内存中写入一条指令
e命令:改写内存中的内容
d命令:查看内存中的内容
u命令:将内存中的机器指令翻译成汇编指令(反汇编)
t命令:单步执行,p,g在上面有
补充
f命令
使用f命令,向内存单元批量填写数据。
-f b800:0f00 0f9f 03 04
写入爱心
table
类似:db 5 dup(16 dup(?))
0b800h
显存位置,80*25,一共25行,每行80个字,160个字节
学习通习题
cpu有8根地址引脚线,它可以访问256个内存地址单元;0000 0000~1111 1111,即0~255.共256个
CPU内存地址空间的大小是由地址总线的宽度决定的。内存地址空间,即逻辑地址空间,是对所有物理内存在逻辑上的统一编址。
对于显示器、键盘、打印机等外部设备,CPU并不是直接控制其工作的,而是通过接口卡间接控制其工作。CPU通过总线向接口卡发送命令,接口卡根据CPU的命令控制外设进行工作。
计算机里,从B(yte)→KB→MB→GB→TB→PB,每一个之间都相差1024即2^10个数量级。
地址总线的宽度决定了CPU寻址能力。数据总线的宽度决定了CPU与外设之间的数据传输速度。
伪指令在汇编阶段由汇编器识别并处理,但不不会产生机器码。
汇编语言和机器语言都依赖机器硬件,用汇编语言和机器语言编写的程序都不具备可移植性。
8086中,对内存地址空间在逻辑上进行"分段"时,段的起始物理地址必须是16的整数倍。
处理器的ISA,全称Instruction Set Architecture(指令集体系结构), 指的是处理器支持的指令以及指令的字节级编码。
intel公司的x86系列cpu和ARM公司ARM架构的cpu,其硬件架构不同,所支持的指令及指令的字节集编码也不同。
IA32,也可以称为X86-32,都是指Intel 32位指令集体系结构。
关于"相同系列的cpu有相同的汇编指令集",以x86系列CPU8086和80386为例,虽然同属于同一系列,但8086是16位cpu, 80386是32位cpu, 指令集向前兼容,后者支持的指令集要比8086支持的指令集丰富得多。
不同的cpu生产厂商,在生产cpu时如果遵从相同的ISA,则认为,这些cpu是在ISA级别上是兼容的。比如,Intel公司和AMD公司,都遵从IA-32指令集体系结构标准生产cpu,它们在ISA级别上是兼容的;再比如,ARM公司把ARM架构的知识产权出售出去,其他厂商都可以基于此生产相同ARM架构的cpu。
8086CPU工作在实模式下。工作在实模式下的操作系统,如DOS,称为实模式操作系统。实模式下,CPU通过物理地址访问内存。在实模式下,所有程序都在同一个物理地址空间下,程序之间可以相互访问对方的内存地址空间,安全性得不到保证。
在8086CPU中,DOS下,00200H ~ 002FFH这一范围内的256个字节的空间,被认为是一般情况下安全可用的空间。
80386CPU及以后的CPU都支持保护模式。工作在保护模式下的操作系统,称为保护模式操作系统。现代操作系统都工作在保护模式下。在保护模式下,引入了虚拟内存机制。每个进程都有一个独立的虚拟地址空间。CPU通过一个地址映射表,把虚拟的内存地址转化为物理内存地址,然后再访问。
assume ds:data只是告诉汇编器,把逻辑段data和ds建立关联,它是汇编期间由汇编器负责处理的伪指令。只有当执行以下汇编指令,明确地把数据段data的段地址送到寄存器ds中,CPU才会把逻辑段data当作数据段来使用。
8086机器的内存,在内存地址C0000
—FFFFF
之间为ROM区域
程序开始位置有一段空间叫psp区,大小为256B。