您的位置:首页 > 其它

汇编学习-分支与循环

2014-11-11 16:30 281 查看
在高级语言程序设计中,我们不仅要求程序能够顺序执行,还要求其能够执行不同分支,或者重复执行某些操作。在汇编语言中,同样具有相同的能力,可以由相应的指令来控制程序的执行流程。因为毕竟高级语言都是汇编实现的,只是不直观而已。


转移

无条件转移为JMP,类似c语言中的
goto。在c语言中,goto是不推荐使用的,会使程序难以控制和理解,但在汇编中,没有相应的if
和 while语句,只能使用
JMP来完成逻辑复杂的控制结构。
JMP分为段内转移和段间转移,不过在windows编程上,一个代码段的大小为
4GB,一般不需要段间转移。

条件转移是由CPU提供多个标志位,在执行这类指令之前,检查之前已经设置的标志位的状态来决定是否进行转移。可以想象,通过条件转移,可以实现分支和循环。


分支

在汇编中,设计一个分支结构的思路基本是这样的,由条件转移指令来判断条件是否满足,若满足,则跳过分支程序,否则继续向下执行,最后会合。



求 x的符号

原c
程序

</pre><pre name="code" class="cpp">int x = 10;
int signX;
int main()
{
if (x > 0)
signX = 1;
else if (x == 0)
signX = 0;
else
signX = -1;
}


对应的汇编
x                SDWORD        -45
signX        SDWORD        ?

mov signX, 0
cmp        x, 0
jz        a70                                ;为0
jg        a60                                ;大于0
mov signX, -1
jmp        a70
a60:
mov        signX, 1
a70:


二分查找
对于一个已排序的数组,最快的查找一个元素的方法不是顺序查找,而是二分查找。这个用c
语言写非常方便。首先我们还是画出流程图,这有助于我们用 JMP转换之。
数组为R,元素个数为n,要查找的数为a。



执行过程为:

(1)先设定查找范围为下界 l到上界h
(2)如果下界大于上界,且没查到,则查找失败
(3)取下界和上界的中点m=(l+h)/2,该数为R[m]
(4)若该数为a,则算法结束
(5)若该数小于a,则修改下界l=m+1,并跳转到第二步
(6)若该数大于a,则修改上界
h=m-1,并跳转到第二步
汇编源码
.386
.model flat,stdcall
optioncasemap:none
includelib  msvcrt.lib
printf      PROTO C :dword, :vararg

.data
dArray      dword 50, 56, 64, 73, 83, 92, 103, 105
ITEMS       equ    $-dArray)/4        ; 数组长度
Index           dword   ?
Count           dword   ?
szFmt           byte    'Index=%d Count=%d Element=%d', 0;  格式化字符串
szErr           byte    'Not Found'

l       sdword ?
h       sdword ?
m       sdword ?
a       sdword 83      ; 所查找的数字
.code
start:
mov    Index, -1;
mov    Count,  0
mov    l, 0
mov    h, ITEMS-1;
mov    ecx, l
mov    edx, h
b10:
cmp    ecx, edx    ; 下界和上界比较
jg     b40         ; 超出,则未找到
mov    esi, ecx;
add    esi, edx
shr    esi, 1      ; m = (l+h)>>1
inc    Count
mov    eax, a      ; 取出被比较的数
cmp    eax, dArray[esi*4] ; 取出该数
jz     b30         ; 相等
jg     b20         ; 比 a 小,修改下界
; 比 a 大,修改上界
mov    edx, esi
dec    edx         ; h = m-1
jmp    b10
b20:
mov    ecx, esi
inc    ecx         ; l = m+1
jmp    b10
b30:
mov    Index, esi
; 调用 c 库的 printf
invoke printf, offset szFmt, Index, Count, dArray[esi*4]
jmp    b50
b40:
; 查找失败
invoke printf, offset szErr
b50:
ret
end start


有序表插入
首先遍历数组,找到m,满足
R[m-1]<a && R[m]>a。然后将R[m..n-1]每一个元素向后移动一个位置,再插入a。
关键部分汇编代码
start:
mov    eax, Element        ; 将插入的元素
mov    esi, 0              ; 当前比较元素的下标
c10:
cmp    dArray[esi*4], eax
ja     c20
inc    esi
cmp    esi, ITEMS          ; 超出数组长度,
jb     c10                 ; 没有超出
;
c20:
mov    edi, ITEMS-1        ; 从数组尾部开始移动
c30:
cmp    edi, esi            ; 与插入位置比较
jl     c40                 ; 移动完成
; 还没完成,继续移动
mov    ebx, dArray[edi*4]
mov    dArray[edi*4+4], ebx ; 向后移动一个元素
dec    edi
jmp    c30                 ; 继续判断,决定是否移动
c40:
mov    dArray[esi*4], eax  ; 移动完成,插入元素


循环
实际编码解决问题时,经常遇到大量重复的动作,利用循环结构可以简化程序的编写。实际在上文中,已经有循环部分出现,但那是不定次数的循环。
一个循环结构分为三部分:循环初始化,循环体,循环结束控制。
一个固定次数的循环,有LOOP命令来实现,循环次数在ECX中。

阶乘
这里直接使用ECX
作为乘数,其会随循环递减,正好符合阶乘的定义。
.data
Fact   dword   ?
N      EQU     5
.code
start:
mov    ecx, N      ; 循环初值,同时也是乘数初值
mov    eax, 1      ; fact 初值
e10:
imul   eax, ecx    ; 相乘
loop   e10

mov    Fact, eax   ; 阶乘结果


冒泡
冒泡算法是一个多重循环。
start:
mov    ecx, ITEMS-1
i10:
xor    esi, esi    ; 清零
i20:
mov    eax, dArray[esi*4]
mov    ebx, dArray[esi*4+4]
cmp    eax, ebx    ; 比较相邻的两个数
jl     i30
mov    dArray[esi*4], ebx    ;较大的数在左边,需要移动
mov    dArray[esi*4+4], eax  ; 需要交换两个数
; 比较下一对数
i30:
inc    esi
cmp    esi, ecx
jb     i20     ; 内循环,一遍下来,最大的数,移到了最右边
loop   i10     ; 外循环


参考文献

[1] 谭毓安, 张雪兰. Windows汇编语言程序设计教程. 北京: 电子工业出版社, 2005.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: