简体   繁体   中英

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. 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:

;-----------------------------------------------
;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:

;-----------------------------------------------
;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. 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. It sets up the buffer for printing via the write system call. Its location is used by the mov ecx, esp line. Note that ret pops off an address from the stack, and returns there. 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.
  2. The cpu continues executing code after the call instruction when the subroutine returns. 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. So even if point #1 was fixed the ret would still fault. 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. 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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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