本笔记来源于《汇编语言》王爽著

基础知识

assembly language

In computing, assembly language (alternatively assembler language or symbolic machine code), often referred to simply as assembly and commonly abbreviated as ASM or asm, is any low-level programming language with a very strong correspondence between the instructions in the language and the architecture’s machine code instructions.

Assembly in the dictionary referred to the translation of assembly language to machine language by an assembler.

汇编语言由以下3类组成:

  1. 汇编指令(机器码的助记符)
  2. 伪指令(由编译器执行)
  3. 其它符号(由编译器识别,如:+ - * /)
    汇编语言的核心是汇编指令,它决定了汇编语言的特性。for example:

CPU要想进行数据的读写,必项和外部器件(标谁的说法是芯片)进行三类信息的交互:

  • 存储单元的地址(地址信息)
  • 器件的选择,读或写命令(控制信息)
  • 独或写的数据(数据信息)
flowchart LR
    CPU[CPU]
    内存[内存]

    subgraph 总线
        地址总线[地址总线]
        数据总线[数据总线]
        控制总线[控制总线]
    end

    CPU --- 地址总线 --- 内存
    CPU --- 数据总线 --- 内存
    CPU --- 控制总线 --- 内存

注意这些箭头也可以是双向的!

存储单元

存储器被划分成若干个存储单元,每个存储单元从0开始顺序编号,例如一个存储器有128个存储单元,编号从0~127。

0
1
2
3
4
…
125
126
127
那么一个存储单元能存储多少信息呢?我们知道电子计算机的最小信息单位是bit(音译为比特),也就是一个二进制位。8个bit组成一个Byte,也就是通常讲的一个字节。微型机存储器的存储单元可以存储一个Byte,即8个二进制位。一个存储器有128个存储单元,它可以存储128个Byte。

微机存储器的容量是以字节为最小单位来计算的。对于拥有128个存储单元的存储器,我们可以说,它的容量是128个字节。
对于大容量的存储器一般还用以下单位来计量容量(以下用B来代表Byte):

磁盘的容量单位同内存的一样,实际上以上单位是微机中常用的计量单位。

CPU对存储器的读写

以上讲到,存储器被划分成多个存储单元,存储单元从零开始顺序编号。这些编号可以看作存储单元在存储器中的地址。就像一条街,每个房子都有门牌号码。

地址总线

CPU是通过地址总线来指定存诸单元的。地址总线上能传送多少个不同的信息,CPU就可以对多少个存储单元井行寻址。(也就是CPU的寻址能力)

Drawing 2025-10-05 18.28.00.excalidraw

⚠ Switch to EXCALIDRAW VIEW in the MORE OPTIONS menu of this document. ⚠ You can decompress Drawing data with the command palette: ‘Decompress current Excalidraw file’. For more info check in plugin settings under ‘Saving’

Excalidraw Data

Text Elements

内
存

C
P
U

地
址
总
线

数据总线

控制总线

1

1

0

0

1

0

1

0

低位

高位

Link to original

一个CPU有N根地址总线,则可以说这个CPU的地址总线的宽度为N。
这样的CPU最多可以寻址2的N次方个存储单元。 ^b3d2c9

每一条地址线可以传递一个二进制信号:

  • 0 表示低电平
  • 1 表示高电平

如果有 1 条地址线,那只能表示两种情况:0 或 1。如果有 2 条地址线,就能表示 4 种情况:00、01、10、11。一般来说,n 条地址线可以组合成 n 位二进制数,能表示 种不同的状态。

每一种二进制地址对应一个唯一的存储单元。 所以,n 条地址线就能唯一指定 个存储单元。

数据总线

CPU与内存或其它器件之间的数据传送是通过数据总线来井行的。
数据总线的宽度决定了CPU和外界的数据传送速度。
传输流程跟上面的地址总线差不多,就不放图了。

控制总线

CPU对外部器件的控制是通过控制总线来井行的。在这里控制总线是个总称,控制总线是些不同控制线的集合。
有多少根控制总线,就意味着CPU提供了对外部器件的多少种控制。
所以,控制总线的宽度决定了CPU对外部器件的控制能力。


小结

  • 汇编指令是机器指令的助记符,同机器指令一一对应。
  • 每一种CPU都有自己的汇编指令集。

1个CPU的寻址能力为8KB,那么它的地址总线的宽度为 13

1KB的存储器有 ❓ 个存储单元。存储单元的编号从❓ 到❓。
所以有1024个存储单元。存储单元的编号从0到1023。

8080、8088、80286、80386的地址总线宽度分别为16根、20根、24根、32
根,则它们的寻址能力分别为:(KB)、(MB)、(MB)、(GB)。

16根地址总线一次可寻个存储单元,一个存储单元为1byte。

8080、8088、8086、80286、80386的数据总线宽度分别为8根、8根、16根、16根、32根。则它们一次可以传送的数据为: 1(B)、 1(B)、 2(B)、 2(B)、 4(B)。

寄存器

一个典型的CPU(此处讨论的不是某一具体的CPU)由运算器、控制器、寄存器(CPU工作原理)等器件构成,这些器件靠内部总线相连。前一章所说的总线,相对于CPU内部来说是外部总线。内部总线实现CPU内部各个器件之间的联系,外部总线实现CPU和主板上其他器件的联系。简单地说,在CPU中:

  • 运算器进行信息处理;
  • 寄存器进行信息存储:
  • 控制器控制各种器件进行工作;
  • 内部总线连接各种器件,在它们之间进行数据的传送。

对于一个汇编程序员来说,CPU中的主要部件是寄存器。寄存器是CPU中程序员可以用指令读写的部件。程序员通过改变各种寄存器中的内容来实现对CPU的控制。

不同的CPU,寄存器的个数、结构是不相同的。8086CPU有14个寄存器,每个寄存器有一个名称。这些寄存器是:AX、BX、CX、DX、SI、DI、SP、BP、IP、CS、SS、DS、ES、PSW。我们不对这些寄存器进行一次性的介绍,在课程的进行中,需要用到哪些寄存器,再介绍哪些寄存器。

通用寄存器

8086CPU的所有寄存器都是16位的,可以存放两个字节。AX、BX、CX、DX这4个寄存器通常用来存放一般性的数据,被称为通用寄存器。

以AX为例,寄存器的逻辑结构如图2.1所示。

AX:

block-beta
  columns 16
  B15["15"] B14["14"] B13["13"] B12["12"] B11["11"] B10["10"] B9["9"] B8["8"] B7["7"] B6["6"] B5["5"] B4["4"] B3["3"] B2["2"] B1["1"] B0["0"]

8086CPU的上一代CPU中的寄存器都是8位的,为了保证兼容,使原来基于上代CPU编写的程序稍加修改就可以运行在8086之上,8086CPU的AX、BX、CX、DX这4个寄存器都可分为两个可独立使用的8位寄存器来用:

  • AX可分为AH和AL:
  • BX可分为BH和BL:
  • CX可分为CH和CL;
  • DX可分为DH和DL。

字在寄存器中的存储

出于对兼容性的考虑,8086CPU可以一次性处理以下两种尺寸的数据。

  • 字节:记为byte,一个字节由8个bit组成,可以存在8位寄存器中。
  • 字:记为wod,一个字由两个字节组成,这两个字节分别称为这个字的高位字
    节和低位字节,如图2.5所示。

几条汇编指令

汇编指令控制CPU完成的操作用高级语法表述
mov ax, 18将18送入寄存器 AXAX=18
mov ah, 78将78送入寄存器 AHAH=78
add ax, 8将寄存器AX中的数值加上8AX=AX+8
mov ax,bx将寄存器BX中的数据送入寄存器AXAX=BX
add ax,bx将AX和BX中的数值相加,结果存在AX中AX=AX+BX
注意,为了使具有高级语言基础的读者更好地理解指令的含义,有时会用文字描述和高级语言描述这两种方式来描述一条汇编指令的含义。在写一条汇编指令或一个寄存器的名称时不区分大小写。如:mov ax,18 和 MOV AX,18 的含义相同;bx和BX的含义相同。

接下来看一下CPU执行表2.2中所列的程序段中的每条指令后,对寄存器中的数据进行的改变。

程序段中指令的执行情况之一(原AX中的值:0000H, 原BX中的值:0000H)

程序段中的指令指令执行后AX中的数据指令执行后BX中的数据
mov ax, 4E20H4E20H0000H
add ax, 1406H6226H0000H
mov bx, 2000H6226H2000H
add ax, bx8226H2000H
mov bx, ax8226H8226H
add ax, bx1044C(溢出后的结果)8226H
8226H + 8226H = 1044C

物理地址

我们知道,CPU访问内存单元时,要给出内存单元的地址。所有的内存单元构成的存储空间是一个一维的线性空间,每一个内存单元在这个空间中都有唯一的地址,我们将这个唯一的地址称为物理地址。

CPU通过地址总线送入存储器的,必须是一个内存单元的物理地址。在CPU向地址总线上发出物理地址之前,必须要在内部先形成这个物理地址。不同的CPU可以有不同的形成物理地址的方式。我们现在讨论8086CPU是如何在内部形成内存单元的物理地址的。

16位结构的CPU

我们说8086CPU的上一代CPU(8080、8085)等是8位机,而8086是16位机,也可以说8086是16位结构的CPU。那么什么是16位结构的CPU呢?

概括地讲,16位结构(16位机、字长为16位等常见说法,与16位结构的含义相同)描述了一个CPU具有下面几方面的结构特性。

  • 运算器一次最多可以处理16位的数据:
  • 寄存器的最大宽度为16位:
  • 寄存器和运算器之间的通路为16位。

8086是16位结构的CPU,这也就是说,在8086内部,能够一次性处理、传输、暂时存储的信息的最大长度是16位的。内存单元的地址在送上地址总线之前,必须在CPU中处理、传输、暂时存放,对于16位CPU,能一次性处理、传输、暂时存储16位的地址。

8086CPU给出物理地址的方法

8086CPU有20位地址总线,可以传送20位地址,达到1MB寻址能力。8086CPU又是16位结构,在内部一次性处理、传输、暂时存储的地址为16位。从8086CPU的内部结构来看,如果将地址从内部简单地发出,那么它只能送出16位的地址,表现出的寻址能力只有64KB。

8086CPU采用一种在内部用两个16位地址合成的方法来形成一个20位的物理地址。

如图2.6所示,当8086CPU要读写内存时:

  1. CPU中的相关部件提供两个16位的地址,一个称为段地址,另一个称为偏移地址;
  2. 段地址和偏移地址通过内部总线送入一个称为地址加法器的部件;
  3. 地址加法器将两个16位地址合成为一个20位的物理地址;
  4. 地址加法器通过内部总线将20位物理地址送入输入输出控制电路;
  5. 输入输出控制电路将20位物理地址送上地址总线;
  6. 20位物理地址被地址总线传送到存储器。

地址加法器采用物理地址=段地址×16+偏移地址的方法用段地址和偏移地址合成物理地址。例如,8086CPU要访问地址为123C8H的内存单元,此时,地址加法器的工作过程如图2.7所示(图中数据皆为十六进制表示)。

“段地址×16”有一个更为常用的说法是左移4位。计算机中的所有信息都是以二进制的形式存储的,段地址当然也不例外。机器只能处理二进制信息,“左移4位”中的位,指的是二进制位。

我们看一个例子,一个数据为2H,二进制形式为10B,对其进行左移运算:

左移位数二进制十六进制十进制
010B2H2
1100B4H4
21000B8H8
310000B10H16
4100000B20H32
观察上面移位次数和各种形式数据的关系,我们可以发现:
  1. 一个数据的二进制形式左移1位,相当于该数据乘以2:
  2. 一个数据的二进制形式左移N位,相当于该数据乘以2的N次方;
  3. 地址加法器如何完成段地址×16的运算?就是将以二进制形式存放的段地址左移4位。

进一步思考,我们可看出:一个数据的十六进制形式左移1位,相当于乘以16:一个数据的十进制形式左移1位,相当于乘以10;一个X进制的数据左移1位,相当于乘以X。

“段地址×16+偏移地址=物理地址”的本质含义

注意,这里讨论的是8086CPU段地址和偏移地址的本质含义,而不是为了解决具体的问题而在本质含义之上引申出来的更高级的逻辑意义。不管以多少种不同的逻辑意义去看待“段地址×16+偏移地址=物理地址”的寻址模式,一定要清楚地知道它的本质含义,这样才能更灵活地利用它来分析、解决问题。如果只拘泥于某一种引申出来的逻辑含义,而模糊本质含义的话,将从意识上限制对这种寻址功能的灵活应用。

“段地址×16+偏移地址=物理地址”的本质含义是:

CPU在访问内存时,用一个基础地址(段地址×16)和一个相对于基础地址的偏移地址相加,给出内存单元的物理地址。

更一般地说,8086CPU的这种寻址功能是“基础地址+偏移地址=物理地址”寻址模式的一种具体实现方案。8086CPU中,段地址×16可看作是基础地址。

比如,只能通过纸条来互相通信,你问我图书馆的地址我只能将它写在纸上告诉你。显然,我必须有一张可以容纳4位数据的纸条,才能写下2826这个数据。

可以写下4位数据的纸条

2826

可不巧的是,我没有能容纳4位数据的纸条,仅有两张可以容纳3位数据的纸条。这样我只能以这种方式告诉你2826这个数据。

两张可以写下3位数据的纸条

200
826

在第一张纸上写上200(段地址),在第二张纸上写上826(偏移地址)。假设我们事前对这种情况又有过相关的约定:你得到这两张纸后,做这样的运算:200(段地址)×10+826(偏移地址)=2826(物理地址)。

8086CPU就是这样一个只能提供两张3位数据纸条的CPU。

段的概念

我们注意到,“段地址”这个名称中包含着“段”的概念。这种说法可能对一些学习者产生了误导,使人误以为内存被划分成了一个一个的段,每一个段有一个段地址。如果我们在一开始形成了这种认识,将影响以后对汇编语言的深入理解和灵活应用。
其实,内存并没有分段,段的划分来自于CPU,由于8086CPU用“基础地址(段地址×16)+偏移地址=物理地址”的方式给出内存单元的物理地址,使得我们可以用分段的方式来管理内存。如图2.9所示,我们可以认为:地址10000H100FFH的内存单元组成一个段,该段的起始地址(基础地址)为10000H,段地址为1000H,大小为100H;我们也可以认为地址10000H1007FH、10080H~100FFH的内存单元组成两个段,它们的起始地址(基础地址)为:10000H和10080H,段地址为:1000H和1008H,大小都为80H。

地址10000H~100FFH的内存单元组成一个段,段地址(Segment)的推导过程。
公式:

{array}{} 10000H = Segment \times 10H +0000H \\ Segment=1000H \end{array}$$ 以后,在编程时可以根据需要,将若干地址连续的内存单元看作一个段,用段地址×16定位段的起始地址(基础地址),用偏移地址定位段中的内存单元。有两点需要注意:段地址×16必然是16的倍数,所以一个段的起始地址也一定是16的倍数:偏移地址为16位,16位地址的寻址能力为64KB,所以一个段的长度最大为64KB。 ## 小结 CPU访问内存单元时,必须向内存提供内存单元的物理地址。 8086CPU在内部用段地址和偏移地址移位相加的方法形成最终的物理地址。 | Physical Address | Segment | Offset | | ---------------- | ------- | ------ | | 21F60H | 2000H | 1F60H | | 21F60H | 2100H | 0F60H | | 21F60H | 21F0H | 0060H | | 21F60H | 21F6H | 0000H | | 21F60H | 1F00H | 2F60H | 结论:CPU可以用不同的段地址和偏移地址形成同一个物理地址。 比如CPU要访问21F60H单元,则它给出的段地址SA和偏移地址EA满足 `SA×16+EA=21F6OH` 即可。 如果给定一个段地址,仅通过变化偏移地址来进行寻址,最多可定位多少个内存单元? 结论:偏移地址16位,变化范围为0 ~ FFFFH,仅用偏移地址来寻址最多可寻64KB个内存单元。 比如给定段地址1000H,用偏移地址寻址,CPU的寻址范围为:10000H ~ 1FFFFH。 “数据在21F60H内存单元中。”这句话对于8086PC机一般不这样讲,取而代之的是两种类似的说法: 1. 数据存在内存2000:1F60单元中; 2. 数据存在内存的2000H段中的1F60H单元中。 这两种描述都表示“数据在内存21F60H单元中”。 --- 给定**段地址**为0001H,仅通过变化偏移地址寻址,CPU的寻址范围为 <u>0010H</u> 到 <u>1000FH</u> 。 > 物理地址=`SA*16+EA` EA的变化范围为0h~FFFFH 物理地址范围为`(SA*16+0H)~(SA*16+FFFFH)` 现在SA=0001h,那么寻址范围为 `(0001H*16+0H)~(0001H*16+FFFFH)` = `0010H ~ 1000FH` 有一数据存放在内存20000H单元中,现给定段地址为SA,若想用偏移地址寻到此单元。则SA应满足的条件是:最小为 <u>1001H</u> ,最大为 <u>2000H </u>。 > 物理地址=`SA*16+EA` `20000H=SA*16+EA` `SA=(20000h-EA)/16=2000H-EA/16` 令SA=y, EA=x,转化为求一元二次函数的极值点问题 `y=(20000h-x)/16=2000H-x/16` ## 段寄存器 我们前面讲到,8086CPU在访问内存时要由相关部件提供内存单元的段地址和偏移地址,送入地址加法器合成物理地址。这里,需要看一下,是什么部件提供段地址。<u>段地址在8086CPU的段寄存器中存放</u>。8086CPU有4个段寄存器:CS、DS、SS、ES。当8086CPU要访问内存时由这4个段寄存器提供内存单元的段地址。本章中只看一下CS。 CS: code [[segment]] 代码段(存放程序指令) DS: data segment 数据段(存放一般数据) SS: stack segment 栈段(存放函数调用返回地址、局部变量等) ES: extra segment 附加段(额外数据段,用于某些特殊的数据操作) ### CS 和 IP CS和IP是8086CPU中两个最关键的寄存器,它们指示了CPU当前要读取指令的地址。 **CS为代码段寄存器**,**IP为指令指针寄存器**,从名称上我们可以看出它们和指令的关系。 IP: Instruction Pointer 在8086PC机中,任意时刻,设CS中的内容为M,IP中的内容为N,8086CPU将从内存 `Mx16+N` 单元开始,读取一条指令并执行。 也可以这样表述:8086机中,任意时刻,CPU将CS:IP指向的内容当作指令执行。 图2.10展示了8086CPU读取、执行指令的工作原理(图中只包括了和所要说明的问题密切相关的部件,图中数字都为十六进制)。 ![[Pasted image 20251026115834.png]] 图2.10 `8086PC` 读取和执行指令的相关部件 1. 8086CPU当前状态:CS中的内容为2000H,IP中的内容为0000H; 2. 内存20000H~20009H单元存放着可执行的机器码; 3. 内存20000H~20009H单元中存放的机器码对应的汇编指令如下。 地址:20000H~20002H,内容:B8 23 01,长度:3Byte,对应汇编指令:mov ax, 0123H 地址:20003H~20005H,内容:BB 03 00,长度:3Byte,对应汇编指令:mov bx, 0003H 地址:20006H~20007H,内容:89D8,长度:2Byte,对应汇编指令:mov ax, bx 地址:20008H~20009H,内容:01D8,长度:2Byte,对应汇编指令:add ax, bx 下面的一组图(图2.11~图2.19),以图2.10描述的情况为初始状态,展示了8086CPU读取、执行一条指令的过程。注意每幅图中发生的变化(下面对8086CPU的描述,是在逻辑结构、宏观过程的层面上进行的,目的是使读者对CPU工作原理有一个清晰、直观的认识,为汇编语言的学习打下基础。其中隐蔽了CPU的物理结构以及具体的工作细节)。 ![[Pasted image 20251026115834.png]] 图2.11初始状态(CS:2000H,IP:0000H,CPU将从内存2000H×16+0000H处读取指令执行) ![[Pasted image 20251026120307.png]] 图2.12CS、P中的内容送入地址加法器(地址加法器完成:物理地址=段地址×16+偏移地址) ![[Pasted image 20251026120337.png]] 图2.13地址加法器将物理地址送入输入输出控制电路 ![[Pasted image 20251026120410.png]] 输入输出控制电路将物理地址20000H送上**地址总线** ![[Pasted image 20251026120435.png]] 图2.15从内存20000H单元开始存放的机器指令 B8 23 01 通过**数据总线**被送入CPU ![[Pasted image 20251026120510.png]] 图2.16输入输出控制电路将机器指令B82301送入**指令缓冲器** ![[Pasted image 20251026120535.png]] 图2.17 `IP` 中的值自动增加 (读取一条指令后,P中的值自动增加,以使CPU可以读取下一条指令。因当前读入的指令B82301长度为3个字节,所以P中的值加3。此时,CS:IP指向内存单元2000:0003。) ![[Pasted image 20251026120746.png]] 图2.18 **执行控制器**执行*指令*B8 23 01(即`mov ax,0123H`) ![[Pasted image 20251026120823.png]] 图2.19指令B8 23 01被执行后AX中的内容为0123H(此时,CPU将从内存单元2000:0003处读取指令。) 下面的一组图(图2.20~图2.26),以图2.19的情况为初始状态,展示了8086CPU继续读取、执行3条指令的过程。注意IP的变化(下面的描述中,**隐蔽了读取每条指令的细节**)。 ![[Pasted image 20251026121704.png]] 图2.20 CS:2000H, IP:0003H(CPU将从内存2000H×16+0003H处读取指令BB 03 00) ![[Pasted image 20251026121747.png]] 图2.21 CPU从内存20003H处读取指令BB 03 00入指令缓冲器(IP中的值加3) ![[Pasted image 20251026121821.png]] 图2.22执行指令BB 03 00(即mov bx,0003H) ![[Pasted image 20251026121901.png]] 图2.23 CPU从内存20006H处读取指令89 D8入指令缓冲器(IP中的值加2) ![[Pasted image 20251026121938.png]] 图2.24执行指令89D8(即mov ax, bx)后,AX中的内容为0003H ![[Pasted image 20251026122004.png]] 图2.25 CPU从内存20008H处读取指令01D8入指令缓冲器(IP中的值加2) ![[Pasted image 20251026122031.png]] 图2.26 执行指令01 D8(即add ax, bx)后,AX中的内容为0006H 通过上面的过程展示,8086CPU的工作过程可以简要描述如下。 1. 从CS:IP指向的内存单元读取指令,读取的指令进入指令缓冲器; 2. IP=IP+所读取指令的长度,从而指向下一条指令; 3. 执行指令。转到步骤(1),重复这个过程。 在8086CPU 加电启动或复位后(即CPU刚开始工作时)CS和IP被设置为 CS=FFFFH,IP=0000H,即在8086PC机刚启动时,CPU从内存FFFFOH单元中读取指令执行,FFFF0H单元中的指令是8086PC机开机后执行的第一条指令。 现在,我们更清楚了CS和P的重要性,它们的内容提供了CPU要执行指令的地址。 我们在第1章中讲过,在内存中,指令和数据没有任何区别,都是二进制信息,CPU在工作的时候把有的信息看作指令,有的信息看作数据。现在,如果提出一个问题:CPU根据什么将内存中的信息看作指令?如何回答?我们可以说,CPU将CS:IP指向的内存单元中的内容看作指令,因为,在任何时候,CPU将CS、IP中的内容当作指令的段地址和偏移地址,用它们合成指令的物理地址,到内存中读取指令码,执行。如果说,内存中的一段信息曾被CPU执行过的话,那么,它所在的内存单元必然被CS:IP指向过。 ### 修改CS、IP的指令 在CPU中,程序员能够用指令读写的部件只有寄存器,程序员可以通过改变寄存器中的内容实现对CPU的控制。CPU从何处执行指令是由CS、IP中的内容决定的,程序员可以通过改变CS、IP中的内容来控制CPU执行目标指令。 我们如何改变CS、P的值呢?显然,8086CPU必须提供相应的指令。我们如何修改AX中的值?可以用mov指令,如mov ax,l23将ax中的值设为123,显然,我们也可以用同样的方法设置其他寄存器的值,如mov bx,123,mov cx,123,mov dx,123等。其实,8086CPU大部分寄存器的值,都可以用mov指令来改变,**mov指令**被称为**传送指令**。 但是,**mov指令不能用于设置CS、IP的值**,原因很简单,因为8086CPU没有提供这样的功能。8086CPU为CS、IP提供了另外的指令来改变它们的值。能够改变CS、IP的内容的指令被统称为转移指令(我们以后会深入研究)。我们现在介绍一个最简单的可以修改CS、P的指令:<span class="text-highlight">jmp指令</span>。 若想同时修改CS、P的内容,可用形如“jmp段地址:偏移地址”的指令完成,如 `jmp `2AE3:3,执行后:CS=2AE3H,IP=O003H,CPU将从2AE33H处读取指令。 `jmp `3:0B16,执行后:CS=0003H,IP=0B16H,CPU将从00B46H处读取指令。

\begin{array}{l}
0003H \times 10H=00030H\
00030H+0B16H=00B46H
\end{array}