Как мы можем сказать, что кадр стека в настоящее время пуст? - PullRequest
0 голосов
/ 25 октября 2019

Предположим, внутри цикла я хочу вытолкнуть элементы из стека на основе некоторого условия сравнения (функция также вытолкнет некоторые элементы в стек на основе некоторого условия). Как избежать появления пустого стека?

Если в начале функции я выполняю

push    %rbp
movq %rsp, %rbp

И внутри цикла я проверяю, если

cmpq %rbp, %rsp
je emptyStack

это возможное решение?

1 Ответ

0 голосов
/ 25 октября 2019

Да, если вы хотите использовать колл-стэк в качестве структуры данных стека, выполнение операции возврата до тех пор, пока указатель стека не вернется в начальную точку, является нормальным. Обращайтесь с адресами как без знака: если вы хотите проверить, находится ли RSP ниже RBP, используйте cmp / jb. Или просто cmp/jne, если вы уверены, что RSP не смог получить выше RBP.

Если вам нужно какое-либо пространство стека для локальных переменных, отличное от структуры данных, вам потребуетсяопорная точка, отличная от rbp, или просто используйте rbp в качестве не совсем традиционного указателя кадра. Например, переместите RSP, чтобы освободить место для местных жителей , прежде чем скопировать его в RBP. Наличие указателя кадра вообще необязательно.

Наличие некоторого пространства над RBP, которое по-прежнему является частью вашей структуры стековых данных, может также упростить обработку в угловом случае без риска наступления на сохраненное значение RBP или адрес возврата. Вы можете просто позволить ему подняться на одну высоту по любой причине.

например,

func:
    push  %rbp
    sub   $32, %rsp
    mov   %rsp, %rbp
      # Space from 0(%rbp) to 31(%rbp) can be used for locals separate from your stack data structure

...

    lea    32(%rbp), %rsp       # point RSP at the saved RBP value
    pop    %rbp
    ret

Обратите внимание, что для режима адресации 0(%rbp) по-прежнему требуется disp8, в отличие от 0(%rbx), который можетпросто не используйте смещение как (%rbx). Поэтому вы можете использовать другой регистр, например, RBX, в качестве привязки. Или даже регистр с замкнутым вызовом, если это конечная функция, например, RDX или R8. (Если вы не собираетесь использовать его в каких-либо режимах адресации, не имеет значения, если вы выберете тот, который требует префикса REX; вы все равно будете использовать его с 64-битным размером операнда при сравнении с RSP. Вы хотите оптимизировать, предполагая, что ваш стек не пересекает границу 4 ГБ и используя cmp %ecx, %esp, чтобы сохранить 1 байт размера кода.)

func:
    lea   -8(%rsp), %rsi        # or just mov, depending what you want.

 ...

    # once RSP is pointing back where it started
    ret
...