вызывать подпрограммы условно в сборке - PullRequest
5 голосов
/ 04 сентября 2011

Я изучаю сборку x86.Мне было интересно, как вы выполняете вызов подпрограммы условно.Насколько я понимаю, переход к метке не работает, потому что обратный адрес не сохраняется и, следовательно, он не знает, куда возвращать.

 cmp bx, 0
 jz zero ; how do I do this correctly ?
 ; do something else and exit

 zero:
 ; do something
 ret

Ответы [ 3 ]

6 голосов
/ 04 сентября 2011

Ну, это работает, если вам не нужно возвращаться по этому адресу. Часто вы можете структурировать свой код так, чтобы это имело место.

В противном случае вам придется выполнить ветвление с помощью Jxx инструкций, которые перемещаются по сайту вызова или иным образом структурируют ваш код вокруг этого ограничения. В этом случае инвертирование теста должно работать:

    cmp bx, 0
    jnz not_zero
    call zero
    ; fall through here, return or do what you want
not_zero:
    ; do something else and exit
    ; ...
    ret 

zero:
    ; do something
    ret

РЕДАКТИРОВАТЬ 2016-04-25: Как упоминает @Peter Cordes в комментариях, приведенный ниже код, вероятно, будет работать ужасно. Смотрите, например эта статья для объяснения, почему.

@ Предложение Мэнни Д. в комментариях вдохновило меня написать следующее. Возможно, он не будет чище или лучше, но это еще один способ структурирования:

    push back_from_zero ; Push where we want to return after possibly branching to 'zero' 
    cmp bx, 0
    jz zero ; branch if bx==0
    add esp, 4 ; adjust stack in case we didn't branch
back_from_zero: ; returning from the zero branch here or continuing from above
    ; do something else and exit

zero:
    ; do something
    ret

Он явно помещает адрес возврата в стек, чтобы функция zero могла возвращать или извлекать значение (add esp, 4) из стека, если мы не вызываем функцию (для перенастройки в стек). Обратите внимание, что вам нужно внести некоторые незначительные корректировки, если вы хотите, чтобы это работало в 16- или 64-битном режиме.

4 голосов
/ 05 сентября 2011

Простой способ сделать это просто:

    cmp bx,0
    jnz notzero
    ; handle case for zero here
    jmp after_notzero
notzero:
    ; handle case for not zero here
after_notzero:
    ; continue with rest of processing

Я не знаю лучшего способа для ситуации «если бы еще». Хорошо, если обе ветви должны вернуться сразу после этого, вы можете сделать:

    cmp bx,0
    jnz notzero
    ; handle case for zero here
    ret

notzero:
    ; handle case for not zero here
    ret

Если какая-то обработка должна быть выполнена перед повторением (например, выталкивание значений, переданных ранее), следует использовать первый подход.

2 голосов
/ 04 сентября 2011

Я считаю, что правильный способ сделать это - инструкция call.Это эквивалентно вызову функции на более высоком языке программирования.ПК хранится в стеке, и поэтому ret в конце вашей подпрограммы zero: делает то, что должен.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...