《x86汇编语言:从实模式到保护模式》勘误表
- 格式:doc
- 大小:38.00 KB
- 文档页数:2
ASM:《X86汇编语⾔-从实模式到保护模式》第11章:进⼊保护模式★PART1:进⼊保护模式1. 全局描述符表(Global Descriptor Table,GDT)32位保护模式下,如果要使⽤⼀个段,必须先登记,登记的信息包括段的起始地址,段的界限和各种访问属性,如果偏移地址超过了段的界限,就会引发异常中断。
和⼀个段有关的信息需要8个字节来描述,这被称为段的描述符(Segement Descriptor),每个段都需要⼀个描述符,为了存放描述符,需要在内存中开辟⼀段空间。
这些描述符集中存放,构成了⼀个描述符表。
为了跟踪全局描述符表,处理器内部有⼀个48位的寄存器,称为全局描述符寄存器(GDTR)。
这个寄存器分为两个部分,前16位为全局描述表的边界,后32位为全局描述表的线性基地址。
GDT的界限是16位的,所以GDT的最⼤是216字节,⼜因为⼀个描述符是8个字节的,所以最多可以定义8192个描述符。
因为进⼊保护模式之前,是实模式,实模式只能访问最多1MB的内存,所以GDT通常都是定义在1MB以下的内存范围中,允许进⼊保护模式之后换个地⽅定义GDT。
因为在进⼊保护模式之前处理器初始化为实模式,同样的,主引导程序是在0x0000:0x7c00这个地⽅加载的,⽽主引导程序最⼤也就512字节,所以我们把GDT放在主引导程序之后,也就是0x7e00后⾯,GDT的界限可以到0x17DFF(64KB最⼤)。
栈段寄存器SS被初始化为0x0000,栈是向下拓展的,我们可以把SP段定义到0x7c00处,然后向下拓展(要注意⼤⼩不能太⼤,因为BIOS数据区和中断向量表都在下⾯)。
描述符不是由⽤户程序⾃⼰创建的,都是由操作系统创建的,如果⽤户程序对段的访问超过了操作系统所规定的范围,或者访问了⼀个不属于它的段,那么这些操作都会被处理器阻⽌。
2. 32位保护模式下GDT每个位置的定义每个描述符在GDT占8个字节,每个位置及其定义见下图:在32位保护模式下,如果未开始页功能,那么段地址就是物理地址,注意描述符段保存器的段界限和基地址是不连续的(其实是为了兼容80286)。
实模式与保护模式在是模式下,16位寄存器需要用“段:偏移”这种方法才能达到1MB的寻址能力,如今我们有了32位寄存器,一个寄存器就可以寻址4GB的空间,是不是从此段值就被抛弃了?,在新的政策下地址仍然用“段:偏移”这样的形式来表示,只不过保护模式下的“段”的概念发生了根本性的变化,是模式下段值还是可以看成地址的一部分的,段值为XXXXh表示以XXXX0h开始的一段内存,而保护模式下虽然段值仍然由原来的16位的CS,DS等寄存器表示,但此时它仅仅变成了一个索引,这个索引指向一个数据结构的一个表项,表项中详细定义了段的起始地址,界限,属性等内容这个数据结构就是GDT(global description table)在Protected Mode下,一个重要的必不可少的数据结构就是GDT(Global Descriptor Table)。
为什么要有GDT?我们首先考虑一下在Real Mode下的编程模型:在Real Mode下,我们对一个内存地址的访问是通过Segment:Offset的方式来进行的,其中Segment是一个段的Base Address,一个Segment的最大长度是64 KB,这是16-bit系统所能表示的最大长度。
而Offset则是相对于此Segment Base Address的偏移量。
Base Address+Offset就是一个内存绝对地址。
由此,我们可以看出,一个段具备两个因素:Base Address和Limit(段的最大长度),而对一个内存地址的访问,则是需要指出:使用哪个段?以及相对于这个段Base Address的Offset,这个Offset应该小于此段的Limit。
当然对于16-bit系统,Limit不要指定,默认为最大长度64KB,而 16-bit的Offset也永远不可能大于此Limit。
我们在实际编程的时候,使用16-bit段寄存器CS(Code Segment),DS (Data Segment),SS(Stack Segment)来指定Segment,CPU将段积存器中的数值向左偏移4-bit,放到20-bit的地址线上就成为20-bit的Base Address。
80X86保护模式及其编程(⼀)80x86系统寄存器和系统指令1、标志寄存器(EFLAGS)标志寄存器EFLAGS的标志位含义如下图:TF 位8是跟踪标志(Trace flag),当设置该位时可为调试操作启动单步执⾏⽅式。
复位时则禁⽌单步执⾏。
在单步执⾏⽅式下,处理器会在每个指令执⾏后产⽣⼀个调试异常,这样我们可以观察执⾏程序在每条指令执⾏后的状态。
IOPL 位13-12时I/O特权级(I/O Privilege Level)字段。
该字段指明当前运⾏程序或任务的I/O特权级别IOPL。
当前任务或程序的CPL必须⼩于这个IOPL才能访问I/O地址空间。
只有当CPL位特权级0时,程序才可以使⽤POPF或IRET指令修改这个字段,IOPL也是控制对IF标志修改的机制之⼀NT 位14是嵌套任务标志(Nested Task)。
它控制着被中断任务和调⽤任务之间的链接关系。
在使⽤CALL指令、中断或异常执⾏任务调⽤时,处理器会设置该标志,在通过IRET指令从⼀个任务返回时,处理器会检查并修改这个NT标志。
使⽤POPF/POPFD指令也可以修改这个标志,但是在应⽤程序中改变这个标志的状态会产⽣不可意料的异常RF 位16时恢复标志(Resume Flag)。
该标志⽤于控制处理器对断点指令的响应。
当设置时,这个标志会临时禁⽌断点指令产⽣调试异常;当标志复位时,则断点指令将会产⽣异常。
RF的主要功能是允许调试异常后重⾏执⾏⼀条指令。
当调试软件使⽤IRETD指令返回被中断程序之前,需要设置堆栈上EFLAGS内容中的RF标志,以防⽌指令断点造成另⼀个异常,处理器会在指令返回之后⾃动清除该标志,从⽽再次允许指令断点异常。
VM位17是虚拟-8086⽅式标志,当设置该标志时,新开启虚拟-8086⽅式,当复位该标志时,则回到保护模式内存管理寄存器处理器提供了4个内存管理寄存器(GDTR、LDTR、IDTR和TR),⽤于指定分段内存管理所使⽤的系统表的基地址,其中包含有分段机制的重要信息。
第十章IA3210.1 IA-32架构的基本执行环境10.1.1 寄存器的扩展在16位处理器内,有8个通用寄存器AX、BX、CX、DX、SI、DI、BP和SP,其中,前4个还可以拆分成两个独立的8位寄存器来用,即AH、AL、BH、BL、CH、CL、DH和DL。
为了在汇编语言程序中使用经过扩展(Extend)的寄存器,需要给它们命名,它们的名字分别是EAX、EBX、ECX、EDX、ESI、EDI、ESP和EBP。
可以在程序中使用这些寄存器,即使是在实模式下:mov eax,0xf0000005mov ecx,eaxadd edx,ecx但是,就像以上指令所示的那样,指令的源操作数和目的操作数必须具有相同的长度,个别特殊用途的指令除外。
因此,像这样的搭配是不允许的,在程序编译时,编译器会报告错误:mov eax,cx ;错误的汇编语言指令如果目的操作数是32位寄存器,源操作数是立即数,那么,立即数被视为32位的:mov eax,0xf5 ;EAX←0x000000f532位通用寄存器的高16位是不可独立使用的,但低16位保持同16位处理器的兼容性。
因此,在任何时候它们都可以照往常一样使用:mov ah,0x02mov al,0x03add ax,si可以在32位处理器上运行16位处理器上的软件。
但是,它并不是16位处理器的简单增强。
事实上,32位处理器有自己的32位工作模式,在本书中,32位模式特指32位保护模式。
在这种模式下,可以完全、充分地发挥处理器的性能。
同时,在这种模式下,处理器可以使用它全部的32根地址线,能够访问4GB内存。
10.1.2 基本的工作模式8086具有16位的段寄存器、指令指针寄存器和通用寄存器(CS、SS、DS、ES、IP、AX、BX、CX、DX、SI、DI、BP、SP),因此,我们称它为16位的处理器。
尽管它可以访问1MB的内存,但是只能分段进行,而且由于只能使用16位的段内偏移量,故段的长度最大只能是64KB。
Linux0.11——从实模式到保护模式综述最近在阅读Linux 0.11的源码时,对于setup.s⽂件中设置GDT表的部分不是很理解,后来经过刘国军⽼师的指点,结合赵炯博⼠的《Linux内核完全注释》的第四章《80X86保护模式及其编程》,对于保护模式有了⼀些粗浅的了解和认识。
备忘。
本⽂章主要讲解保护模式的寻址机制与setup.s中的切换部分。
保护模式保护模式运⾏在80286及其之后的所有CPU上,但是为了保证向前兼容性,正常的CPU在启动时并不会默认进⼊保护模式,⽽是会进⼊实模式,随后通过⼀系列设定转⼊保护模式。
在16位实模式下,CPU寻址时使⽤16位段寄存器的内容乘以16当作段基地址,加上16位段偏移地址形成20位的物理地址,所以最⼤寻址仅为1MB字节,最⼤段长度64KB。
在实模式下,所有的段都是可以任意访问的,即任意读、写和执⾏。
虽然在80286点CPU上已经出现了保护模式,但是其寄存器的位宽仍然是16位,只不过其地址线由20位扩⼤到了24位,寻址空间随即扩⼤到了16MB。
真正的32位保护模式出现在80386上,其地址总线和寄存器都是32位宽的,因此寻址空间扩⼤到了4GB。
保护模式下,CPU寻址主要有两种模式,⼀是分段模式,⼆是分段和分页相结合,分页⽆法单独出现。
保护模式的分段模式为每⼀段增加了段属性来限制⽤户程序对内存中⼀些段的操作。
在全局描述符表(GDT)中,每个段的表项存储了⼀个段的基本属性,例如段的基地址、段的界限、段的类型(代码段、数据段)、段的执⾏权限等。
分页模式的出现使得程序员可以编写远远⼤于内存的程序⽽⽆需担⼼内存的容量,在该模式下,内存被划分为“页”存储,磁盘的⼀部分⽤作虚拟内存,当应⽤程序执⾏时需要的某些代码或数据所在的页不在内存中时,CPU就会产⽣⼀个缺页异常,从磁盘中将所需的页调⼊内存中后恢复执⾏,在应⽤程序看来,所需的代码或数据仿佛⼀直存在内存上。
重要数据结构在保护模式中,有⼏个长得很像的名字⼀直是我们⼼头噩梦:GDT、GDTR、LGDT、LDT、LDTR、LLDT……事实上,并不是那么难区分。
保护模式的主要数据结构分段机制段描述符在保护模式下,把有关一个段的信息,即段基址、限长(段的字节数)、类型、访问权限及其他属性信息存放在一个8字节长的数据结构中,这种数据结构称为段描述符,简称描述符。
描述符有两种类型:非系统段描述符和系统段描述符。
后面将具体给出这两种描述符的格式及各字段的功能定义。
这里所说的非系统段即应用程序段,也就是通常的代码段、数据段和堆栈段;而系统段包括任务状态段(Task State Segment,TSS)和各种门,另外,局部描述符表(下面即将介绍)也是一种系统段。
任务状态段是多任务系统中的一种特殊数据结构,它对应一个任务的各种信息。
所谓门,实际上是一种特殊的段描述符。
有4种不同类型的门,即调用门、任务门、中断门及陷阱门。
调用门用来改变任务或者程序的特权级別;任务门像个开关一样,用来执行任务切换;中断门和陷阱门用来指出中断服务程序的同入口。
描述符表为了査找和识别,把系统中的描述符按线性表的形式来组织,即构成描述符表。
描述符表的每一项就是一个描述符。
描述符表由操作系统建立,并由操作系统维护和管理。
有三种类型的描述符表:全局描述符表(Global Descriptor Table,GDT)、局部描述符表(Local Descriptor T able,LDT)和中断描述符表(Interrupt Descriptor Table,IDT)。
全局描述符表GDT含有可供系统中所有任务使用的段描述符。
另外,系统把每个局部描述符表也看成一种特殊的段,并分别赋予描述符,所以,GDT中还包含各个局部描述符表LDT的描述符;还有,如上所述,任务状态段TSS也是一种系统段,该段对应的描述符称为TSS描述符,TSS描述符也放在GDT中。
也就是说,GDT中除了含有可供所有任务使用的全局描述符外,还包含有LDT描述符和TSS 描述符。
局部描述符表LDT只含有与系统中某一个给定任务相关联的描述符。
《x86汇编语⾔:从实模式到保护模式》配套代码清单c05_mbr.asm;代码清单5-1;⽂件名:c05_mbr.asm;⽂件说明:硬盘主引导扇区代码;创建⽇期:2011-3-3121:15mov ax,0xb800;指向⽂本模式的显⽰缓冲区mov es,ax;以下显⽰字符串"Label offset:"mov byte [es:0x00],'L'mov byte [es:0x01],0x07mov byte [es:0x02],'a'mov byte [es:0x03],0x07mov byte [es:0x04],'b'mov byte [es:0x05],0x07mov byte [es:0x06],'e'mov byte [es:0x07],0x07mov byte [es:0x08],'l'mov byte [es:0x09],0x07mov byte [es:0x0a],' 'mov byte [es:0x0b],0x07mov byte [es:0x0c],"o"mov byte [es:0x0d],0x07mov byte [es:0x0e],'f'mov byte [es:0x0f],0x07mov byte [es:0x10],'f'mov byte [es:0x11],0x07mov byte [es:0x12],'s'mov byte [es:0x13],0x07mov byte [es:0x14],'e'mov byte [es:0x15],0x07mov byte [es:0x16],'t'mov byte [es:0x17],0x07mov byte [es:0x18],':'mov byte [es:0x19],0x07mov ax,number ;取得标号number的偏移地址mov bx,10;设置数据段的基地址mov cx,csmov ds,cx;求个位上的数字mov dx,0div bxmov [0x7c00+number+0x00],dl ;保存个位上的数字;求⼗位上的数字xor dx,dxdiv bxmov [0x7c00+number+0x01],dl ;保存⼗位上的数字;求百位上的数字xor dx,dxdiv bxmov [0x7c00+number+0x02],dl ;保存百位上的数字div bxmov [0x7c00+number+0x03],dl ;保存千位上的数字;求万位上的数字xor dx,dxdiv bxmov [0x7c00+number+0x04],dl ;保存万位上的数字;以下⽤⼗进制显⽰标号的偏移地址mov al,[0x7c00+number+0x04]add al,0x30mov [es:0x1a],almov byte [es:0x1b],0x04mov al,[0x7c00+number+0x03]add al,0x30mov [es:0x1c],almov byte [es:0x1d],0x04mov al,[0x7c00+number+0x02]add al,0x30mov [es:0x1e],almov byte [es:0x1f],0x04mov al,[0x7c00+number+0x01]add al,0x30mov [es:0x20],almov byte [es:0x21],0x04mov al,[0x7c00+number+0x00]add al,0x30mov [es:0x22],almov byte [es:0x23],0x04mov byte [es:0x24],'D'mov byte [es:0x25],0x07infi: jmp near infi ;⽆限循环number db 0,0,0,0,0times 203 db 0db 0x55,0xaac06_mbr.asmjmp near startmytext db 'L',0x07,'a',0x07,'b',0x07,'e',0x07,'l',0x07,' ',0x07,'o',0x07,\'f',0x07,'f',0x07,'s',0x07,'e',0x07,'t',0x07,':',0x07number db 0,0,0,0,0start:mov ax,0x07c0;设置数据段基地址mov ds,ax ;ds寄存器⼀般保存数据段基地址mov ax,0xb800;设置附加段基地址mov es,ax ;这⾥附加段指向显存位置,存放在es寄存器中cld ;将⽅向标志位DF清零,以指⽰传送是负⽅向的,与此相对应的指令是stdmov si,mytext ;movsw指令原始数据串需要存放在ds:si位置,⽬的地址为es:di,因为ds⽬前指⽰的是当前代码段基地址地址,因此只要把偏移mytext存⼊si寄存器即可mov di,0;当前es指⽰显存起始位置,因此只要把偏移0存⼊di即可mov cx,(number-mytext)/2;实际上等于13,cx作为计数器,每进⾏⼀次rep指令cx-1rep movsw ;⼀次传送⼀个字(两个字节);得到标号所代表的偏移地址mov ax,number ;此代码⽬的旨在显⽰number的偏移地址;计算各个数位mov bx,ax ;bx指向当前number偏移地址mov cx,5;循环次数mov si,10;除数digit:xor dx,dx ;dx(被除数⾼16位)清零div si ;除法mov [bx],dl ;保存数位;为什么这⾥不⽤加0x7c00了?inc bx ;bx⾃加1,指向下⼀个内存单元,number⼀共定义了5个字节内存单元loop digit;显⽰各个数位mov bx,numbermov si,4show:mov al,[bx+si];从后往前显⽰add al,0x30mov ah,0x04mov [es:di],axadd di,2dec sijns show ;上⼀条指令符号位为SF=0(结果为⾮负)时跳转mov word [es:di],0x0744jmp near $ ;⽆限循环times 510-($-$$) db 0;512字节减去之后两个db指令=510字节,$当前指令偏移,$$当前代码段起始位置,填充字节0(db 0)db 0x55,0xaac07_mbr.asmjmp near startmessage db '1+2+3+...+100='start:mov ax,0x7c0;设置数据段的段基地址mov ds,axmov ax,0xb800;设置附加段基址到显⽰缓冲区mov es,ax;以下显⽰字符串mov si,messagemov di,0mov cx,start-message@g:mov al,[si];因为这是硬盘主引导扇区代码,因此被加载到0x7c00,[si]=[ds:si],就是相对于代码段开头的相对偏移,这个相对偏移就是标签message的值mov [es:di],alinc di ;di⽤做显存段地址的相对偏移,字符内容信息放在低⼀个字节mov byte [es:di],0x07inc di ;字符显⽰信息放在⾼⼀个字节inc si ;si⽤作寻址字符串相对偏移loop @g;以下计算1到100的和xor ax,ax ;清空ax寄存器,存放结果mov cx,1@f:add ax,cxinc cx ;cx做累加器cmp cx,100jle @f ;⼩于等于时跳转;以下计算累加和的每个数位xor cx,cx ;设置堆栈段的段基地址mov ss,cxmov sp,cx ;堆栈段指针和段基址都在0x0000处,堆栈段从⾼地址向低地址⽣长mov bx,10xor cx,cx@d:inc cx ;压栈中⽤cx记录⼀共压⼊栈元素个数,以便之后出栈时能及时停⽌popxor dx,dx ;被除数[dx:ax]div bx ;除数bxor dl,0x30;余数在dx中,但是余数最多到9,因此在dl中就够了,加0x30得到ASCII码push dx ;dx中只有dl有意义,但是压栈的单位必须是字(两个字节)cmp ax,0jne @d ;循环跳出时,结果5050每⼀位被放在栈中;以下显⽰各个数位@a:pop dx ;出栈,栈顶元素是千位,百位,⼗位,个位mov [es:di],dlinc dimov byte [es:di],0x07inc diloop @a8086寻址⽅式总结:1.寄存器寻址 :mov ax,cx2.⽴即寻址 :add bx,0xf000 (⽬的操作数⽴即数寻址,源操作数寄存器寻址)3.直接寻址 :mov ax,[0x5c0f]4.基址寻址:利⽤基址寄存器bx/bp中的值作为偏移地址,其中bx默认段寄存器为ds(数据段),bp默认段寄存器为ss(堆栈段)。
《x86汇编语⾔:从实模式到保护模式》检测点和习题答案检测点1.1:按顺序分别为:13 15 78 255 128 56091检测点1.2:按顺序分别为:1000 1010 1100 1111 11001 1000000 1100100 11111111 1111101000 1111111111111111 100000000000000000000检测点1.3:按顺序分别为:8 10 11 12 13 14 15 16 31 1741 1022 4092 65535检测点1.4:按顺序分别为:8 a c f 19 40 64 ff 3e8 ffff 100000检测点1.5:1.按顺序分别为:11 1010 1100 1111 100000 111111 1011111110 1111111111111111 100111111100000001011101 11111001100111111111110111111112.按顺序分别为:1/1 11/3 0101/5 111/7 1001/9 1011/A 1101/D 1111/F 0/0 10/2 100/4 110/6 1000/8 1100/C 1110/E检测点1.6:1.4092/111111111100 2.27B6100/10011110110110000100000000第1章习题:1.5 C =15D=1111B =12D=1100B =10D=1010B =8H=1000B =11D=1011B =14D=1110B =16D=10000B 2.12 10101 10001111 1000000000 1FF检测点2.1:1.(2) (16) (4) (32) 2. (7) (8) 最⾼位 3. (00) (0F) (8) (00、02、04、06、08、0A、0C、0E) 双字时,是00、04、08、0C检测点2.2:A3D8H检测点2.3:1.8 (AX BX CX DX SI DI BP SP) (AH AL BH BL CH CL DH DL) 2.(A) (C) (D F) 3.(A B C D F)第2章习题:1. 64个 2. 25BC0H~35BBFH检测点3.1:1.(略) 2. (B) (A) (C)第3章习题:1. 00H、35H、40H 2. 49H(即73个字节)检测点4.1:1.(0) (0) (1) (0) (0) (1) 2. (A B C)检测点4.2:1.(略) 2. (略) 3.应在屏幕克上⾓显⽰a、s、m三个字母检测点5.1:1.(0xB8000) (0xB800) (0xF9E) (0x27) (0x48) 2. (E F G H J L) A错误的原因是企图向8位寄存器传送16位字; B错误的原因是向段寄存器传送⽴即数; C错误的原因是通过8位寄存器AL向段寄存器传送; D错误的原因是未指⽰内存操作数的长度; I错误的原因是两个寄存器不匹配; K错误的原因是在两个内存单元之间传送。
ASM:《X86汇编语⾔-从实模式到保护模式》第8章:实模式下硬盘的访问,程序重定位和加载第⼋章是⼀个⾮常重要的章节,讲述的是实模式下对硬件的访问(这⼀节主要讲的是硬盘),还有⽤户程序重定位的问题。
现在整理出来刚好能和保护模式下的⽤户程序定位作⼀个对⽐。
★PART1:⽤户程序的重定位,硬盘的访问1. 分段、段的汇编地址和段内汇编地址NASM编译器使⽤汇编指令“SECTION”或者“SEGMENT”来定义段。
他的⼀般格式是SECTION 段名称或者SEGMENT段名称(段名称不能重复),另外NASM对段没有数量的限制,⼀个程序可以有很多的代码段和数据段。
Intel处理器要求段在内存中的其是物理地址起码是16字节对齐的,⽽NASM 提供了段的修饰符align,使每⼀个段可以16字节对齐或者32字节对齐,⽐如所谓段的汇编地址其实就是段内第⼀个元素(数据,指令)的汇编地址,16字节对齐的意思是所有段⾸的汇编地址都要可以被16整除,如果存在⼀个段要求16字节对齐,⽽这个段的前⼀个段长度不够使当前段不能16字节对齐,那么编译器会⾃动将前⼀个段补0来使这⼀个段满⾜16字节对齐。
NASM编译器提供以下形式section.段名称.start来获得段的汇编地址,⽐如:另外段还可以加⼀个vsart修饰符,因为在NASM编译器中,即使你定义了⼀个段,段的汇编地址就是段内第⼀个元素的汇编地址,但是在引⽤某个标号的时候(包括section.段名称.start),这个标号的汇编地址还是从整个程序的开头开始计算的,⽽不是对段⾸的偏移。
不过再加了vsart=0的时候,段内所有标号的地址都是相对于当前段⾸的偏移了(当然也可以设定为其他数值,标号的偏移值是在这个值的基础上加上与段⾸的偏移地址。
)2. ⽤户程序头部加载⼀个⽤户程序需要⼀个加载器(在实模式下),⽽加载器是不知道⽤户程序⾥⾯具体的结构和功能的,⼀个程序想要运⾏,那么这个程序就要满⾜运⾏环境的⼀些约定俗成的条件,也就是程序哪些部分要怎么写是固定的,现在我们在MBR加载⼀个程序也是⼀样的,只要⽤户程序在某些部分满⾜⼀些条件,我们的加载器就可以识别并加载它。
1,第42页,检测点4.2,第1题。
本程序有误,正确的内容是:(由网易邮箱读者'小小鸟'、QQ读者'闪耀'、'流星梦'和'二玉'发现)
mov ax,0xb800
mov ds,ax
mov byte [0x00],'a'
mov byte [0x02],'s'
mov byte [0x04],'m'
jmp $
times 510-($-$$) db 0
db 0x55,0xaa
2,第52页,第24行,正确的内容是:(由QQ读者'闪耀'发现)
mov ax,[0x02] ;按字操作
3,第53页,第4行,正确的内容是:(由QQ读者'tome'发现)
mov [0x02],bl
4,第65、80、94、129、138页中,需要更正和明确loop指令、短转移指令jmp short、相对近转移指令jmp near和相对近调用指令call near的操作数计算方法和执行过程。
(由网易邮箱读者'小小鸟'、QQ读者'艾小羊'提出)
首先,这些指令的操作数都是相对于目标位置处的偏移量。
但需要指出的是,偏移量的计算方法取决于实际的编译器,书中所说的“用目标位置处的汇编地址减去当前指令的汇编地址,再减去当前指令的长度”,不应算错。
其次,处理器的执行过程严格地说,是非IA-32架构的组成部分。
因此,除了结果是确定的,各步骤的先后次序取决于处理器的设计。
历史上,指令的执行过程有不同的解释和说法。
但本书对这些指令执行过程的解释比较模糊和武断。
为严谨起见,再统一描述如下:在以上指令的编译阶段,编译器用目标位置处的汇编地址减去当前指令的下一条指令的汇编地址,结果做为操作数;处理器在执行一条指令时,指令指针寄存器IP会自动指向下一条指令。
因此,当以上指令执行时,IP的内容就是下一条指令的偏移地址。
处理器用IP的内容加上指令的操作数(如果是call near指令,还要压入IP的内容),并用该值取代IP中的原有内容。
5,第79页,检测点6.1。
正确的内容是:(由QQ读者'闪耀'发现)
选择填空:MOVSB指令每次传送一个(),MOVSW指令每次……
6,第86页,第26行:(由QQ读者'闪耀'发现)
原指令为“idiv bl”,正确的是“idiv bx”
7,第92页,检测点6.4,第2题,(由QQ读者'闪耀'发现)
中间一句的正确内容是:“AX的内容等于BX的内容时,转移到标号lbz处执行;”8,第101页,7.5.2节。
本节第10行:(由QQ读者'闪耀'发现)
正确的内容是:“……为了方便,源程序第50行,直接将DL中的余数……。
”
9,第104页,7.5.4节。
本节第12行。
(由QQ读者'闪耀'发现)
正确的内容是:mov ax,cs
10,第136页,倒数第11行。
(由QQ读者'闪耀'发现)
正确的内容是:第四种指令格式和第三种类似,只是……
11,第137页,倒数第14行。
(由QQ读者'tome发现)
正确的内容是:如图8-15所示。
12,第144页,8.4.6小节内第2行。
少了一个字。
应当是“为此,需要首先识别出它们。
”
13,第152页,倒数第3行。
(由QQ读者'闪耀'发现)
应改为“那么它每个引脚IR0~IR7所对应的中断号分别为0x08~0x0F。
”
14,第155页,图9-4。
(由QQ读者'艾小羊'提出)
改为下图:。