写这个系列文章的次要目标是记录书中重要的知识点,并和大家分享一些集体了解与实际。因为笔记中的知识点比拟零散,而书中零碎的介绍了一个 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:stacksgdatasg segment db 'welcome to masm!' db 02H, 24H, 71H ; 三种属性:黑底绿色、绿底红色、白底蓝色datasg endsstacksg segment dd 0,0,0,0stacksg endscodesg 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 21Hcodesg endsend 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