Мое первое упражнение в сборке - PullRequest
1 голос
/ 22 ноября 2010

Я работаю в Visual Studio 2005 со сборкой (я новичок) и хочу создать программу, которая рассчитывает арифметическую прогрессию с этим правилом: A n = 2 * A n-1 + A n-2 но. Я действительно не знаю, как работать с регистрами, и мне нужен только один пример от вас, чтобы продолжить мои упражнения.

Это мой код:

.386
.MODEL flat,stdcall

.STACK 4096

extern ExitProcess@4:Near

.data                               
arraysize DWORD 10

setarray  DWORD 0 DUP(arraysize)
firstvar  DWORD 1
secondvar DWORD 2

.code                               
_main:                              
mov eax,[firstvar]
mov [setarray+0],eax        
mov eax,[secondvar]
mov [setarray+4],eax

mov ecx, arraysize              ;loop definition
mov ax, 8

Lp:
mov eax,[setarray+ax-4]
add eax,[setarray+ax-4]
add eax,[setarray+ax-8]
mov [setarray+ax],eax

add ax,4;
loop Lp

add ax,4;

    push    0                   ;Black box. Always terminate
    call    ExitProcess@4       ;program with this sequence

    end   _main              ;End of program. Label is the entry point.

Ответы [ 3 ]

1 голос
/ 22 ноября 2010

Вы не можете использовать топор как индексный регистр и eax как регистр данных одновременно.Для 32-битного кода придерживайтесь 32-битных регистров, если только вы не знаете, что делаете.Вы случайно использовали 16-битный режим адресации, который вам, вероятно, не нужен.

mov ecx, arraysize-1              ;loop definition
mov ebx, 8

Lp:
mov eax,[setarray+ebx-4]
add eax,[setarray+ebx-4]
add eax,[setarray+ebx-8]
mov [setarray+ebx],eax

add ebx,4
dec ecx
jnc Lp

Никогда не используйте инструкцию цикла, даже если некоторые современные процессоры могут выполнять ее быстро (большинство не может).

0 голосов
/ 27 октября 2016

A n = 2 * A n-1 + A n-2 - это почти та же формула, что и последовательность Фибоначчи, поэтому вы можете найтимного полезного, ища это.(например, это q & a ).Но вместо простого добавления нам нужны 2a + b, и x86 может сделать это в одной инструкции LEA.

Вам никогда не нужно хранить переменные цикла в памяти, для этого нужны регистры.Таким образом, вместо каждой итерации, требующей извлечения данных из памяти (задержка ~ 5 циклов в оба конца), он может просто использовать регистры (дополнительная задержка 0 циклов).

Ваш массив может быть в .bss,вместо .data, поэтому вы не сохраняете эти нули в своем объектном файле.

arraysize equ 10     ; not DWORD: this is an assemble-time constant, not a value stored in memory

.bss
seq  DWORD 0 DUP(arraysize)   ; I think this is the right MASM syntax?
; NASM equivalent:  seq RESD arraysize

.code
_main:

    mov  edx, 1         ; A[0]
    mov  [seq], edx
    mov  eax, 2         ; A[1]
    mov  [seq+4], eax

    mov  ecx, 8         ; first 8 bytes stored
    ; assume the arraysize is > 2 and even, so no checks here
seqloop:
    lea  edx, [eax*2 + edx]  ;    edx=A[n],   eax=A[n-1]
    mov  [seq + ecx], edx    ; or edx=A[n-1], eax=A[n-2]
    lea  eax, [edx*2 + eax]  
    mov  [seq + ecx + 4], eax
    ; unrolled by two, so we don't need any MOV or XCHG instructions between registers, or any reloading from memory.

    add  ecx, 8             ; +8 bytes
    cmp  ecx, arraysize*4   ; (the *4 happens at assemble time)
    jb   seqloop

    ret

Использование индекса массива для условия цикла означает, что мы использовали всего 3 регистра, и все же не нужносохранить / восстановить любой из обычных регистров ESI, EDI, EBX или EBP с сохранением вызовов.(И, конечно, ESP вызывающей стороны также восстанавливается).

Если вы заботитесь о производительности, цикл составляет всего 6 моп (слитый домен) на процессорах семейства Intel SnB.Для большего размера массива он может работать с одним результатом за такт (одна итерация на 2 такта).

0 голосов
/ 28 ноября 2010

Я тоже новичок в ассемблере, но мой алгоритм немного отличается:


    A   dword   1026 dup (0)          ; declare this in the data segm.</p>

<p>;       ...</p>

<pre><code>    mov     esi, offset A         ; point at the results array
    mov     [esi], 1               ; initialize A(0)
    mov     [esi + 4], 2           ;  and A(1)
    xor  ecx, ecx

lp: add esi, 8
mov eax, [esi - 4];получить A (n-1) добавить eax, eax;удвоить, добавить eax, [esi - 8];вычисляет A (n) mov [esi], eax;и сохранить его в формате ecx;следующий n cmp ecx, n;будь уверен, что это меч, используй;cmp ecx, dword ptr n;если это не JB LP;цикл до ecx

Я не скомпилировал его, чтобы посмотреть, хорошо ли работает, но он должен ..

...