序文
この記事では、インライン アセンブリの概念について説明し、インライン アセンブリ コードの記述方法を説明します。
1. 組み込みアセンブリ
インライン アセンブリは、アセンブリ コードを高級言語に埋め込むコーディング テクノロジです。インライン アセンブリでは、低レベルのマシン コードと高レベルの高級言語コードをシームレスに組み合わせることができるため、プログラマはより優れた柔軟性と制御を実現できます。
インライン アセンブリを使用すると、プログラマはアセンブリ ファイルを作成してコンパイルとリンクを待つ代わりに、アセンブリ コードをアセンブラに直接送信できるため、コードの開発とデバッグを迅速に行うことができます。
インライン アセンブリの構文は標準アセンブリ言語の構文に似ています。通常、キーワード asm はインライン アセンブリの開始を示すために使用され、中括弧 {} はアセンブリ コードを含めるのに使用されます。アセンブリ コードでは高級言語の変数や関数を使用できるため、高級言語でデータを操作できます。
2. インラインアセンブリ例
サンプルコード:
#include <stdio.h>
int main(void)
{
int result = 0;
int input = 1;
asm volatile (
"movl %1, %0\n"
: "=r"(result)
: "r"(input));
printf("result = %d\n", result);
printf("input = %d\n", input);
return 0;
}
このコードは、C コードにアセンブリ コードを埋め込み、整数の入力値を変数の結果に割り当て、これら 2 つの変数の値を出力する方法を示します。
具体的には、このコードは asm volatile を使用して後続のコードがインライン アセンブリ コードであることを宣言し、movl 命令によって入力値を変数 result に移動します。ここで、%0 と %1 はプレースホルダーで、それぞれ出力制約と入力制約に対応します。"=r" (結果) は出力制約を表し、結果変数の値をレジスタに割り当てます。一方、"r" (入力) は入力制約を表し、入力変数の値をレジスタに保存します。
操作結果:
3. printfを使わずに印刷する
#include <stdio.h>
int main() {
char* message = "Hello, world!\n";
// 使用内嵌汇编将字符串输出到标准输出
asm(
"movl $1, %%eax\n" // 将系统调用号1(write)放入eax寄存器
"movl $1, %%ebx\n" // 将文件描述符1(标准输出)放入ebx寄存器
"movl %0, %%ecx\n" // 将message变量的地址放入ecx寄存器
"movl $14, %%edx\n" // 将字符串长度放入edx寄存器
"int $0x80\n" // 触发系统调用
:
: "r"(message)
: "%eax", "%ebx", "%ecx", "%edx"
);
return 0;
}
このプログラム例では、ファイル記述子 1 (標準出力)、出力する文字列を指すアドレス、および文字列の長さをパラメータとして、インライン アセンブリを使用して write システム コールを呼び出します。GNU C コンパイラでは、C スタイルの拡張機能を使用してレジスタ使用の制約を指定できます。
インライン アセンブリはコンパイラおよびプラットフォームに固有であることに注意してください。上記のコード例は、x86 アーキテクチャと GNU C コンパイラに基づいています。別のプラットフォームでインライン アセンブリを使用する場合は、コードに適切な変更を加えるか、そのプラットフォームに固有の構文と呼び出し規則を使用する必要がある場合があります。
4. INT 80H
INT 80H は、x86 アーキテクチャ プロセッサでソフトウェア割り込みをトリガーするために使用されるアセンブリ命令です。この命令を通じて、プログラムはオペレーティング システムにサービスを要求して、特権操作を実行したり、オペレーティング システムが提供する機能を使用したりできます。
INT 80H は次のように使用されます。
mov eax, <系统调用号>
mov ebx, <参数1>
mov ecx, <参数2>
mov edx, <参数3>
int 0x80
このうち、eax レジスタは、要求する必要があるサービスや機能を示すシステム コール番号を格納するために使用されます。オペレーティング システムやサービスが異なれば、提供されるシステム コール番号も異なります。たとえば、Linux では、システム コール番号 1 が write 関数に対応し、システム コール番号 11 が execve 関数に対応します。
ebx、ecx、edx などのレジスタは、システム コールのパラメータを渡すために使用されます。パラメータの具体的な数と意味は、システム コールの要件によって異なります。たとえば、write システム コールでは、ファイル記述子、データ バッファー、およびデータ長を対応するレジスターに渡す必要があります。
INT 80H 命令を実行すると、プロセッサはソフト割り込みをトリガーし、カーネル状態に入り、対応する割り込みサービス ルーチンを実行します。カーネルでは、eax レジスタの値に従って、対応するシステム コール関数が実行され、渡されたパラメータに従って操作が実行されます。操作が完了すると、制御はユーザー モード プログラムに戻り、実行が継続されます。
需要注意的是,INT 80H是一种较为低级别的调用系统调用的方式,在现代操作系统中,更常用的方式是使用C库提供的高级接口,比如在Linux上使用libc库中的syscall()函数。这些高级接口会封装底层的系统调用,并提供更方便和安全的使用方式。
要約する
インライン アセンブリをマスターすると、カーネル ソース コードを解釈し、アセンブリに関する知識を理解するのに役立ち、この部分の整理にもっと時間を費やすことができます。