4

以前は、既存のライブラリを使用せずに Linux で直接システム コールを行う必要がある場合は、インクルードするだけで、次<linux/unistd.h>のようなマクロを定義できました。

#define _syscall3(type,name,type1,arg1,type2,arg2,type3,arg3) \
type name(type1 arg1,type2 arg2,type3 arg3) \
{ \
long __res; \
__asm__ volatile ("int $0x80" \
  : "=a" (__res) \
  : "0" (__NR_##name),"b" ((long)(arg1)),"c" ((long)(arg2)), \
      "d" ((long)(arg3))); \
if (__res>=0) \
  return (type) __res; \
errno=-__res; \
return -1; \
}

次に、コードのどこかに置くことができます:

_syscall3(ssize_t, write, int, fd, const void *, buf, size_t, count);

writeシステムコールを適切に実行する関数を定義します。

このシステムは、より堅牢な何か (すべてのプロセスが取得する "[vsyscall]" ページと推測しています) に取って代わられているようです。

では、プログラムが新しい Linux カーネルで直接システム コールを実行するための適切な方法 (具体的に教えてください) は何ですか? 私は、libc を使用する必要があることを理解しており、それで作業を完了できます。しかし、これを行う方法を知りたいという正当な理由があると仮定しましょう:-)。

4

1 に答える 1

4

OK、ここであまり反応が得られなかったので、さらに調べて、いくつかの良い情報を見つけました。まず、従来の argc、argv、envp パラメーターに加えて、Linux でアプリケーションが起動されたとき。auxv と呼ばれる追加のデータとともに渡される別の配列があります。詳細はこちらをご覧ください。

これらのキーと値のペアの 1 つに、 と同等のキーがありますAT_SYSINFO/usr/include/asm/auxvec.hまたはで定義されます/usr/include/elf

このキーに関連付けられた値は、システム コール関数へのエントリ ポイントです (すべてのプロセスにマップされた「vdso」または「vsyscall」ページ内)。

int 0x80従来のor命令をこのアドレスへの呼び出しに置き換えるだけsyscallで、実際にシステム コールが実行されます。残念ながら、これは醜いです。そのため、libc 関係者は優れた解決策を思いつきます。を割り当ててセグメントTCBに割り当てるとき。gs彼らはの値をAT_SYSINFOいくつかの固定オフセットに入れますTCB(残念ながら、バージョン間で固定されていないため、オフセットが常に同じ定数であることに依存することはできません)。したがって、従来の代わりに、セクションにあるシステム コール ルーチンを呼び出すものを指定int 0x80できます。call *%gs:0x10vdso

ここでの目標は、libc を書きやすくすることだと思います。これにより、libc 担当者は 1 つのコード ブロックを記述してシステム コールを処理することができ、二度とシステム コールについて心配する必要がなくなります。カーネル担当者は、いつでもシステム コールの実行方法を変更できますvdso。新しいメカニズムを使用するには、ページの内容を変更するだけでよいのです。実際、libc を再コンパイルする必要さえありません! ただし、これは、インライン アセンブリを作成し、ボンネットの下にあるものをいじろうとする私たちにとっては厄介なことです。

幸いなことに、本当に手動でやりたい場合は、古い方法でも機能します:-)。

編集:私の実験で気づいたことの1つはAT_SYSINFO、x86_64ボックスのプログラムに与えられていないように見えることです(AT_SYSINFO_EHDRただし、それをどのように利用するかはまだわかりません)。したがって、この状況でシステムコール関数のアドレスがどのように決定されるかは 100% わかりません。

于 2010-05-24T15:51:03.643 に答える