写这个系列文章的主要目的是记录书中重要的知识点,并和大家分享一些个人理解与实践。由于笔记中的知识点比较零散,而书中系统的介绍了一个 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 ???? ????<br/>标号在段中的偏移地址 标号所在段地址 | 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://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。