简体   繁体   中英

Loop Assembly x86

I am a beginner in Assembly(x86 ATT Syntax). I am working on an assignment where I have to go through each index of a 2d array and find the number of 1's. The method takes in 2d int array,int w, int h. How do I implement the loop to go go from 0 to w and bounce out with loop instruction. I know how to do it with a jmp instruction but loop just gives me errors/segFaults. This is my attempt with a jump statement and it works. How would I go about converting the inner loop using a loop instruction?

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

Generally using loop has no advantages except maybe smaller code. It's usually slower and less flexible, thus not recommended.

That said, if you still want to use it you should know that it employs the ecx register for counting down to zero. So you need to restructure your code to accommodate that. In your case, that means loading ecx with the value of w and letting it count down. You will also need to apply an offset of -1 during indexing, since your current loop variable goes from 0 to w-1 , but ecx will go from w down to 1 (inclusive).

Furthermore, the loop instruction is used after the loop body, that is it implements a do-while loop. To skip the loop body if the count is zero a companion instruction, JECXZ , can be used.

You can use lodsl (which moves %esi up by default) and loop (which moves %ecx down) in tandem. I am not sure if it is more efficient than what gcc generates from c, which is basically your code, but it looks prettier.

What I have done here doesn't answer your question precisely -- rather than use loop for the inner loop I have assumed the whole array is stored contiguously and then there is only a single loop to worry about. When compiling from c on my machine, it is stored contiguously, but I'm not sure you should rely on that. Hopefully what I have done gives you enough to understand how loop and lodsl work, and you can modify your code to use them just in the inner loop.

.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

It really is prettier without all the comments.

.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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM