[英]NASM subroutines and segmentation fault
I have been experimenting with NASM and assembly language in general, and as such, I have an elementary idea as to how the subroutines work within this language. 我一直在尝试使用NASM和汇编语言,因此,我对子例程在该语言中的工作方式有一个基本的了解。 My question however is, how can I bundle different labels within the same procedure.
但是,我的问题是,如何在同一过程中捆绑不同的标签。 For instance in the following code which I found in SO:
例如,在我在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
Would it be possible to bundle innerLoop, outerLoop, biggerThan, innerEnd, and so on within a single procedure and call that procedure like so: 是否可以在单个过程中将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
Doing it this way results consistently in segmentation fault error within Linux, so there is definitely something wrong in the way I am attempting to do this. 这样做会始终导致Linux中的分段错误错误,因此我尝试执行此操作的方式肯定存在问题。 Any help would be greatly appreciated!
任何帮助将不胜感激!
At least 2 problems there: 至少有两个问题:
push ecx
should not be part of the subroutine, because that is already code in the main program. push ecx
不应成为子例程的一部分,因为该子例程已经在主程序中进行了编码。 It sets up the buffer for printing via the write
system call. write
系统调用进行打印。 Its location is used by the mov ecx, esp
line. mov ecx, esp
行使用。 Note that ret
pops off an address from the stack, and returns there. ret
从堆栈中弹出一个地址,然后返回堆栈。 As such, in this case it will pop off your ecx
value and try to use it as the return address which will cause the fault. ecx
值,并尝试将其用作将导致故障的返回地址。 call
instruction when the subroutine returns. call
指令之后继续执行代码。 In your case that means it will go into the findSmallestNumber
subroutine again (because that's directly after the call
) but this time there will be no return address on the stack. findSmallestNumber
子例程(因为它直接在call
),但是这次堆栈上没有返回地址。 So even if point #1 was fixed the ret
would still fault. ret
仍然会发生故障。 The solution to this is to move the subroutine out of the direct execution path. PS: If you intend to play around with assembly code, you should learn to use a debugger, so you can single step your code and see where any problems are. PS:如果您打算使用汇编代码,则应该学习使用调试器,这样您就可以单步执行代码并查看问题所在。 You might also want to read about calling conventions which are normally in use.
您可能还想阅读有关通常使用的调用约定的信息 。 You will need this if you ever want to interface with other code.
如果您想与其他代码交互,则将需要此代码。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.