Selasa, 08 Desember 2009

C language program Lecture 1

The above described service can be used to get the size of a file in the described manner. The following C language program tries to accomplish just that. This program has been saved as .C file and not as .CPP file and then compiled.

Example 21H/42H:
#include
#include

#include
#include

#include

unsigned int handle;
void main()

{
union REGS regs;

unsigned long int size;
handle = open("c:\\abc.txt",O_RDONLY);
regs.x.bx = handle;
regs.h.ah = 0x42;
regs.h.al = 0x02; //correction
regs.x.cx = 0;
regs.x.dx = 0;

int86(0x21,&regs,&regs);
*((int*)(&size)) = regs.x.ax;
*(((int*)(&size))+1) =regs.x.dx;

printf ("Size is %d“ ,size);
}

This program opens a file and saves its handle in the handle variable. This handle is passed to the ISR 21H/42H along with the move technique whose value is 2 signifing movement relative to the EOF and the number of bytes to move are specified to be zero indicating that the pointer should move to the EOF. As the file was just opened the previous location of the file pointer will be BOF. On return of this service DX-AX will contain the size of the file. The low word of this size in ax is placed in the low word of size variable and the high word in dx is placed in the high word of size variable.

Another Example:
Lets now illustrate how ISR can be invoked by means of another example of BIOS service. Here we are choosing the ISR 10h/01h. This interrupt is used to perform I/O on the monitor. Moreover this service is used to change the size of cursor in text mode. The description of this service is given as under.



Int # 10H Service # 01H
Entry
AH = 01

CH = Beginning Scan Line
CL = Ending Scan Line
On Exit
Unchanged


The size of the cursor depends upon the number of net scan lines used to display the cursor if the beginning scan line is greater than the ending scan line the cursor will disappear. The following tries to accomplish just that

void main()
{
char st[80];
union REGS regs;
regs.h.ah = 0x01;

regs.h.ch = 0x01;
regs.h.cl = 0x00;
int86(0x10,&regs,&regs); //corrected

gets(st);
}


The program is quite self explanatory as it puts the starting scan line to be 1 and the ending scan line to be 0. Henceforth when the service execute the cursor will disappear.
Use of ISRs for C Library functions
There are various library function that a program
mer would typically use in a program to perform input output operations. These library functions perform trivial I/O operations like character input (putch()) and character output (getch(), getc() etc). All these function call various ISRs to perform this I/O. In BIOS and DOS documentation number of services can be found that lie in correspondence with some C library function in terms of its functionality.
Writing S/W ISRs

Lets now see how can a programmer write an ISR
routine and what needs to be done in order make the service work properly. To exhibit this we will make use of an interrupt which is not used by DOS or BIOS so that our experiment does not put any interference to the normal functions of DOS and BIOS. One such interrupt is interrupt # 65H. The vector of int 65H is typically filled with zeros another indication that it is not being used.
Getting interrupt vector

As we have discussed earlier IVT is a table contai
ning 4 byte entries each of which is a far address of an interrupt service routine. All the vectors are arranged serially such that the interrupt number can be used as an index into the IVT.
Getting interrupt vector refers to the operation which used to reading the far address stored within the vector. The vector is double word, the lower word of it being the offset address and the higher word being the segment address. Moreover the address read from a vector can be used as a function pointer. The C library function used to do the exactly
same is getvect(int#) which requires the interrupt number a parameter and returns the value of its vector.

Fig 1 (Vector being read from IVT )
Function pointers
Another thing required to be understood are the function pointers. C language is a very flexible language just like there are pointers for integers, characters and other data types there are pointers for functions as well as illustrated by the following example


void myfunc()
{

}


void (*funcptr) ( )


funcptr = myfunc;

(*funcptr) ( );
myfunc();

There are three fragments of code in this example. The first fragment shows the declaration of a function myfunc()
The second fragment show declaration of a pointer to function named funcptr which is a pointer to a function that returns void.

In the third fragment funcptr is assigned the address of myfunc as the name of the function can be used as its address just like in the cases of arrays in C. Then the function pointed by funcptr by the statement (*funcptr)(); is called and then the original myfunc() is called. The user will observe in both the cases same function myproc() will be invoked.

Interrupt pointers and functions

Interrupt functions are special function that as compared to simple functions for reasons discussed earlier. It can be declared using the keyword interrupt as shown in the following examples.

void interrupt newint ( )
{
...
...
}


Similarly a pointer to such interrupt type function can also be declared as following
void interrupt (*intptr) ( );

where intptr is the interrupt pointer and it can be assigned an address using the getvect() function

intptr = getvect(0x08);

Now interrupt number 8 can be invoked using the interrupt vector as following

(*intptr) ( );

Setting Interrupt Vector

Setting interrupt vector is just the reverse process of getting interrupt vector. To set the interrupt vector means is to change the double word sized interrupt vector within the IVT. This task can be accomplished using the function setvect(int #, newint) which requires the number of interrupt whose vector is to be changed and the new value of the vector.
In the following example a certain interrupt type function has been declared. The address of this function can be placed on to the vector of any interrupt using setvect() function as following. The following code places the address of newint function at the vector of int 8

void interrupt newint ( )
{


}

setvect(0x08, newint);

C program making use of Int 65H

Here is a listing of a program that makes use of int 65H to exhibit how software interrupts needs to be programmed.

void interrupt (*oldint65)( );
char st[80] = {“Hello World$”};
void interrupt newint65(void);
void main()
{
oldint65 = getvect(0x65);
setvect(0x65, newint65);
geninterrupt (0x65);
geninterrupt (0x65);
geninterrupt (0x65);
setvect(0x65, oldint65);
}
void interrupt newint65( )
{
_AH = 0x09;
_DX=(unsigned int)st;
geninterrupt (0x21);
}
The above listing saves the address of original int 65H in the pointer oldint65. It then places the address of its own function newint65 at the vector of interrupt number 65H. From this point onwards whenever int 65H is invokes the function newint65 will be invoked. Int 65 is invoked thrice which will force the newint65 function to be invoked thrice accordingly. After this the original value of the vector stored in oldint65 is restored. The newint65 function only displays the string st. As the interrupt 65 is invoked thrice this string will be printed thrice.


The Keep function
One deficiency in the above listing is that it is not good enough for other application i.e. after the termination of this program the newint65 function is de-allocated from the memory and the interrupt vector needs to be restored otherwise it will act as a dangling pointer (pointing to a place where there is garbage or where there is no meaningful function). To make the effect of this program permanent the newint65 function need to be memory resident. This can be achieved by the function keep() which is quite similar to exit() function. The exit() function returns the execution to the parent shell program and de-allocates the memory allocated to the program whereas the keep() function also returns the execution to the parent program but the memory allocated to the process may still remain allocated.

keep (return code, no. of paras);

the keep() function requires the return code which is usually zero for normal termination and the number of paragraphs required to be allocated. Each paragraph is 16 bytes in size.

TSR Programs
Following is a listing of a TSR (Terminate and Stay Resident) program which programs the interrupt number 65H but in this case the new interrupt 65H function remains in memory even after the termination of the program and hence the vector of int 65h does not become a dangling pointer.

#include
#include

char st[80] ={"Hello World$"};
void interrupt (*oldint65)( );
void interrupt newint65( );
void main()
{
oldint65 = getvect(0x65);
setvect(0x65, newint65);
keep(0, 1000);
}
void interrupt newint65( )
{
_AH = 0x09;
_DX=(unsigned int)st;
geninterrupt (0x21);
}
The main()function gets and sets the vector of int 65H such that the address of newint65 is placed at its vector. In this case the program is made memory resident using the keep function and 1000 paragraphs of memory is reserved for the program (the amount of paragraphs is just a calculated guess work based upon the size of application). Now if any application as in the following case invokes int 65H the string st which is also now memory resident will be displayed.




#include
#include

void main()
{
geninterrupt (0x65);
geninterrupt (0x65);
}


This program invokes the interrupt 65H twice which has been made resident.

Tidak ada komentar:

Posting Komentar