2014-11-01 50 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