第7章 比高斯更快的计算

第七章 比高斯更快的计算

这一章的主题是汇编计算累加和,以及寻址方式的学习。

and、or指令

and是按位与,or是按位或。

两者的目的操作数都必须是8位或者16位的内存单元或者通用寄存器,源操作数必须是与目的操作数同宽度的内存单元、通用寄存器或者立即数。注意,与其他指令一样,源操作数和目的操作数不能都为内存单元。

两者对标志寄存器的影响相同:OF和CF被清零,SF、ZF、PF依计算结果而定,AF位的状态未定义。

计算机中的栈段一般是从高地址向低地址生长,也就是说压栈减地址,出栈加地址。在这里,我们选的栈段初始地址为0x0000,由于计算机内部采用补码运算,所以在压栈第一个元素时,采用0x0000-0x10,即从0xfffe开始存。由于Intel处理器采用小端方式,所以低地址存低字节,即0xfffe存低字节,0xffff存高字节,之后再压栈、出栈都按这个逻辑。

栈段

数据段段基地址在DS中保存,附加段段基地址在ES中保存,栈段段基地址在SS中保存。

push

  • 对于当前的8086平台,push的操作数必须为16位,也就是说,压栈内容必须为2字节。
  • push指令执行时,首先将栈指针寄存器SP的内容减去操作数的字节长度(此处为2),然后把要压栈的数据存放到逻辑地址SS:SP所指向的内存位置。
  • 不影响任何标志位

pop

与push相反,过程是先取数据,再+2。同样不影响任何标志位。

Bochs栈调试

在Bochs中,查看栈信息使用命令“print-stack”,后面可以跟参数指定要打印接下来的多少元素,使用该命令会打印出从SP指向的栈顶向下的一系列元素。但是由于此处计算机不会区分数据区和栈区,而我们的栈高地址处是栈底元素,所以可能会打印出不在栈中的值。

8086处理器的寻址方式

1. 寄存器寻址

操作数直接位于寄存器中

2. 立即数寻址

操作数是个立即数

3. 内存寻址

3.1 直接寻址

给出一个内存地址作为偏移地址,以此访问

3.2 基址寻址

使用基址寄存器BX或BP来保存偏移地址。这允许在基址寄存器的基础上使用一个偏移量,比如

mov dx, [bp-2]

3.3 变址寻址

类似于基址寻址,但是不同的是这里使用的是变址寄存器SI和DI,同样允许偏移量

3.4 基址变址寻址

组合BX、BP和SI、DI,来提供地址,同样允许偏移量。

本章习题

  1. 把line31~37改成如下代码即可
         ;以下计算1到100的和 
         xor ax,ax
         mov cx,100
     @f:
         add ax,cx
         loop @f
  1. 要求用汇编计算并显示1+2+···+1000的结果。这个实验有水平,很多东西我都没想到,最后没写出来。下面是修改的从line30往后。
         ;修改计算1到1000的和 
         xor ax,ax
         xor dx,dx
         mov cx,1000
     @f:
         add ax,cx
         adc dx,0
         loop @f

         ;以下计算累加和的每个数位 
         xor cx,cx              ;设置堆栈段的段基地址
         mov ss,cx
         mov sp,cx

         mov bx,10              ;line 17~line 20还必须得有,不然不行
         xor cx,cx
         inc cx
         div bx
         or dl,0x30
         push dx
     @d:                        ;如果没有上面那一块,直接这一块计算,原先dx中的高位值就会清零,结果就错了
         inc cx                 ;而如果上面17~20做了,由于除以了10,高位dx中就不会再有非零数据了,只保存每次计算的余数,所以不再会出错
         xor dx,dx
         div bx
         or dl,0x30
         push dx
         cmp ax,0
         jne @d

         ;以下显示各个数位 
     @a:
         pop dx
         mov [es:di],dl
         inc di
         mov byte [es:di],0x07
         inc di
         loop @a
       
         jmp near $ 
       

times 510-($-$$) db 0
                 db 0x55,0xaa

adc指令就是一个add指令的扩展,在计算完add之后会把CF位也加上,这样可以使用16位寄存器计算多于16位的数据。比如这里。**注意,因为两个二进制数相加,最多只能进一位,不可能进两位(比较容易证),所以line6~7简单两行代码就能完成多于16位的计算。**因为每次最多进一位,所以直接adc dx,0 即可保存所有高于16位的信息,不用考虑那么多。

相比于源代码,多出来了line17~20,原因注释里说了。由于计算后,dx中保存高16位,ax中保存低16位,而结果是500500,要大于16位的最大值65535,但是在一次÷10之后,50050<65535,所以在低16位,即ax中就能放得开了,dx就可以清零了,用来每次除法保存余数。

你可能感兴趣的:(汇编语言)