Языки ассемблера 1960-х годов использовали самоизменяющийся код для реализации вызовов функций без стека.
Кнут, v1, 1-е стр.182:
MAX100 STJ EXIT ;Subroutine linkage
ENT3 100 ;M1. Initialize
JMP 2F
1H CMPA X,3 ;M3. Compare
JGE *+3
2H ENT2 0,3 ;M4. Change m
LDA X,3 ;(New maximum found)
DEC3 1 ;M5. Decrease k
J3P 1B ;M2. All tested?
EXIT JMP * ;Return to main program
В более крупной программе, содержащей это кодирование в качестве подпрограммы, одиночная инструкция "JMP MAX100" заставит регистр A установить текущее максимальное значение местоположений от X + 1 до X + 100, а позиция максимума будет появляются в R2. Связывание подпрограмм в этом случае достигается с помощью инструкций «MAX100 STJ EXIT», а затем «EXIT JMP *». Из-за того, как работает J-регистр, инструкция выхода затем перейдет в место, следующее за местом, где была сделана первоначальная ссылка на MAX100.
Редактировать: Может быть трудно увидеть, что происходит, даже с кратким объяснением здесь. В строке MAX100 STJ EXIT
, MAX100
- метка для инструкции (и, следовательно, для всей процедуры), STJ
означает STORE регистр перехода (куда мы только что пришли из ), EXIT
означает, что ячейка памяти с надписью «EXIT» является целью хранилища. EXIT
, мы увидим позже ярлык для последней инструкции. Так что это переписывает код! Но многие инструкции (включая STJ
здесь) неявно перезаписывают только часть операнда командного слова. Таким образом, JMP
остается нетронутым, а *
является фиктивным токеном, поскольку на самом деле в нем нет ничего значимого, он будет только перезаписан.
Самоизменяющийся код также используется в тех случаях, когда косвенная адресация в регистре недоступна, а нужный вам адрес находится прямо в реестре. PDP-1 LISP:
dap .+1 ;deposit address part of accumulator in (IP+1)
lac xy ;load accumulator with (ADDRESS) [xy is a dummy symbol, just like * above]
Эти две инструкции выполняют ACC := (ACC)
, изменяя операнд инструкции загрузки.
Такие модификации относительно безопасны, а на старинных архитектурах они необходимы.