DS:内存段地址寄存器
段地址、偏移地址与物理地址
-
内存中数据的地址由段地址和偏移地址组成,其中段地址乘以16再加上偏移地址就是真实的物理地址。
对于16进制的数来说,乘以十六就是整体向左移一位,例如:0xFE * 16 = 0xFE0
-
物理地址可以由多种段地址+偏移地址组合而成
例如物理地址:0x21F60都可以由下面段地址+偏移地址表示
段地址 偏移地址 0x2000 0x1F60 0x2100 0x0F60 0x21F0 0x0060 0x21F6 0x0000 0x1F00 0x2F60
操作DS
读写内存与DS寄存器的关系
读写内存中的数据需要知道该内存的地址,而地址是段地址+偏移地址组成的,其中段地址在ds寄存器中,偏移地址由手动指定。
我们指定偏移地址后,程序自动在ds中取出段地址,与我们指定的偏移地址组成实际的物理地址,从而操作该地址的数据。
所以在访问内存的数据前,要先设置ds段地址寄存器,再手动指定偏移地址
设置DS寄存器的注意事项
在8086CPU中,ds不支持直接将立即数放到ds中,要用另一个寄存器传输数据
mov bs,21f6 // 不支持这样写
mov ax,21f6 // 把段地址先写入另一个寄存器
mov ds,ax // 再通过寄存器与寄存器传输数据的方式为ds传输数据
示例:操作0x21F60处的数据
mov ax,21f6
mov ds,ax // 设置段地址为0x21f6
mov ax,[0] // 设置偏移地址为0x0000,对应的物理地址为:0x21F60。并将该地址的值复制到ax中
add al,[0] // 0x21f60处的值加上al中的值,结果放到al中
mov [0],bl // 把bl的值复制到0x21f60
add [0],bh // bh加上0x21f60处的值,结果放到0x21f60
CS-IP:代码地址寄存器
作用:CS存的是段地址,IP存的是偏移地址,代码从这两个寄存器指向的地址开始运行
示例:在地址:0x20000处写代码,并改变CS-IP寄存器,从0x20000处开始运行代码
JMP指令:在代码中改变程序运行的位置
示例:
-
在代码中改变程序运行的位置为:0x20000(CS和IP一起改变)
jmp 2000:0000 // cs设置为0x2000,IP设置为0x0000
-
只改变IP
jmp 3 // 只设置IP为0x0003,CS不变
利用JMP指令写一个死循环
使用a 2000:0
指令将代码写在地址0x20000处
在运行代码前将CS-IP设置为:2000:0000。
mov ax,00
inc ax
mov bx,ax
jmp 3
SS-SP:栈顶地址寄存器
栈的概念
先进后出
入栈:
出栈:
栈顶元素的地址
CPU要进行入栈和出栈的操作,就需要知道栈顶元素的地址,而SS-SP寄存器存放的就是栈顶元素的地址,其中SS为段地址,SP为偏移地址
设置SS-SP寄存器就是设置栈顶的地址
示例:设置栈顶地址为:0x10010
mov ax,1000
mov bx,0010
mov ss,ax // 设置栈顶地址的段地址
mov sp,bx // 设置栈顶地址的偏移地址
PUSH指令:入栈
注意:
-
入栈时,栈顶从高地址向低地址增长
-
栈操作都是以字为单位的,也就是16位数据
-
每一次入栈SP都会减2,因为栈空间是16位的
-
入栈时,高位先入栈,低位后入
-
如果想将地址:0x10000~0x1000F作为栈空间,那么栈顶地址要设置为:0x10010。也就是栈顶地址比栈的起始地址大一,如下图
示例:
// 设置栈顶地址
mov ax,1000
mov bx,0010
mov ss,ax // 设置栈顶地址的段地址
mov sp,bx // 设置栈顶地址的偏移地址
// 入栈
mov ax,0123
mov bx,2266
mov cx,1122
push ax // 将ax中的值放到栈顶
push bx // 将bx的值放到栈顶
push cx // 将cx的值放到栈顶
使用d 1000:0000 F
命令查看地址0x10000~0x1000F之间的数据
POP指令:出栈
沿用上面入栈代码运行后的栈空间、栈空间中的元素及栈顶地址
注意:
- 每一次出栈SP都会加2
- 栈操作都是以字为单位的,也就是16位数据
示例:
pop ax // 取出栈顶的元素放到ax中
pop bx // 取出栈顶的元素放到bx中
pop cx // 取出栈顶的元素放到cx中
出栈入栈完整示意图
栈顶越界
8060没有记录栈顶上限和栈底的寄存器,需要我们使用时自己注意不要让栈越界
SI、DI、BX、BP:寻址
BX作为偏移地址
bx中的值也可以表示为偏移地址,如下
mov ax,1000
mov ds,ax // 设置段地址为1000
mov bx,0010
mov ax,[bx] // 把bx中的值当偏移地址,也就是将地址0x10010的值复制到ax中
mov cx,[bx+2] // 把bx中的值加2后当做偏移地址
mov cx,[bx-5] // 把bx中的值减5后当做偏移地址
注意:bx为偏移地址时,他的段地址在DS寄存器中
BP与BX的区别
BP与BX一样,都是作为偏移地址,也可以加减立即数
- 只不过BX作为偏移地址时,段地址是DS寄存器中的值;
- 而BP作为偏移地址时,段地址是SS寄存器中的值。也就是说BP操作的是栈
示例:
-
设置DS为:0x3000,SS为:0x1000
-
运行如下代码
mov ax,1234 mov cx,6789 mov bp,0000 mov bx,0000 mov [bp],ax // 将ax的值放到地址0x10000处 mov [bx],cx // 将cx的值放到地址0x30000处
-
验证结果
SI、DI与BX、BP
SI和DI有这与BX一模一样的作用和写法,可以单独使用,也可以加减立即数,默认段地址也是DS寄存器
与BX不同的是SI、DI可以单独与BX或BP相加,如下
mov ax,[si]
mov ax,[si+1]
mov ax,[di]
mov ax,[di+2]
mov ax,[bx+si]
mov ax,[bx+di]
mov ax,[bx+si+2]
mov ax,[bx+di+3]
// si或bi与bp相加后,默认段地址会变成ss
mov ax,[bp+si]
mov ax,[bp+di]
mov ax,[bp+si+1]
mov ax,[bp+di+4]
注意:si和di不能同时出现,以下写法都是错误的
mov ax,[si+bi] // 错误的
mov ax,[bx+si+bi] // 错误的
mov ax,[bp+si+bi] // 错误的
寻址总结
其中:EA表示偏移地址;SA表示段地址;idata表示立即数
[bx].idata = [bx+idata]
idata[si] = [si+idata]
idata[di] = [di+idata]
[bx][idata] = [bx+idata]
[bx][si] = [bx+si]
[bx].idata[si] = [bx+idata+si]
idata[bx][si] = [bx+si+idata]
标志寄存器
概述
标志位寄存器在debug中的表现
标志位寄存器 | 值为1时的表现 | 值为0时的表现 |
---|---|---|
OF | OV | NV |
SF | NG | PL |
ZF | ZR | NZ |
PF | PE | PO |
CF | CY | NC |
DF | DN | UP |
ZF:零标志位
作用:记录相关指令执行后,其结果是否为0。如果结果为0,那么zf = 1;如果结果不为0,那么zf = 0
示例:
mov ax,1 // 设置ax的值为1
dec ax // ax自减1
inc ax // ax自增1
PF:奇偶校验位
作用:相关指令执行后,其结果的所有位中1的个数是否为偶数。如果1的个数为偶数,pf=1;如果为奇数,那么pf=0。
示例:
mov ax,0 // 设置ax的值为0
inc ax // 结果为:0x01,1的位数为奇数
dec ax // 结果为:0x00,1的位数为偶数
SF:符号标志位
作用:记录相关指令执行后,其结果是否为负。如果结果为负,sf=1;如果非负,sf=0
计算机中表示正负数:
-
最高位为0,表示这个数是正数。直接转化为十进制就是结果
-
最高位为1,表示这个数是负数。对他按位取反后加一(也就是求补),转化为十进制后再加上负号就是结果
-
对于同一个二进制,计算机可以将他当做无符号数据,也可以当做有符号数据
例如:
00000001B,可以看作为无符号数1,或有符号数+1
10000001B,可以看作为无符号数129,也可以看作有符号数-127.
总结:SF标志,就是CPU对有符号数运算结果的一种记录,它记录数据的正负。在我们将数据当作有符号数来运算的时候,可以通过它来得知结果的正负。如果我们将数据当作无符号数来运算,SF的值则没有意义,虽然相关的指令影响了它的值。
示例:
mov al,3
sub al,5 // 3-5 = -2为负数
add al,10 // -2+16 = 14为正数
CF:进位标志位
作用:一般情况下,在进行无符号数运算的时候,它记录了运算结果的最高有效位向更高位的进位值,或从更高位的借位值。
示例:
-
进位
mov al,ff mov bl,22 add al,bl // al+bl = 0x121,发生了进位
-
借位
mov al,01 mov bl,02 sub al,bl
OF:溢出标志位
溢出的概念:在进行有符号数运算的时候,如结果超过了机器所能表示的范围称为溢出。
例如:两个八位数98和99相加,其结果为197,显然该结果超过了8位有符号数可以表示的范围:-128~127。这就是相加溢出。相减的溢出也是同理
如果在进行有符号数运算时发生了溢出,那么结果将不正确,如下:
98+99=197=0xC5。0xC5在计算机中用有符号数表示为-59,这结果显然是错误的
作用:由于在进行有符号数运算时,可能发生溢出而造成结果的错误。则CPU需要对指令执行后是否产生溢出进行记录。因此有了溢出标志位。一般情况下,OF记录了有符号数运算的结果是否发生了溢出。如果发生溢出,OF=1;如果没有,OF=0。
示例:
-
相加溢出
mov al,62 // 正数98 mov bl,63 // 正数99 add al,bl // 0x62+0x63=0xC5;98+00=-59,发生了溢出
-
相减溢出
mov al,f0 // -16的补码 mov bl,78 // 正数120 sub al,bl // 0xf0-0x78=0x78;-16-120=120,这结果明显不对,发生溢出
进位和溢出标志位的区别
CF和OF所表示的进位和溢出,是分别对无符号数和有符号数运算而言的,它们之间没有任何关系。
基于标志位的运算
ADC指令:带进位的加法
作用:用来计算很大的数据
示例:
-
计算:0x1EF000 + 0x201000,结果放到ax(高16位)和bx(低16位)中
这两个数据都大于16位,用add指令无法直接计算。
所以要将计算分为两步,先将低16位相加,然后再将高16位及进位值相加,如下
mov ax,001e // 将0x1EF000 的高位放到ax中 mov bx,f000 // 将0x1EF000 的低位放到bx中 add bx,1000 // 用add指令将低16位相加,他们产生的进位会记录到cf中 adc ax,0020 // 用adc指令将高16位及进位值相加
adc指令执行后也可能会进位,也可以对cf进行设置。这样,我们就可以对任意大的数进行相加
-
计算:0x1EF0001000 + 0x2010001EF0,结果放在ax(最高16位),bx(次高16位),cx(低 16 位)中。
mov ax,001e mov bx,f000 mov cx,1000 add cx,1ef0 // 先将低16位相加,完成后,CF中记录本次相加的进位值 adc bx,1000 // 再将次高16位和CF(来自低16位的进位值)相加,完成后,CF中记录本次相加的进位值 adc ax,0020 // 最后高16位和CF(来自次高16位的进位值)相加,完成后,CF中记录本次相加的进位值
使用计算机验证:
SDD指令:带借位的减法
作用:用来计算很大的数据
示例:计算:0x003E1000 - 0x00202000,结果放到ax和bx中
mov ax,003e
mov bx,1000
sub bx,2000
sbb ax,0020
使用计算机验证
CMP指令:比较指令
作用:比较两个数的大小。本质上cmp的功能相当于减法指令,只是不保存结果,cmp指令执行后,将对标志位寄存器产生影响。其他指令通过识别这些被影响的寄存器位来得知比较结果
-
无符号数比较
假设要比较的两个数存放在ax和bx中,执行指令:
cmp ax,bx
结果 标志位 描述 ax = bx zf = 1 计算结果为0 ax != bx zf = 0 计算结果不为0 ax < bx cf = 1 计算结果产生借位 ax >= bx cf = 0 计算结果没有借位 ax > bx cf = 0 且 zf = 0 计算结果没有借位且不为0 ax <= bx cf = 1 或 zf = 1 计算结果产生借位或结果为0 -
有符号数比较
结果 标志位 ax = bx zf = 1 ax != bx zf = 0 ax < bx (sf = 1且 of = 0) 或 (sf = 0 且 of = 1) ax > bx sf = 1且 of = 1 ax >= bx sf = 0 且 of = 0 ax <= bx (sf = 1且 of = 0 或 zf = 1) 或 (sf = 0 且 of = 1或 zf = 1) 逻辑如下:
检测比较结果的条件转移指令
转移指的是能修改IP寄存器,而条件指的是可以根据某种条件,决定是否修改IP
示例:
如果ah = bh,则ah = ah+ah,否则ah = ah+bh
cmp ah,bh
je s // 判断ah是否等于bh,如果等于,则跳转到标号s处执行指令
add ah,bh // 如果不是,则执行该指令
jmp short ok // 跳转到ok处执行指令
s:add ah,ah
ok:...
其他指令同上
汇编语言寄存器的英文全称中文对照表
16位寄存器
寄存器 | 英文全称 | 中文描述 |
---|---|---|
AX(AL&AH) | accumulator | 累加寄存器 |
BX(BL&BH) | base | 基址寄存器 |
CX(CL&CH) | count | 计数寄存器 |
DX(DL&DH) | data | 数据寄存器 |
SP | stack pointer | 堆栈指针寄存器 |
BP | base pointer | 基址指针寄存器 |
SI | source index | 源变址寄存器 |
DI | destination index | 目的变址寄存器 |
IP | instruction pointer | 指令指针寄存器 |
CS | code segment | 代码段寄存器 |
DS | data segment | 数据段寄存器 |
SS | stack segment | 堆栈段寄存器 |
ES | extra segment | 附加段寄存器 |
标志位寄存器
寄存器 | 英文全称 | 中文描述 |
---|---|---|
OF | overflow flag | 溢出标志位。溢出时为1 |
SF | sign flag | 符号标志位。为负时为1 |
ZF | zero flag | 零标志位。为0时为1 |
CF | carry flag | 进位标志位。进位或借位时为1 |
AF | auxiliary carry flag | 辅助进位标志位。第三位向第四位进位时为1 |
PF | parity flag | 奇偶标志位。1的位数为偶数时为1 |
DF | direction flag | 方向标志位。DF为1时,操作后使SI和DI减小,反之则增大 |
IF | interrupt falg | 中断标志位。为1时允许响应中断 |
TF | trap flag | 陷阱标志位。用于调试单步模式 |