码迷,mamicode.com
首页 > 编程语言 > 详细

《汇编语言》笔记

时间:2014-06-27 16:49:40      阅读:414      评论:0      收藏:0      [点我收藏+]

标签:des   code   http   com   使用   width   

教材《汇编语言》第二版 王爽

 

第一章 :基础知识
0. 机器语言:(010000001000000)0 和 1 的组成。
1. 汇编语言有三类指令组成
 · 汇编指令:汇编指令和机器指令一一对应,有编译器翻译识别,计算机无法直接识别。
 · 伪指令:没有对应机器码,有编译器执行
  · 其他符号:如+,-,*,/,由编译器识别。
   汇编语言的核心是汇编指令,它决定了汇编语言的特性。
2. 一个内存单元=1Byte=8bit。1KB=1024Byte(字节)
3. CPU要进行读写(外部通讯)需要进行以下三个交互
  · 地址总线:CPU是通过地址总线来指定存储单元的。8086CPU 一共 16 条,每条传送 0 或 1。
  · 数据总线:数据总线决定了CPU与外界数据传输的速度。
  · 控制总线:CPU对外部的控制是通过控制总线进行的。决定CPU对外部器件的控制能力。多少种控制总线是 CPU 对外界器件有多少种控制,  有些命令是几根控制线综合发出的。
4. 一个CPU有N根地址总线,则可以说这个CPU的地址总线宽度为N,这样的CPU可以寻找到2的N方个内存单元。(就是说cpu寻址范围是2的N次方个存储单元)
5. 数据总线N根,即一次可传送N位二进制数,即N位 ,例:8根数据总线可以传送一个8位二进制数据(即一个字节)。8根=8bit=1Byte
6. 在CPU,存储器中,数据和指令都是以二进制的形式存放的。
7. 磁盘的数据,CPU无法直接使用,只能读到内存中,才能被CPU使用。CPU可以使用的数据,是在存储器中存储器被划分为很多存储单元,以0开始编号,一个单元存储一字节,即8位。
8. 寄存器是一种比内存和二级缓存更低一层,更接近CPU的存储器。
9. 存储器分为:随即存储器RAM和只读存储器ROM
       随即存储器,断电后数据丢失,如内存,显存
       只读存储器,关机后内存不消失,如主板,网卡的BIOS
10. CPU对各类存储器只看做一个逻辑的存储器,每个物理上的存储器在逻辑上占有一段地址段,CPU对其段进行操作,就是对物理存储进行操作。
11. 8086 CPU的内存地址分配:
                                                 00000—9FFFF为主存储器
                                                 A0000—BFFFF为显存地址空间
                                                 C0000—FFFFF为各类ROM地址空间

第二章:寄存器

1. 8086CPU 内存空间有 1MB,但 8086CPU 的地址总线只有十六位 ,2 的 16 次方等于65536(0~65535)等于十六进制的 FFFF,65536B/1024=64kb,也就是一个段的长度。最后引进了段地址*16(十进制)+偏移地址=物理地址。因为物理地址表达方法是十六进制*16 相当于把十六进制向前移了 1 位, 4 个二进制等于 16 进 制 , FFFFF(10485575)/1024=1023KB(0~1023KB), 
2. CS 段地址*10H+IP(偏移地址)=CS:IP(debug)
3. 汇编:修改 CS 和 IP 值(JMP CS :IP)直接跳转到某地址。
4. Debug:-R CS -R IP
5. CS(代码寄存器)指到的内存段,当作代码要执行,执行汇编语句。和 DS 一样的是数据都是十六,但一个解释为数据,一个解释为执行命令。CS 和 IP 决定从哪执行,把后面的数据当代码执行。
6.Debug常用指令:
-R 查看寄存器值
-T 执行(CS:IP)
-A 写汇编指令
-U 查看(内存地址 十六进制 汇编指令)
-D 查看(二进制)-D 段地址:偏移地址首 偏移地址尾
-E 改写内存
7. 8086 16位 一个寄存器能存储16个2进制数 
例如:al和ah没有关系,当ah的值超出8位时,CPU就会丢弃数据,当al的值超出8位时,CPU不会丢弃数据。但不会进位到ah寄存器中,汇编指令进行操作时,要注意双方位数和数据大小溢出问题
8. CPU访问内存时要给出内存单元的地址。所有的内存单元构成的存储空间是一个一维的线性空间,每一个内存单元在一个空间中都有唯一的地址,我们称为物理地址。
9. 8086为16位CPU,16为CPU有以下特性:
  运算器一次最多处理16位数据
  寄存器的宽度为16位
  寄存器和运算器的通路为16位
10.段地址的概念,是来自CPU,来分段管理内存!
10000H——100FFH组成一个段
基础地址为10000H
段地址为1000H
大小为:100H
这里的段地址大小,很多人都晕,确实难理解,想通就好
100H的来源:100FFH—10000H=FFH
这个FFH,转换为10进制就255,而计算机是从零开始,那么就有0—255,256个数,再把256转换为16进制,那就是100,即大小为100H,这是最笨的方法
11. 一个段地址必然是16的倍数。偏移地址为16位,16位寻址能力为64kb,一个段的最大为64kb
12. 8086CPU的工作过程:
     1.从CS:IP指向德内存单元读取指令,指令进入缓冲器
     2.IP=IP+所读指令的长度,从而指向下一条指令
     3.执行指令,转到步骤一,重复这个过程
记住:8086CPU加电复位后,CS和IP的设置为CS=FFFFH,IP=0000H。即CPU从内存FFFF0H单元中读取执行,也是8086CPU的第一条执行指令。
13. CPU主要有有运算器,控制器,寄存器,三部分组成 
14. 8086CPU有14个寄存器,AX、BX、CX、DX、SI、DI、SP、BP、IP、CS、SS、DS、ES、PSW,其中有八个十六位通用寄存器,可分为两组,一,数据寄存器四个,1累加器ax,2基址寄存器bx,3记数寄存器cx,4数据寄存器dx。二,指针和变址寄存器,堆栈指针sp,基址指针bp,源变址寄存器si,目的变址寄存器di 
15. 8086CPU所有寄存器都是16位的,可以存放两个字节。
16. AX、BX、CX、DX通常用来存放一般性数据被成为通用寄存器。
17. 8086CPU为了兼容上一代的8位CPU,AX、BX、CX、DX这四个可以分为两个独立的8位寄存器。比如AH(高位)和AL(低位)。
18. 1字=2字节=16位(1Word=2Byte=16bit)。
19. 8086是16为结构的CPU,就是说,在8086内部,能过一次性处理、传输、暂时存储的信息的最大长度是16位。
20. 8086CPU有20位的数据总线,有1MB寻址能力(2的20次方),8086CPU是16位结构,只能送出16位的地址,也就是64K的寻址能力,那怎么内部和外部怎么协同工作呢?
8086CPU采用一种在内部用两个16位地址合成的方法形成一个20位的物理地址。
地址加法器采用物理地址=段地址x16+偏移地址的方法用段地址和偏移地址合成物理地址。比如段地址1230H,偏移地址00C8,经过地址加法器时,将1230HX16(如同1230X10)变成的12300H(向左偏移了一位,相对二进制,向左偏移了4位),然后12300H+00C8=1230C8。
21.段寄存器就是提供段地址的。8086CPU有4个段寄存器:CS(代码),DS(数据),SS(堆栈),ES(不够的时候放这里)。
22. CS和IP是8086CPU中两个最关键的寄存器,它们只是了CPU当前要读取指令的物理地址。CS为代码段寄存器,IP为指令指针寄存器(偏移地址)。
23.CPU将CS:IP指向的内存单元中的内容看作指令,如果说,内存中的一段形象曾被CPU执行过,那么他一定被CS:IP指向过。
24. 程序员可以通过改变寄存器中的内容实现对CPU的控制。
25. mov指令不能用于设置CS、IP的值,我们可以用最简单的jmp指令,若想同时修改CS、IP的内容,可用“jmp 段地址:偏移地址”指令完成,如jmp 2AE3:3,执行后:CS=2AE3H,IP=0003H,CPU将从2AE33H读取指令。
26. “jmp 段地址:偏移地址”指令功能为:用指令中给出的段地址修改CS,偏移地址修改IP。

第三章 :寄存器(内存访问)

 

 

· CPU中,用16位来存储一个字。高8位存放高位字节,低8位存放低位字节。

· 内存存储中,内存单元是字节单元(1单元=1字节),则一个字要用两个地址连续的内存单元存放。

· 内存存储中,高位字节,和低位字节是相对的,指令指向的是低位字节。

· 字单元,即存放一个字型数据(16位=2字节)的内存单元,由两个地址连续的内存单元组成。

· 8086CPU中有一个DS寄存器,通常用来存放要访问数据的段地址。

o MOV指令的几种种功能:
将数据直接送入寄存器 mov ax,1000H

o 将一个寄存器中的内容送入另一个寄存器 mov ax,bx;mov ds,ax

o 将一个内存单元中的内容送入寄存器 mov ax,[...]

o 将寄存器中的内容送入内存单元 mov [...],ax

o ...

· “[...]”表示一个内存单元,“[...]”中的内容则表示内存单元的偏移地址。

· 8086CPU中,不能给DS寄存器直接赋值,需要通过通用寄存器间接赋值,如“段地址-->通用寄存器-->DS寄存器”。

· add指令表示相加,sub指令表示相减。

· [address]便是一个偏移地址为address的内存单元。

· mov、add、sub是具有两个操作对象的指令。jmp是具有一个操作对象的指令。

· 栈是一种具有特殊的访问方式的存储空间,它的特殊性就在于,先进后出的特性。

· 8086CPU提供了入栈和出栈指令,最基本的两个是PUSH(入栈)和POP(出栈)。

· 8086CPU的入栈和出栈操作都是以字(2字节)为单位进行的。

· 8086CPU中,有两个寄存器,段寄存器SS和寄存器SP,栈顶的段地址存放在SS中,偏移地址存放在SP中。

· 任意时刻,SS:SP指向栈顶元素。

· PUSH入栈时,SP=SP-2(1字),栈顶从高地址向低地址方向增长,出栈时则SP=SP+2.

· 当栈为空时,栈中没有元素,也就不存在栈顶元素,所以SS:SP只能指向最底部单元下面的单元。

· 8086CPU不能保证我们对栈的操作不会超界,它只知道栈顶在何处(有SS:SP指示),并不知道这个栈有多大。

· push和pop指令可以有如下形式:

· push  寄存器

· pop   寄存器

· push  段寄存器

· pop   段寄存器

· push  内存单元

· pop   内存单元

21.  请灵活,仔细运用CS:IP(指令),DS:[...](数据),SS:SP(栈)

· 对于数据段,将它的段地址放在DS中,用mov,add,sub等访问内存单元的指令时,CPU就将我们第一的数据段内容当成数据来访问。

· 对于代码段,将它的段地址放在CS中,将段中的第一条执行的指令的偏移地址放在IP中,这样CPU就会执行代码段中的指令。

· 对于栈段,将它的段地址放在SS中,将栈顶单元的偏移地址放在SP中,这样CPU在需要进行栈操作时,比如push,pop指令时,就将栈段当成栈空间来用了。


第四章 

1.一个最简单的汇编语言源程序:
assume cs:codesg
codesg segment
  mov ax,0123H
  mov bx,0456H
  add ax,bx
  add ax,ax
  mov ax,4c00H
  int 21H
codesg ends
end
2.assume是“假设”的意思,它是将有特定用途的段和相关段寄存器关联起来的。
3.sgment和ends是一对成对使用的伪指令,也是一对必须用到的伪指令,xxxx segment用来声明该段的名称,中间则是存放汇编指令。
4.end是一个汇编程序的结束标记。
5.一个有意义的汇编程序必须有一个代码段。
6.一个程序结束后,会将CPU的控制权交还给使他运行的程序,这就是程序返回。程序返回的指令如下:
mov ax,4c00H
int 21H
7.汇编程序从写出到执行的过程:
编程-->1.asm-->编译-->1.obj-->连接-->加载-->内存中的程序-->运行
8.程序加载到内存中,这个内存区的前256个字节存放的是PSP(程序段前缀),是DOS用来和程序进行通讯的,从256字节向后的空间存放的才是程序。所以,从ds中可以得到PSP的段地址SA,PSP的偏移地址为0,则物理地址为SAX16+0,所以程序可用段地址和偏移地址可以表示为:SA+10H:0。

 

第五章 
1.Debug和MASN中读取内存单元的区别:
Debug中:
mov ax,0ffffh
mov ds,ax
mov al,[1] 

MASN中:
mov ax,0ffffh
mov ds,ax
mov bx,1
mov al,[bx]或者
mov ax,0ffffh
mov ds,ax
mov al,ds:[1]
 
2.Loop指令
assume cs:code
code sement
   mov ax,2
   mov cx,3
s: add ax,ax
    loop s
code edns
end 
其中s为loop的标号,代表一个地址,它标识了一个地址,该表示可以随意命名,要与loop XX 相同即可;cx为循环次数,当执行loop s时,cx会减1,直到cx=0才停止循环;
loop s代表,当cx不为0时,运行到这时会找到s标识地址开始执行。
3.在汇编源程序中,数据不能以字母开头,可以在开头多加一个0.
4.在进行数据计算式,要考虑到运算结果是否会超过寄存器的范围
5.用于显式锝指明内存单元的段地址的"ds:","cs:","ss:","es",,在汇编中称为段前缀。
6.在一般PC机中,0:200~0:fff之间的256个字节空间一般都是安全的。


第六章

1:【包含多个代码段程序】汇编查的地址不同,翻译的语句不同(一个字节内容对应指令,没有设入口点一堆字节乱对应)。设置入口点辨别代码从哪个地址开始翻译。使用入口标志符,前面的可以用 DW 定义数据,执行的时候从开始标识符执行CS:IP CS 段地址不变 IP 加偏移

2: 【在代码段中使用数据】方法如同在代码段中使用数据一样(入口标识符前定义),如果定义 8 个字单元(0~15)数据,和 8 个字单元栈(16~31),因为栈的初始化是空的一堆 0,所以 sp 指向的栈顶+2也就是栈的下一字节。

3: 【包含多个段的程序】
 【assume cs:a,ds:b,ss:c】【mov ax,b mov ds,ax】 

第七章  更灵活 定位内存地址的方法

1: 【AND 和 OR】AND 和 OR 的运算
补充:【XOR 和 NOT】XOR 异或逻辑运算:XOR 操作数一,操作数二,如果两个数相等为假,两个书不想等为 1。NOT 非逻辑运算,NOT 操作数一,对操作数取反吧= =。
2:【ASCII】
128 位标准 ASCII 码,及扩展 ASCII 码。

3: 【字符形式给出的数据】
【db ‘A’】定义的字节数据
【dw ‘A’】定义的字数据,A 是字型的。
【db 1,2,3】定义的 1,2,3 是字节数据。

4: 【SI 和 DI】
SI 和 DI 十六的寄存器,作用和 BX 相似但不可以拆分成两个 8 位寄存器

5: 【bx+idate】
偏移地址的组合,灵活运用。比如【二维数组】

6: 【bx+si】
比如【嵌套循环】,由于循环 LOOP 与 CX 绑定,所以进入第二层循环时会覆盖第一层循环导致程序错误。
这时栈便发生了他的作用,先进后出,可以用栈 PUSH 外层数据后进入内层循环,内层循环后在用 POP 恢复外层数据。

7: 【bx+si+idata】

......

注意:[DI+SI]不可以用这种表现方式,BX 是女的,SI 和 DI 是男的。[SI+DI]等于搞基。 
 

第八章:数据处理两个基本问题
 

1: 【BX DI SI BP】
BP 默认段地址在 SS 中。

2: 【数据处理位置的表达】
1:立刻数
 直接包含在机器码中的数据(执行前在 CPU 缓冲器中)
2:寄存器
 指令要处理的数据在寄存器中
3:段地址×16+偏移地址指令要处理的数据在指定的内存中
bubuko.com,布布扣
以上三种数据位置表达方式的翻译。

3: 【寻址方式】

1:直接寻址                 mov ax,[0]
2:寄存器间接寻址     mov ax,bx
3:寄存器相对寻址     mov ax,[bx+1]
4:基址变址寻址         mov ax,[bx+si]
5 相对基址变址寻址 mov ax,[bx+si+idate]

4: 【指令要处理的数据是多长】
1:在寄存器位数的情况下 

MOV AX,10H 这个指令处理 16 位
MOV AL,10 这个指令处理 8 位
 ......

2:在没有寄存器位数的情况下
push AX栈一次推进 2 字节 (sp-2).......

3:ptr 指令制定访问单元是 byte 还是 word
mov byte ptr ds:[10],1 ds:[10]01
mov word ptr ds:[10],1 ds:[11]01 ds[10]00

5: 【寻址方式的综合利用】
模拟高级语言的数组及结构体

6: 【div 指令】
纠结的除法指令= =,被除数放在 AX 或 AX 和 DX 中。
div 除数(寄存器,或内存单元)
被除数÷除数=商...余数
除数是 8 位时,AX 放的是被除数,div 后...AL 放的是商,AH 放的是余数(AX)=(AX)/(BL)。
除数的 16 位时,AX 和 DX 结合成被除数。(ax)(dx)=(DX×10000h+ax)/bx

DX 乘 10000H 代表的是高十六位,变成 32 位十六进制后面加 4 个 0 和 段地址×16(10H)相似。

DX=DE45 AX=1111 组合 DE45(16 位)×10000H=DE450000【变成 32 位了。1 个十六进制换 4 个二进制】DE450000+AX(1111)=DEA51111(组合完成的被除数)bubuko.com,布布扣

7: 【dd】
双字 dd,32 位(4 个字节)

8: 【dup】
简洁方便快速安全常用省事懒人必备。
db 5 dup(0)等于 db 0,0,0,0,0,
db 3 dup(a,b,c)等于 db a,b,c,a,b,c,a,b,c

9: 【实验】纠结的代码,核心是用到【bx+idate+si(di)】,div,一个字节一个字节的放数据。

mov al,[bx+0]
mov es:[si+0],ax
mov al,[bx+1]
mov es:[si+1],ax
mov al,[bx+2]
mov es:[si+2],ax
mov al,[bx+3]
mov es:[si+3],ax     10909050 是双字(四字节),BX 主管双字节偏移,一次偏四字节(年份收入)。SI 主管大循环填充结果的。一次偏 16 字节
mov ax,16[bx]
mov es:[si+5],ax
mov dx,18[bx]
mov es:[si+7],dx   偏移数据一样,用常量改地址
mov ax,32[di]
mov es:[si+10],ax di 是单节,一偏移一字,主管每次循环(人数)
div word ptr es:[si+9] 平均后的结果,除数 word 定义 16 位,结合上面的 dx 和 ax
mov es:[si+13],ax

结构类型,改地址处理下一行,改变量处理元素。


第九章:转移指令的原理

1: 【转移指令】
短转移 jmp short 标号    
汇编翻译成机器码是两字节,比如 EB03 向下偏移 3 个字节, 向上转-位移字节向下转+位置字节(FF 距离-128~127)。实现的是段内短转移。

近转移 jmp near ptr 标号 
和短转移相似,机器码是三字节,××FFFF(上下距离)可以在段内任何地方转移

远转移 jmp far ptr 标号 
段间转移机器码是五字节,比如 EA0B01BD0B,除了EA 高字对应 CS 低字对应 IP,高低字节对应,所以转移到 CS:IP B0BD:01B0。

条件转移 jcxz 标号 
可以理解成如果 CX 等于 0,执行跳转的短转移。

转移地址在寄存器中 
jmp ax(十六位) 段内转移,IP 偏移地址等于 AX转移地址在内存中

jmp word ptr ds:[0] 两字节,段内转移,偏移地址在内存中。

【不是跳转到 ds:[0]中,而是取出 ds:[0]内存中的值进行跳转,在一个段之间跳转】
jmp dword ptr IP:CS 四字节,段间转移。和远转移相似高低对应。

bubuko.com,布布扣 

2: 【offset】
Mov ax,offset s,把标号 s 的地址给 ax。段内两字节。

第十章:call 和 ret 指令

1: 【ret 和 retf】
Ret 把栈中的数据取出放入 ip 相当于 pop ip
Retf 把栈中的数据取出放入 cs 和 ip pop ip pop cs

40: 【call 标号】
call 标号 把当前地址存入栈,然后跳到标号处(近转移 2 字节,内存中存放的是位移字节,和 jmp 原理相似)

call far ptr 标号 把当前地址存入栈,然后转到标号处(远转移 4 字节,内存中存放的是跳转地方的段地址和偏移地址)

bubuko.com,布布扣
bubuko.com,布布扣

第十一章:标志寄存器

补充: 【补码】
正数补码等于源码,负数补码等于正数补码取反加 1,为了弥补-0 的错误。

1: 【标志寄存器和标志】
标志寄存器 flag 和普通寄存器不同,它是按位起作用的(0~15 位)。8086 中 1 3 5 12 13 14 15 这几位是空的。比如第六位的 zf 标志代表运算结果是否为 0,是 0 zf 标志为真(1)否则为假。

【ZF】结果是否为零。是零为 1
【PF】判断结果是否偶数
【SF】判断最高位是否为 1,如果是一当作有符号数则为负数
【CF】无符号数,是否进位或借位,add al,al al=98h al=30h,进位了...

mov al,97h sub al,98h 不够减于是 97h 借了以为变成 197h-98h

CF 的衍生 adc 和 sbb,adc 操作对象 1,操作对象 2 +CF,这里的 CF 是上一次运算是否进位。sbb 作对象 1,操作对象 2 -CF 这里的 CF 是上一次运算是否借位。adc 与 sbb 皆从低位到高方便进位和借位,可以实现大数相加减。

例如:54AB 003BH+89A CD23H
mov bx,54abh
mov ax,003BH
add ax,CD23H
adc bx,089ah
【OF】有符号数,判断是否溢出。 

2: 【cmp 与(jump)】

标致寄存器,比较指令(cmp)。不改变操作对象的值。而只是把比较的结果放到标志寄存器中。

cmp ax,bx[1]:无符号数比较(ZF,CF)无符号数看借位

ZF=0 AX≠BX
ZF=1 AX=BX
CF=0 AX>=BX
CF=1 AX<BX
CF=0 和 ZF=0 AX>BX
CF=1 或 ZF=1 AX<=BX
(总结,看到 zf 考虑是否等于,看到 cf 考虑是否小于,cf 等于 0 时并且考虑等于 0 未借位)

[2]:有符号数比较(ZF,OF,SF)有符号数看溢出,同上两者有些相似。

ZF=0 AX≠BX
zf=1 ax=bx
ZF=1 或 SF=1 OF=0 ax<=bx(OF 溢出如果 1,正常逻辑的反结果)ZF=1 或 SF=0 OF=0 AX>=BX
ZF=1 或 SF=1 OF=1 ax<=bx(OF 溢出如果 1,正常逻辑的反结果)ZF=1 或 SF=0 OF=1 AX<=BX
ZF=0 SF=1 OF=1 AX>BX
ZF=0 SF=0 OF=0 AX>BX
ZF=0 SF=0 OF=1 AX<BX
ZF=0 SF=0 OF=1 AX<BX
 (上面的逻辑没有验证,总结遇到 of 值等于 1 其他逻辑的反结果是正确的)

【总结的总结:用逻辑判断,记这些不如看到位寄存器的值来得快,主要是 cf 等于 0时考虑结果是否为 0,还有 of 溢出正常逻辑的反结果。总结一段,无符号看 cf zf cf 注意 0zx 看是否等 0。有符号看 of sf zf,zf 同上 of 反结果 sf 结果是否为负。】

[3]cmp 和各种(jump)的结合(这些检测的是标志寄存器位)
je ZF 是都等于 1
jne ZF 不等于 1
ja 仅检测标志位的值,详细百度= =
jna ==
jb ==
jnb  同上 

3: 【df】
df 方向传递,当 df=0 时 si+1,di+1(cls 指令设置,正方向传递)。当 df=1 时 si-1 di-1(std 设置,反方向传递)与 cx,rep,movsb(movsw)配合可以实现字符串传递。
rep 循环         cx 次后面的语句一般是 movsw。

movsw 之类的,相当于 mov ax,ds:[si+0] mov es:[di+0],ax。 

 


 




《汇编语言》笔记,布布扣,bubuko.com

《汇编语言》笔记

标签:des   code   http   com   使用   width   

原文地址:http://www.cnblogs.com/guidovanrossum/p/3810035.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!