[英]NASM subroutines and segmentation fault
我一直在嘗試使用NASM和匯編語言,因此,我對子例程在該語言中的工作方式有一個基本的了解。 但是,我的問題是,如何在同一過程中捆綁不同的標簽。 例如,在我在SO中找到的以下代碼中:
;-----------------------------------------------
;SECTION .DATA
;Instantiated variables/Constants
;-----------------------------------------------
section .data
result: db "The smallest number is: " , 0x0a
result_len: equ $-result
nl: db " ", 0x0a
nl_len equ $-nl
matrix: dw 25, 24, 23, 22, 21
dw 20, 19, 18, 17, 16
dw 15, 14, 13, 12, 11
dw 10, 9, 8, 7, 6
dw 5, 4, 3, 2, 1
;-----------------------------------------------
;SECTION .BSS
;Non initialized variables
;-----------------------------------------------
section .bss
;-----------------------------------------------
;SECTION .TEXT
;Code
;-----------------------------------------------
section .text
global _start
_start:
mov edi, 0
mov esi, 0
mov ecx, 12
outerLoop:
cmp edi, 50 ;each element is 2 bytes (2 ascii characters)
ja endloop ;we need 50 because it's 5 elements per row
mov esi, 0 ;and 5 rows
innerLoop:
cmp esi, 5 ;Compare esi(inner loop index) to 5
jae innerEnd ;jump if it reached the end of the row
mov ax, [matrix + edi + esi*2]
cmp ax, cx
jg biggerThan
mov cx, ax
biggerThan:
inc esi
jmp innerLoop
innerEnd:
add edi, 10 ;row has been complete, go to next
jmp outerLoop
endloop:
push ecx
mov eax, 4
mov ebx, 1
mov ecx, result
mov edx, result_len
int 0x80
mov eax, 4
mov ebx, 1
mov ecx, esp
add [ecx], DWORD 30h
mov edx, 2
int 0x80
; display new line
mov eax, 4
mov ebx, 1
mov ecx, nl
mov edx, nl_len
int 0x80
exit:
mov eax, 1 ;eax contains 1 so quit
mov ebx, 0
int 0x80
是否可以在單個過程中將innerLoop,outerLoop,bigThan,innerEnd等捆綁在一起,然后像這樣調用該過程:
;-----------------------------------------------
;SECTION .DATA
;Instantiated variables/Constants
;-----------------------------------------------
section .data
result: db "The smallest number is: " , 0x0a
result_len: equ $-result
nl: db " ", 0x0a
nl_len equ $-nl
matrix: dw 25, 24, 23, 22, 21
dw 20, 19, 18, 17, 16
dw 15, 14, 13, 12, 11
dw 10, 9, 8, 7, 6
dw 5, 4, 3, 2, 1
;-----------------------------------------------
;SECTION .BSS
;Non initialized variables
;-----------------------------------------------
section .bss
;-----------------------------------------------
;SECTION .TEXT
;Code
;-----------------------------------------------
section .text
global _start
_start:
mov edi, 0
mov esi, 0
mov ecx, 12
call findSmallestNumber
findSmallestNumber:
outerLoop:
cmp edi, 50 ;each element is 2 bytes (2 ascii characters)
ja endloop ;we need 50 because it's 5 elements per row
mov esi, 0 ;and 5 rows
innerLoop:
cmp esi, 5 ;Compare esi(inner loop index) to 5
jae innerEnd ;jump if it reached the end of the row
mov ax, [matrix + edi + esi*2]
cmp ax, cx
jg biggerThan
mov cx, ax
biggerThan:
inc esi
jmp innerLoop
innerEnd:
add edi, 10 ;row has been complete, go to next
jmp outerLoop
endloop:
push ecx
ret
mov eax, 4
mov ebx, 1
mov ecx, result
mov edx, result_len
int 0x80
mov eax, 4
mov ebx, 1
mov ecx, esp
add [ecx], DWORD 30h
mov edx, 2
int 0x80
; display new line
mov eax, 4
mov ebx, 1
mov ecx, nl
mov edx, nl_len
int 0x80
exit:
mov eax, 1 ;eax contains 1 so quit
mov ebx, 0
int 0x80
這樣做會始終導致Linux中的分段錯誤錯誤,因此我嘗試執行此操作的方式肯定存在問題。 任何幫助將不勝感激!
至少有兩個問題:
push ecx
不應成為子例程的一部分,因為該子例程已經在主程序中進行了編碼。 它設置緩沖區以通過write
系統調用進行打印。 其位置由mov ecx, esp
行使用。 請注意, ret
從堆棧中彈出一個地址,然后返回堆棧。 因此,在這種情況下,它將彈出您的ecx
值,並嘗試將其用作將導致故障的返回地址。 call
指令之后繼續執行代碼。 在您的情況下,這意味着它將再次進入findSmallestNumber
子例程(因為它直接在call
),但是這次堆棧上沒有返回地址。 因此,即使固定了#1點, ret
仍然會發生故障。 解決方案是將子例程移出直接執行路徑。 在進行退出調用之后,將整個子例程放在代碼的末尾。 PS:如果您打算使用匯編代碼,則應該學習使用調試器,這樣您就可以單步執行代碼並查看問題所在。 您可能還想閱讀有關通常使用的調用約定的信息 。 如果您想與其他代碼交互,則將需要此代碼。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.