千哥读书笔记:汇编语言(王爽第四版)第11章标志寄存器

本章的内容相对简单,但需要学习的知识点很多,也需要我们耐心去学习和理解一些细节内容。

不过,既然是做读书笔记,那只需要记录一下重点需要理解和记忆的内容,有些知识点原书上就有,可以一笔带过。

标志寄存器,说的是一种特殊的寄存器,它可以实现的功能是:

1、用来存储相关指令的某些执行结果。

2、用来为CPU执行相关指令提供行为依据。

3、用来控制CPU的相关工作方式。

这种寄存器称为“标志寄存器”,其中存储的信息通常被称为程序状态字(PSW)。而PSW,也就是Program status word的缩写。

但王爽老师的书中,有很多看似不太重要、但对理解和记忆有帮助的信息却没有讲出来。

比如这个“标志寄存器”,英文名叫作Flags Register,而其存储的信息称为PSW,但这一点却没有介绍清楚,往往导致初学者误认为“标志寄存器”就是PSW。

在8086CPU中标志寄存器有16位,其结构如下图所示:

从右到左,标志寄存器(FLAG)的第0、2、4、6、7、8、9、10、11位具有特殊的含义,一共9个标志位。

而在本章,一共介绍了CF、PF、ZF、SF、OF、DF 6个标志位的具体用法,并且介绍了与之相关的adc、sbb、cmp,以及串传送指令(movsb、movsw)、pushf、popf等指令。

在8086CPU的指令集中,有的指令执行是影响标志寄存器的,比如:add、sub、mul、div、inc、or、and 等。

有些指令对标志寄存器没有影响,比如:mov、push、pop等。

一、ZF标志(zero flag)

ZF位于FLAG寄存器第6位,英文全称是zero flag。它记录相关指令执行后,如果结果为0,那么ZF=1;如果结果不为0,那么ZF=0。

例如:

mov ax,1

and ax,0

执行后,结果为0,则ZF=1,表示结果为0。以此类推。

二、PF标志(parity flag)

PF位于FLAG寄存器第2位,英文全称是parity flag。parity的就是“奇偶校验”的意思,从字面意义上讲,是在相关指令执行后,CPU将判断其结果的所有bit位中1的个数是否为偶数。如果1的个数为偶数,PF=1;如果为奇数,那么PF=0。

例如:

mov al,1

add al,10

执行后,结果为00001011B,其中1的个数为3个(奇数),则PF=0。以此类推。

三、SF标志(sign flag)

SF位于FLAG寄存器第7位,英文全称是sign flag,也就是符号标志的意思,以此判断数据是有符号,还是无符号的。

对于二进制数据,计算机既可以将它当作无符号的数据来运算,也可以当作有符号的数据来运算,比如:

00000001B,可以看作无符号数1,也可以看作有符号数+1

10000001B,可以看作无符号数129,也可以看作有符号数-127

为什么10000001B可以看作有符号数-127呢?这就涉及计算机补码的知识。

计算机中的整数数据分成有符号数和无符号数。无符号数是用所有的数据位表示数值,有符号数则是用最高位表示数据的正负性,其余位表示数值。

例如:

对于八位数无符号数,所有8位均是数据位,编码 00000000~11111111 表示0~255。

而八位有符号数,从右到左其最高位代表符号,其他7位表示数据。最高位的符号位是0代表正数,是1代表负数。

对于有符号数,当最高位为 0 时,代表正数,低 7位就是这个正数的编码,如0111 1111 。最高位1 表示负数,低 7位111 1111 表示其数值 127,而最高位和低7位联合起来,1111 1111 表示-1。

而每一个代表正数的二进制数据,按位取反后加1后得到的二进制数据,也就是补码,代表这个正数相对应的负数。

比如有符号数127,其二进制为:01111111,此时SF=0。按位取反后,就是1000000,再加1,就是10000001。10000001就是-127的补码,而此时SF=1。

对于有符号的十进制数,转化为二进制数的方式是:

1、如果是正数,保持十进制数不变,直接转化为二进制数。

2、如果是负数,首先将负数采取绝对值操作,转化为正数,然后转化为二制数;接下来,将这个二进制数,按位取反加1,就得到了负数的二进制数。这个二进制数,就是负数的补码。

需注意的是:

1、正数的补码和原码相同,而负数的补码是在相对应的正数的反码的末位加1。

2、如果将数据当作无符号数来运算,SF的值无意义。

3、如果指令进行的是有符号数运算,如果SF=1,那么结果为负。

4、如果指令进行的是有符号数运算,如果SF=0,那么结果为非负。

例如:

mov al,10000001B

add al,1

执行后,结果为10000010B。此时,SF=1,表示:如果指令进行的是有符号数运算,结果为负。以此类推。

需注意的是:

某些指令将影响标志寄存器中的多个标志位。比如指令sub al,al执行后,ZF、PF、SF等标志位都要受到影响,它们分别是:1、1、0

四、CF标志(carry flag)

CF位于FLAG寄存器第0位,英文全称是carry flag。carry就是“进位”的意思。

需注意的是:

1、CF标志仅用于无符号数的运算。

2、在进行无符号数运算的时候,记录了运算结果的最高有效位向更高位的进位值,或者从更高位借位值。

3、对于位数为N的无符号数来说,其对应的二进制信息的最高位,即第N-1位,就是它的最高有效位。

比如,有一个8位的无符号二进制数据:00011100

从右到左第0位到第7位都是代表数值(无符号),最高有效位是第7位。如果在运算的过程中,向假想的更高位产生了进位,或者产生了借位,那么CF=1。

比如产生进位的例子:

mov al,98H

add al,al;执行后:(al)=30H,CF=1,CF记录了从最高有效位向更高位的进位值

add al,al;执行后:(al)=60H,CF=0,CE记录了从最高有效位向更高位的进位值

这是原书第216页的描述。现在用二进制演算一下,以帮助理解:

1、无符号数98H,对应的二进制是:10011000,当执行第一个add al,al之后:98H+98H = 100110000。此时结果已由8位二进制数据,进位成了9位二进制数据。从右到左,最高位为1,而高位1后面的00110000,就是16进制数30H,而CF则记录了最高位的1。所以,结果为30H,CF=1。

2、无符号数30H,对应的二进制是:00110000,当执行第二个add a,al之后:

30H+30H = 01100000,此时结果仍然是8位二进制数据,没有产生进位,所以CF=0。

又比如产生借位的例子:

mov al,97H

sub al,98H;执行后:(al)=FFH,CF=1,CF 记录了向更高位的借位值;

sub al,al;执行后:(al)=0,CF=0,CF 记录了向更高位的借位值

用二进制演算一下,以帮助理解:

1、无符号数97H,对应的二进制是10010111;无符号数98H,对应的二进制是10011000。在执行sub al,98H时,10010111(97H)减去10011000(98H),10011000(97H)需要向假想的更高位借一个1,构成110010111,也就是197H,才能完成对10011000(98H)的减法运算。此时,CF=1。

2、在执行sub al,al时,其结果为0,既不产生进位,也不产生借位,故CF=0。

五、OF标志(overflow flag)

OF位于FLAG寄存器第11位,英文全称是overflow flag。overflow就是“溢出”的意思。当进行有符号运算时,计算结果产生了溢出,就会影响到OF标志。

对于8位有符号数据,机器所能表示的范围就是-128~127;对于16位有符号数据,机器所能表示的范围是-32768~32767,如果运算结果超出了机器所能表达的范围,将产生溢出。

下面,来分析一下原书217页所给出的两个例子。

例1:

mov al,98

add,al,99

对于有符号运算,执行后将产生溢出。

1、十进制98,对应的二进制是01100010;十进制99,对应的二进制是01100011。

2、98+99=197,对应的二进制是11000101,而11000101则代表了有符号数-59。因为59的二进制是00111011,按位取反加1后就是11000101,这也就是-59的补码。

因此,在有符号运算过程中,98+99不是等于197,而是等于-59。这样的结果让人无法接受,其原因,就是实际的结果197超出了8位有符号数的范围:-128~127,在8位寄存器al中存放不下,产生了溢出。

在这个例子中,对于无符号运算,98+99没有进位,CF=0;而对于有符号运算,98+99发生了溢出,OF=1。

例2:

mov al,0F0H;0F0H,为有符号数-16 的补码

add al,088H;88H,为有符号数-120的补码

对于有符号运算,执行后将产生溢出。

1、16进制0F0H,对应的二进制是11110000,其原码就是按位取反加1,也就是00010000,对应的十进制是16。也就是说,作为有符号数F0H代表的就是-16。

2、16进制88H,对应的二进制是10001000,其原码就是按位取反加1,也就是01111000,对应的十进制是120,也就是说,作为有符号数88H,代表的是-120。

3、0F0H和88H通过add指令运算,假想中按照人的十进制运算规则:-16+(-120),结果应该是-136,而-136的补码,也就是136(二进制10001000)按位取反加1,也就是01111000,对应的十进制是120,也就是16进制78H。也就是说,这个结果作为有符号数,代表的是120。

因此,在有符号运算过程中,0F0H+88H不是等于-136,而是等于120。显然,这样的结果也是无法让人接受的。

其原因,就是实际的结果-136,超出了8位有符号数的范围:-128~127,在8位寄存器al中存放不下,产生了溢出。

需注意的是:

1、对于无符号运算,0F0H+88H有进位,即11110000+10001000= 101111000,CF=1。

2、对于有符号运算,0F0H+88H发生溢出(结果为-136,超出了机器对于8位有符号数据的表达范围-128~127),OF=1。

结合前面学习的CF标志,需注意的是:

1、OF是对有符号运算有意义的标志位。

3、对于有符号数运算,CPU用OF来记录是否产生了溢出,还要用SF位来记录结果的符号。

2、CF是对无符号运算有意义的标志位。

4、对于无符号数运算,CPU用CF来记录是否产生了进位。

5、CF和OF所表示的进位和溢出,分别对应了无符号数和有符号数运算,它们之间没有任何关系。

那么,CPU是如何判断在计算中,是进行无符号运算还是有符号运算的呢?

答案是,CPU本身并不作区分。也就是说,一个数字在计算的时候,既可以作为无符号数处理,也可以作为有符号数处理。关键在于程序员如何去看待结果:

1、CPU的运算结果将同时影响进位标志CF与溢出标志OF。

2、如果程序员认为这是无符号数运算,则只考虑进位标志CF,而忽略溢出标志OF。

3、反之,如果程序员认为这是有符号数运算,则只考虑溢出标志OF,而忽略进位标志CF。

六、ADC指令

adc是带进位加法指令,它利用了CF位上记录的进位值。

指令格式:adc 操作对象1,操作对象2

功能:操作对象1=操作对象1+操作对象2+CF

比如指令 adc ax,bx 实现的功能是:(ax)=(ax)+(bx)+ CF

例如:

mov ax,2

mov bx,1

sub bx,ax

adc ax,1

执行后,(ax)=4。在第三步,sub bx,ax中,由于bx的值小于ax,因此需要产生借位,使CF=1。

故在第四步时,adc ax,1,就相当于计算:(ax)+1+CF=2+1+1=4。

又例如:

mov al,98H

add al,al

adc al,3

执行后,(ax)=34H。

1、98H对应的二进制是10011000,在执行add al,al之后,其结果为100110000,这是一个9位的二进制,产生了进位,CF=1。

2、其结果100110000,在8位的寄存器AL,其有效位是00110000,对应的16进制就是30H。

3、在执行adc al,3时,相当于计算(ax)+1+CF=30H+3+1=34H。

简单地说,adc指令比add指令多加了一个CF位的值。那为什么要用到adc这个指令呢?因为用adc指令,可以进行更大位数的相加。

原书第220页提供了这样一个例子:用两个16位寄存器AX和BX进行198H+183H的运算:

在王爽老师的讲解中:“可以看出,加法可以分两步来进行:①低位相加;②高位相加再加上低位相加产生的进位值”,其实列出的竖式并没有很好解释这个原理。下面,通过二进制演算逐一讲解:

1、AX中保存的16进制198H,对应的二进制是00000001 10011000;其低8位是10011000,高8位则是00000001。

2、BX中保存的16进制183H,对应的二进制是00000001 10000011;其低8位是10000011,高8位则是00000001 。

3、当进行add,al,bl时,即10011000+10000011 = 0001 00011011,此时al的结果,是 00011011,也就是16进制1B,并且产生了一个进位值0001,故CF=1。

3、当进行adc ah,bh时,先进行ah+bh运算,即00000001+00000001 = 00000010,再加上CF的值1,其结果就等于 00000011(也就是16进制03)。

4、运算结束,AL=00011011,AH=00000011,两个8位寄存器联合起来就是00000011 00011011。也就是最终的结果,16进制的031B。

有这个分析,就不难理解后面的例子:

1、这两个数的低16位,分别是1000H和1EF0H。

2、这两个数的次高16位,分别是F000H和1000H。

3、这两个数的最后高16位,分别是1EH和20H。

因此,后面的代码就是:

mov ax,001EH

mov bx,0F000H

mov cx,1000H

add cx,1EF0H

adc bx,1000H

adc ax,0020H

这段代码,后面连用了2个adc运算,最终实现了1EF0001000H和2010001EF0H这样两个大数的相加。

七、SBB指令

sbb 是带借位减法指令,它利用了 CF 位上记录的借位值。

指令格式:sbb 操作对象1,操作对象2

功能:操作对象1=操作对象1-操作对象 2-CF

比如指令 sbb ax,bx 实现的功能是:(ax)=(ax)-(bx)-CF

有了对adc指令的理解,sbb指令也就很容易理解。

例如,计算003E1000H-00202000H:

mov bx,1000H

mov ax,003EH

sub bx,2000H

sbb ax,0020H

1、先通过sub bx,2000H,将两个数的低位1000H和2000H相减,产生CF的借位值1。

2、再通过sbb ax,0020H,将两个数的高位003EH和0020H相减,再减去CF的值1。

八、CMP指令

cmp 是比较指令,cmp 的功能相当于减法指令,只是不保存结果。cmp指令执行后,将对标志寄存器产生影响。其他相关指令通过识别这些被影响的标志寄存器位来得知比较结果。

cmp 指令格式:cmp 操作对象1,操作对象2

功能:计算操作对象1-操作对象2,但并不保存结果,仅仅根据计算结果对标志寄存器进行设置。

比如,指令 cmp ax,ax,做(ax)-(ax)的运算,结果为 0,但并不在 ax 中保存,仅影响flag 的相关各位。指令执行后:zf=1,pf=1,sf=0,cf=0,of=0。

这里需注意的是:结果为0,也就意味着所有bit位中1的个数也为0,而0在数学中是定义为偶数的,所以PF值为1。

此外,原书第223页,介绍了执行cmp ax,bx后,相关标志位的值:

反之,指令 cmp ax,bx 的逻辑含义是比较 ax 和 bx 中的值,如果执行后:

需注意的是:

同 add、sub 指令一样,CPU 在执行 cmp 指令的时候,也包含两种含义:进行无符号数运算和进行有符号数运算。所以利用cmp指令可以对无符号数进行比较,也可以对有符号数进行比较。

1、如果比较的是两个无符号数

如下表格所示:

执行cmp指令

ZF值

CF值

目的操作数 < 源操作数

0

1

目的操作数 > 源操作数

0

0

目的操作数 = 源操作数

1

0

这个表格理解起来相对简单:

1)当目的操作数小于源操作数时,由于两数不相等,结果不为0,故ZF为0;并且由于产生了借位,故CF值为1

2)当目的操作数大于源操作数时,由于两数不相等,结果不为0,故ZF为0;并且没有产生借位,故CF值为0

3)当目的操作数等于源操作数时,由于两数相等,结果为0,故ZF为1;并且没有产生借位,故CF值为0。

2、如果比较的是两个有符号数

原书的通篇解释比较复杂,但经过理解,归纳一下:

1)当目的操作数 < 源操作数时的情况有:

① SF = 1 且 OF = 0

② SF = 0 且 OF = 1

2)目的操作数 > 源操作数时的情况有:

① SF = 1 且 OF = 1

② SF = 0 且 OF = 0

3)目的操作数 = 源操作数时的情况:

SF = 0 且 OF = 0

但其实只要关注SF、OF的关系与ZF的值,就可以简化理解。如下表格所示:

执行cmp指令

相关标志位的关系

目的操作数 < 源操作数

SF ≠ OF

目的操作数 > 源操作数

SF = OF

目的操作数 = 源操作数

ZF = 1

也就是说:

1)当目的操作数小于源操作数时,SF和OF不相等

2)当目的操作数大于源操作数时,SF等于OF(都为1或0)

3)当目的操作数等于源操作数时,由于两数相等,结果为0,故ZF为1。

cmp指令主要用于,根据比较结果配合一些条件转移指令:

cmp指令可以同时对无符号数比较和有符号数的比较,然后根据相应的结果进行条件转移。

在原书中,只是重点介绍了无符号数的比较结果导致的条件转移,而根据有符号数的比较结果进行条件转移,原书一笔带过,因为基本原理相同,只是后者检测了不同的标志位:

1、根据无符号数的比较结果进行条件转移,CPU检测ZF、CF的值。

2、根据有符号数的比较结果进行条件转移,CPU检测SF、OF和ZF的值。

这两点,笔记前面的两个表格有详细说明。

而对于je、jne等条件转移的含义,原书也有更详细的说明:

而在原书第227页中,重点以je指令为例,介绍了这些转移指令的工作原理。

比如,je指令检测的是ZF的位置,不管je指令前面是什么指令,只要CPU执行je指令之前ZF=1,那么就会发生转移:

mov ax,0

add ax,0

je s

inc ax

S:inc ax

执行后,(ax)=1。add ax,0 使得 zf-1。

需注意的是:

1、je指令将进行转移。此处的 je指令检测到的 ZF=1,不是由 cmp等比较指令设置的,而是由 add 指令设置的,并不具有“两数相等”的含义。

2、但无论“ZF=1”的含义如何,是什么指令设置的,只要是ZF=1,就可以使得je指令发生转移。

3、对于 jne、jb、jnb、ja、jna 等指令和 cmp 指令配合使用的思想和 je 相同。

4、在联合应用它们的时候,不必再考虑 cmp 指令对相关标志位的影响和 je 等指令对相关标志位的检测。因为相关的标志位,只是为 cmp 和 je 等指令传递比较结果。

5、可以直接考虑cmp 和ie 等指令配合使用时,表现出来的逻辑含义。它们在联合使用的时候表现出来的功能有些像高级语言中的IF语句。

九、DF标志(direction Flags)和串传送指令

DF位于FLAG寄存器第10位,英文全称是direction Flags。direction就是“方向”的意思。DF标志主要是配合串传送指令movsb、movsw的执行,控制每次操作后si、di的增减。

df = 0 ,每次操作后si、di递增

df = 1,每次操作后si、di递减

(一)MOVSB指令

movsb 的功能是将 ds:si 指向的内存单元中的字节送入 es:di 中,然后根据标志寄存器 df位的值,将 si 和 di 递增或递减。

格式:movsb

功能:执行 movsb 指令相当于进行下面几步操作。

1、((es)*16+(di))=((ds)*16+(si))

2、如果 df=0 则:

(si)=(si)+1

(di)=(di)+1

如果 df=1 则:

(si)=(si)-1

(di)=(di)-1

在原书的第231页,王爽老师给出了一个并不存在的指令,只是用于描述movsb指令的功能:

mov es:[di] byte ptr ds:[si]

如果 df=0:

inc si

inc di

如果 df=1:

dec si

dec di

需注意的是:

1、SI这个寄存器,全名是Source Index,也就是源变址寄存器,用于存放源操作数的偏移地址,并且SI的内容有自动修改的功能。

2、DI这个寄存器,全名是Destination Index,也就是目的变址寄存器 ,用于存放目的操作数的偏移地址,并且DI的内容有自动修改的功能。

3、SI、DI可以和BX、BP联用。它们和BX连用时,段地址默认在DS中;和BP联用时,段地址默认在SS中。它们也可以单独使用,单独使用时,段地址默认在DS中,想要越段使用,加上段前缀即可。

4、在串指令操作中,一般来说,SI和DS联用,确定源地址;DI和ES(附加段寄存器)联用,确定传送的目的地址;在这种使用过程中,SI和DI具有自加和自减功能。

(二)MOVSW指令

格式:movsw

movsw 的功能是将 ds:si 指向的内存字单元中的字送入 es:di 中,然后根据标志寄存器df 位的值,将 si 和 di 递增 2 或递减 2。

同样,王爽老师给出了一个并不存在的指令,只是用于描述movsw指令的功能:

mov es:ldil ,word ptr ds:[si]

如果 df=0:

add si,2

add di,2

如果 df=1:

sub si,2

sub di,2

需注意的是:

1、movsb传送的是字节单元的内容,而movsw传送的是字单元的内容。所以两个指令所影响的SI、DI的增减量不一样,一个是1,另一个是2。

2、一般来说,movsb和movsw都和rep配合使用,格式为:rep movsb和 rep movsw 。

而以rep movsb为例,用汇编的语法来描述其功能就是:

s:movsb

loop s

可见,rep的作用是根据CX的值,重复执行后面的串传送指令,每执行一次movsb指令SI和DI都会递增或递减,指向后一个单元或者前一个单元。

同样,rep movsw也相当于:

s:movsw

loops

而标志寄存器(FLAG)的DF位则决定了串传送指令执行后,SI和DI改变的方向。8086CPU提供了下面两条指令对DF进行设置:

1、cld指令:将标志寄存器的DF位置0,也就是所谓的“正向传送”。

2、std指令:将标志寄存器的DF位置1,也就是所谓的“逆向传送”。

需注意的是:

1、在设置好数据(按字节或字)的源地址和目标地址后,用CLD 和 串传送指令(movsb或movsw)进行正向传送的时候,SI要指向源地址的第一个单元,DI要指向目标地址的第一个单元。

2、在设置好数据(按字节或字)的源地址和目标地址后,用STD 和 串传送指令(movsb或movsw)进行逆向传送的时候,SI要指向源地址的最后一个单元,DI要指向目标地址的最后一个单元。

关于这两点,原书第232页和第233页有详细介绍,这里不再赘述。

而串传送指令movsb和movsw,在编写和安装中断程序的时候用得比较多,在原书的第12章、13章、14章、15章涉及得比较多,所以应重点理解。

十、PUSHF和POPF指令

这两个指令是本章中最简单,最容易理解的两个指令。

pushf的功能是将标志寄存器的值压栈,而popf是从栈中弹出数据,送入标志寄存器。这两个指令为直接访问标志寄存器提供了一种方法。

这里,重点分析一下原书第233页,检测点11.4,以加深理解:

下面的程序执行后:(ax)=?

mov ax,0

push ax

popf

mov ax 0fff0h

add ax,0010h

pushf

pop ax

and al,11000101B

and ah,00001000B

1、通过第一条mov指令,使AX寄存器里的16位数据全部为0。

2、执行push ax之后,也就是将AX的数据0压入栈中。

3、执行popf,就是将栈中弹出数据0,将标志寄存器里面的所有标志(前面提到的CF、PF、ZF、SF、OF、DF等标志)归零。

4、经过mov ax 0fff0h和add ax,0010h两条指令的操作结果,二进制为1 0000 0000 0000 0000,很明显,这个值已经超出了AX的数据容纳范围(16位),达到了17位。此时AX中的内容为 0000 0000 0000 0000,也就是0H。

5、对于无符号数运算,0fff0H对应的二进制数据是1111 1111 1111 0000 ,0010H对应的二进制数据是0000 0000 0001 0000;这两个数的所有位数值都是有效数据(最高位不代表符号),0fff0H与0010H相加,产生了进位,因此CF=1。

6、对于有符号数运算,0fff0h对应的二进制数据是1111 1111 1111 0000,其最高位是符号位,1代表负数;1111 1111 1111 0000代表的是-10h;因此与0010H相加,结果为0H,没发生溢出(或者说,结果0H没有超出机器能表示的16位范围-32768~32767),因此OF=0。

7、而结果是0H,因此ZF=1;而0H作为非负数,所以SF=0;0H的二进制是0000 0000 0000 0000,其中1的个数为0,是偶数,因此PF=1。因此,此时FLAG中相关标志的值:CF=1,OF=0,ZF=1,SF=0,PF=1。

8、在标志寄存器中,CF位于第0位,PF位于第2位,ZF位于第6位。因此,此时的标示寄存器的内容为:

0000 0000 0100 0101,也就是45H。

9、在执行pushf指令后,将标志寄存器的值45H压栈。

10、在执行pop ax指令后,AX获得了弹出的数据45H。

11、执行and al,11000101B指令,AL的内容是AX的低8位数据,也就是0100 0101,其结果为0100 0101,也就是45H。

12、执行and ah,00001000B指令,AH的内容是AX的高8位数据,也就是0000 0000 ,其结果为0000 0000。

13、因此,最后的结果:AX = 0000 0000 0100 0101,也就是45H。

十一、标志寄存器在Debug中的表示

这个知识点没什么好说的,直接贴出原书第234页的内容以作参考:

最后,贴出实验11 编写子程序的代码:

===========

assume cs:codesg

datasg segment

db "Beginner's All-purpose Symbolic Instruction Code.",0

datasg ends

codesg segment

begin: mov ax,datasg

mov ds,ax

mov si,0

call letterc

mov ax,4c00h

int 21h

letterc:

mov al,[si]

mov ch,0

mov cl,al

jcxz ok

cmp byte ptr [si],27H;比较是否为单引号

je notchar

cmp byte ptr [si],20H;比较是否为空格

je notchar

cmp byte ptr [si],2DH;比较是否为横杠号

je notchar

cmp byte ptr [si],2EH;比较是否为减号

je notchar

and al,11011111b

mov [si],al

inc si

jmp short letterc

notchar: inc si

jmp short letterc

ok:ret

codesg ends

end begin

===========

实验11很简单,没什么可说的,一看就明白。

小结一下学习本章的体会:

1、本章的信息量很大,特别是补码和原码的关系、无符号数与有符号数的操作、进位和溢出的原理,很多细节都需要逐步去推敲和理解才能掌握相关知识。

2、和学习王爽老师写的其他章节一样,很多坑得自己去填,如果图省事跳过一些内容,就会造成知识点的断档,导致后面的学习无法推进,所以必须多复习几遍,所谓“慢就是快”。

3、这一章很多内容,是12章以后内容的基础,特别是串传送指令(movsb和movsw)需要深入理解。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值