Идея такова: в свободную (теоретически) память я закидываю свой обработчик, переустанавливаю вектор на него, а в конце своего обработчика возвращаюсь по старому вектору (что бы и досовский обработчик сделал свои дела). Но на деле по какой-то причине после того, как мой обработчик всё сделал - система виснет 8((. (сейчас запускаю это всё в DOS 6.22) Ниже небольшой код. (зы. на столе лежит две книги Юрова и одна Пирогова вроде сделал всё по науке) Код (Text): /* ----------------------------------------------------------------- */ int main( void ) { void (*FuncPtr)( void ); //func ptr DWORD* Ptr; DWORD i; /* копируем мой обработчик куда-то */ FuncPtr = MyHandler; Ptr = SYS_ADDR_TO_PTR( 0x000001E0 ); //якобы свободное место memcpy( Ptr, FuncPtr, 32 ); /* устанавливаем новый вектор */ Ptr = SYS_ADDR_TO_PTR( 0x0000020 ); //irq0 asm cli *Ptr = SYS_PTR_TO_ADDR( 0x000001E0 ); asm sti return 0; } /* --------------------------------------------------------------- */ /* ----------------------------------------------------------------- */ void MyHandler( void ) { /* выводим на экран морду */ asm { xor bh, bh mov dh, 1 mov dl, 1 mov ah, 2 int 0x10 mov al, 1 mov ah, 0x0A mov cx, 1 int 0x10 } //SYSPC_MASTER_EOI; //asm iret /* возврат по старому вектору */ asm db 0xEA //jmp asm dw 0x0000, 0x0020 } /* --------------------------------------------------------------- */
А чего бы ему не виснуть? Во-первых адрес 1E0 это никак не свободная память. Это часть таблицы векторов прерываний. Во-вторых переход к оригинальному обработчику написан неправильно. Это jmp 0020:0000 А ты хотел наверное написать jmp 0:20h, но и это неправильно. По адресу 0:20h лежит указатель на оригинальный обработчик, ты управление передаёш в таблицу векторов прерываний (по сути на данные), а не на код обработчика. Надо примерно так: Код (Text): xor ax,ax mov ds,ax jmp dword ptr ds:[20h] Да и регистры изменённые сохранять в обработчике надо. В общем тут одна большая ошибка...
cppasm 1) цель: записать код именно в конец таблицы векторов прерываний и никуда иначе. Т.к. всё остальное беспощадно уничтожаеться загрузчиком одной ОС. А т.к. согласно карте таблици прерываний - всё, что после 1E0 это свободная или зарезервированная для басика память, то я ей и воспользовался 2)с адресом джампа согласен я накосячил. но это произошло просто потому, что я криво прочитал содержимое ячейки по адресу 20. мне показалось что там было 20000, по которым я и прыгнул. И в это похоже как раз беда и заключаеться.. щас проверю. 3) регистры сохранять пробовал. просто тут этого кода не привёл. ЗЫ кстати запись типа мой bASM отказываеться понимать.
я нашел где был сильно неправ ): сегмент нужно смещать на 4 влево. Я же в 16-и разрядном режиме. так вот. по адресу 20 лежит "0x0387001F". старшая часть это смещение, а младшая это сегмент. Соответственно я поменял джамп вот так: Код (Text): asm db 0xEA asm dw 0x0387, 0x01F0 но легче почему-то не стало. система всё равно виснет. cppasm это борланд асемблер. который в bcc3.1 встроен.
Arisu А надо asm dw 0x0387, 0x001F Сегмент надо смещать только при вычислении адреса, в командах процессор делает это автоматом.
valterg да. и так тоже пробовал, но это не помогло к сожалению. я уже тихо начинаю рвать на себе волосы. всего-то надо подставить свой обработчик перед дефолтным и потом вернуть управление дефолтному 8(( а уже который день никак.
Я собственно так и подумал. Только у меня в нём компилируются оба варианта: Код (Text): asm jmp dword ptr ds:[20h] asm jmp dword ptr [ds:20h] Как конкретно ты считал это число? Как Dword читал? Если как Dword - ты его неправильно интерпретируеш. МЛАДШИЕ два байта (находятся по младшим адресам) это смещение, а СТАРШИЕ - сегмент.
cppasm ты меня совсем запутал. "0x0387001F" это то, что выводиться в printf (код ниже) приведу ещё раз код. он немного изменился Код (Text): #define SYS_ADDR_TO_PTR( Addr ) \ (void*)( (((DWORD)Addr >> 4) << 16) | ((WORD)Addr & 0x0F) ) #define SYS_PTR_TO_ADDR( Ptr ) \ ( (((DWORD)Ptr & 0xFFFF0000) >> 12) + ((WORD)Ptr) ) Код (Text): /* ----------------------------------------------------------------- */ int main( void ) { void (*FuncPtr)( void ); //func ptr DWORD* VecPtr; DWORD* MemPtr; VecPtr = SYS_ADDR_TO_PTR( 0x20 ); printf( "old vector = %08lX \n", *VecPtr ); /* копируем мой обработчик куда-то */ FuncPtr = MyHandler; MemPtr = SYS_ADDR_TO_PTR( 0x1E0 ); //якобы свободное место memcpy( MemPtr, FuncPtr, 64 ); /* устанавливаем новый вектор */ asm cli *VecPtr = 0x1E0; asm sti return 0; } /* --------------------------------------------------------------- */ Код (Text): /* ----------------------------------------------------------------- */ void MyHandler( void ) { asm pusha /* вывод рожи */ asm { xor bh, bh mov dh, 1 mov dl, 1 mov ah, 2 int 0x10 mov al, 1 mov ah, 0x0A mov cx, 1 int 0x10 } asm popa /* возврат по старому вектору */ asm db 0xEA //jmp ofs,seg asm dw 0x001F, 0x0387 } /* --------------------------------------------------------------- */ в итоге происходит прерывание и рожа таки выводиться. но дальше - висяк. пробовал в начале функции сохранять все регистры кроме флаговых (не использовать pusha), но это не спасает.
valterg пробовал и так. Вчера решил ещё забить на джамп и сделать просто обработчик который бы выводил рожу и всё. т.е. сделал С функцию с модификатором interrupt и в ней код вывода на экран. В теории всё должно было быть хорошо, однако и это приводит к зависону. 8(( что-то я делаю совсем не так видимо вспомнил, что я забыл про пролог функции, который вполне себе мешает, но попытавшись его компенсировать я ничего интересного не добился. Теперь ищу префикс к функции что бы она была сгенерирована без пролога короче мне это надоело. написал в виде шеллкода и всё стало нормально.