2014-11-12 2 views
0

Я экспериментировал с NASM и ассемблером в целом, и поэтому у меня есть элементарная идея о том, как подпрограммы работают на этом языке. Однако мой вопрос заключается в том, как я могу связать разные метки в рамках одной и той же процедуры. Например, в следующем коде, который я нашел в SO:Подпрограммы NASM и ошибка сегментации

;----------------------------------------------- 
;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, biggerThan, 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, поэтому, безусловно, что-то не так в том, как я пытаюсь это сделать. Любая помощь будет принята с благодарностью!

ответ

1

По крайней мере 2 проблем нет:

  1. push ecx не должна быть частью подпрограммы, потому что это уже код в основной программе. Он устанавливает буфер для печати через системный вызов write. Его местоположение используется линией mov ecx, esp. Обратите внимание: ret выталкивает адрес из стека и возвращается туда. Таким образом, в этом случае он выскочит с вашего значения ecx и попытается использовать его в качестве обратного адреса, который вызовет ошибку.
  2. Процессор продолжает выполнять код после команды call, когда возвращается подпрограмма. В вашем случае это означает, что он снова войдет в подпрограмму findSmallestNumber (потому что это сразу после call), но на этот раз в стеке не будет обратного адреса. Поэтому даже если была зафиксирована точка № 1, ошибка ret. Решением этого является перемещение подпрограммы из пути прямого выполнения. Это поместит всю подпрограмму в конец кода после того, как был сделан вызов выхода.

PS: Если вы собираетесь играть с ассемблерным кодом, вам следует научиться использовать отладчик, чтобы вы могли сделать один шаг своего кода и посмотреть, где возникают проблемы. Вы также можете прочитать около calling conventions, которые обычно используются. Это вам понадобится, если вы захотите взаимодействовать с другим кодом.

Смежные вопросы