[英]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.