简体   繁体   English

NASM子例程和分段错误

[英]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: 至少有两个问题:

  1. The 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值,并尝试将其用作将导致故障的返回地址。
  2. The cpu continues executing code after the call instruction when the subroutine returns. 当子例程返回时,cpu在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. 因此,即使固定了#1点, ret仍然会发生故障。 The solution to this is to move the subroutine out of the direct execution path. 解决方案是将子例程移出直接执行路径。 That is put the whole subroutine at the end of the code, after the exit call has been made. 在进行退出调用之后,将整个子例程放在代码的末尾。

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM