Вот самое оригинальное решение топика . Алгоритм, естественно, можно модифицировать. Но идею я постараюсь до вас донести, спектрумисты.
Процедура, естественно, релоцируема.
Прерывания можно и не запрещать, если вы уверены в том что не данная процедура не модифицирует код процедуры обработки прерываний и вызываемых ею подпрограмм в неподходящий момент.)

В общем, эта процедура ищет в памяти последовательность #18,#02
и если находит, то обнуляет смещение, и если получается что она модифицировала сама себя, то IX будет указывать на нашу программу и мы его скорректируем с PC, а если модифицировала что-то иное - то тут же восстановит данные и поиск продолжится.

Код:
 ;тут надо бы запомнить режим прерываний, процедуру писать не буду

	       di
;а можно и не запрещать прерывания по вышеизложенным причинам.
        ld ix,#4000		;начинаем искать в памяти с этого адреса
bad	ld a,#18		;ищем код JR
not_jr	cp (ix+0)		;в памяти лежит JR?
	inc ix
	jr nz,not_jr	;если не JR, поиск далее
	ld a,(ix+0)		;иначе берем смещение за JR
	cp 2	;сравниваем с величиной относительного смещения нашего JR
	jr	nz,bad	;оно не такое как у нас?
	ld (ix+0),0 ;если значение такое же, то уничтожаем смещение
        DEFB	#18	;вот тут после JR (код #18)	
	DEFB	2	;cмещение указывает через ловушку
	jr trapped	;<----сюда попадем если обнулили искомое смещение.
	ld (ix+0),a	;иначе попадаем сюда. восстанавливаем смещение
	jr bad 		;и снова ищем JR
trapped ;cюда попадаем, если уничтожили нужное смещение
        ld (ix+0),a ;восстанавливаем байт смещения
	;IX установлен на байт смещения
        LD DE,16
        ADD IX,DE
;вот и все. PC вычислен
        ;IX=$  !!!
        ;тут можно восстановить режим прерываний, если изменяли его ранее