写这个系列文章的主要目的是记录书中重要的知识点,并和大家分享一些个人理解与实践。由于笔记中的知识点比较零散,而书中系统的介绍了一个 x86-16 处理器在实模式下的工作原理以及如何使用汇编语言与其进行“沟通”,所以推荐想要系统学习的朋友们去学习这本书。当我们掌握了实模式的工作原理之后,就可以进一步研究后来出现的其他运行模式(如保护模式)。除此之外,熟悉汇编语言有助于我们掌握上层语言(如 C)的执行原理,因为它们都要对汇编(机器码)进行抽象,而汇编程序就是基于 CPU 的执行机理写出来的。
第九章
转移行为分类
-
段内转移(只修改
IP
, 根据转移的范围不同又分为:短转移 和 近转移) -
段间转移(同时修改
CS
和IP
)
jmp
指令的两种实现差异
在一般的汇编指令中,立即数不论表示一个数据还是内存单元的偏移地址,都会在对应的机器指令中出现。
-
基于转移的距离——指令中不包含目的地址,而包含的是位移量(向前或向后移动的距离)
- 优点,可浮动装配,即位移量不变的情况下,这段程序可在任何地方执行
- 基于要转移的目的地址
以上两个维度的汇总
基于转移的距离(间接转移) | 基于要转移的目的地址(直接转移) | |
---|---|---|
段内转移 |
jmp short Label jmp Label 、jmp near ptr Label
|
jmp 某一合法16位寄存器 ——将寄存器中的内容写入 IP jmp word ptr 地址 ——转移到目的偏移地址 |
段间转移 |
jmp far ptr Label (注:它也能够实现段内转移的效果)jmp dword ptr 地址 (h_word=段地址,l_word=目的偏移地址) |
-
jmp short Label
: 翻译成的机器码为EB??H
, ?? 代表 8 位的位移量(这种方式是短转移)本质为:IP = IP + 8位的位移量 【重点(容易被忽略):CPU 在执行该指令时,是使用这个位移量来计算 IP 的】 - short 指明此处的位移为 8 位位移,范围是 -128~127, 用【补码】表示 - 8位的位移量 = 标号处的地址 - jmp指令后的第一个字节的地址,编译器在【编译时】算出
-
为什么是
jmp
指令后的第一个字节的地址aj
?为什么这么设计呢?因为取址之后(执行之前)IP
寄存器中的地址会被设置为该地址aj
,这样在执行转移指令时,可以直接参与目的偏移地址的计算!- 编译时:
disp=as-aj
, 执行指令时:IP(as) = IP(aj) + disp(位移量)
即直接完成该指令的功能
- 编译时:
-
-
jmp near ptr Label
(近转移,本质与短转移相同,区别仅仅是它支持16位的位移量) -
jmp far ptr Label
(远转移)CS 设置为 标号所在段的【段地址】 IP 设置为 标号在该段中的【偏移地址】
masm 对 jmp 内部转移的编译实现
【条件转移】和【循环指令】是对【短转移】的功能扩展
-
jcxz
指令的伪代码:...... if ((cx) == 0) { jmp short s } s: ......
-
loop
指令的伪代码s: ...... (cx)--; if ((cx) != 0) { jmp short s } ......
实验八:分析一个奇怪的程序
注意:是将 jmp short s1
的机器码 EBF6
拷贝至 076C:0008~076C:0009
两个存储单元中,F6
是 -10
的补码,表示位移量
其实补码 F6
表示什么有符号数,可以不用图片中的方法计算,而使用以下方法计算更为简单:
-
因为补码
1111 1111
表示十进制有符号数-1
, 这个-1
的计算方式是:$$
-1 = -1*2^7 + 1*2^6 + 1*2^5 + 1*2^4 + 1*2^3 + 1*2^2 + 1*2^1 + 1*2^0
$$$$
= -128 + 64 + 32 + 16 + 8 + 4 + 2 + 1
$$ -
那么补码
1111 0110(0xF6)
就等于:$$
-1*2^7 + 1*2^6 + 1*2^5 + 1*2^4 + 0*2^3 + 1*2^2 + 1*2^1 + 0*2^0
$$$$
(-1*2^7+1*2^6+1*2^5+1*2^4+1*2^3+1*2^2+1*2^1+1*2^0) – 1*2^3 – 1*2^0 = -1 – 8 – 1 = -10
$$
实验九:80x25
彩色字符模式缓冲区输出程序
- 显示缓冲区:
B8000H~BFFFFH(共32KB, 8页,每页4KB)
-
80x25
——每页由 25 行组成,每行由 80 个字符(160byte)组成 - 注:dosbox 中执行完可执行文件,输出结果会被向上顶一行(弹出输入提示符导致),所以以下程序的输出就显示在 11,12,13 行了
; 在屏幕中间分别显示黑底绿色、绿底红色、白底蓝色的字符串'welcome to masm!'
; 题目要求屏幕中间显示?那就 12,13,14 行显示
assume cs:codesg, ds:datasg, ss:stacksg
datasg segment
db 'welcome to masm!'
db 02H, 24H, 71H ; 三种属性:黑底绿色、绿底红色、白底蓝色
datasg ends
stacksg segment
dd 0,0,0,0
stacksg ends
codesg segment
start: mov ax, datasg
mov ds, ax
mov ax, stacksg
mov ss, ax
mov sp, 10H
mov ax, 0B800H ; masm 汇编器要求立即数不能以字母开头
mov es, ax
mov bx, 0
mov bp, 16
mov cx, 3 ; 共写入3行
s0: mov si, 0
mov di, 1824 ; di=1760+64, 1760是12行第一字节的offset, 每行中间位置的offset=64
add di, bx ; 计算每一行开始写入的偏移地址
mov ah, ds:[bp] ; 该行要显示的属性值
push cx ; 保存
mov cx, 16
s: mov al, [si]
mov es:[di], al ; 显存区域:字符低字节表示 ASCII
inc di
mov es:[di], ah ; 字符高字节对应颜色属性
inc si
inc di
loop s
add bx, 160 ; 0-160-320 (控制写入下一行)
inc bp ; 16-17-18(控制获取下一行的属性值)
pop cx ; 恢复
loop s0
mov ax, 4c00H
int 21H
codesg ends
end start
第十章
模块化程序设计
-
call
和ret
指令配合使用(近转移)-
call
等价于:push IP + jmp ...
- ret等价于:
pop IP
-
-
call和retf指令配合使用(远转移)
- call等价于:
push CS + push IP + jmp ...
- retf等价于:
pop IP + pop CS
(注意这个顺序)
- call等价于:
call指令
相当于将call指令之后的那一个指令的IP
或CS+IP
压栈之后,进行jmp
转移。
支持近转移或远转移,不支持短转移。
-
call Label
push IP
jmp near ptr Label
-
call far ptr Label
push CS
push IP
jmp far ptr Label
-
call 16位寄存器
push IP
jmp 16位寄存器
-
call word ptr 内存地址
push IP
jmp word ptr 内存地址
-
call dword ptr 内存地址
push CS
push IP
jmp dword ptr 内存地址
总结——【目前已经介绍的】转移指令对应的机器码
call 转移指令 | 机器码 | jmp 转移指令 | 机器码 |
---|---|---|---|
call L |
E8 ????(16位位移量) | jmp near ptr L |
E9 ???? |
call far ptr L |
9A ???? ???? 标号在段中的偏移地址 标号所在段地址 |
jmp far ptr L |
EA ???? ???? |
call ax、call bx |
FFD0、FFD3 | jmp ax、jmp bx |
FFE0、FFE3 |
call word ptr addr |
FF160000 (todo) | jmp word ptr addr |
FF260000 (todo) |
call dword ptr addr |
FF1E0000 (todo) | jmp dword ptr addr |
FF2E0000 (todo) |
8086 中乘法的计算规则
汇编指令:mul 乘数(在内存或某个寄存器中)
,【被乘数和乘数】要么都是 8 位,要么都是 16 位
8位乘数 | 16位乘数 | |
---|---|---|
被乘数 | 8位——在 al 中 |
16位——在 ax 中 |
结果 |
ax 中 |
dx 存高16位、ax 存低 16 位 |
实验十:编写子程序
(1)指定位置打印字符串
exp10_1.asm
(2)解决除法溢出的问题
exp10_2.asm
(3)二进制转十进制,打印
exp10_3.asm
服务器托管,北京服务器托管,服务器租用 http://www.fwqtg.net