Придумайте, как писать программу так, чтобы она могла быть в любой момент прервана (INT) и перемещена в памяти (возможно, с пересчётом каких-то ячеек по какому-то списку, возможно, динамически генерируемому). Так что при возврате указатели на переменные или массивы устаревают. И стек вызовов тоже. Допустим, перемещение производится по 256 или кратное число байт.
Мне пока видятся только следующие методы:
1) Типизация стека и регистров. В стек каждый раз пишется не 2 байта, а 4 (данные и тип - число/указатель). Области смены типа регистров, а также EXX'ы обрамляются системными вызовами.
2) Чтение данных по указателям - только через системные вызовы (очень медленно!). В указателях только смещения относительно начала блока программы. CALL и RET - через системные макросы (тоже по смещению, и в стеке лежит смещение точки возврата).
3) CALL и RET - через системные макросы (в стеке лежит смещение точки возврата). Типы регистров никогда не меняются.
Если указатели - HL и DE, то проблема с 16-битной арифметикой.
Если указатели - IX и IY, то всё медленно.
Если только один указатель и буферизация данных в стеке, то ещё медленнее и вообще изврат.
Компромисс - IX и DE (или DE и DE').
4) Интерпретируемый язык (очень медленно!).