Рекурсивная функция сборки NASM - PullRequest
0 голосов
/ 06 мая 2020

Я только начал осваивать сборку. У меня есть последовательность:

  • seq (1) = 3;
  • seq (2) = 4;
  • seq (n) = 0,5 * seq (n-1) + 2 * seq (n-2), dla n> 2;

и оценка должна производиться с двойной точностью

А пока я просто пытаюсь узнать о рекурсивных функциях. Это мой код:

;       In the comments, we assume: int *esp;

        [bits 32]

;       esp -> [ret] ; ret - adres powrotu do asmloader

        sub esp, 2*4 ; esp = esp - 8 ; make room for double precision result

;       esp ->[ ][ ][ret]

n       equ 3

        mov ecx, n ; ecx = n = 3

        push ecx ; esp -> [ecx][ ][ ][ret]    => esp -> [n][ ][ ][ret]

        call sequence
addr:

;       esp -> [n][ ][ ][ret]

        lea eax, [esp+4] ; eax = esp + 4

;       eax ->    |
;       esp -> [n][ ][ ][ret]

        fstp qword [eax] ; *(double*)eax <- st =  ; fpu store top element
                                                  ; and pop fpu stack
;       st = []

        call print
format:
        db "seq(%d) = %lf", 0xA, 0

offset  equ $ - addr

a       dq 3.0
b       dq 4.0
y       dq 2.0
x       dq 0.5

sequence:

;       esp ->[addr][n][ ][ ][ret]

        finit ; fpu init

        mov eax, [esp]        ; eax = *(int*)esp = addr
        lea eax, [eax+offset] ; eax = eax + offset = st3

        cmp ecx, 1 ; ecx - 1           ; ZF affected
        jne next1  ; jump if not equal ; jump if ZF = 0

        fld qword [eax] ; *(double*)eax = *(double*)a -> st ; fpu load double

;       st = [st0] = [*a] ; fpu stack

        ret

next1:

        cmp ecx, 2 ; ecx - 2           ; ZF affected
        jne next2  ; jump if not equal ; jump if ZF = 0

        fld qword [eax+8] ; *(double*)eax = *(double*)b -> st ; fpu load double

;       st = [st0] = [*b] ; fpu stack

        ret

next2:
        dec ecx ; ecx = ecx - 1 = 2
        dec ecx ; ecx = ecx - 1 = 1
        call sequence ; calculate sequence for ECX = 1

;       st = [st0] = [*a] ; fpu stack

        fld qword [eax+2*8] ; *(double*)eax = *(double*)y -> st ; fpu load double

;       st = [st1, st0] = [*y, *a]

        fmulp ; st = [st0] = [y*a]

        ret

print:

;       esp -> [format][n][ ][ ][ret]

        call [ebx+3*4] ; printf("seq(%d) = %lf\n", n, *eax);
        add esp, 4*4   ; esp = esp + 16

;       esp -> [ret]

        push 0         ; esp -> [0][ret]
        call [ebx+0*4] ; exit(0);

; asmloader API
;
; call [ebx + FUNCTION_NUMBER*4]
;
; FUNCTIONS:
;
; 0 - exit
; 1 - putchar
; 2 - getchar
; 3 - printf
; 4 - scanf

Если n = 1 или n = 2, у меня правильный результат. Но когда у меня n = 3, он выводит: seq (3) = -0.000000, но должно быть 6.000000

...