2014-11-01 109 views
0

我是Assembly(x86 ATT语法)的初学者。我正在做一个任务,我必须通过二维数组的每个索引并找出1的数目。该方法接受2d int数组,int w,int h。我如何实现循环从0到W,并用循环指令反弹出来。我知道如何用jmp指令来做到这一点,但循环只是给我错误/ segFaults。这是我尝试使用跳跃声明并且工作正常。我将如何使用循环指令转换内部循环?循环组件x86

pushl %ebp 
movl %esp, %ebp 

movl $0, -4(%ebp) 
movl $0, -8(%ebp) 
movl $0, -12(%ebp) 
movl $0, -4(%ebp) #outside loop 
jmp .L10 

.L14: #Inner Loop 
movl $0, -8(%ebp) 
jmp .L11 

.L13: 
movl -4(%ebp), %eax 
leal 0(,%eax,4), %edx 
movl 8(%ebp), %eax 
addl %edx, %eax 
movl (%eax), %eax 
movl -8(%ebp), %edx 
sall $2, %edx 
addl %edx, %eax 
movl (%eax), %eax 
cmpl $1, %eax 
jne .L12 
addl $1, -12(%ebp) 

.L12: 
addl $1, -8(%ebp) 
.L11: #check inner loop 
movl -8(%ebp), %eax 
cmpl 12(%ebp), %eax 
jl .L13 
addl $1, -4(%ebp) 

.L10: #check outside loop 
movl -4(%ebp), %eax 
cmpl 16(%ebp), %eax 
jl .L14 
movl -12(%ebp), %eax 

leave 
ret 

回答

3

通常使用loop除了可能代码较小之外没有任何优势。它通常速度较慢,灵活性较差,因此不推荐。

这就是说,如果你仍然想使用它,你应该知道它使用ecx寄存器来倒计数到零。所以你需要重构你的代码来适应这个。在你的情况下,这意味着加载ecx的值为w并让它倒数。由于您的当前循环变量从0变为w-1,但ecx将从w降至1(含),因此您在索引期间还需要应用-1的偏移量。

此外,loop指令在循环体之后使用,即它实现了do-while循环。如果计数为零,则跳过循环体,可以使用配套指令JECXZ

+0

请您详细说明一下吗?是否有可能计数ecx,所以0到w以及如何执行检查,比如如果y 0。那去哪里? 所以我有 mov 12(%ebp),%ecx .L14#如上所述。它完成了所有工作,然后返回到ecx = 0? loop .L14 – beginner 2014-11-01 23:44:50

+0

不,如我所说,'循环'倒数到零。你不能让它数起来。 – Jester 2014-11-01 23:47:36

+0

请注意,您可以使用'mov w,%edx'和'sub%ecx,%edx'这样的东西来获取'%edx'中从'0'到'w-1'的递增计数器。 – 2014-11-04 03:58:46

0

您可以使用lodsl(默认将%esi向上移动)和loop(向下移动%ecx)。我不确定它是否比gcc从c生成的效率更高,这基本上是你的代码,但看起来更漂亮。

我在这里所做的并不是完全回答你的问题 - 而是使用loop作为内部循环我假设整个数组是连续存储的,然后只有一个循环需要担心。在我的机器上用c编译时,它是连续存储的,但我不确定你应该依赖它。希望我所做的已经足够了解looplodsl是如何工作的,你可以修改你的代码,只在内部循环中使用它们。

.data 
x: 
    .long 6 
y: 
    .long 5 
array: 
    .long 1,1,1,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,1,1,0,0,1,1 

.text 
.global _start 
_start: 
    # set up for procedure call 
    push x 
    push y 
    push $array 
    # call and cleanup 
    call cnt 
    add $0xc, %esp 
    # put result in %ebx and finish up 
    #(echo $? gives value in bash if <256) 
    mov %eax, %ebx 
    mov $1, %eax 
    int $0x80 

# %ebx will hold the count of 1s 
# %ecx will hold the number of elements to check 
# %esi will hold the address of the first element 
# Assumes elements are stored contiguously in memory 
cnt: 
    # do progogue 
    enter $0, $1 
    # set %ebx to 0 
    xorl %ebx, %ebx 
    # grab x and y parameters from stack and 
    # multiply together to get the number of elements 
    # in the array 
    movl 0x10(%ebp), %eax 
    movl 0xc(%ebp), %ecx 
    mul %ecx 
    movl %eax, %ecx 
    # get address of first element in array 
    movl 0x8(%ebp), %esi 
getel: 
    # grab the value at the address in %esi and increment %esi 
    # it is put in %eax 
    lodsl 
    # if the value in %eax is 1, increment %ebx 
    cmpl $1, %eax 
    jne ne 
    incl %ebx 
ne: 
    # decrement %ecx and if it is greater than 0, keep going 
    loop getel 
    # %ecx is zero so we are done. Put the count in %eax 
    movl %ebx, %eax 
    # do epilogue 
    leave 
    ret 

没有所有评论,它确实更漂亮。

.data 
x: 
    .long 6 
y: 
    .long 5 
array: 
    .long 1,1,1,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,1,1,0,0,1,1 

.text 
.global _start 
_start: 
    push x 
    push y 
    push $array 
    call cnt 
    add $0xc, %esp 
    mov %eax, %ebx 
    mov $1, %eax 
    int $0x80 

cnt: 
    enter $0, $1 
    xorl %ebx, %ebx 
    movl 0x10(%ebp), %eax 
    movl 0xc(%ebp), %ecx 
    mul %ecx 
    movl %eax, %ecx 
    movl 0x8(%ebp), %esi 
getel: 
    lodsl 
    cmpl $1, %eax 
    jne ne 
    incl %ebx 
ne: 
    loop getel 
    movl %ebx, %eax 
    leave 
    ret