汇编学习杂记(1~8章)

来源:互联网 发布:java基础入门教程 编辑:程序博客网 时间:2024/05/16 18:25

CPU寻址能力为
X = 13 这就是寻址宽度
寻址能力为2^13=8192byte=8KB
那么寻址范围就是0 --- 8191

一根数据线传送1位bit(0或1)
8根=1byte  16根=2byte  32根=4byte

8bit = 1byte
1024byte = 1kb
1024kb  =  1MB
1024MB  =  1GB
1024GB  =  1TB

8086CPU寻址问题
段地址 * 16 + 偏移地址 = 物理地址
段地址 * 16.这个的概念。相当于左移二进制四位。16是十进制数。段地址是十六进制数。进制转换一样后。等于 段地址 * 10H 。(16十进制转换为十六进制为10)

8086CPU段寄存器(不可直接赋值操作比如 MOV DS,1000H)
CS DS SS ES

CS用来存放指令的段地址
IP存放指令的偏移地址。
设CS内容为M,IP内容为N。寻址:M * 16 + N
8086机中。任意时刻,CPU将CS:IP指向的内容作为指令执行,而不是作为数据。
每次读取完一条指令后。IP=IP+所读取指令的长度,从而指向下一条指令.(切忌,切忌)

DS通常用来存放需要访问数据的段地址。
mov bx,1000H
mov ds,bx
mov al,[0] (通过参考操作的寄存器位数,判断内存中的读写单元是多少位,这里寄存器为8位及            1byte,那么就读取内存中一个单元的数据)
将10000H(1000:0)中的数据读到al中(mov ds,1000H 是非法指令.DS的值必须由通用寄存器或者[...]内存单元数据传入,并且不可做运算操作)

修改CS:IP的内容
jmp 2AE3:3  CS=2AE3H  IP=0003H  指向物理地址 2AE33H (只能在Debug中使用)
jmp 3:0B16  CS=0003H  IP=0B16H  指向物理地址 00B46H (只能在Debug中使用)
jmp 某一合法寄存器  功能为 用寄存器中的值修改IP
jmp ax  等于修改IP的值为AX的值

Debug初试
修改寄存器                     R
查看内存                       D
修改内存                       E
内存数据编译为机器码和汇编指令 U
执行CS:IP指向的指令            T
以汇编指令形式向内存写入       A
(CMD)c:/debug 程序名.exe 载入程序到内存.
int 21H 用P命令执行,至于为什么,现在还不知道.
G 0012 执行程序到当前代码段(段地址在CS中)的0012H处
P 指令自动重复 "标号:代码" 到 "LOOP 标号" 这一区域段的指令,直到(CX)=0 最后停在 "loop 标号" 的下一条指令

内存中字的存储,困惑我N久,终于理解了。
CPU中16位寄存器存储一个字。高8位放高位字节,低8位放低位字节。
而内存中存储时,内存单元是字节单元(一个单元存放一个字节,也是8bit),那么一个字就要用到两个连续的单元来存放,这个字的低位字节就存放在低地址单元中,顺之,高位字节存到高地址单元中。当我们用CE等内存读写工具时,显示的内存顺序为00 01 02……。所以当我们存放比如20000(4E20H)时。内存中16进制写入就是20  4E
我们称内存中的这个地址段为 字单元 既存放一个字型数据(16位)的内存单元,由两个地址连续的内存单元组成。高地址内存单元中存放字型数据的高位字节,低地址内存单元中存放字型数据的低位字节。

栈机制
PUSH 入栈指令
POP  出栈指令
入栈和出栈的操作单位为字.16bit 2byte 也就是两个内存单元
ss 寄存器存放栈顶的段地址     (不能直接赋值,需要寄存器或者内存单元中转赋值)
SP 寄存器存放栈顶的偏移地址   (可用MOV直接赋值,可进行运算操作)
任意时刻,SS:SP指向栈顶元素。
当PUSH入栈时,比如PUSH AX   CPU先执行SP=SP-2 再将AX入栈。
入栈时,栈顶从高地址向低地址方向增长。当栈空时。SP=栈顶最后一个字单元 + 2(指向栈底的下一个单元及栈底减一)
当POP 出栈时,比如POP  AX   CPU先将SS:SP指向的内存单元处数据送入AX 再执行SP=SP+2
当Debug的T命令在执行修改寄存器SS的指令时,下一条指令也紧接着被执行(备注)

伪指令 是用来告诉编译器,让其执行的.最终不由计算机执行.
源程序 是程序文件中的所有内容,包括伪指令
程序   且是单指最终由计算机执行.处理的指令或数据.就没有伪指令了.

伪指令
segment和ends 是一对成对使用的伪指令.功能是定义一个段.
段名 segament  <--- 开始  段名 也称为 标号 最终被编译.连接程序处理为一个段的段地址
段名 ends      <--- 结束
end 是一个汇编程序的结束标记.如果在它后面加上标号,那么这个标号就代表程序的入口,
如end start 这个标号就是程序的真正入口
assume 它假设某一段寄存器和程序中的某一个用segment……ends定义的段相关联.
assume cs: 段名 将段名于CS段寄存器相关联
mov ax,标号 含义就是将标号所指定的段的段地址送入AX

程序返回 将CPU的控制权交还给使得当前程序P2得与运行的P1程序
mov ax,4c00H
int 21H

shell(操作系统的外壳) 用户使用这个程序来操作计算机系统进行工作
程序加载情况 空闲内存区:SA:0
             PSP区     :SA:0 (占位256字节100H)(SA:00 ~ SA:FF)
             程序区    :SA+10H:0
程序载入内存后 初试状态中 CX存放的是程序的长度(字节byte)  DS 存放该内存区的段地址(SA) CS:IP指向程序入口(SA+10:0)

"()" 括号的意思现在定义为描述符,相当于指针的概念.如:(ax)表示AX中的内容.(20000H)表示内存20000H单元中的内容.
((DS)*16+(BX))表示 (段地址(DS) * 16 + 偏移地址(DX)) 这个地址所指向的内存单元的内容 (牢记,牢记)
约定符号 idata 表示常量 如: MOV AX,[idata] 表示 mov ax,[0] mov ax[1] 等等

[bx] 表示一个内存单元,BX的值为偏移地址,段地址在DS中
LOOP 标号  执行过程为,判断(CX寄存器) 第一步:(CX)=(CX)-1 第二步:(CX)不为零且转至标号出执行,否者且向下执行 (loop 标号 实际上是为IP寄存器赋值,如果标号不写在LOOP前面,切无法实现循环目的)
CX 寄存器可直接MOV赋值,可运算操作
用CX和LOOP指令相配合实现循环功能的程序框架
mov cx,循环次数
S:
    循环执行的程序段
    LOOP S
标号所标示的地址要在前面,要循环执行的程序段,要写在标号和LOOP指令的中间

在汇编源程序中,数据不能以字母开头.所以要在字母前面加0.比如0A000H
Debug 解释 mov ax,[0] 为 将 ds:0000H 内存单元的数据送入 AX
masm编译器 mov ax,[0] 解释为 mov ax,0000
那么要实现这句指令,在源程序中必须这样 mov ax ds:[0] 明确指定段寄存器 或者抛弃常量 [0] 而使用 [dx] 等寄存器中转

段前缀
出现在访问内存单元的指令中,用于显示地指明内存单元的段地址的"DS:"."CS:"."SS:"或"ES:"。在汇编的语言中称为段前缀。

安全的内存空间
DOS方式下,一般情况,0:200 ~ 0:300 (00200H ~ 00300H)空间中没有系统或其它程序的数据或代码。

inc 指令 表示当前操作数 = 自身 +1 如 inc ax 等于 ax = ax +1
dec 指令 表示当前操作数 = 自身 +1 如 dec ax 等于 (ax)=(ax)-1
add 加法运算符
sub 减法运算符
dw (define word)定义字型数据.如 dw 0123H,0456H,.......

如果汇编程序中有下面两个连续的段定义,汇编编译程序会怎么做呢?
name1 segment
d1 db 0
name1 ends
name2 segment
d2 db 0
name2 ends
编译器实际的处理方式是将name1中的所有内容放在一个段的起始地址处(比如0001:0),name2里的所有内容放在后续一个段的起始地址处(比如0002:0)(这也是汇编指令segment的本义:将不同数据分段)。这样,即使name1中只包含一个字节,也要占一个段(16个字节),所以,一个段实际占用的空间=
(段中字节数+15)/16*16  [(段中字节数+15)/16只取整数部分]
(N/16+1)*16 [说明:N/16只取整数部分]
所以,8086处理器的内部寻址原理和汇编程序编译器共同决定了segment定义的段必须放在按16的倍数对准的段地址边界上,占用的空间也是16的倍数。

and 逻辑与命令 两个操作数为真,结果为真,否则为假
or  逻辑或命令 两个操作数其中一个为真,结果为真

[bx+idata] 也可以写作 idata[bx] 可以看做数组的实现方法。段地址 * 16 + 相对地址 + 偏移地址
mov ax,[bx][si] 同上面的解释一样
mov ax,[bx+si+idata]
mov ax,200[bx][si]
mov ax,[bx].200[si]
mov ax,[bx][si].200
[idata]用一个常量来表示地址,可用于直接定位一个内存单元
[bx]用一个变量来表示内存地址,可用于间接定位一个内存单元
[bx+idata]用一个变量和常量表示地址,可在一个起始地址的基础上用变量间接定位一个内存单元
[bx+si]用两个变量表示地址
[bx+si+idata]用两个变量和一个常量表示地址
[bx+idata+si]一般来说可以用来访问结构体中的数据,BX定位整个结构体,idata定位结构体中的某一个数据项,SI定位数组项中的每个元素,那么就可以这样书写[bx].idata[si]  [bx].idata

SI和DI寄存器 不能分成两个8位寄存器

约定 reg 用来表示一个寄存器
     sreg用来表示一个段寄存器

只有 bx si di bp 这四个寄存器可以用在[...]中来进行内存单元的寻址
[...]中,这4个寄存器可以单个出现,或只能以四种组合出现:BX和SI,BX和DI,BP和SI,BP和DI
只要在[...]中使用寄存器 bp ,没指令中没有显示地给出段地址, 那么默认的段地址在SS中
bx不能与bp合用,因为它们默认为不同的段寄存器。

在没有寄存器名存在的情况下,用操作符 X ptr 指明内存单元的长度,X 在汇编指令中可以为 word 或 byte
mov word ptr ds:[0],1  (word指明操作数为一个字型数据16位)
mov byte ptr ds:[0],1  (byte指明操作数为一个字节型数据8位)
(prt 是指针的意思,可以解释为一个指向 X 类型的指针)

div 是除法指令
除数:有8位和16位两种,在一个寄存器或内存单元中
被除数:默认放在AX或DX和AX中,如果除数为8位,被除数则为16位,默认在AX中存放;如果除数为16位,被除数则为32位,在DX和AX中存放,DX存放高16位,AX存放低16位。
结果:如果除数为8位,则AL存储除法操作的商,AH存储除法操作的余数;如果除数为16位,则AX存储除法操作的商,DX存储除法操作的余数。

mul 是乘法指令
两个相乘数,如果是8位,一个默认放在AL中,另一个放在8位寄存器或内存字节单元中;
如果是16位,一个默认在AX中,另一个放在16位寄存器或内存字单元中.
结果:8位乘法,默认放在AX中;16位乘法,结果高位默认放在DX中,低位放在AX中.

伪指令
db 占位一个字节,一个内存单元
dw 占位一个字,  二个内存单元
dd 占位二个字,  四个内存单元

dup 是一个操作符 它和db dw dd等数据定义伪指令配合使用,用来进行数据的重复 db 3 dup (1,2,3) 相当于 db 0,1,2,0,1,2,0,1,2

原创粉丝点击