Locating Interrupt Handlers


Here is an example of using a DOS service to get information about the location of interrupt handlers. This program can help you locate the handlers for all 256 possible interrupts. A table of 16 lines and 16 columns that contain the interrupt numbers followed by the letters B, D or N is output to the screen. These letters indicate the area where the segment address of the interrupt points. The letter B stands for BIOS and the letter D stands for DOS. N means that the interrupt has a dummy handler - a handler which has an IRET instruction as its first instruction. Let's have a look then at how this program works.

;
;       Program Ch18Pr8 ( ch18pr8.asm )
;
.model small
.stack
.data
tbint   db      16 dup ('nu-H ') , '$'
HexSym  db      '0','1','2','3','4','5','6','7'
        db      '8','9','A','B','C','D','E','F'
NumInt  db      0
NumIntL db      0

The data area contains a pattern for the output string, an array of constants and two variables. The pattern for the output string is made up of 16 fields each of which is 5 bytes long (tbint). The next array HexSym contains 16 text constants which are ASCII representations of 16 Hexadecimal numbers. The variable NumInt contains the number of the first interrupt to be output in the line. The variable NumIntL is the number of the interrupt in the current column of this line. The initial value for both these variables is 0.

.code
begin:
	mov	ax,@data
        mov     ds,ax
        mov     cx,16           ; Line counter

The program begins as usual by loading segment register DS. Following that, the value 16 is placed into the register CX. This specifies the number of lines to be printed, and register CX will be used as a counter for the corresponding cycle. Beginning with the Label Rows:, the first instruction saves the cycle counter CX because CX will be used in a nested cycle that starts with the label Intrs:. By putting the inital value in the registers DI and CX, the next cycle is prepared.

Rows:                           ; Cycle starts here
        push    cx              ; Save this counter
        mov     di,0            ; Counter within line
        mov     cx,16           ; Columns counter
        mov     al,NumInt
        mov     NumIntL,al

DI is used as an index of the current element in the output string and CX as a cycle counter. NumIntL now contains the first interrupt number and we are ready to begin the next cycle. The first thing being done here is the setup for INT 21h Function 35 (Get Interrupt Vector) DOS service. To use this Service, put the number of the interrupt you want to locate into register AL. The result will be given in registers ES and BX - ES will contain the segment address of the corresponding interrupt handler and BX will contain its offset address.

Intrs:                          ;
        mov     al,NumintL      ; Load interrupt number
        mov     ah,35h          ; Get interrupt vector (ES:BX)
        int     21h             ; DOS service call
        mov     dx,es           ; Segment address of interrupt handler
        cmp     dx,0A000h       ; Compare it to the BIOS start address
        ja      InBios          ; If DX is greater - handler is in BIOS
        mov     tbint[di+3],'D' ; Set indicator 'DOS'
        jmp     DoneIn          ; To the end of block
InBios: mov     tbint[di+3],'B' ; Set indicator 'BIOS'
DoneIn:                         ; This is the end of block

Next we load the segment address found from ES into DX and compare it with the value A000h, which is the beginning of most BIOS areas. For segment locations above this address, we fill the tbint[di+3] string with the letter 'B'. Locations below this get assigned the letter 'D'. Each field is output in one column. The expression tbint[di+3] defines the place-holder for this letter. Here, DI contains the offset current field from the beginning of the string - 0 for the first element, 5 for the second, 10 for third and, eventually, 75 for the last one. Constant offset 3 defines the position of the letter within the current field.

Next set of instructions checks whether the first instruction of our found handler is an IRET instruction. The operation code for this instruction is 0CFh. If this code is found at location es:[bx] (the beginning of the interrupt handler), the corresponding interrupt is marked by the letter 'N' (Not set).

        cmp     byte ptr es:[bx],0CFh   ; First instruction IRET?
        jne     PresHan                 ; If not - handler presented
        mov     tbint[di+3],'N' ; Set indicator 'Not set'

Register AL contains an unsigned integer number of the interrupt and needs to be converted into symbolic representation suitable for output. Because this number is less than 256, it cannot consist of more than two hexadecimal digits. Divide the 8-bit number by 16 to get these digits. The quotient is the first digit of the result and the remainder - the second digit. Note that after the DIV command for 8-bit integers, the quotient from the DIV command is stored in register AL and the remainder in register AH.

PresHan:                        ;
        mov     ah,0            ; AL keeps the interrupt number
        mov     dl,16           ; Prepare to converting AL to symbols
        div     dl              ; AX / 16

        mov     bx,offset HexSym
        xlat			; translate into AL by table lookup in DS:BX
        mov     byte ptr tbint[di],al   ;    symbol into output line
        mov     al,ah
        xlat
        mov     byte ptr tbint[di+1],al   ;    symbol into output line

Transforming the 8-bit integers contained in registers AL and AH into ASCII codes is possible using the XLAT instruction. The value in AL is used as an index for looking into the corresponding HexSym table. Once AL has been converted, the result is stored in the proper byte position of tbint[di]. Register AH is next for the XLAT instruction and loading of the proper byte position + 1 (tbint[di+1]).

DI register is increased by 5 (the width of one column in a table to be printed) and NumIntL by 16 (the difference between the number off interrupts in adjoining columns). The entire cycle is executed again until such time as the CX register (our cycle counter) is equal to 0.

        add     di,5            ; Next position in the line
        add     NumIntL,16      ; Increase interrupt number
        loop    Intrs           ; Next step - next interrupt

Now that one line has been created by the execution of the nested cycle Intrs, the text string is ready to be displayed onto the screen using the function 09h of interrupt 21h(Display ASCIIZ String). Using this Function requires the address of the string in registers DS (segment) and DX (offset).

        pop     cx              ; Restore cycle counter
        mov     ah,09           ; Function 09 - output string
        mov     dx,offset tbint ; Address of string in DS:DX
        int     21h             ; Output one string
        inc     NumInt          ;
        loop    Rows            ; Next step - next string

Once all 16 Rows are displayed, we can finish the program using the standard Interrupt 21h Function 4Ch (Terminate with Output Code). The Return Code will be zero to indicated Successful Completion. DOS likes to interpret Error Level's of Zero as Success.

        mov     ax,4C00h
        int     21h
	end	begin

A sample of the output created by this program is shown below. You may get a slightly different picture, depending on what resident programs and installable device drivers you are using.

00-D 10-B 20-D 30-B 40-B 50-B 60-D 70-D 80-D 90-D A0-D B0-D C0-D D0-D E0-D F0-D
01-N 11-B 21-D 31-B 41-B 51-B 61-D 71-B 81-D 91-D A1-D B1-D C1-D D1-D E1-D F1-D
02-D 12-B 22-D 32-N 42-B 52-B 62-D 72-B 82-D 92-D A2-D B2-D C2-D D2-D E2-D F2-D
03-N 13-B 23-D 33-D 43-B 53-B 63-D 73-B 83-D 93-D A3-D B3-D C3-D D3-D E3-D F3-B
04-N 14-B 24-D 34-N 44-B 54-B 64-D 74-D 84-D 94-D A4-D B4-D C4-D D4-D E4-D F4-D
05-B 15-D 25-D 35-N 45-B 55-B 65-D 75-B 85-D 95-D A5-D B5-D C5-D D5-D E5-D F5-D
06-B 16-D 26-D 36-N 46-B 56-B 66-D 76-D 86-D 96-D A6-D B6-D C6-D D6-D E6-D F6-D
07-B 17-D 27-D 37-N 47-B 57-B 67-D 77-D 87-D 97-D A7-D B7-D C7-D D7-D E7-D F7-D
08-B 18-B 28-N 38-N 48-B 58-B 68-B 78-D 88-D 98-D A8-D B8-D C8-D D8-D E8-D F8-D
09-D 19-D 29-D 39-N 49-B 59-B 69-B 79-D 89-D 99-D A9-D B9-D C9-D D9-D E9-D F9-D
0A-B 1A-B 2A-D 3A-N 4A-B 5A-B 6A-B 7A-D 8A-D 9A-D AA-D BA-D CA-D DA-D EA-D FA-D
0B-B 1B-D 2B-N 3B-N 4B-B 5B-B 6B-B 7B-D 8B-D 9B-D AB-D BB-D CB-D DB-D EB-D FB-D
0C-B 1C-B 2C-N 3C-N 4C-B 5C-D 6C-B 7C-D 8C-D 9C-D AC-D BC-D CC-D DC-D EC-B FC-D
0D-B 1D-B 2D-N 3D-N 4D-B 5D-B 6D-B 7D-D 8D-D 9D-D AD-D BD-D CD-D DD-D ED-D FD-D
0E-D 1E-D 2E-D 3E-N 4E-B 5E-B 6E-B 7E-D 8E-D 9E-D AE-D BE-D CE-D DE-D EE-D FE-D
0F-N 1F-B 2F-D 3F-N 4F-D 5F-B 6F-B 7F-D 8F-B 9F-D AF-D BF-D CF-D DF-D EF-D FF-D 

Using Win98 Dos Sessions, the above values were reported. As you may have guessed, the Operating System also influences the results.


Using ROM BIOS Routines Chapter 18....Direct Access to the IVT

Monday, February 12, 2007

Hosted by www.Geocities.ws

1