编译原理目标代码生成课件.ppt
编译原理目标代码生编译原理目标代码生成成第1页,此课件共74页哦7.1 一个简单代码生成器一个简单代码生成器我们首先介绍一个简单的代码生成器,此生成器依次把每条中间代码变换成目标代码,并且在一个基本块范围内考虑如何充分利用寄存器的问题。一方面,在基本块中,当生成计算某变量值的目标代码时,尽可能地让该变量的值保留在寄存器中(即不编出把该变量的值存到内存单元的指令),直到该寄存器必须用来存放其它变量的值或已达基本块出口为止;另一方面,后续的目标代码尽可能地引用变量在寄存器中的值而不访问内存。第2页,此课件共74页哦例如,一C语言语句为A=(B+C)*D+E,把它翻译为四元式G:T1=B+CT2=T1*DA=T2+E如果不考虑代码的效率,可以简单地把每条中间代码(四元式)映射成若干条目标指令,如将x=y+z映射为:MOVAX,y/*AX为寄存器*/ADDAX,zMOVx,AX第3页,此课件共74页哦其中,x、y、z均为数据区的内存变量。这样,上述四元式代码序列G就可翻译为:(1)MOVAX,B(2)ADDAX,C(3)MOVT1,AX(4)MOVAX,T1(5)MULAX,D(6)MOVT2,AX(7)MOVAX,T2(8)ADDAX,E(9)MOVA,AX第4页,此课件共74页哦虽然从正确性来看,这种翻译不存在问题,但它却存在冗余。在上述指令序列中,(4)和(7)两条指令是多余的;而T1、T2均是中间代码生成时产生的临时变量,它们在出了基本块后将不再使用,故(3)、(6)两条指令也可删去。所以,在考虑了效率和充分使用寄存器之后,应生成如下代码:第5页,此课件共74页哦(1)MOVAX,B(2)ADDAX,C(3)MULAX,D(4)ADDAX,E(5)MOVA,AX为了实现这一目的,代码生成器就必须了解一些信息:在产生T2=T1*D对应的目标代码时,为了省去指令MOVAX,T1,就必须知道T1的当前值已在寄存器AX中;为了省去MOVT1,AX,就必须知道出了基本块后T1不再被引用。第6页,此课件共74页哦7.1.1待用信息与活跃信息在一个基本块内的目标代码中,为了提高寄存器的使用效率,应将基本块内还要被引用的值尽可能地保留在寄存器中,而将基本块内不再被引用的变量所占用的寄存器尽早释放。每当翻译一条四元式如A=BopC时,需要知道在基本块中还有哪些四元式要对变量A、B、C进行引用,为此,需要收集一些待用信息。在一个基本块中,四元式i对变量A定值,如果i后面的四元式j要引用A且从i到j的四元式没有其它对A的定值点,则称j是四元式i中对变量A的待用信息,同时也称A是活跃的;如果A被多处引用,则构成了A的待用信息链与活跃信息链。第7页,此课件共74页哦为了取得每个变量在基本块内的待用信息和活跃信息,可从基本块的出口由后向前扫描,对每个变量建立相应的待用信息链与活跃信息链。如果没有进行数据流分析并且临时变量不允许跨基本块引用,则把基本块中的临时变量均看作基本块出口之后的非活跃变量,而把所有的非临时变量均看作基本块出口之后的活跃变量。如果某些临时变量能够跨基本块使用,则把这些临时变量也看成基本块出口之后的活跃变量。假设变量的符号表内有待用信息和活跃信息栏,则计算变量待用信息的算法如下:第8页,此课件共74页哦(1)首先将基本块中各变量的符号表的待用信息栏置为“非待用”,对活跃信息栏则根据该变量在基本块出口之后是否活跃而将该栏中的信息置为“活跃”或“非活跃”。(2)从基本块出口到基本块入口由后向前依次处理各四元式。对每个四元式i:A=BopC依次执行以下步骤:第9页,此课件共74页哦把符号表中变量A的待用信息和活跃信息附加到四元式i上;把符号表中变量A的待用信息和活跃信息分别置为“非待用”和“非活跃”;把符号表中变量B和C的待用信息和活跃信息附加到四元式i上;把符号表中B和C的待用信息置为i,活跃信息置为“活跃”。第10页,此课件共74页哦例7.1考察基本块:(1)T=AB(2)U=AC(3)V=T+U(4)D=V+U其中,A、B、C、D为变量,T、U、V为中间变量,试求各变量的待用信息链和活跃信息链。第11页,此课件共74页哦解答我们根据计算变量待用信息的算法得到各变量的待用信息链和活跃信息链如表7.1所示。表中的“F”表示“非待用”或“非活跃”,“L”表示“活跃”,(1)(4)分别表示基本块中的四个四元式。待用信息链和活跃信息链的每列从左到右为每行从后向前扫描一个四元式时相应变量的信息变化情况(空白处表示没有变化)。第12页,此课件共74页哦表7.1例7.1的待用信息链和活跃信息链变量名待用信息活跃信息初值待用信息链初值活跃信息链TF(3)FFLLFAF(2)(1)LLBF(1)LLCF(2)LLUF(4)(3)FFLLFVF(4)FFLFDFFLF第13页,此课件共74页哦待用信息和活跃信息在四元式上的标记如下:(1)T(3)L=A(2)LBFL(2)U(3)L=AFLCFL(3)V(4)L=TFF+U(4)L(4)DFL=VFF+UFF第14页,此课件共74页哦7.1.2代码生成算法为了在代码生成中进行寄存器分配,需要随时掌握各寄存器的使用情况,即它是处于空闲状态还是已分配给某个变量或已分配给某几个变量。通常用一个寄存器描述数组RVALUE动态地记录各寄存器的当前状况,并用寄存器Ri的编号作为它的下标。此外,还需建立一个变量地址描述数组AVALUE来记录各变量现行值存放的位置,即其是在某寄存器中还是在某内存单元中,或者同时存在于某寄存器和某内存单元中,可以有如下表示:第15页,此课件共74页哦RVALUERi=A/*寄存器Ri分配给变量A*/RVALUERi=A,B/*寄存器Ri分配给变量A和B*/RVALUERi=/*未分配*/AVALUEA=A/*表示A的值在内存中*/AVALUEA=Ri/*表示A的值在寄存器Ri中*/AVALUEA=Ri,A/*表示A的值既在寄存器Ri中又在内存中*/第16页,此课件共74页哦为了简单起见,假设基本块中每个四元式的形式都是A=BopC,则代码生成算法是对每个四元式i:A=BopC执行下述步骤:(1)调用函数GETREG(i:A=BopC)返回存放A值结果的寄存器R。(2)通过地址描述数组AVALUEB和AVALUEC确定出变量B和变量C的现行值存放位置B和C;如果是存放在寄存器中,则把寄存器取作B和C。第17页,此课件共74页哦(3)如果BR,则生成目标代码:MOVR,BopR,C否则生成目标代码:opR,C如果B或C为R,则删除AVALUEB或AVALUEC中的R。(4)令AVALUEA=R并令RVALUER=A,表示变量A的现行值只在R中且R中的值只代表A的现行值。第18页,此课件共74页哦(5)如果B和C的现行值在基本块中不再被引用,它们也不是基本块出口之后的活跃变量且它们的现行值存放在寄存器Rk中,则删除RVALUERk中的B和C以及AVALUEB中的Rk,使寄存器Rk不再为B和C所占用。函数GETREG(i:A=BopC)用来得到存放A的当前值的寄存器R;其算法如下:(1)如果B的现行值在某寄存器Ri中,且该寄存器只包含B的值,或者B和A是同一标识符,或者B在该四元式之后不再被引用,则选取Ri为所需寄存器并转(4)。第19页,此课件共74页哦(2)如有尚未分配的寄存器,则从中选取一个Ri为所需寄存器并转(4)。(3)从已分配的寄存器中选取一个Ri为所需寄存器R。选取原则为:占用Ri的变量的值也同时放在内存中,或者该值在基本块中要在最远的位置才会引用到。这样,对寄存器Ri所含的变量和变量在内存中的情况必须先做如下调整:对RVALUERi中的每一个变量M,如果M不是A或者M既是A又是C却不是B,而B又不在RVALUERi中,则:如果AVALUERi中不包含M,则生成目标代码MOVM,Ri;第20页,此课件共74页哦当M不是A时,如果M是B或者M是C且同时B也在RVALUE Ri中,则令AVALUE M=M,R,否则令AVALUEM=M;删除RVALUERi中的M;(4)给出R,返回。例7.2对例7.1,假设只有AX和BX是可用寄存器,用代码生成算法生成目标代码和相应的RVALUE和AVALUE。解答用代码生成算法生成的目标代码和相应的RVALUE及AVALUE如表7.2所示。第21页,此课件共74页哦表7.2例7.2的目标代码四元式目标代码RVALUEAVALUET=ABMOVAX,ASUBAX,BAX含有TT在AX中U=ACMOVBX,ASUBBX,CAX含有TBX含有UT在AX中U在BX中V=T+UADDAX,BXAX含有VBX含有UV在AX中U在BX中D=V+UADDAX,BXAX含有DD在AX中第22页,此课件共74页哦对其它形式的四元式也可仿照上述算法生成其目标代码。这里特别要指出的是,对形如A=B的复写,如果B的现行值在某寄存器Ri中,那么无需生成目标代码,只需在RVALUERi中增加一个A(即把Ri同时分配给B和A),把AVALUEA改为Ri;而且如果其后B不再被引用,还可把RVALUERi中的B和AVALUEB中的Ri删除。处理完基本块中所有的四元式后,对现行只在某寄存器中的每个变量,如果它在基本块出口之后是活跃的,则要用MOV指令把它在寄存器中的值存放到数据区以它命名的内存单元中。第23页,此课件共74页哦为进行这一工作,我们利用寄存器描述数组RVALUE来决定其中哪些变量的现行值在寄存器中,再利用地址描述数组AVALUE来决定其中哪些变量的现行值尚不在其内存单元中,最后利用活跃变量信息来决定其中哪些变量是活跃的。例如,由例7.2的表7.2查RVALUE栏可知:U和D的值在寄存器中,而从AVALUE栏知U和D的值都不在内存单元中,又由例7.1表7.1知,D在基本块出口之后是活跃变量,所以,在表7.2所生成的目标代码后面还要生成一条目标代码:MOVD,AX第24页,此课件共74页哦7.1.3寄存器分配由于寄存器数量有限,为了生成更有效的目标代码,就必须考虑如何更有效地利用寄存器。为此,我们定义指令的执行代价如下:每条指令的执行代价=每条指令访问内存单元次数+1假定在循环中,某寄存器固定分配给某变量使用,那么对循环中的每个基本块,相对于原简单代码生成算法所生成的目标代码,所节省的执行代价可用下述方法计算:第25页,此课件共74页哦(1)在原代码生成算法中,仅当变量在基本块中被定值时,其值才存放在寄存器中。现在把寄存器固定分配给某变量使用,当该变量在基本块中被定值前,每引用它一次就可以少访问一次内存,则执行代价节省1。(2)在原代码生成算法中,如果某变量在基本块中被定值且在基本块出口之后是活跃的,则出基本块时要把它在寄存器中的值存放到内存单元中。现在把寄存器固定分配给某变量使用,出基本块时就无需把它的值存放到其内存单元中,则执行代价节省2。第26页,此课件共74页哦因此,对循环L中的变量M,如果分配一个寄存器给它专用,那么每执行循环一次,其执行代价的节省数可用下式计算:其中,USE(M,B)=基本块B中对M定值前引用M的次数1如果M在基本块B中被定值且在B的出口之后是活跃的LIVE(M,B)=0其它情况第27页,此课件共74页哦例7.3一代码序列及程序流图如图71所示。假定各基本块出口之后的活跃变量均为a、b、c,循环中的固定寄存器为AX、BX,则将AX、BX固定分配给循环中哪两个变量可使执行代价节省得最多?第28页,此课件共74页哦图71程序流图第29页,此课件共74页哦解答(1)考虑变量a的情况:基本块B2中没有对a进行定值,且引用的次数为1(e=ab);基本块B3没有对a进行定值,也没有引用a;基本块B4对a进行了定值,并且定值前引用的次数为1(a=af)。根据执行代价节省数的计算公式得到:USE(a,B2)=1;LIVE(a,B2)=0;USE(a,B3)=0;LIVE(a,B3)=0;USE(a,B4)=1;LIVE(a,B4)=1;因此,变量a在一次循环中执行代价的节省总数为:USE(a,B)+2*LIVE(a,B)BL=1+0+1+2*(0+0+1)=4第30页,此课件共74页哦(2)对于变量b有:USE(b,B2)=2;LIVE(b,B2)=1;USE(b,B3)=1;LIVE(b,B3)=1;USE(b,B4)=0;LIVE(b,B4)=0;因此,变量b在一次循环中执行代价的节省总数为:USE(b,B)+2*LIVE(b,B)BL=2+1+0+2*(1+1+0)=7第31页,此课件共74页哦(3)对于变量c有:USE(c,B2)=2;LIVE(c,B2)=1;USE(c,B3)=1;LIVE(c,B3)=0;USE(c,B4)=1;LIVE(c,B4)=0;因此,变量c在一次循环中执行代价的节省总数为:USE(c,B)+2*LIVE(c,B)BL=2+1+1+2*(1+0+0)=6第32页,此课件共74页哦7.1.4源程序到目标代码生成示例我们以PC机的汇编语言作为目标代码,且假定可用的寄存器为AX、BX、CX和DX,则一C语言源程序转换为四元式代码序列,然后再转换为目标代码程序(转换中不考虑优化)的结果如下:第33页,此课件共74页哦(1)C语言源程序(局部)while(ab)if(m=n)a=a+1;elsewhile(k=h)x=x+2;m=n+x*(m+y);第34页,此课件共74页哦(2)四元式代码序列100(j,a,b,102)101(j,_,_,117)102(j=,m,n,104)103(j,_,_,107)104(+,a,1,T1)105(=,T1,_,a)106(j,_,_,112)107(j=,k,h,109)108(j,_,_,112)109(+,x,2,T2)第35页,此课件共74页哦110(=,T2,_,x)111(j,_,_,107)112(+,m,y,T3)113(*,x,T3,T4)114(+,n,T4,T5)115(=,T5,_,m)116(j,_,_,100)第36页,此课件共74页哦(3)目标代码程序(汇编语言程序);File:compile.asm;*datasegment;定义数据段hDW kDW mDW nDW xDW第37页,此课件共74页哦yDW aDWbDWdataends;数据段定义结束;*codesegment;定义代码段mainprocfar;程序的执行部分assumcs:code,ds:data第38页,此课件共74页哦start:pushdssubbx,bxpushbxmovbx,data;设置DS段为当前数据段movds,bx;语句翻译由此开始:100:movAX,acmpAX,bjg102第39页,此课件共74页哦101:mp117102:movAX,mcmpAX,njge104103:jmp107104:movAX,aaddAX,1D105:movBX,AXmova,BX;跳出基本块前保存寄存器中已改变的变量值106:jmp112第40页,此课件共74页哦107:movAX,kcmpAX,hje109108:jmp112109:movAX,xaddAX,2D110:movBX,AXmovx,BX;跳出基本块前保存寄存器中已改变的变量值111:jmp107112:movAX,m第41页,此课件共74页哦addAX,y113:mulx114:movBX,naddBX,AX115:movCX,BXmovm,CX;跳出基本块前保存寄存器中已改变的变量值116:jmp100117:retmainendp第42页,此课件共74页哦codeends;代码段定义结束endstart第43页,此课件共74页哦*7.2 汇编指令到机器代码的翻译概述汇编指令到机器代码的翻译概述虽然我们已经在微机原理或汇编语言程序设计课程中学习了8086/8088指令系统,但那是从掌握汇编语言和微机的原理及使用的角度来学习指令系统的。现在,我们从编译的角度来深入了解8086/8088指令系统的设计特点及实现方法。第44页,此课件共74页哦8086/8088指令系统的编码格式非常紧凑并且灵活,其机器码指令长度为16个字节(不包括前缀),通常指令的第一字节为操作码,用以规定操作的类型;第二字节规定操作数的寻址方式。典型的单操作数指令结构如图72所示。第45页,此课件共74页哦图72典型的单操作数指令第46页,此课件共74页哦典型的双操作数指令结构如图73所示。图73典型的双操作数指令第47页,此课件共74页哦其中,reg表示寄存器寻址代码;mod表示寻址方式代码;r/m表示寄存器或存储器寻址方式(与mod字段组合决定);d位表示指示操作数的传送方向,用于双操作数指令;w位表示字操作标志位。d=0时,reg字段为源操作数,r/m和mod字段为目的操作数;d=1时,r/m和mod字段为源操作数,reg字段为目的操作数。w=0是字节操作指令;w=1是字操作指令。第48页,此课件共74页哦由于双操作数指令只有一个w位,因此,两个操作数要么都是8位,要么都是16位。然而,对于值很小的立即数操作来说,如果用16位表示就有些浪费存储空间了。为了减少这种情况下立即数所占用的字节数,8086/8088指令系统对诸如加法、减法和比较的立即数操作指令设置了符号扩展位s,s位只对16位操作数(w=1)有效,即:0116位(字)操作,不进行符号扩展1116位(字)操作,但立即数仅给出低8位,应进行符号扩展sw=第49页,此课件共74页哦这样对一些16位立即数操作指令,立即数的存储仅是8位的,节省了存储空间和取指时间,只是当CPU执行该操作时再将立即数扩展为16位。8086/8088指令格式主要由操作码域和操作数域构成。操作码域指出了该指令操作的类型,操作码域中的d、w位(如果有的话)随传送方向及字还是字节操作而变化,少量指令存在着第二操作码。8086/8088指令格式设计的精妙之处在于操作数域,根据寻址方式、传送方向(d位)、字或字节操作(w位)决定了第二字节(寻址方式字节)中mod字段、r/m字段以及reg字段的取值及该条指令机器码的长度(须特别注意机器码长度的确定)。第50页,此课件共74页哦表7.3寻址方式表mod=11寄存器寻址MOD11存储器寻址,有效地址的计算r/mw=1w=0modr/m00(不带位移量)01(带8位位移量D8)10(带16位位移量D16)000AXAL000BX+SIBX+SI+D8BX+SI+D16001CXCL001BX+DIBX+DI+D8BX+DI+D16010DXDL010BP+SIBP+SI+D8BP+SI+D16011BXBL011BP+DIBP+DI+D8BP+DI+D16100SPAH100SISI+D8SI+D16101BPCH101DIDI+D8DI+D16110SIDH110D16(直接寻址)BP+D8BP+D16111DIBH111BXBX+D8BX+D16第51页,此课件共74页哦表7.4寄存器表寄存器寻址编码寄存器段寄存器寻址编码段寄存器w=1w=0000AXAL00ES001CXCL01CS010DXDL10SS011BXBL11DS100SPAH101BPCH110SIDH111DIBH第52页,此课件共74页哦有了表7.3和表7.4,我们就可以根据传送方向位d、字或字节操作位w的值以及所要求的寻址方式及参加操作的寄存器或存储器地址来构造由mod、r/m和reg字段组成的寻址方式字节并形成属于操作数域的其后各字节内容。例如,数据传送类指令MOV所允许出现的指令格式有:(1)寄存器/存储器寄存器:100010dwmodregr/m第53页,此课件共74页哦(2)立即数寄存器/存储器:1110001wmod000r/mdatadataifw=1(3)立即数寄存器:1011wregdatadataifw=1(4)存储器累加器:101000dwaddrlowaddrhight第54页,此课件共74页哦(5)累加器存储器:1010001waddrlowaddrhight(6)寄存器/存储器分段寄存器:10001110mod0regr/m(7)分段寄存器寄存器/存储器:10001100mod0regr/m第55页,此课件共74页哦对于寄存器/存储器与寄存器之间的传送命令可以采用方式(1),如:MOVAX,BX;(BX)AX由于d位值不同,第二字节的编码可以有两种形式:当d=0时,reg对应源操作数BX,即为BX的编码011;r/m对应目的操作数AX,即为AX的编码000;此时mod值为11,表示操作数为寄存器,即mod值和r/m值共同决定了这个操作数的类型是寄存器并且是AX(000)。因此该指令的机器码如下:操作码dwmodregr/m1000100111011000第56页,此课件共74页哦当d=1时,reg对应目的操作数AX,即为AX的编码000;r/m对应源操作数BX,即为BX的编码011;mod值指示寄存器应为11;所以此时该指令的机器码如下:操作码dwmodregr/m1000101111000011第57页,此课件共74页哦如果指令是寄存器与存储器之间的传送操作,例如:MOVAX,BX+DI+1234H,则对应的机器指令只能有一种形式。这是因为reg段只能表示寄存器而无法表示存储器,而mod和r/m字段的组合根据mod域值既可以表示寄存器又可以表示存储器,故当操作数的一方是存储器时就只能用mod和r/m字段来表示了。究竟是将寄存器的内容传送到存储器还是将存储器的内容传送到寄存器,这取决于传送方向位d的值。第58页,此课件共74页哦本条指令的存储器地址通过查找表7.3可知,mod值为10,r/m值为001;而由表7.4得知reg所对应的操作数AX值为000,并且d位值必须为1才能保证将mod和r/m指定的内容送AX,所以此时该指令对应的机器码为:操作码dwmodregr/m16位位移量10001011100000010011010000010010第59页,此课件共74页哦对于立即数传送到寄存器/存储器的操作可采用方式(2),如:MOVCL,12H;立即数12HCL这是一个字节传送指令,即w=0,因此mod=11和r/m=001表示寄存器CL,第三字节为立即数12H,即该指令的机器码如下:操作码wmodregr/m立即数 110001101100000100010010第60页,此课件共74页哦如果用方式(3)实现该操作则更加简单。由于此时w=0,reg=001,则该指令所对应的机器码为:操作码wreg立即数 1 0 1 1 0 0 0 1 0 0 0 1 0 0 1 0 第61页,此课件共74页哦与方式(2)的机器码相比节省了一个字节。下面,我们看一下立即数传送到存储器的操作,这种操作只能用方式(2)实现,例如:MOVBX+DI+1234H,5678H查表7.3可知:mod=10,r/m=001;此时该指令对应的机器码为:操作码dwmodregr/m16位位移量16位立即数110001111000000100110100000100100111100001010110第62页,此课件共74页哦由mod=10可知,存储器操作数还带有16位位移量,这个16位位移量是紧随在机器码第二字节即寻址方式字节之后的,所以位移量必须插到立即数之前,以便形成存储器的有效地址。注意,此时的机器码指令长度为6个字节,这是8086/8088指令系统中最长的机器码指令形式。通过机器码指令的形成过程可知,机器码指令的长度是由字或字节操作以及寻址方式决定的。这一点对编译来说很重要,因为在编译过程中必须根据源指令来确定形成的机器码指令所应具有的字节数(即长度)。第63页,此课件共74页哦由8086/8088指令系统的寻址方式和机器码指令的寻址方式字节即mod、r/m和reg字段可以看出:双操作数指令允许寄存器与寄存器、寄存器与存储器之间进行操作,此外还允许立即数到寄存器/存储器的操作;但无法用mod、r/m和reg字段来同时表示两个存储器的地址。如果允许存储器到存储器操作的指令出现,将会使机器码指令变得更长、更复杂。故此,8086/8088舍去了直接进行存储器之间操作的指令,使得机器指令更加简洁有效。如果要实现存储器到存储器的操作,只需经过寄存器过渡:先进行存储器到寄存器的操作,并将结果保存在寄存器中,然后再使用一条由寄存器传送到存储器的指令操作即可。第64页,此课件共74页哦我们再看一下增量指令INC的处理。INC指令可以采用的机器码格式如下:(1)寄存器:01000reg(2)寄存器/存储器:100010dwmod000r/m第65页,此课件共74页哦01000100方式(1)为单操作数指令,由于reg字段无法表示出是8位寄存器还是16位寄存器,因而系统规定它为16位寄存器的操作,如表示为INCSP,而不是INCAH。对8位(或16位)寄存器或存储器进行INC操作可采用方式(2),但16位寄存器的INC则最好按方式(1)翻译成机器码,这样可节省一个字节空间。算术运算中的加法指令ADD可以采用的机器码格式如下:(1)寄存器/存储器与寄存器相加,其结果送二者之一:01000100第66页,此课件共74页哦(2)立即数与寄存器/存储器相加,结果送寄存器/存储器:000000dwmod000r/m100000swmod000r/mdatadataifw=1(3)立即数与累加器相加,结果送累加器(累加器16位:AX;8位:AL):0000010wdatadataifw=1第67页,此课件共74页哦例如,立即数与寄存器相加的指令:ADDAX,12H;(AX)+12HAX采用方式(2)实现时,由于该指令是字操作指令,但立即数却是以字节(8位)表示的,故执行此操作时CPU要进行符号扩展(s=1时将8位补码操作数扩展为16位补码操作数,使高字节的各位与低位字节的最高位相同)。因此置s位为1,该指令对应的机器码为操作码swmodregr/m立即数 1 0 0 0 0 0 1 1 1 1 0 0 0 0 0 0 0 0 0 1 0 0 1 0 第68页,此课件共74页哦当CPU执行到该机器码指令时,便自动将第三字节的立即数12H扩展为0012H参与运算。当然,也可以将该指令改写为ADDAX,0012H此时该指令对应的机器码为操作码swmodregr/m16位立即数10000001110000000001001000000000第69页,此课件共74页哦即sw=01,对应的机器码指令长度为4个字节。也可以采用方式(3)来实现该相加指令,此方式只对累加器AX、AL与立即数的相加有效:操作码w立即数000001010001001000000000第70页,此课件共74页哦这种方式机器码长度为3个字节。如果是字节操作的话,如ADDAL,12H,则与方式(2)相比可节省一个字节。通过上述的例子,我们对8086/8088汇编助记符指令到机器码指令的翻译过程有了初步的认识,实际翻译的过程也大致如此。最后,我们将8086/8088指令系统的机器码格式归纳如下:(1)单字节指令(隐含操作数):操 作 码 第71页,此课件共74页哦(2)单字节指令(寄存器寻址):操作码reg(3)寄存器到寄存器:操作码11regr/m(4)不带位移量的寄存器与存储器之间的传送:(mod11)操作码mod reg r/m第72页,此课件共74页哦(5)带位移量的寄存器与存储器之间的传送(mod=01或mod=10):操作码modregr/m位移量低字节位移量高字节(使用16位位移量时)(6)立即数送寄存器:操作码11000r/m立即数低字节立即数高字节(使用16位位移量时)第73页,此课件共74页哦(7)立即数送存储器:操 作 码 11000r/m 立即数低字节 立即数高字节 立即数低字节 立即数高字节(使用16位位移量时)mod=01或mod=10时(使用16位数据时)8086/8088指令系统的编码空间表见附录2。第74页,此课件共74页哦