Сразу скажу - не стоит держать в памяти 2 копии и больше одной резидентной программы. Для этого нужна
очень весомая причина. Зачем память захламлять?
Как всегда есть 2 пути: правильный и легкий.
"Правильный" путь использует то же самое int 2Fh вкупе с int 2Dh. Эта навернутая каша называется AMIS (
альтернативная спецификация мультиплексорного прерывания). Как оно работает знает похоже только Microsoft. Чтобы соответствовать этой спецификации резидент должен поддерживать определенные правила. Так как я об AMIS знаю (вернее помню) мало, то перейдем к более "веселому" пути (наиболее часто использовавшемся).
Алгоритм такой: программа устанаяливает на себя какой-нибудь мало использующийся вектор прерывания (вроде DDh и проч.) для того, чтобы если программа будет запущена еще раз - она знала, что копия уже в памяти есть и соваться туда не надо. В обработчике резидент проверяет регистр (например ax) на соответствие какому-либо значению (например 0DEADh

) и если ax == 0DEADh, значит надо сообщить другой копии, что память уже занята (например вернуть в ax == 0AAAAh и т.п.).
Если же
действительно необходимо держать несколько клонов резидента в памяти, то принцип такой (навскидку):
1. Если резидент первый - забрать 2Fh и запомнить предыдущий обработчик
-- его адрес возвращать по запросу (типа 01234h) прерывания (вроде 0EFh) в ax - сегмент, bx - смещение (например).
2. Если резидент не первый - забрать себе 2Fh а адрес самого первого получать вышеуказанным способом.
Но так ли это надо? Ведь n-1 копий просто без дела висеть будут?