x86汇编语言复习笔记
<h1 align="left">0 写在前面</h1><p> 为了更深入的了解程序的实现原理,近期我学习了<span style="color: rgba(255, 102, 0, 1)">IBM-PC</span>相关原理,并手工编写了一些<span style="color: rgba(0, 0, 255, 1)">x86汇编程序</span>。</p>
<p> 在2017年的计算机组成原理中,曾对<span style="color: rgba(128, 0, 128, 1)">MIPS体系结构及其汇编语言</span>有过一定的了解,考虑到x86体系结构在目前的广泛应用,我通过两个月左右的时间对x86的相关内容进行了学习。</p>
<p> 在<span style="color: rgba(255, 0, 0, 1)">《x86汇编语言实践》系列</span>中(包括本篇、x86汇编语言实践(1)、x86汇编语言实践(2)、x86汇编语言实践(3)以及x86汇编语言实践(4)),我通过几个具体案例对x86汇编语言进行实践操作,并记录了自己再编写汇编代码中遇到的困难和心得体会,与各位学习x86汇编的朋友共同分享。</p>
<p> 我将我编写的一些汇编代码放到了github上,感兴趣的朋友可以点击屏幕左上角的小猫咪进入我的github,或请点击这里下载源代码。</p>
<p> 这是<span style="color: rgba(255, 0, 0, 1)">《x86汇编语言实践》系列<span style="color: rgba(0, 0, 0, 1)">的<span style="color: rgba(0, 0, 255, 1)">最后一篇文章</span>,明天就要迎来<span style="color: rgba(255, 102, 0, 1)">x86汇编的期末考试</span>了,希望所有朋友们以及先先能够考试顺利!</span></span></p>
<h1 align="left">1 基础知识</h1>
<p><span style="color: rgba(255, 0, 0, 1)"><span style="color: rgba(0, 0, 0, 1)">1.Intel 8086/8088PC机的CPU<span style="text-decoration: underline; color: rgba(255, 102, 0, 1)">字长为16</span>位,16位的信息称为1个字,内存的基本单元为1个字节,但任何相邻两个单元都可以组成1个字。Intel 8086/8088PC机共有<span style="text-decoration: underline"><span style="color: rgba(255, 102, 0, 1); text-decoration: underline">20根地址线</span></span>,其寻址范围为<span style="text-decoration: underline"><span style="color: rgba(255, 102, 0, 1); text-decoration: underline">00000H~FFFFFH</span></span>。</span></span></p>
<p><span style="color: rgba(255, 0, 0, 1)"><span style="color: rgba(0, 0, 0, 1)">2.用于间接寻址的寄存器有<span style="text-decoration: underline"><span style="color: rgba(128, 0, 128, 1); text-decoration: underline">BX,SP,BP,SI,DI</span></span>,其中,<span style="text-decoration: underline"><span style="color: rgba(128, 0, 128, 1); text-decoration: underline">BX</span></span>一般用于存放<span style="text-decoration: underline"><span style="color: rgba(128, 0, 128, 1); text-decoration: underline">基址</span></span>;在采用基址变址寻址时,采用<span style="text-decoration: underline"><span style="color: rgba(128, 0, 128, 1); text-decoration: underline">SI或BX或DI</span></span>寄存器,基址寻址默认的段是<span style="text-decoration: underline"><span style="color: rgba(128, 0, 128, 1); text-decoration: underline">DS</span></span>段(DS:);采用<span style="text-decoration: underline"><span style="color: rgba(128, 0, 128, 1); text-decoration: underline">BP或SP</span></span>寄存器,基址寻址默认的段是<span style="text-decoration: underline"><span style="color: rgba(128, 0, 128, 1); text-decoration: underline">SS</span></span>段(堆栈的位置和大小是由SP和SS共同决定的)。</span></span></p>
<p><span style="color: rgba(255, 0, 0, 1)"><span style="color: rgba(0, 0, 0, 1)">3.串操作指令如<span style="text-decoration: underline"><span style="color: rgba(255, 0, 255, 1); text-decoration: underline">MOVSB,STOSB,LODSB,SCASB,CMPSB,MOVSW,LODSW,STOSW,SCASW,CMPSW</span></span>等,<span style="color: rgba(0, 0, 255, 1)">源操作数</span>对应的地址是<span style="text-decoration: underline; color: rgba(255, 0, 255, 1)">DS:</span>,<span style="color: rgba(0, 0, 255, 1)">目的操作数</span>对应的地址是<span style="text-decoration: underline"><span style="color: rgba(255, 0, 255, 1); text-decoration: underline">ES:</span></span>。</span></span></p>
<p><span style="color: rgba(255, 0, 0, 1)"><span style="color: rgba(0, 0, 0, 1)">4.Intel8086/8088CPU共有9个1为的标志寄存器(标志位),为了便于CPU的加工,他们被组合在一起形成一个16位的程序状态字寄存器PSW中。</span></span><span style="color: rgba(255, 0, 0, 1)"><span style="color: rgba(0, 0, 0, 1)">几个比较重要的标志位有:</span></span></p>
<ul>
<li><span style="color: rgba(255, 0, 0, 1)"><span style="color: rgba(0, 0, 0, 1)">ZF:<span style="color: rgba(255, 0, 0, 1)">当运算结果为0时,ZF=1</span>,否则ZF=0</span></span></li>
<li><span style="color: rgba(255, 0, 0, 1)"><span style="color: rgba(0, 0, 0, 1)">SF:运算结果<span style="color: rgba(0, 0, 255, 1)">为负时,SF=1</span>,否则SF=0</span></span></li>
<li>CF:算术运算最高位产生进位,CF=1.否则CF=0;还用于移位指令保存最高位左移或最低位右移移出的代码。</li>
<li>DF:DF=1时每次串操作SI和DI减1,DF=0时每次串操作SI和DI加1。使用CLD可以将DF清零,即规定为正向操作字符串。</li>
<li>TF:TF=1时执行完一条产生单步中断,中断处理程序将TF置0。TF标志用于调试。</li>
<li><span style="text-decoration: line-through; color: rgba(204, 153, 255, 1)">PF,AF,IF,OF这里我斗胆预测一啵,不考(因为真的没有使用过)。</span></li>
</ul>
<p><span style="color: rgba(255, 0, 0, 1)"><span style="color: rgba(0, 0, 0, 1)">5.STD是将<span style="color: rgba(0, 128, 0, 1)">DF置1</span>的指令,与CLD将DF清零的效果相反。<span style="color: rgba(0, 128, 0, 1)">使用<span style="text-decoration: underline">STD</span>后</span>,串指令对应的DI,SI寄存器每次操作后根据是SB还是SW操作<span style="text-decoration: underline"><span style="color: rgba(0, 128, 0, 1); text-decoration: underline">自动减少</span></span>1或2</span></span></p>
<p><span style="color: rgba(255, 0, 0, 1)"><span style="color: rgba(0, 0, 0, 1)">6.逻辑地址向物理地址的转化(书上P24)。地址转化的动机:20位物理地址无法直接在16位字长的机器中直接运算,因此可以<span style="color: rgba(255, 102, 0, 1)">采用Intel的分段方法将其划分为16位段地址和16位段内地址</span>(也称为偏移地址)逻辑地址的基本形式为0000H:0000H,该逻辑地址表示物理地址的00000H。</span></span></p>
<p><span style="color: rgba(255, 0, 0, 1)"><span style="color: rgba(0, 0, 0, 1)"> 那么逻辑地址向物理地址的转换方式可以表述为以下公式:<span style="color: rgba(255, 0, 0, 1)">段地址x10H + 偏移地址 = 物理地址</span></span></span></p>
<p><span style="color: rgba(255, 0, 0, 1)"><span style="color: rgba(0, 0, 0, 1)"> 举例说明:逻辑地址1234H:5678H转换为物理地址为:1234Hx10H + 5678H = 12340H + 5678H = 179B8H。再如:<span style="color: rgba(51, 102, 255, 1)">1234H:2001H = 12340H + 2001H = 14341H</span></span></span></p>
<p><span style="color: rgba(0, 0, 0, 1)">7.几个重要的数据传送指令PUSH,POP,PUSHF,POPF</span></p>
<ul>
<li>PUSH SRC:先SP = SP - 2 再 SS: <- SRC </li>
<li>PUSHF :先SP = SP - 2 再 SS: <- PSW</li>
<li>POP SRC:先SRC <- SS: 再 SP = SP + 2</li>
<li>POPF :先PSW <- SS: 再SP = SP + 2 </li>
</ul>
<p> 总结而言,<span style="color: rgba(255, 102, 0, 1)">PUSH和POP是将操作数压(弹)栈,POPF和PUSHF是将PSW标志寄存器压(弹)栈</span></p>
<h1 align="left">2 寻址方式</h1>
<h2 align="left">2-1 六种与数据有关的寻址方式</h2>
<h3>2-1-1 立即寻址</h3>
<p><span style="color: rgba(255, 0, 0, 1)"><span style="color: rgba(0, 0, 0, 1)"> 直接将立即数写到指令中的寻址方式。<span style="color: rgba(0, 0, 255, 1)">注意不得超出寄存器的字节范围</span>:AL8位,AX16位。</span></span></p>
<p><span style="color: rgba(0, 128, 0, 1)"> 【例】</span></p>
<ul>
<li><span style="color: rgba(0, 0, 0, 1)">AND AX,0FFFEH</span></li>
<li>MOV AL,100H</li>
<li>MOV AL,00000101B</li>
<li>MOV AX,512</li>
</ul>
<p> <span style="color: rgba(255, 0, 0, 1)"> 【不能使用】</span></p>
<ul>
<li><span style="text-decoration: line-through">MOV AL,100H</span></li>
<li><span style="text-decoration: line-through">MOV AX,10000H (超出了字节范围)</span></li>
</ul>
<h3>2-1-2 寄存器寻址</h3>
<p><span style="color: rgba(255, 0, 0, 1)"><span style="color: rgba(0, 0, 0, 1)"> 使用寄存器的寻址方式。可以显示使用,也可以隐式使用。也可以使用段寄存器CS,DS,SS,ES。</span></span></p>
<p><span style="color: rgba(0, 128, 0, 1)"> 【例】</span></p>
<ul>
<li><span style="color: rgba(255, 0, 0, 1)"><span style="color: rgba(0, 0, 0, 1)">MOV DS,AX </span></span></li>
<li><span style="color: rgba(255, 0, 0, 1)"><span style="color: rgba(0, 0, 0, 1)">PUSH DS</span></span></li>
<li><span style="color: rgba(255, 0, 255, 1)">PUSHF (隐式操作PSW)</span></li>
<li><span style="color: rgba(255, 0, 255, 1)">STD (隐式操作PSW)</span></li>
<li><span style="color: rgba(255, 0, 255, 1)">CMC (对CF取反操作,隐式操作PSW)</span></li>
</ul>
<h3>2-1-3 直接寻址</h3>
<p><span style="color: rgba(255, 0, 0, 1)"><span style="color: rgba(0, 0, 0, 1)"> 直接使用操作数的偏移地址进行寻址的方式,偏移地址用[立即数]的形式表示,或者直接用数据段中定义的变量名表示,或用数据段中定义的变量名+立即数的形式表示。</span></span></p>
<p><span style="color: rgba(255, 0, 0, 1)"><span style="color: rgba(0, 0, 0, 1)"> <span style="color: rgba(0, 128, 0, 1)">【例】</span></span></span></p>
<ul>
<li><span style="color: rgba(0, 0, 0, 1)">AND AX,</span></li>
<li><span style="color: rgba(0, 0, 0, 1)">MOV AX,X ;其中X为数据段中定义好的数据</span></li>
<li><span style="color: rgba(0, 0, 0, 1)"><span style="color: rgba(255, 0, 255, 1)">MOV AX,STR+1</span> ;其中STR为数据段中定义好的数据,STR+1直接寻址到STR下一个字节单元的内容</span></li>
</ul>
<h3>2-1-4 寄存器间接寻址</h3>
<p><span style="color: rgba(255, 0, 0, 1)"><span style="color: rgba(0, 0, 0, 1)"> 使用寄存器中存储的偏移地址进行寻址。注意只能使用寻址寄存器BX,BP,SI,DI进行寻址,而不能用DX等进行寻址。此外,寻址的地址必须为16位,即不能使用BL等进行寻址。</span></span></p>
<p><span style="color: rgba(0, 128, 0, 1)"> 【例】</span></p>
<ul>
<li><span style="color: rgba(0, 0, 0, 1)">MOV AX.</span></li>
<li><span style="color: rgba(0, 0, 0, 1)">MOV BH,</span></li>
<li><span style="color: rgba(0, 0, 0, 1)">MOV CX,</span></li>
<li><span style="color: rgba(0, 0, 0, 1)">MOV DL,</span></li>
</ul>
<p><span style="color: rgba(0, 0, 0, 1)"> 以上四条指令等价于</span></p>
<ul>
<li>MOV AX.DS:</li>
<li>MOV BH,SS:</li>
<li>MOV CX,DS:</li>
<li>MOV DL,ES:</li>
</ul>
<p> 但是在每条指令前加上一个段超越的段名,既麻烦又没必要,因此通常都默认缺省为上述隐含段规则。</p>
<p> <span style="color: rgba(255, 0, 0, 1)">【不能使用】</span></p>
<ul>
<li><span style="text-decoration: line-through">MOV AX, (不能用DX)</span></li>
<li><span style="text-decoration: line-through">MOV DL, (必须为16位寻址)</span></li>
</ul>
<h3>2-1-5 寄存器相对寻址</h3>
<p><span style="color: rgba(255, 0, 0, 1)"><span style="color: rgba(0, 0, 0, 1)"> 在寄存器间接寻址的基础上,再增加一个常偏移量。形式多变,大致有如下几种</span></span></p>
<p><span style="color: rgba(0, 128, 0, 1)"> 【例】</span></p>
<ul>
<li><span style="color: rgba(255, 0, 0, 1)"><span style="color: rgba(0, 0, 0, 1)">MOV AX,</span></span></li>
<li><span style="color: rgba(255, 0, 0, 1)"><span style="color: rgba(0, 0, 0, 1)">MOV AX, <==> MOV AX,10H</span></span></li>
<li><span style="color: rgba(255, 0, 0, 1)"><span style="color: rgba(0, 0, 0, 1)">MOV AX,ARRAY</span></span></li>
<li><span style="color: rgba(255, 0, 0, 1)"><span style="color: rgba(0, 0, 0, 1)">MOV TABLE,AL</span></span></li>
<li><span style="color: rgba(255, 0, 0, 1)"><span style="color: rgba(0, 0, 0, 1)">MOV TABLE,AL 3~5展示了立即数也可以是数据段中定义好的变量名</span></span></li>
</ul>
<p><span style="color: rgba(255, 0, 0, 1)"><span style="color: rgba(0, 0, 0, 1)"> 最终在debug下所有的寻址有效地址会被计算成的形式,XXXX是一个十六进制数。</span></span></p>
<h3>2-1-6 基址变址寻址</h3>
<p><span style="color: rgba(255, 0, 0, 1)"><span style="color: rgba(0, 0, 0, 1)"> 即基址加变址寻址方式,基址采用BX,BP寻址,变址采用DI,SI寻址,寻址规则相对固定。</span></span></p>
<p><span style="color: rgba(0, 128, 0, 1)"> 【例】</span></p>
<ul>
<li>MOV AX,</li>
<li>MOV AX,</li>
<li>MOV ES:,AL</li>
<li>MOV ,AX </li>
<li>MOV AX,</li>
<li>MOV ARRAY,AX</li>
</ul>
<p> 其中,段取决于基址寄存器,如<span style="color: rgba(255, 153, 0, 1)">BX的段就默认为DS;BP缺省为SS</span>。当然,有指定段的情况除外。也可以在两个寄存器加和的基础上再增加一个立即数。</p>
<p> <span style="color: rgba(255, 0, 0, 1)"> 【不能使用】</span></p>
<ul>
<li><span style="text-decoration: line-through">MOV ,AX (CX不能做变址寄存器)</span></li>
<li><span style="text-decoration: line-through">MOV ,AX (BP不能做变址寄存器)</span></li>
<li><span style="text-decoration: line-through">MOV ,ARRAY (两个全在内存中的操作数,不符合语法)</span></li>
</ul>
<h2 align="left">2-1 五种与转移地址有关的寻址方式</h2>
<h3>2-2-1 标号与过程名</h3>
<p> 与转移地址相关的指令主要是JMP和CALL指令,而要让代码能够跳跃执行到指定的IP处则需要通过标号指示某行代码,或是通过过程名定义进行CALL调用。</p>
<h3>2-2-2 段内直接寻址</h3>
<p> 即直接使用标号与过程名进行跳转。根据位移量的不同,可以加<span style="color: rgba(153, 51, 102, 1)">SHORT(8BITS)和NEAR PTR(16BITS)</span>操作符。其中,条件跳转只能是8位因此省略SHORT,而JMP则缺省为16位位移量。因此,在跳转位移已知的前提下,使用JMP SHORT可以提高程序的执行效率。</p>
<p><span style="color: rgba(0, 128, 0, 1)"> 【例】</span></p>
<ul>
<li>JMP L1</li>
<li>CALL P1</li>
<li>JMP SHORT L1</li>
<li>JMP NEAR PTR L1 (L!与当前IP位移量为16位的数值)</li>
</ul>
<h3>2-2-3 段内间接寻址</h3>
<p> 即将转移目的地址放入寄存器中进行存储,调用的也是寄存器中的相应数值。</p>
<p> <span style="color: rgba(0, 128, 0, 1)">【例】</span></p>
<ul>
<li>MOV AX,OFFSET P1 CALL AX</li>
<li>JMP BX</li>
</ul>
<p> 这里要特别注意段内间接寻址与数据寻址中寄存器间接寻址的区别,后者有[]进行寻址。</p>
<ul>
<li>MOV AX,OFFSET P1 MOV ADD1,AX CALL ADD1</li>
<li>MOV BX,OFFSET ADD1 CALL </li>
</ul>
<p> <span style="color: rgba(255, 102, 0, 1)">以上两种也是段内间接寻址</span>,注意这里ADD1不是过程名,而是数据段中的一个数据的地址,存放了子程序P1的位移量。BX则存放了ADD1的地址,因此调用CALL 也属于段内间接寻址。</p>
<h3>2-2-4 段间直接寻址</h3>
<p> 具备FAR属性的寻址。例如P2为一个有FAR属性定义的过程:</p>
<ul>
<li>CALL FAR P2</li>
</ul>
<h3>2-2-5 段间间接寻址</h3>
<p> 形式如下:</p>
<ul>
<li>JMP DWORD PTR </li>
</ul>
<p> 只要DWORD PTR后面是<span style="color: rgba(128, 0, 128, 1)">除了<span style="text-decoration: line-through">立即寻址</span>和<span style="text-decoration: line-through">寄存器寻址</span></span>之外的任何一种数据寻址方式即可。</p>
<h1>3 语法知识</h1>
<p>【判断指令正误】</p>
<ul>
<li><span style="text-decoration: line-through"><span style="color: rgba(255, 0, 0, 1); text-decoration: line-through">MOV ,AL</span></span><span style="color: rgba(255, 0, 0, 1)"> </span><span style="color: rgba(255, 0, 0, 1)"> 不正确。<span style="color: rgba(51, 102, 255, 1)">CX不能作为寄存器间接寻址的寄存器</span></span></li>
<li><span style="color: rgba(255, 0, 0, 1)"><span style="text-decoration: line-through">MOV BH,320 </span> 不正确。<span style="color: rgba(51, 102, 255, 1)">320超出了8位范围(255)</span></span></li>
<li><span style="color: rgba(255, 0, 0, 1)"><span style="text-decoration: line-through">MOV DS,2000H</span> 不正确。<span style="color: rgba(51, 102, 255, 1)">不存在从立即数到段寄存器的数据通路。此外,段寄存器作目的操作数时,不允许使用CS作为目的操作数。</span></span></li>
<li><span style="color: rgba(255, 102, 0, 1)">ADD SI,FDDH 不能确定。</span><span style="color: rgba(0, 128, 0, 1)">如果在数据段定义过一个名为FDDH的数据变量,且该数据在字节范围内,则此指令正确。否则会认为FDDH是一个未定义的变量,改成0FFDH后正确。</span></li>
<li><span style="color: rgba(255, 0, 0, 1)"><span style="text-decoration: line-through">SHL AX,2 </span> 不正确。</span><span style="color: rgba(51, 102, 255, 1)">移位指令格式中,移位的数量count只能是1或CL。移动位数大于1(0和1也可以)必须放入CL寄存器中操作。</span></li>
<li><span style="color: rgba(255, 0, 0, 1)"><span style="text-decoration: line-through">CMP BYTE PTR ,X</span> 不正确。</span><span style="color: rgba(51, 102, 255, 1)">源操作数和目的操作数不能同时为内存中的数。</span></li>
<li><span style="color: rgba(0, 128, 0, 1)">LEA BX,</span> <span style="color: rgba(0, 128, 0, 1)"> 正确。</span></li>
<li><span style="color: rgba(255, 0, 0, 1)"><span style="text-decoration: line-through">LDS BX,</span> 不正确。</span><span style="color: rgba(51, 102, 255, 1)">DX不能用作寄存器间接寻址的寄存器</span></li>
<li><span style="color: rgba(255, 0, 0, 1)"><span style="text-decoration: line-through">JMP BYTE PTR AX</span> 不正确。</span><span style="color: rgba(128, 0, 128, 1)">转移只有NEAR/FAR PTR + 标号或SHORT+标号或只有标号/寄存器</span><span style="color: rgba(51, 102, 255, 1)">的形式。没有JMP BYTE PTR的形式</span></li>
<li><span style="color: rgba(51, 153, 102, 1)">JMP AX 正确。</span></li>
<li><span style="color: rgba(51, 153, 102, 1)"><span style="color: rgba(255, 0, 0, 1)"><span style="text-decoration: line-through">JMP </span> 不正确。</span><span style="color: rgba(51, 102, 255, 1)">AX不能用作间接寻址的寄存器。</span></span></li>
<li><span style="color: rgba(255, 0, 0, 1)"><span style="text-decoration: line-through">RET 5 </span> 不正确。</span><span style="color: rgba(51, 102, 255, 1)">后面的立即数必须为偶数。这是为了带参数调用的子程序在返回时要弹出几个参数的位置,进而维持堆栈的平衡。</span></li>
<li><span style="color: rgba(255, 0, 0, 1)"><span style="text-decoration: line-through">MOV ,100</span> 不正确。</span><span style="color: rgba(51, 102, 255, 1)">注意只有在寄存器相对寻址取数(作为源操作数)时直接寻址即可,若作为目的操作数则必须指定size。修改为MOV BYTE PTR,100即可。</span></li>
<li><span style="color: rgba(0, 128, 0, 1)">DIV AL 正确。执行结果为AX=0001即除以本身,商1余0。</span></li>
</ul>
<h1>4 简答问题</h1>
<h2>4-1 解读指令执行过程</h2>
<p> 1. RET EXP</p>
<p> IP ← </p>
<p> SP ← SP + 2</p>
<p> SP ← SP + EXP</p>
<p>2.RETF</p>
<p> 注意<span style="color: rgba(0, 0, 255, 1)">如果是FAR属性的过程,返回时是段间返回(即在汇编器中会被汇编成RETF指令)</span>,会执行以下过程</p>
<p> IP ← </p>
<p> SP ← SP + 2</p>
<p> CS ← </p>
<p> SP ← SP + 2</p>
<p>3.PUSH SRC</p>
<p> SP ← SP - 2</p>
<p> SS: ← SRC</p>
<p>4.PUSHF</p>
<p> SP ← SP - 2</p>
<p> SS: ← PSW</p>
<p>5.POP DST</p>
<p> DST ← SS:</p>
<p> SP ← SP + 2</p>
<p>6.POPF</p>
<p> PSW ← SS:</p>
<p> SP ← SP + 2</p>
<p>7.LEA REG,SRC</p>
<p> 将SRC的<span style="color: rgba(255, 102, 0, 1)">偏移地址</span>送入REG </p>
<p>8.LDS/LES REG,SRC</p>
<p> 将SRC中的<span style="color: rgba(255, 102, 0, 1)">双字内容</span>分别送REG和DS/ES中。</p>
<p> 这里的<span style="color: rgba(51, 102, 255, 1)">SRC中的双字通常保存的是某个程序或变量的逻辑地址(SEG:OFFSET)</span>,前面的低字送入REG,后面的高字送入DS/ES。</p>
<p><span style="color: rgba(255, 0, 0, 1)">9.CALL FAR PTR P1 </span></p>
<p> SP ← SP - 2</p>
<p> SS: ← 返回地址段值</p>
<p> SP ← SP - 2</p>
<p> SS: ← 返回地址偏移值</p>
<p> IP ← 目的偏移地址</p>
<p> CS ← 目的段地址 </p>
<p>10.CALL AX(假设为段内间接调用)</p>
<p> SP ← SP - 2</p>
<p> SS: ← 返回地址偏移值</p>
<p> IP ← AX中有效地址</p>
<p>11.JMP </p>
<p> 从内存中根据BX间接寻址,取得的标号值送IP进行跳转。</p>
<p>12.JMP DX</p>
<p> 将DX中有效地址偏移值送入IP进行跳转。</p>
<p>13.CALL DWORD PTR </p>
<p> 段间间接调用,过程地址CS:IP(这是一个双字,因此用DWORD PTR)位于数据段中通过BX间接寻址得到。</p>
<p>14.LOOP LP1</p>
<p> CX = CX - 1</p>
<p> 若<span style="color: rgba(255, 0, 255, 1)">CX ≠ 0</span>,则跳转至LP1,否则顺序执行之后代码。</p>
<p>15.CMP BX,X1</p>
<p> 分别通过寄存器寻址和直接寻址取得BX与X1的值,计算BX-X1并影响标志位。(如<span style="color: rgba(255, 102, 0, 1)">可用ZF判断两数是否相等、CF=1或SF=1则BX<X1等等,再配合JC,JS等指令即可进行条件跳转</span>)</p>
<p><span style="color: rgba(255, 0, 0, 1)">16.INT 21H / IRET</span></p>
<blockquote>
<p> Intel8086/8088指令系统中用于支持中断调用的指令为INT n,返回中断的指令时IRET。此外,CLI用于清除中断标志,STI用于设置中断标志。</p>
<p> ----《书》P173</p>
</blockquote>
<p> <span style="color: rgba(51, 102, 255, 1)">INT 21H的执行过程:</span></p>
<ul>
<li>SP ← SP - 2</li>
<li>SS: ← PSW</li>
<li>SP ← SP - 2</li>
<li>SS: ← INT N 下一条指令的CS</li>
<li>SP ← SP - 2</li>
<li>SS: ← INT N 下一条指令的IP</li>
<li>IP ← </li>
<li>CS ← </li>
</ul>
<p> <span style="color: rgba(51, 102, 255, 1)"> IRET的执行过程:</span></p>
<ul>
<li>IP ← SS:</li>
<li>SP ← SP + 2</li>
<li>CS ← SS:</li>
<li>SP ← SP + 2</li>
<li>PSW ← SS:</li>
<li>SP ← SP + 2</li>
</ul>
<h2>4-2 图解移位指令</h2>
<p><img src="https://img2018.cnblogs.com/blog/1346958/201905/1346958-20190509154142450-1972683874.png" alt="" width="891" height="445"></p>
<h2>4-3 指出目的寄存器中的内容</h2>
<p> 已知:DS = 2100H,BX = 0100H,SI = 0002H;内存中: = 12H, = 34H, = 56H, = 78H。</p>
<ul>
<li>MOV AX, ;直接寻址,默认段DS。AX的结果为3456H <span style="color: rgba(0, 0, 255, 1)">?在DOS下,汇编后变成了MOV AX,101这种立即寻址形式,使得AX最终的结果为0101H</span></li>
<li>MOV AX,WORD PTR ;寄存器相对寻址。AX结果为7856H</li>
<li>MOV AL,BYTE PTR ;基址变址寻址。AL结果为78H</li>
<li>MOV AX,100H ;寄存器相对寻址。AX结果为7856H(<span style="color: rgba(255, 0, 0, 1)">注意取出的为一个字!而且是小端存储!低字节在高位!</span>)</li>
</ul>
<h2>4-4 指出CS与IP的值</h2>
<p> 已知:DS = 2100H,BX = 0101H,CS = 1900H;内存中: = 0C7H, = 0FFH, = 00H, = 0F0H。</p>
<ul>
<li>JMP BX ;CS = 1900H,IP=0101H</li>
<li>JMP ;CS = 1900H,IP=0FFC7H </li>
<li>JMP WORD PTR ;CS = 1900H,IP=00FFH <span style="color: rgba(255, 0, 0, 1)">(注意小端存储,低字节在低地址)</span></li>
<li>JMP DWORD PTR ;CS = 0F000H,IP=0FFC7H <span style="color: rgba(255, 102, 0, 1)">(取双字分别取得的是段地址与偏移值)</span></li>
</ul>
<h2><span style="color: rgba(0, 0, 0, 1)">4-5 根据要求画内存示意图</span></h2>
<p><span style="color: rgba(0, 0, 0, 1)"> 1.定义MYSEG数据段,其中有S1,内容'ABCD'以00H结尾;S2是能用AH=9,INT 21H显示的字符串;S3为10x10的二维字数组。L1为S1+S2+S3的长度。</span></p>
<p><span style="color: rgba(0, 0, 0, 1)"> 则可以画出该数据段内存示意图如下:</span></p>
<p><span style="color: rgba(0, 0, 0, 1)"> <img src="https://img2018.cnblogs.com/blog/1346958/201905/1346958-20190509154105854-83734945.png" alt=""></span></p>
<p> </p>
<p> 其中<span style="color: rgba(255, 102, 0, 1)">一个英文字母占据1字节</span>,即一个内存单元;显示字符串必须以'$'结尾。常量定义形式应为 <span style="color: rgba(128, 0, 128, 1)">L1 EQU $-S1</span>。注意,<span style="color: rgba(255, 0, 0, 1)">字数组一个字占两个字节</span>。故L1的值为<span style="color: rgba(255, 102, 0, 1)">210</span>。</p>
<p> 2.书P96第2题的数据段可以定义如下:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 128, 1)">1</span> <span style="color: rgba(0, 0, 0, 1)">DATA SEGMENT PARA
</span><span style="color: rgba(0, 128, 128, 1)">2</span> X1 DB <span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">Display string</span><span style="color: rgba(128, 0, 0, 1)">'</span>,0DH,0AH,<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">$</span><span style="color: rgba(128, 0, 0, 1)">'</span>
<span style="color: rgba(0, 128, 128, 1)">3</span> X2 DB <span style="color: rgba(128, 0, 128, 1)">32</span>
<span style="color: rgba(0, 128, 128, 1)">4</span> <span style="color: rgba(0, 0, 0, 1)"> X3 DW 40H
</span><span style="color: rgba(0, 128, 128, 1)">5</span> <span style="color: rgba(0, 0, 0, 1)"> X4 DD A000H,0120H
</span><span style="color: rgba(0, 128, 128, 1)">6</span> X5 DW <span style="color: rgba(128, 0, 128, 1)">10</span> DUP(<span style="color: rgba(128, 0, 128, 1)">8</span> DUP(<span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">))
</span><span style="color: rgba(0, 128, 128, 1)">7</span> <span style="color: rgba(0, 0, 0, 1)"> X6 EQU $-X1
</span><span style="color: rgba(0, 128, 128, 1)">8</span> DATA ENDS</pre>
</div>
<h2>4-6 综合练习题</h2>
<p> 【题签】有数据段定义如下:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 128, 1)">1</span> <span style="color: rgba(0, 0, 0, 1)">DATA1 SEGMENT PARA
</span><span style="color: rgba(0, 128, 128, 1)">2</span> X1 DB 20H,?,<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">A</span><span style="color: rgba(128, 0, 0, 1)">'</span>
<span style="color: rgba(0, 128, 128, 1)">3</span> X2 DW <span style="color: rgba(128, 0, 128, 1)">2</span> DUP(<span style="color: rgba(128, 0, 128, 1)">1</span>,2DUP(<span style="color: rgba(128, 0, 128, 1)">1</span><span style="color: rgba(0, 0, 0, 1)">,?))
</span><span style="color: rgba(0, 128, 128, 1)">4</span> <span style="color: rgba(0, 0, 0, 1)"> X3 DD 12345678H
</span><span style="color: rgba(0, 128, 128, 1)">5</span> <span style="color: rgba(0, 0, 0, 1)"> LEN EQU $-X2
</span><span style="color: rgba(0, 128, 128, 1)">6</span> DATA1 ENDS</pre>
</div>
<p> (1)画出内存图</p>
<p> (2)执行MOV AX,X3+1后,AX为?</p>
<p> (3)执行MOV CX,LEN后,CX为?</p>
<p> 【解】</p>
<p> (1)内存图如下:</p>
<p> <img src="https://img2018.cnblogs.com/blog/1346958/201905/1346958-20190509162633192-985112349.png" alt=""></p>
<p> 说明:<span style="color: rgba(255, 102, 0, 1)">对于字和双字的定义,低字节在低位</span>,因此如对于DW 1234H来说,在内存中<span style="color: rgba(51, 102, 255, 1)">由低地址到高地址依次为34H、12H</span>;对于DD 12345678H而言,在内存中<span style="color: rgba(51, 102, 255, 1)">由低地址到高地址依次为78H、56H、34H、12H。<span style="color: rgba(0, 0, 0, 1)">而对于数组的定义而言,如DUP,则是按照其定义先后顺序在内存中由低到高排列的。<span style="color: rgba(255, 102, 0, 1)">必须注意的是:由于前面定义的是字DW,所以<span style="color: rgba(255, 0, 0, 1)">DUP中的每一个数值都占据两个内存单元,即1个字的空间</span>,这在画内存图时必须要注意!</span></span></span></p>
<p><span style="color: rgba(51, 102, 255, 1)"><span style="color: rgba(0, 0, 0, 1)"> (2)AX = 3456H这道题这里有点小bug,编译后会报告1个warning,更好的<span style="color: rgba(0, 0, 255, 1)">改进</span>是使用<span style="color: rgba(128, 0, 128, 1)">MOV AX,WORD PTR X3+1</span>。</span></span></p>
<p><span style="color: rgba(51, 102, 255, 1)"><span style="color: rgba(0, 0, 0, 1)"> 这道题可以改进成一个<span style="color: rgba(128, 0, 128, 1)">更有意思的考法</span>:<span style="color: rgba(255, 153, 0, 1)">MOV AX,WORD PTR X3+2</span></span></span></p>
<p><span style="color: rgba(51, 102, 255, 1)"><span style="color: rgba(0, 0, 0, 1)"> 这样以来就要联系(1)中画的内存图了。内存中高地址存放的是数据中的高字节。因此<span style="color: rgba(255, 0, 255, 1)">结果应该是AX=1234H</span></span></span></p>
<p><span style="color: rgba(51, 102, 255, 1)"><span style="color: rgba(0, 0, 0, 1)"> (3)CX = 18H(可以表示为16进制,<span style="color: rgba(255, 0, 0, 1)">一定注意数组定义DW DUP的问题</span>!这会对LEN的计算产生影响)</span></span></p>
<h1><span style="color: rgba(51, 102, 255, 1)"><span style="color: rgba(0, 0, 0, 1)">5 编程题</span></span></h1>
<h2><span style="color: rgba(51, 102, 255, 1)"><span style="color: rgba(0, 0, 0, 1)">5-1 加法</span></span></h2>
<p><span style="color: rgba(51, 102, 255, 1)"><span style="color: rgba(0, 0, 0, 1)"> 计算Z=X+Y。其中X,Y为16位数,Z为32位数。</span></span></p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 128, 1)">1</span> <span style="color: rgba(0, 0, 255, 1)">XOR</span><span style="color: rgba(0, 0, 0, 1)"> DX,DX
</span><span style="color: rgba(0, 128, 128, 1)">2</span> <span style="color: rgba(0, 0, 255, 1)">MOV</span><span style="color: rgba(0, 0, 0, 1)"> AX,X
</span><span style="color: rgba(0, 128, 128, 1)">3</span> <span style="color: rgba(0, 0, 255, 1)">ADD</span><span style="color: rgba(0, 0, 0, 1)"> AX,Y
</span><span style="color: rgba(0, 128, 128, 1)">4</span> <span style="color: rgba(0, 0, 255, 1)">ADC</span> DX,<span style="color: rgba(128, 0, 128, 1)">0</span>
<span style="color: rgba(0, 128, 128, 1)">5</span> <span style="color: rgba(0, 0, 255, 1)">MOV</span> WORD PTR Z+<span style="color: rgba(128, 0, 128, 1)">2</span><span style="color: rgba(0, 0, 0, 1)">,DX
</span><span style="color: rgba(0, 128, 128, 1)">6</span> <span style="color: rgba(0, 0, 255, 1)">MOV</span> WORD PTR Z,AX</pre>
</div>
<p><span style="color: rgba(51, 102, 255, 1)"><span style="color: rgba(0, 0, 0, 1)"> 这里引入一个技巧:<span style="color: rgba(51, 102, 255, 1)">为了操作32位数,我们需要借用DX:AX进行操作</span>,我们一个一个地计算这两个寄存器中的数值,低位产生的进位补到DX中去,使用ADC指令。最后为内存中的Z使用WORD PTR进行赋值即可。</span></span></p>
<h2><span style="color: rgba(51, 102, 255, 1)"><span style="color: rgba(0, 0, 0, 1)">5-2 右移</span></span></h2>
<p><span style="color: rgba(51, 102, 255, 1)"><span style="color: rgba(0, 0, 0, 1)"> 将32位X右移4位。</span></span></p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 128, 1)"> 1</span> <span style="color: rgba(0, 0, 255, 1)">MOV</span><span style="color: rgba(0, 0, 0, 1)"> AX,WORD PTR X
</span><span style="color: rgba(0, 128, 128, 1)"> 2</span> <span style="color: rgba(0, 0, 255, 1)">MOV</span> DX,WORD PTR X+<span style="color: rgba(128, 0, 128, 1)">2</span>
<span style="color: rgba(0, 128, 128, 1)"> 3</span> <span style="color: rgba(0, 0, 255, 1)">SHR</span> DX,<span style="color: rgba(128, 0, 128, 1)">1</span>
<span style="color: rgba(0, 128, 128, 1)"> 4</span> <span style="color: rgba(0, 0, 255, 1)">RCR</span> AX,<span style="color: rgba(128, 0, 128, 1)">1</span>
<span style="color: rgba(0, 128, 128, 1)"> 5</span> <span style="color: rgba(0, 0, 255, 1)">SHR</span> DX,<span style="color: rgba(128, 0, 128, 1)">1</span>
<span style="color: rgba(0, 128, 128, 1)"> 6</span> <span style="color: rgba(0, 0, 255, 1)">RCR</span> AX,<span style="color: rgba(128, 0, 128, 1)">1</span>
<span style="color: rgba(0, 128, 128, 1)"> 7</span> <span style="color: rgba(0, 0, 255, 1)">SHR</span> DX,<span style="color: rgba(128, 0, 128, 1)">1</span>
<span style="color: rgba(0, 128, 128, 1)"> 8</span> <span style="color: rgba(0, 0, 255, 1)">RCR</span> AX,<span style="color: rgba(128, 0, 128, 1)">1</span>
<span style="color: rgba(0, 128, 128, 1)"> 9</span> <span style="color: rgba(0, 0, 255, 1)">SHR</span> DX,<span style="color: rgba(128, 0, 128, 1)">1</span>
<span style="color: rgba(0, 128, 128, 1)">10</span> <span style="color: rgba(0, 0, 255, 1)">RCR</span> AX,<span style="color: rgba(128, 0, 128, 1)">1</span></pre>
</div>
<p> 必须要注意的是<span style="color: rgba(128, 0, 128, 1)">这里必须使用SHR与RCR指令配合4次,每次移动1位进行使用</span>,这是由于,<span style="color: rgba(255, 0, 0, 1)">CF只能存放1位数字</span>!</p>
<h2><span style="color: rgba(51, 102, 255, 1)"><span style="color: rgba(0, 0, 0, 1)">5-3 乘法</span></span></h2>
<p><span style="color: rgba(51, 102, 255, 1)"><span style="color: rgba(0, 0, 0, 1)"> 用移位及加法指令,将32位数X计算X = X * 10。</span></span></p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 128, 1)"> 1</span> <span style="color: rgba(0, 0, 255, 1)">MOV</span><span style="color: rgba(0, 0, 0, 1)"> AX,WORD PTR X
</span><span style="color: rgba(0, 128, 128, 1)"> 2</span> <span style="color: rgba(0, 0, 255, 1)">MOV</span> DX,WORD PTR X+<span style="color: rgba(128, 0, 128, 1)">2</span>
<span style="color: rgba(0, 128, 128, 1)"> 3</span> <span style="color: rgba(0, 0, 255, 1)">SHL</span> AX,<span style="color: rgba(128, 0, 128, 1)">1</span>
<span style="color: rgba(0, 128, 128, 1)"> 4</span> <span style="color: rgba(0, 0, 255, 1)">RCL</span> DX,<span style="color: rgba(128, 0, 128, 1)">1</span>
<span style="color: rgba(0, 128, 128, 1)"> 5</span> <span style="color: rgba(0, 0, 255, 1)">MOV</span><span style="color: rgba(0, 0, 0, 1)"> BX,AX
</span><span style="color: rgba(0, 128, 128, 1)"> 6</span> <span style="color: rgba(0, 0, 255, 1)">MOV</span><span style="color: rgba(0, 0, 0, 1)"> CX,DX
</span><span style="color: rgba(0, 128, 128, 1)"> 7</span> <span style="color: rgba(0, 0, 255, 1)">SHL</span> AX,<span style="color: rgba(128, 0, 128, 1)">1</span>
<span style="color: rgba(0, 128, 128, 1)"> 8</span> <span style="color: rgba(0, 0, 255, 1)">RCL</span> DX,<span style="color: rgba(128, 0, 128, 1)">1</span>
<span style="color: rgba(0, 128, 128, 1)"> 9</span> <span style="color: rgba(0, 0, 255, 1)">SHL</span> AX,<span style="color: rgba(128, 0, 128, 1)">1</span>
<span style="color: rgba(0, 128, 128, 1)">10</span> <span style="color: rgba(0, 0, 255, 1)">RCL</span> DX,<span style="color: rgba(128, 0, 128, 1)">1</span>
<span style="color: rgba(0, 128, 128, 1)">11</span> <span style="color: rgba(0, 0, 255, 1)">ADD</span><span style="color: rgba(0, 0, 0, 1)"> AX,BX
</span><span style="color: rgba(0, 128, 128, 1)">12</span> <span style="color: rgba(0, 0, 255, 1)">ADC</span><span style="color: rgba(0, 0, 0, 1)"> DX,CX
</span><span style="color: rgba(0, 128, 128, 1)">13</span> <span style="color: rgba(0, 0, 255, 1)">MOV</span><span style="color: rgba(0, 0, 0, 1)"> WORD PTR X,AX
</span><span style="color: rgba(0, 128, 128, 1)">14</span> <span style="color: rgba(0, 0, 255, 1)">MOV</span> WORD PTR X+<span style="color: rgba(128, 0, 128, 1)">2</span>,DX</pre>
</div>
<p> 这里用到的技巧是<span style="color: rgba(0, 128, 0, 1)">将X*10分解成X*2 + X*8来计算</span>,也就是将X左移1位保存下来再左移2位加上刚才保存的值即可。</p>
<h2><span style="color: rgba(51, 102, 255, 1)"><span style="color: rgba(0, 0, 0, 1)">5-4 打印</span></span></h2>
<p><span style="color: rgba(51, 102, 255, 1)"><span style="color: rgba(0, 0, 0, 1)"> 将内存中16位X显示为十六进制ASCII码。</span></span></p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 128, 1)"> 1</span> <span style="color: rgba(0, 0, 255, 1)">MOV</span><span style="color: rgba(0, 0, 0, 1)"> BX,X
</span><span style="color: rgba(0, 128, 128, 1)"> 2</span> <span style="color: rgba(0, 0, 255, 1)">MOV</span> CX,<span style="color: rgba(128, 0, 128, 1)">4</span>
<span style="color: rgba(0, 128, 128, 1)"> 3</span> <span style="color: rgba(0, 128, 128, 1)">LP:</span>
<span style="color: rgba(0, 128, 128, 1)"> 4</span> <span style="color: rgba(0, 0, 255, 1)">PUSH</span><span style="color: rgba(0, 0, 0, 1)"> CX
</span><span style="color: rgba(0, 128, 128, 1)"> 5</span> <span style="color: rgba(0, 0, 255, 1)">MOV</span> CL,<span style="color: rgba(128, 0, 128, 1)">4</span>
<span style="color: rgba(0, 128, 128, 1)"> 6</span> <span style="color: rgba(0, 0, 255, 1)">ROL</span><span style="color: rgba(0, 0, 0, 1)"> BX,CL
</span><span style="color: rgba(0, 128, 128, 1)"> 7</span> <span style="color: rgba(0, 0, 255, 1)">MOV</span><span style="color: rgba(0, 0, 0, 1)"> AL,BL
</span><span style="color: rgba(0, 128, 128, 1)"> 8</span> <span style="color: rgba(0, 0, 255, 1)">AND</span><span style="color: rgba(0, 0, 0, 1)"> AL,0FH
</span><span style="color: rgba(0, 128, 128, 1)"> 9</span> <span style="color: rgba(0, 0, 255, 1)">ADD</span><span style="color: rgba(0, 0, 0, 1)"> AL,30H
</span><span style="color: rgba(0, 128, 128, 1)">10</span> <span style="color: rgba(0, 0, 255, 1)">CMP</span><span style="color: rgba(0, 0, 0, 1)"> AL,39H
</span><span style="color: rgba(0, 128, 128, 1)">11</span> <span style="color: rgba(0, 0, 255, 1)">JBE</span><span style="color: rgba(0, 0, 0, 1)"> DISP
</span><span style="color: rgba(0, 128, 128, 1)">12</span> <span style="color: rgba(0, 0, 255, 1)">ADD</span> AL,<span style="color: rgba(128, 0, 128, 1)">7</span>
<span style="color: rgba(0, 128, 128, 1)">13</span>
<span style="color: rgba(0, 128, 128, 1)">14</span> <span style="color: rgba(0, 128, 128, 1)">DISP:</span>
<span style="color: rgba(0, 128, 128, 1)">15</span> <span style="color: rgba(0, 0, 255, 1)">MOV</span><span style="color: rgba(0, 0, 0, 1)"> DL,AL
</span><span style="color: rgba(0, 128, 128, 1)">16</span> <span style="color: rgba(0, 0, 255, 1)">MOV</span> AH,<span style="color: rgba(128, 0, 128, 1)">2</span>
<span style="color: rgba(0, 128, 128, 1)">17</span> <span style="color: rgba(0, 0, 255, 1)">INT</span><span style="color: rgba(0, 0, 0, 1)"> 21H
</span><span style="color: rgba(0, 128, 128, 1)">18</span> <span style="color: rgba(0, 0, 255, 1)">POP</span><span style="color: rgba(0, 0, 0, 1)"> CX
</span><span style="color: rgba(0, 128, 128, 1)">19</span> LOOP LP</pre>
</div>
<p> 注意以下几点技巧:</p>
<ul>
<li>16位数字X需要输出4位数字,因此设置CX的值为4作为外层循环次数</li>
<li><span style="color: rgba(51, 102, 255, 1)">输出每次对X的值进行循环左移4位(不带CF)的ROL指令</span>,这样每次BL的低4位即为当前要输出的值</li>
<li>由于又用到了CL,因此外层循环的CX需要在第4行处压栈处理</li>
<li>由于每次输出只有4位,而最少取出AL为8位,因此需要<span style="color: rgba(255, 102, 0, 1)">使用第8行AND AL,0FH来屏蔽AL的高4位</span></li>
<li>需要注意的是,在16进制中超过9的数字变成了A,由于ASCII码中‘9’与‘A’之间相差8,<span style="color: rgba(0, 128, 0, 1)">因此需要判断是否需要给AL增加相应值,使用的是ADD AL,7实现</span></li>
<li>输出单个字符的中断调用为2号中断调用</li>
</ul>
<h1>6 写在最后</h1>
<p> 熊老师的《x86汇编语言》这门课程是本学期选的最成功的一门课程,熊老师对学生也十分认真负责。这也再次印证了那个真理,那就是只有实践,才能真正把理论中的内容理解、消化。</p>
<p> 从最开始的连课都听不懂、程序写不出、编程毫无头绪,到后来经历了几次作业的历练后,思路渐渐清晰,我不得不十分感谢熊老师的严格要求。</p>
<p> 汇编是一种十分贴近计算机底层的语言,它深刻的揭示了程序运行的过程以及内存的使用和分配机制,在本科阶段,有汇编编程的锻炼经历,我认为是十分有必要的。</p>
<p> 最后,在编写这篇笔记的过程中,还<span style="color: rgba(255, 102, 0, 1)">要特别感谢<span style="color: rgba(51, 102, 255, 1)">小马哥</span>和<span style="color: rgba(51, 102, 255, 1)">乔</span>给我提出的宝贵的修改意见!</span></p>
<p> 明天就要期末考试了。<span style="color: rgba(128, 0, 128, 1)">真心的希望先先能够发挥高水平,取得好成绩</span>。与各位共勉!</p><br><br>
来源:https://www.cnblogs.com/chrischen98/p/10836078.html
頁:
[1]