2014-11-01 2 views
0

Я новичок в Assembly (x86 ATT Syntax). Я работаю над назначением, где мне нужно пройти каждый индекс массива 2d и найти число 1. Метод принимает в 2d int array, int w, int h. Как реализовать цикл, чтобы перейти от 0 до w и отскочить с помощью инструкции цикла. Я знаю, как это сделать с помощью команды jmp, но цикл просто дает мне ошибки/segFaults. Это моя попытка с помощью инструкции перехода, и она работает. Как я мог бы преобразовать внутренний цикл с помощью инструкции цикла?Loop Assembly 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 и разрешение на обратный отсчет. Вам также необходимо будет применить смещение -1 во время индексации, так как ваша текущая переменная цикла изменяется от 0 до w-1, но ecx будет идти от w до 1 (включительно).

Кроме того, инструкция loop используется после тела цикла, то есть она реализует цикл while-while. Чтобы пропустить тело цикла, если счетчик равен нулю, может использоваться команда компаньона, JECXZ.

+0

Не могли бы вы уточнить? Можно ли подсчитать ecx так, чтобы от 0 до w и как выполнять проверки, например, как y 0. Где это будет? поэтому у меня есть mov 12 (% ebp),% ecx .L14 # вышеперечислен. Он делает все это, а затем возвращается до ecx = 0? loop .L14 – beginner

+0

Нет, как я уже сказал, 'loop' отсчитывает до нуля. Вы не можете его подсчитать. – Jester

+0

Обратите внимание, что вы можете использовать что-то вроде 'mov w,% edx' и' sub% ecx,% edx', чтобы увеличить счетчик от '0' до' w-1' в '% edx'. –

0

Вы можете использовать lodsl (который перемещает% esi по умолчанию) и loop (который перемещает% ecx вниз) в тандеме. Я не уверен, что он более эффективен, чем то, что gcc генерирует из c, который является в основном вашим кодом, но он выглядит красивее.

То, что я здесь сделал, точно не отвечает на ваш вопрос, а не использует loop для внутреннего цикла. Я предположил, что весь массив хранится смежно, а затем существует только один цикл, о котором нужно беспокоиться. При компиляции из c на моей машине он хранится соприкосновенно, но я не уверен, что вы должны полагаться на это. Надеюсь, что то, что я сделал, дает вам достаточно, чтобы понять, как работают loop и lodsl, и вы можете изменить свой код, чтобы использовать их только во внутреннем цикле.

.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