Это правильный метод для передачи переменных в стеке? - PullRequest
0 голосов
/ 06 апреля 2011

Я написал простую программу, которая принимает предопределенное число в предопределенную степень и возвращает результат. Это в сборке NASM, для Linux. Я пытался понять, как использовать стек для передачи переменных в функции, и хотел убедиться, что я сделал это правильно. Он возвращает правильное число, но я не знаю, правильно ли это:

section .text
    global _start

_start:
    push dword 3        ;(power)
    push dword 2        ;(num)

    call power

    mov ebx, eax
    mov eax, 1
    int 0x80

power:
    push ebp
    mov ebp, esp
    sub esp, 8      ;reserve space for two local vars
    push dword [ebp+8]
    pop dword [ebp-4]   ;store original num as a local var
    push dword [ebp+12] 
    pop dword [ebp-8]   ;store power in a local counter var
    dec dword [ebp-8]
    mov eax, [ebp-4]    ;store original num in eax (current val)    
    jmp power_loop  

power_loop:
    imul eax, dword [ebp-4] ;multiply current val by original num
    dec dword [ebp-8]   ;decrement counter

    cmp dword [ebp-8], 0
    jne power_loop

    mov esp, ebp        ;restore stack pointer
    pop ebp
    ret 

Любой совет будет высоко ценится!

1 Ответ

1 голос
/ 06 апреля 2011

выглядит хорошо по большей части. Однако после восстановления питания вы должны удалить переменные из стека. В этих обстоятельствах это не имеет значения, поскольку _start не возвращается, но будет иметь значение, если вы попытаетесь вызвать функцию из функции, которая возвращает и не очищает. Адрес возврата функции сохраняется в стеке и извлекается инструкцией ret, поэтому, если у вас есть что-то еще на вершине стека, вы вернетесь в неправильное место.

_start:
    push dword 3
    push dword 2
    call power
    add esp,8 ; Removes two dwords from stack

Если вы пишете функцию, которая вызывает много других функций, лучше выделить место для аргументов стека в начале функции, записать в нее перед каждым вызовом функции и удалить ее из стека в конце функция. Таким образом, вы тратите меньше времени на нажатия и выталкивание, потому что вместо этого вы можете использовать mov с правильным адресом.

_start:
    sub esp,8 ; Make room for two dwords
    mov dword [esp+4], 3
    mov dword [esp], 2
    call power
    add esp,8 ; Removes two dwords from stack

Как комментарий к вашей функции питания: в настоящее время она работает, только если мощность не меньше 2. Вы можете изменить минимальную мощность на 0 следующим образом:

  • Начните eax с 1
  • Не уменьшать переменную счетчика перед циклом
  • Проверьте, не равен ли счетчик 0 в начале цикла

Пример:

    ; dec dword [ebp-8] ; Don't do this
    mov eax, dword 1
    jmp power_loop  

power_loop:
    cmp dword [ebp-8], 0
    je end_loop

    imul eax, dword [ebp-4] ;multiply current val by original num
    dec dword [ebp-8]   ;decrement counter
    jmp power_loop

end_loop:
    mov esp, ebp
...