assume cs:code
code segment
start:
mov ax,0a000H
mov cx 11
s: add ax,ax
loop s
segment ends
end
上面的LOOP S时 ,首先是将(CX)减1,然后若(CX)!=0,则向前转至s:,所以使用CX来控制 add ax,ax的执行次数。
mov ax,0a000H 为什么要加 0 呢,在汇编中 ,第一个字符不允许是字母
在DEBUG中
MOV AX,[0] // 表示把 DS:0处的 数据放入到AX
在 masm编译器中
MOV AX,[0] // 则表示 mov ax,0 会当成10进制 0 来看
2.解释
mov al,[0] //把 十进制 0 放入到AL
mov al,ds:[0] //把DS地址的第一个地址值放入AL
mov al,[bx] //把 DS地址段偏移量为BX的地址值复制给AL
mov al,ds:[bx] // 同上
loop和[BX]联合使用
3. 一段安全的空间
0:200H ~ 0:2FFH
4.
reg 的集合包括: ax bx cx dx ah bh ch dh al bl cl dl sp bp si di
sreg:ds ss cs es
在8086CPU中 、只有4个寄存器(bx bp si di) 可以用在[...] 中来进行内存单元寻址
只能 组合 [bx+si] [bx+di] [bp+si] [bp+di]
bp默认的段地址 ss ,类似sp
bx 默认的段地址 ds
mov ax,bx 把 地址bx里面的值 放到寄存器 ax
指定数据长度
mov word ptr ds:[0],1
inc byte ptr [bx]
必要性如 FFH
FFH+1=? 如果是字型那么没有问题,但是如果是字节型 就会溢出 00H
上图的指令解说:
首先 cs:ip = 20018H 到对应的内存地址中找相应的指令(01408BH),
把这个机器码读取到 指令缓冲寄存器中,然后执行命令,
是: 取出ds:[bx+si+1]=2000*10+000F+0002+1=20012H 的值(8B07) 放入到寄存器AX中
Call和Ret指令
ret指令用栈中的数据,修改IP的内容,从而实现近转移
CPU执行ret指令时,进行下面2步操作:
(IP)=((ss)*16+(SP))
(sp)=(sp)+2
--- pop IP
retf 指令使用栈中的数据,修改CS和IP的内容,从而实现远转移
CPU执行retf指令时,进行下面两步操作:
(IP)= ((ss)*16+(sp))
(sp)=(sp)+2
(cs)=((ss)*16+(sp))
(sp) = (sp) +2
pop IP
pop CS
call指令
执行call标号时 相当于进行
push IP
jmp near ptr 标号
CPU在执行call far ptr 标号,相当于执行
push CS
push IP
jmp far ptr 标号
执行 call 16寄存器 相当于
push IP
jmp 16位 reg
标志寄存器
标志位 6 ZF ( zero flag) 指令计算的结果为0 zf = 1
2 PF (parity flag) 二进制 1的个数为偶数 pf = 1
7 SF 指令计算结果为负数 SF=1
0 CF 记录最高有效位向更高位的进位值 或者减法的时候向高位的借位值
11 OF (overflow flag) 如果结果超过寄存器的范围, OF =1 表示溢出
10 DF
WINDOWS的实模式、保护模式、虚拟8086模式
实模式: CS:IP --》 程序段, 段地址+偏移地址 = 20位物理地址
保护模式: CS:IP --》 程序段,寻址方式不同。 (为的是起到保护的作用) 程序分等级了(数据段,代码段)
保护模式:
其中, 0 级代表最高的权限级别, 3 级代表最低的权限级别,
0、1、2为系统级, 环3 为用户级
中断
MOV AX,0
jmp short s ;段内短转移 (范围 -128 ~ 127) (IP)=(IP)+ 8 jmp near 标号(段内近转移 (IP)=(IP)+16 范围:(-32768 ~ 32768))
add ax,1
s:inc ax
位移是03
所以执行指令EB03会 跳转到 0005+0003 = 0008 --> IP
jmp far ptr 标号 段间转移 (远转移)
是直接修改 CS:IP的值
EA0B01BD0B 直接修改CS:IP
转移地址在内存中的JMP指令
1. jmp word ptr 内存单元地址(段内转移)
例如:
mov ax, 0123H
mov ds:[0],ax
jmp word ptr [0]
执行后 (IP)=0123H
2. jmp dword ptr 内存单元地址(段间转移)
功能:从内存单元地址处开始存放着两个字,高地址处的字是转移的目的段地址(CS),低地址处是转移的目的偏移地址(IP)
(CS)=(内存单元地址+2)
(IP)=(内存单元地址)
例如:
mov ax 0123H
mov ds;[0],ax
mov word ptr ds:[2],0
jmp dword ptr ds:[0]
执行后:(CS)=0 ,(IP)= 0123H cs:ip = 0000:0123
3. jcxz 指令
if ((cx)==0)
jmp short 标号
4.loop指令
(cx)=(cx)-1
if((cx)!=0)
jmp short 标号
要注意编译器对转移位移超界的检测
最简单的汇编程序结构分析
编写1.asm
assume cs:codesg
codesg segment
start: mov ax,4c00H
int 21h
codesg ends
end start
assume cs:codesg
codesg segment
codesg ends
end start
是伪指令
start- 程序的如果标识
end 后面的start 与前面入口对应, 也可以不写 默认代码段如果标记
编译链接
masm.exe 1.asm link 1.obj 或者直接ml 1.asm
16进制 -使用uedit32查看
PE 文件格式 可以看到前面 512 字节 是PE头相关信息
最下面是程序的入口
载入 debug . debug 1.exe
可以看到 CX 的大小就是 指令的长度 机器码长度 5个字节
DS=0b2f cs=0b3f 可以知道 ds和CS段地址相差10H 物理地址也就是相差10H*10 = 100H =256 个字节
PSP功能: 程序和系统通信的接口
查看 ds后的256个字节
-u 0b2f:0 100
再往下查看就是指令了
-u 0b2f:100 20
程序加载后分配空间是以16个字节为单位的,也就是说如果不足16个字节的也分配16个字节。
如果段中的数据占N个字节,则程序加载后,该段实际占有的空间为 ((N+15)/16)*16 。