web-dev-qa-db-ja.com

アセンブリコードで「int 0x80」とはどういう意味ですか?

誰かが次のアセンブリコードの機能を説明できますか?

 int 0x80  
73
Josh Curren

割り込みベクトル0x80に制御を渡します

http://en.wikipedia.org/wiki/Interrupt_vector を参照してください

Linuxでは、 this をご覧ください。system_call。もちろん、別のOSでは、これはまったく異なるものを意味する場合があります。

54
jldupont

intは割り込みを意味し、番号_0x80_は割り込み番号です。割り込みは、その割り込みを処理している人、この場合は割り込み_0x80_にプログラムフローを転送します。 Linuxでは、_0x80_割り込みハンドラーはカーネルであり、他のプログラムによるカーネルへのシステム呼び出しを行うために使用されます。

カーネルは、レジスター_%eax_(ガス構文、およびIntel構文のEAX)の値を調べることにより、プログラムがどのシステム呼び出しを行うかについて通知されます。各システムコールには、他のレジスタの使用に関する異なる要件があります。たとえば、_1_の_%eax_の値はexit()のシステムコールを意味し、_%ebx_の値はexit()

106
Polat Tuzla

0x80 = 80h = 128であることを忘れないでください

here を見ることができます[〜#〜] int [〜#〜]は多くの命令の1つにすぎません(実際にはアセンブリ言語表現(またはx86命令セットに存在する「ニーモニック」と言います)。また、 here にあるIntelのマニュアルで、この手順の詳細を確認することもできます。

PDFから要約するには:

INT n/INTO/INT 3-割り込み手順の呼び出し

INT n命令は、宛先オペランドで指定された割り込みハンドラーまたは例外ハンドラーへの呼び出しを生成します。宛先オペランドは、8ビットの符号なし中間値としてエンコードされた0〜255のベクトルを指定します。 INT n命令は、割り込みハンドラーへのソフトウェア生成呼び出しを実行するための一般的なニーモニックです。

ご覧のとおり、0x80は、質問の宛先オペランドです。この時点で、CPUはカーネルに存在するコードを実行する必要があることを認識していますが、どのコードですか?これは、Linuxの割り込みベクターによって決定されます。

最も有用なDOSソフトウェア割り込みの1つは、割り込み0x21でした。レジスタ内の異なるパラメーター(ほとんどがahとal)で呼び出すことにより、さまざまなIO操作、文字列出力などにアクセスできます。

ほとんどのUnixシステムおよび派生物は、システム呼び出しを行うために使用される割り込み0x80を除き、ソフトウェア割り込みを使用しません。これは、プロセッサのEAXレジスタにカーネル関数に対応する32ビット値を入力し、を実行してからINT 0x80を実行することで実現されます。

割り込みハンドラテーブルの他の利用可能な値が表示されている場所で、これを見てください:

enter image description here

表からわかるように、CPUはシステムコールを実行するようにポイントされています。 Linuxシステムコールテーブルは here にあります。

そのため、値0x1をEAXレジスタに移動し、プログラムでINT 0x80を呼び出すことにより、現在実行中のプロセス(Linux、x86 Intel CPU)を停止(終了)するカーネル内のコードをプロセスに実行させることができます。

ハードウェア割り込みとソフトウェア割り込みを混同しないでください。 here は、この点に関する非常に良い答えです。

This も良いソースです。

アクション hereint 80hを確認できます。

35
Koray Tugay

int 0x80は、x86(Intel互換)プロセッサ上のLinuxでシステムコールを呼び出すために使用されるアセンブリ言語命令です。

http://www.linfo.org/int_0x80.html

9
Tom

最小限の実行可能なLinuxシステムコールの例

Linuxは0x80の割り込みハンドラーをセットアップして、システムコールを実装します。これは、ユーザーランドプログラムがカーネルと通信するための方法です。

.data
    s:
        .ascii "hello world\n"
        len = . - s
.text
    .global _start
    _start:

        movl $4, %eax   /* write system call number */
        movl $1, %ebx   /* stdout */
        movl $s, %ecx   /* the data to print */
        movl $len, %edx /* length of the buffer */
        int $0x80

        movl $1, %eax   /* exit system call number */
        movl $0, %ebx   /* exit status */
        int $0x80

コンパイルして実行:

as -o main.o main.S
ld -o main.out main.o
./main.out

結果:プログラムは標準出力に出力します:

hello world

そしてきれいに終了します。

リング3およびLinuxでは禁止されている しかないため、ユーザーランドから独自の割り込みハンドラーを直接設定することはできません。

GitHubアップストリーム 。 Ubuntu 16.04でテスト済み。

より良い代替案

int 0x80は、システム呼び出しを行うためのより優れた代替手段に取って代わられました。最初のsysenter、次にVDSOです。

x86_64には 新しいsyscall命令 があります。

参照: 「int 0x80」または「syscall」の方が良いですか?

最小16ビットの例

最初に、ここで説明したように、最小限のブートローダーOSを作成し、QEMUおよび実際のハードウェアで実行する方法を学びます。 https://stackoverflow.com/a/32483545/895245

これで、16ビットリアルモードで実行できます。

    movw $handler0, 0x00
    mov %cs, 0x02
    movw $handler1, 0x04
    mov %cs, 0x06
    int $0
    int $1
    hlt
handler0:
    /* Do 0. */
    iret
handler1:
    /* Do 1. */
    iret

これは順番に行います:

  • Do 0.
  • Do 1.
  • hlt:実行を停止

プロセッサがアドレス0で最初のハンドラーを探し、4で2番目のハンドラーを探す方法に注意してください。これは [〜#〜] ivt [〜#〜 ] 、各エントリは4バイトです。

IOを実行する最小限の例 ハンドラーを表示します。

最小保護モードの例

最新のオペレーティングシステムは、いわゆる保護モードで実行されます。

このモードでは処理のオプションが多いため、より複雑ですが、その精神は同じです。

重要なステップは、ハンドラーを記述するインメモリデータ構造(割り込み記述子テーブル)のアドレスを指すLGDTおよびLIDT命令を使用することです。

最小限の例

「int」命令により割り込みが発生します。

割り込みとは何ですか?

単純な答え:割り込みは、簡単に言えば、CPUに割り込み、特定のタスクを実行するように伝えるイベントです。

詳細な回答

CPUには、メモリに格納された割り込みサービスルーチン(またはISR)のテーブルがあります。リアル(16ビット)モードでは、これは[〜#〜] ivt [〜#〜]、または[〜#〜] i [〜 #〜]nterrupt[〜#〜] v [〜#〜]ector[〜#〜] t [〜#〜]可能。 IVTは通常0x0000:0x0000(物理アドレス0x00000)にあり、ISRを指す一連のセグメントオフセットアドレスです。 OSは、既存のIVTエントリを独自のISRで置き換える場合があります。

(注:IVTのサイズは1024(0x400)バイトに固定されています。)

保護(32ビット)モードでは、CPUはIDTを使用します。 IDTは、descriptors(別名ゲートとも呼ばれる)で構成される可変長構造体であり、CPUに割り込みハンドラーについて通知します。これらの記述子の構造は、IVTの単純なセグメントオフセットエントリよりもはるかに複雑です。ここにあります:

bytes 0, 1: Lower 16 bits of the ISR's address.
bytes 2, 3: A code segment selector (in the GDT/LDT)
byte 4: Zero.
byte 5: A type field consisting of several bitfields.
    bit 0:  P (Present): 0 for unused interrupts, 1 for used interrupts.*
    bits 1, 2: DPL (Descriptor Privilege Level): The privilege level the descriptor (bytes 2, 3) must have.
    bit 3: S (Storage Segment): Is 0 for interrupt and trap gates. Otherwise, is one. 
    bits 4, 5, 6, 7: GateType:
        0101: 32 bit task gate
        0110: 16-bit interrupt gate
        0111: 16-bit trap gate
        1110: 32-bit interrupt gate
        1111: 32-bit trap gate

* IDTは可変サイズの場合がありますが、連続している必要があります。つまり、IDTを0x00から0x50に宣言する場合、0x00から0x50のすべての割り込みが必要です。 OSは必ずしもそれらのすべてを使用するわけではないため、Presentビットを使用すると、OSが処理しない割り込みをCPUが適切に処理できます。

割り込みが発生すると(IRQの外部トリガー(ハードウェアデバイスなど)、またはプログラムからのint命令)、CPUはEFLAGS、CS、EIPの順にプッシュします。 (これらは、割り込み戻り命令iretによって自動的に復元されます。)OSは通常、マシンの状態に関する詳細情報を保存し、割り込みを処理し、マシンの状態を復元して、続行します。

多くの* NIX OS(Linuxを含む)では、システムコールは割り込みベースです。プログラムはシステムコールへの引数をレジスタ(EAX、EBX、ECX、EDXなど)に入れ、割り込み0x80を呼び出します。カーネルは、0x80の割り込みハンドラーを含むようにIDTをすでに設定しています。これは、割り込み0x80を受け取ったときに呼び出されます。その後、カーネルは引数を読み取り、それに応じてカーネル関数を呼び出します。 EAX/EBXにリターンを保存する場合があります。システムコールは、主にsysenterおよびsysexit(またはAMDではsyscallおよびsysret)命令に置き換えられ、リング0へのより高速なエントリが可能になりました。

この割り込みは、異なるOSでは異なる意味を持つ場合があります。必ずドキュメントを確認してください。

3
Adrian Zhang

前述のように、制御により割り込みベクトル0x80にジャンプします。実際には(少なくともLinuxでは)これが意味することは、システムコールが呼び出されることです。正確なシステムコールと引数は、レジスタの内容によって定義されます。たとえば、%eaxを1に設定し、その後に「int 0x80」を設定すると、exit()を呼び出すことができます。

2
Steve Smith

これは、CPUに割り込みベクトル0x80をアクティブにするように指示します。これは、Linux OSではシステムコール割り込みであり、ファイルなどのopen()などのシステム関数を呼び出すために使用されます。

1
Amber