我正在用C編寫一個AVX矩陣向量乘法函數,但是實現了我需要的指令並未在GCC中實現,所以我將它看作是學習某些x86程序集的絕好機會。我首先在MIPS程序集中編寫了一個例程,然後嘗試翻譯它。我的代碼不工作,我得到段錯誤,我不知道爲什麼。如果我在代碼中刪除了兩個jnz
,它可以工作,但我不明白他們爲什麼會產生任何影響。這種類型的跳轉銷燬是否註冊了我正在使用的?NASM矩陣向量乘法
編輯:看起來main
中的前兩條指令並沒有將rdi
設置爲2,而是將其設置爲0x1000000002
,這會在以後造成麻煩。爲什麼不裝2?
EDIT2:明白了。正如@rkhb指出的那樣,使用rXX寄存器加載的數據比我預期的要多。我將寄存器更改爲32位(如果適用),這解決了段錯誤問題。但是,現在該程序打印0,0。這是因爲循環將eax提前8(在下面的例子中),但是在返回之前不會減去該數量。因此,值爲addr
和addr+4
,但返回的指針爲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]'加載8個字節。但'N:dd 2'只有4個字節大。將'dd'改爲'dq'。 – rkhb
謝謝。我認爲這可能與它有關,所以我做了更麻煩的更改,即將所有regs從rax更改爲eax等。現在它可以工作,但在返回main之後,rax中的值被清零,或者更確切地說,rax指向爲零。 –
如果你已經解決了這個問題,你應該把它作爲答案發布,而不是作爲你的問題的編輯。 –