J'écrivais une fonction de multiplication matricielle-vectorielle AVX en C mais j'ai réalisé qu'une instruction dont j'avais besoin n'était pas implémentée dans GCC, donc j'ai vu cela comme une occasion en or d'apprendre l'assemblage x86. J'ai d'abord écrit une routine dans l'assemblage MIPS, puis j'ai essayé de le traduire. Mon code ne fonctionne pas, je me suis trompé et je ne sais pas pourquoi. Si je supprime les deux jnz
dans le code, cela fonctionne, mais je ne comprends pas pourquoi ils auraient un impact. Ce type de saut détruit-il les registres que j'utilise?Multiplication matricielle-vectorielle NASM
EDIT: Il semble que les deux premières instructions dans main
ne définissent pas rdi
sur 2, mais plutôt sur 0x1000000002
, ce qui provoque des problèmes plus tard. Pourquoi est-ce que 2 n'est pas chargé?
EDIT2: J'ai compris. Comme l'a souligné @rkhb, l'utilisation de registres rXX charge plus de données que ce que j'avais prévu. J'ai changé les registres à ceux de 32 bits (le cas échéant), ce qui a résolu le problème segfault. Cependant, maintenant le programme imprimé 0,0. C'est parce que la boucle avance eax de 8 (dans l'exemple ci-dessous), mais ne soustrait pas ce montant avant de revenir. Ainsi, les valeurs sont dans et addr+4
, mais le pointeur renvoyé est addr+8
.
; nasm -felf64 filename.asm
; gcc filename.o
global main
extern printf
section .data
N: dd 2 ; dimension
a: dd 1, 2, 3, 4 ; matrix
b: dd 1, 2 ; vector
format: db "%d", 10, 0
section .bss
c: resb 8 ; reserve 8B
section .text
main:
; set up arguments
lea rdi, [N] ; fix: change regs to edi, etc
mov rdi, [rdi]
lea rsi, [a]
lea rdx, [b]
lea rcx, [c]
call matvec ; c = a*b
; print results
mov rsi, [rax]
mov rdi, format
push rax
mov rax, 0
call printf ; print c[0], should be 5
pop rax
add rax, 4
mov rsi, [rax]
mov rdi, format
mov rax, 0
call printf ; print c[1], should be 11
ret
; rdi = N, rsi = int*, rdx = int*, rcx = int*
matvec:
mov rax, rcx ; rax = c
mov R14, rdi ; r14 = N
mov R15, R14
shl R15, 2 ; r15 = 4*N
xor R8, R8 ; i = 0
xor R9, R9 ; j = 0
xor R10, R10 ; sum = 0
loop:
mov R11, [rsi] ; r11 = *a
mov R12, [rdx] ; r12 = *b
imul R11, R12 ; r11 *= r12
add R10, R11 ; r10 += r11
add rsi, 4 ; a++
add rdx, 4 ; b++
add R9, 1 ; j++
cmp R14, R9
jnz loop ; loop while r14-r9 = N-j != 0
mov [rax], R10 ; *c = sum
xor R10, R10 ; sum = 0
xor R9, R9 ; j = 0 on every i loop
sub rdx, R15 ; b -= 4*N
add rax, 4 ; c++
add R8, 1 ; i++
cmp R14, R8
jnz loop ; loop while r14-r8 = N-i != 0
sub rax, R15 ; fix: subtract 4*N from return pointer
ret
'mov rdi, [rdi]' charge 8 octets. Mais 'N: dd 2' est juste 4 octets gros. change 'dd' en' dq'. – rkhb
Merci. J'ai pensé que cela pourrait avoir quelque chose à voir avec ça et j'ai donc fait le changement le plus encombrant, à savoir changer tous les regs de rax à eax etc. Maintenant ça marche mais après retour à main, les valeurs dans rax sont mises à zéro, ou plutôt les points sont mis à zéro. –
Si vous avez résolu le problème, vous devriez le poster comme une réponse plutôt que comme une modification à votre question. –