syscall -
間接システムコール
#define _GNU_SOURCE /* feature_test_macros(7) 参照 */
#include <unistd.h>
#include <sys/syscall.h> /* SYS_xxx の定義用 */
int syscall(int number, ...);
syscall()
は、システムコールを起動する小さなライブラリ関数で、
number
で指定されたアセンブリ言語インターフェースのシステムコールを、指定された引き数をつけて実行する。
syscall()
が役に立つのは、例えば
C
ライブラリにラッパー関数が存在しないシステムコールを呼び出したい場合である。
syscall()
は、システムコールを行う前に
CPU
レジスタを保存し、システムコールから返った際にレジスタを復元し、エラーが発生した場合はシステムコールが返したエラーコードを
errno(3) に格納する。
システムコールのシンボル定数は、ヘッダファイル
<sys/syscall.h>
に書かれている。
返り値¶
返り値は呼び出されたシステムコールによって定義される。
一般に、返り値 0
は成功を表す。 -1
はエラーを表し、エラーコードは
errno に入れられる。
syscall() は 4BSD
で最初に登場した。
アーキテクチャ固有の要件¶
各アーキテクチャの ABI
には、
システムコールの引き数のカーネルへの渡し方に関する独自の要件がある。
(ほとんどのシステムコールのように)
glibc
ラッパー関数があるシステムコールでは、
glibc
が詳細を処理し、アーキテクチャに応じた方法で引き数が適切なレジスタにコピーされる。
しかし、
システムコールを呼び出すのに
syscall()
を使う場合には、
呼び出し側でアーキテクチャ依存の詳細を処理しなければならない場合がある。
これはいくつかの 32
ビットアーキテクチャでは非常によくあることだ。
例えば、ARM
アーキテクチャの Embedded ABI
(EABI) では、 (
long long などの)
64
ビット値は偶数番地のレジスタのペアに境界があっていなければならない。したがって、
glibc
が提供するラッパー関数ではなく
syscall()
を使う場合には、
readahead()
システムコールは ARM
アーキテクチャの EABI
では以下のようにして起動されることになる。
syscall(SYS_readahead, fd, 0,
(unsigned int) (offset >> 32),
(unsigned int) (offset & 0xFFFFFFFF),
count);
オフセット引き数は 64
ビットで、最初の引き数
(
fd) は
r0
で渡されるので、呼び出し側では手動で
64
ビット値を分割して境界を合わせて、
64 ビット値が
r2/
r3
レジスタペアで渡されるようにしなければならない。このため、
r1 (2 番目の引数 0)
としてダミー値を挿入している。
同様のことが、 MIPS の O32
ABI、 PowerPC の 32 ビット ABI や Xtensa
でも起こりうる。
次のシステムコールに影響がある:
fadvise64_64(2),
ftruncate64(2),
posix_fadvise(2),
pread64(2),
pwrite64(2),
readahead(2),
sync_file_range(2),
truncate64(2)
アーキテクチャ毎の呼び出し規約¶
各アーキテクチャには、それぞれ独自のシステムコール起動方法とカーネルへの引き数の渡し方がある。
各種のアーキテクチャの詳細を以下の
2 つの表にまとめる。
最初の表は、
カーネルモードに遷移するのに使用される命令、
システムコール番号を示すのに使用されるレジスタ、
システムコールの結果を返すのに使用されるレジスタの一覧である
(なお、
ここに載っているカーネルモードに遷移するのに使用される命令は、
カーネルモードに遷移する最速や最善の方法でない場合もあるので、
vdso(7)
を参照する必要があるかもしれない)。
arch/ABI |
instruction |
syscall # |
retval |
Notes |
|
arm/OABI |
swi NR |
- |
a1 |
NR
はシステムコール番号 |
arm/EABI |
swi 0x0 |
r7 |
r0 |
|
blackfin |
excpt 0x0 |
P0 |
R0 |
|
i386 |
int $0x80 |
eax |
eax |
|
ia64 |
break 0x100000 |
r15 |
r10/r8 |
真偽値のエラー/
エラー値 |
parisc |
ble 0x100(%sr2, %r0) |
r20 |
r28 |
|
s390 |
svc 0 |
r1 |
r2 |
下記参照 |
s390 |
svc 0 |
r1 |
r2 |
下記参照 |
sparc/32 |
t 0x10 |
g1 |
o0 |
|
sparc/64 |
t 0x6d |
g1 |
o0 |
|
x86_64 |
syscall |
rax |
rax |
|
s390 と s390x では、 NR
(システムコール番号)
が 256 未満の場合 "svc NR"
で NR
が直接渡される場合がある。
2
つ目の表は、システムコールの引き数を渡すのに使用されるレジスタの一覧である。
arch/ABI |
arg1 |
arg2 |
arg3 |
arg4 |
arg5 |
arg6 |
arg7 |
|
arm/OABI |
a1 |
a2 |
a3 |
a4 |
v1 |
v2 |
v3 |
arm/EABI |
r0 |
r1 |
r2 |
r3 |
r4 |
r5 |
r6 |
blackfin |
R0 |
R1 |
R2 |
R3 |
R4 |
R5 |
- |
i386 |
ebx |
ecx |
edx |
esi |
edi |
ebp |
- |
ia64 |
out0 |
out1 |
out2 |
out3 |
out4 |
out5 |
- |
parisc |
r26 |
r25 |
r24 |
r23 |
r22 |
r21 |
- |
s390 |
r2 |
r3 |
r4 |
r5 |
r6 |
r7 |
- |
s390x |
r2 |
r3 |
r4 |
r5 |
r6 |
r7 |
- |
sparc/32 |
o0 |
o1 |
o2 |
o3 |
o4 |
o5 |
- |
sparc/64 |
o0 |
o1 |
o2 |
o3 |
o4 |
o5 |
- |
x86_64 |
rdi |
rsi |
rdx |
r10 |
r8 |
r9 |
- |
これらの表にはすべての呼び出し規約が記載されているわけではない点に注意すること
—
アーキテクチャによっては、ここに記載されていない他のレジスタが見境なく上書きされる場合もある。
#define _GNU_SOURCE
#include <unistd.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <signal.h>
int
main(int argc, char *argv[])
{
pid_t tid;
tid = syscall(SYS_gettid);
tid = syscall(SYS_tgkill, getpid(), tid, SIGHUP);
}
関連項目¶
_syscall(2),
intro(2),
syscalls(2),
vdso(7)
この文書について¶
この man ページは Linux
man-pages
プロジェクトのリリース
3.65 の一部
である。プロジェクトの説明とバグ報告に関する情報は
http://www.kernel.org/doc/man-pages/
に書かれている。