Mon premier exercice dans l'assemblage
Question
Je travaille sous visual studio 2005 avec l'ensemble (je suis un débutant) et je veux créer un programme qui calcule la progression arithmétique avec cette règle: A n = 2 * A n-1 + A n-2 mais. Je ne sais vraiment pas comment travailler avec les registres et j'ai besoin juste un exemple de vous de continuer avec mes exercices.
Ceci est mon code:
.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.
La solution
Vous ne pouvez pas utiliser la hache comme registre d'index et EAX comme registre de données en même temps. Pour le code 32bit, bâton à 32 registres de bits, à moins que vous maintenant ce que vous faites. Vous utilisez un mode inadvertance adressage 16 bits, que vous probablement ne voulait pas.
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
Ne jamais utiliser l'instruction de boucle, même si certains processeurs modernes peuvent exécuter ist rapide (la plupart ne peuvent pas).
Autres conseils
Je suis un débutant en assembleur aussi, mais mon algorithme est un peu différent:
A dword 1026 dup (0) ; declare this in the data segm.
; ...
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] ; get A(n-1)
add eax, eax ; double it
add eax, [esi - 8] ; computes A(n)
mov [esi], eax ; and save it
inc ecx ; next n
cmp ecx, n ; be sure n is a dword, use
; cmp ecx, dword ptr n ; if it isn't
jb lp ; loop until ecx < n
;
; now you should have the results in the A array with
; esi pointing to the end of it
Je n'ai pas compilé pour voir si fonctionne bien, mais il se doit ..
A n = 2 * A n-1 + A n-2 est presque la même formule que la suite de Fibonacci, de sorte que vous peut trouver beaucoup de choses utiles en cherchant pour cela. (Par exemple ce q & ). Mais au lieu d'un ajout, nous avons besoin 2a + b, et x86 peuvent le faire dans une instruction LEA.
Vous ne besoin de stocker vos variables de boucle en mémoire, c'est ce que les registres sont pour. Ainsi, au lieu de chaque itération besoin de données de retirer de mémoire (~ 5 cycles de latence pour un aller-retour), il peut simplement utiliser des registres (0 cycles de latence supplémentaire).
Votre tableau peut aller .bss, plutôt que .data, de sorte que vous ne stockez pas les zéros dans votre fichier objet.
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
En utilisant l'index de tableau pour les moyens de l'état de la boucle, nous avons utilisé seulement 3 registres au total, et encore ne pas besoin de sauvegarder / restaurer l'un des registres d'appels conservés habituels ESI, EDI, EBX, ou RASE. (Et bien sûr, est restauré ESP de l'appelant, aussi).
Si vous vous souciez de la performance, la boucle est seulement 6 UOP (-domaine de fusion) sur processeurs Intel SNB-famille. Pour plus arraySize, il pourrait fonctionner à un résultat par horloge (une itération par 2 horloges).