Команда MARK - это единственная команда во всех известных мне архитектурах, которая предназначена исключительно для исполнения в стеке (как трамплин), а не в составе базового исполняемого кода:
Ассемблерный код | Содержимое стека и R5 при входе в процедуру |
---|---|
| R5 = RET |
Стек (растет вниз): | |
old value of R5 | |
n parameters | |
#(MARK n) |
Или, если предполагается использовать стандартную процедуру, возвращающуюся по R5:
Ассемблерный код | Содержимое стека и R5 при входе в процедуру |
---|---|
| R5 = SP+2 (адрес команды MARK в стеке) |
Стек (растет вниз): | |
old value of R5 | |
n parameters | |
#(MARK n) | |
RET |
Такая последовательность команд удобна для процедур с переменным числом параметров, типа printf. Преимуществ два: ни вызывающая, ни вызываемая процедура не должна беспокоиться об очистке стека от параметров, а с другой - вызываемой процедуре доступно количество переданных параметров в младшем байте на вершине стека.
Обратите внимание, что команда MARK может использоваться только в сочетании с регистром R5 - это ещё одна её особенность. Тем самым в PDP-11 (БК-0010) аппаратно предопределены функции не двух регистров, как это обычно считается (R7 = PC, R6 = SP), а трёх (R5 = регистр возврата). К сожалению, т.к. команда MARK была реализована только на старших моделях PDP-11, известные мне Си-компиляторы для PDP-11 её не используют.
Вот как выглядит формальное определение команды MARK:
MARK N:
SP = PC + (2 * N)
PC = R5
R5 = M[SP++]