Изучение сборки NASM на 32-битном Ubuntu. Теперь я пытаюсь узнать о рекурсивных функциях, начиная с factorial (обратите внимание: здесь я предполагаю, что параметр всегда будет неотрицательным).Понимание рекурсивной факторной функции в сборке NASM
Если предположить, что у меня есть
push 3
call factorial
Я хочу, чтобы в конечном итоге с 6
в EAX
.
Вот моя попытка:
SECTION .text
global main
main:
; -----------------------------------------------------------
; Main
; -----------------------------------------------------------
push 3
call factorial
; -----------------------------------------------------------
; Exit
; -----------------------------------------------------------
mov EAX,1
int 0x80
; -----------------------------------------------------------
; Recursive Factorial: n! = n * (n - 1)!
; -----------------------------------------------------------
factorial:
push EBP ; Retrieve parameter and put it
mov EBP,ESP ; into EBX register
add EBP,8 ;
mov EBX,[EBP] ; EBX = Param
cmp EBX,0 ; Check for base case
je base ; It is base if (n == 0)
dec EBX ; Decrement EBX to put it in the stack
push EBX ; Put (EBX - 1) in stack
inc EBX ; Restore EBX
call factorial ; Calculate factorial for (EBX - 1)
mul EBX ; EAX = (EAX * EBX) = (EBX - 1)! * EBX
pop EBX ; Retrieve EBX from the stack
jmp end
base: ; Base case
mov EAX,1 ; The result would be 1
end:
pop EBP ; Release EBP
ret
По крайней мере, это работает для базового случая, ха ... Но для любого другого значения я толкнуть, она всегда возвращает 0
. У меня было подозрение, что, может быть, с EAX
будет 0
, MUL
всегда будет приводить к 0
, объясняя это. Чтобы проверить, я решил дать EAX
значение 2
, ожидая некоторого ненулевого значения, но оно продолжалось в результате 0
.
Можете ли вы посоветовать мне, как сделать рекурсивную факторную функцию, которая принимает свой параметр из стека? Я верю, что видел некоторые примеры, но либо они не были рекурсивными, либо принимали свои параметры из других мест, либо использовали кучу переменных (когда я думаю, что это можно сделать только с помощью регистров).
Подсказка: записать функцию в C, скомпилировать с 'GCC -Wall -O3 -m32 -S ...' затем использовать полученный компилятор генерируется источником ассемблерного в качестве шаблона для вашей собственной функции (или даже для общего руководства по управлению стеком, передачи параметры и результаты функции и т. д.). –
@PaulR: Спасибо за совет. Кто-то однажды рассказал мне о сайте, который перевел C++ на Assembly (http://assembly.ynh.io/), как вы думаете, это хорошо для этой цели? – Voldemort
Поскольку вы используете Linux, у вас уже есть все необходимые инструменты (например, gcc), но у вас никогда не будет слишком много инструментов, и если сайт может сгенерировать asm в формате Intel, подходящем для NASM, тогда вам может быть более полезно в этом частный случай. Попробуйте оба в любом случае - это хороший способ изучить материал. –