9

最近のLinuxカーネル(少なくともamd64では)はlinux-vdso.so.1、カーネルへのsyscallインターフェースを抽象化するという魔法のオブジェクトファイルを提供し、カーネルが最適な呼び出し規約を選択できるようにします。Cでコードを記述する場合、glibcはこのオブジェクトを自動的に使用します。

さて、glibcを使用せずにプログラムを作成したい場合、このオブジェクトをどのように使用できますか?それが提供するインターフェースはどこかに文書化されていますか?呼び出し規約はどうですか?

4

2 に答える 2

9

実装が低レベルのユーティリティにCインターフェイスを使用しているかどうかによって異なります。

言語実装がCラッパーを経由せずにsyscallに直接アクセスできる場合は、VDSOを使用する必要はありません(たとえばSYSENTER、syscallを実行するための適切なマシン命令を生成できます)が、VDSOを使用してから利用することを決定できます。それの。その場合、言語はすべてのABI規則に従う必要はなく、カーネルの規則に従う必要があります。(たとえば、レジ​​スタ上でABIが提供する呼び出し元に対して安全な呼び出しに対して安全な区別は必要ありません。また、スタックの使用を回避することもできます)。

使用すらしていない言語実装の例は、libc.soBonesSchemeです。あなたは他のいくつかを見つけることができます。

VDSOについての私の理解は、x86プロセッサのさまざまなファミリ間で、syscallの実装におけるさまざまな小さな違い(ユーザーランド->カーネル遷移に関連する)を抽象化するための、カーネルによって提供される抽象化であるということです。特定のプロセッサターゲットを選択した場合、VDSOは必要なく、いつでも回避できます。

AFAIU、VDSOはELF共有オブジェクトであり、セグメント内に(最近コンパイルされた3.8.3カーネルを備えた私のDebian / AMD64上に)ありますffffffffff600000-ffffffffff601000。それがどこにあるかを正確に確認してくださいcat /proc/self/maps)。したがって、ELF共有オブジェクトの構成を理解し、そこからシンボルを取得する必要があります。これそのリンクを参照してください。VDSOは、x86-64ABI仕様に記載されている呼び出しにC規則を使用します。

つまり、プロセススペースからVDSOを抽出してディスクファイルに書き込むと、整形式のELF共有オブジェクトが作成されます。

ELFは十分に文書化された形式です。また、x86-64 ABI規約 (Cの呼び出し規約を正確に定義し、プロセスのイメージがどのように開始されるかを正確に定義します。execve(2)も参照してください)のマニュアルページ、そしてもちろんカーネルのドキュメントもそうです。あなたの問題は何ですか。ELFの理解には時間がかかることに同意します(10年前に理解しましたが、記憶が錆びています)。<elf.h>マシンのヘッダーファイルも読んでください。

例えば; 実行中(zsh64ビットDebian x86-64で)

 % file $(which sash)
 /bin/sash: ELF 64-bit LSB executable, x86-64, version 1 (SYSV),
      statically linked, for GNU/Linux 2.6.26,
      BuildID[sha1]=0x0347fcc08fba2f811f58af99f26111d0f579a9f6, stripped

 % ldd $(which sash)
 not a dynamic executable

  % sash
  Stand-alone shell (version 3.7)
  > ps |grep sash
  21635 pts/3    00:00:00 sash
  > cat /proc/21635/maps
  00400000-004da000 r-xp 00000000 08:01 4985590                            /bin/sash
  006da000-006dc000 rw-p 000da000 08:01 4985590                            /bin/sash
  006dc000-006e1000 rw-p 00000000 00:00 0 
  017e3000-01806000 rw-p 00000000 00:00 0                                  [heap]
  7fe4950e5000-7fe4950e7000 rw-p 00000000 00:00 0 
  7fff3f130000-7fff3f151000 rw-p 00000000 00:00 0                          [stack]
  7fff3f173000-7fff3f175000 r-xp 00000000 00:00 0                          [vdso]
  ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0                  [vsyscall]

この回答も参照してください。

ランタイム内で、VDSOを単純に解析できる最小バージョンのダイナミックリンカーが必要になる場合があります。プロセスが開始される正確な状態、特に補助ベクトルの役割を理解する必要がありますauxv(これらの詳細は本当に忘れていますが、重要であることを覚えています)。たとえば、この記事を参照してください

実際、ランタイムを確実に開始することは、VDSOの問題よりもおそらく難しいでしょう。

また、いくつかのことを説明しているLinuxアセンブリのハウツーも読むことをお勧めします(ただし、x86-64よりもx86についての詳細)

ところで、 http://musl-libc.org/ (代替libc)のコードははるかに読みやすく理解しやすいです(そして、動的リンクやpthreadなどをどのように行うかを簡単に学ぶことができます)。

于 2013-03-24T19:51:18.807 に答える
5

Linuxカーネルツリーにあるこれらのファイルは役に立ちました。

vDSOオブジェクトは、Linuxではamd64プロセスのアドレス空間に常にマップされる仮想動的共有オブジェクトです。迅速なシステムコールを実装するために使用できます。vDSOオブジェクト内の関数にアクセスするには、次のことを行う必要があります。

  • オブジェクトを見つけます
  • シンボルテーブルからアドレスを抽出します

どちらも、CC0ライセンスのリファレンス実装parse_vdso.cを使用して実行できます。

于 2013-03-24T20:55:14.177 に答える