パソコン活用研究C&C++であそぼ(C、C++、の活用研究)

割り込み(システムコールの利用@)

1 割り込み関数
C言語で、システムコール(ファンクションコールとも言う いわゆるint21Hというやつ)を使いたい場面
もあるかもしれません。今回から数回にわたりC言語での割り込み(システムコールやその他のBIOS
コール)について説明していきます。

基礎知識として、そもそも割り込みってなに、システムコールとは?、レジスターってなんじゃ、という話
がありますが、別の機会にまとめるとしてここでは割愛いたします。
レジスターについては、PCマニアック道場/8086CPUの基礎に書いてありますのでご参照下さい。

C言語でシステムコールを利用する場合、レジスターの共用体について、知っておく必要があります。
レジスター共用体については共用対その2に書いてありますので、ご参照下さい。

コンパイラによって用意されている割り込み関数は異なると思いますが、LSICのdos.hを見てみると、
以下のような割り込み関係の関数が用意されていることがわかります。

char bdos(char, int, char);
char bdosp(char, void *);
void segread(struct SREGS *);
int int86(int, union REGS *, union REGS *);
int int86y(int, union REGS *, union REGS *);
int int86x(int, union REGS *, union REGS *, struct SREGS *);
int intdos(union REGS *, union REGS *);
int intdosy(union REGS *, union REGS *);
int intdosx(union REGS *, union REGS *, struct SREGS *);

今回は、いわゆるint21Hと呼ばれるシステムコールのうちシンプルなものについて、その利用法
を見てみたいと思います。
この場合は、いろいろある割り込み関数のうち、intdosというやつを使います。
intdosはint21H専用のシステムコール関数で、関数の引数は以下のようにレジスタ共用体を
2つだけ使います。
int intdos(union REGS *, union REGS *);
ひとつめが、割り込みコール時に設定するレジスタの値用、もうひとつは、割り込みから復帰後に
レジスタへの戻り値の保持用に使われます。通常は、ひとつめは&in、ふたつめを&outなどと
書くことが多く(またはひとつめを&inreg, ふたつめを&outregs)、プログラム上ではよく以下のように
書いたりします。
union REGS in,out;
intdos(&in,&out);

2 intdosの使用例
(1) MS-DOSのバージョンの取得(ファンクション30H)
シンプルな例として、int21Hシステムコールのファンクション30H(MS-DOSのバージョンの取得)
を利用したプログラムを作ってみます。
コール時に設定するレジスター値およびコールから復帰後のレジスター値の内容は、以下の通りです。

コール(&in) AH  30H
リターン(&out) AL  バージョン番号の整数部
AH  バージョン番号の小数部
BH  OEMのシリアル番号
BL:CX 24ビットのユーザ番号

とりあえず、リターン後のレジスタAL,AHのみ読み取って、バージョンを表示するだけのシンプルな
プログラムにしました。コール時はAHに30Hを設定するだけなので、in.h.ah=0x30H; としてintdos
を呼ぶだけです。
復帰時(リターン時)には、ALにバージョン番号の整数部、AHにバージョン番号の小数部が戻り値
として保持されていますので、これを表示するだけ(整数部と小数部の間にドット"."をおいてある)
のプログラムです。

version.c
#include <stdio.h>
#include <dos.h>

union REGS in,out;

main()
{
in.h.ah=0x30;
intdos(&in,&out);
printf ("Dos Version %d.%d\n",out.h.al,out.h.ah);
printf("Registerの値(16進) AX: %04x AL: %02x AH: %02x \n",out.x.ax,out.h.al,out.h.ah);
}

以下はWindow XPでの実行例です。バージョン5.0という結果がかえってきました。
ちなみに、蛇足ながら一般のバージョンを調べるDOSコマンドverを試してみると、
Microsoft Windows XP [Version 5.1.2600]
という答えがかえってきました。verコマンドは単純にファンクション30Hをコールしているだけ
ではないようです。

D:\win95\C>version
Dos Version 5.0
Registerの値(16進) AX: 0005 AL: 05 AH: 00

D:\win95\C>ver

Microsoft Windows XP [Version 5.1.2600]


(2) 日付の取得(ファンクション2aH)
もうひとつシンプルな例として日付の取得のプログラムを作ってみましょう。

コール時に設定するレジスター値およびコールから復帰後のレジスター値の内容は、以下の通りです。

コール(&in) AH  2AH
リターン(&out) AL  曜日(0・・日 1・・月  6・・土)
CX  年
DL  日
DH  月

もう説明もいらないと思いますので、コードだけ掲載します。

get_date.c
#include <stdio.h>
#include <dos.h>

union REGS in,out;
int year,month,date;
main()
{
in.h.ah=0x2a;
intdos(&in,&out);
year=out.x.cx;
month=out.h.dh;
date=out.h.dl;
printf("year:%d month:%d date:%d\n", year,month,date);
}


実行例です。2008年10月15日に実行しました。

D:\win95\C>get_date
year:2008 month:10 date:15

D:\win95\C>




TopPage