4

組み込み ARM デバイスに Qt を使用する大規模な C++ 実行可能ファイルを事前リンクするために、クロス プレリンクを使用しています。Yocto を使用しているのではなく、カスタム ディストリビューションを使用していることに注意してください。そのため、現時点では手動で prelink を実行しています。

prelink の出力を見ると、うまくいっているようです:

$ prelink --verbose --ld-library-path=/opt/<product>/lib:/usr/local/Qt-5.3.1/lib --root=$PRODUCT_TARGET_ROOT/<product>/rfs/ /path/to/binary
Laying out 56 libraries in virtual address space 41000000-50000000
Assigned virtual address space slots for libraries:
/lib/ld-linux.so.3                                           41000000-41027908
/opt/<product>/lib/lib<product>common.so.1                   41030000-41cf0fd0
/lib/libc.so.6                                               442b0000-443e3980
/usr/local/Qt-5.3.1/lib/libQt5Qml.so.5                       434f0000-4380ee84
[..]
Prelinking /lib/ld-2.17.so
Prelinking /lib/libc-2.17.so
Prelinking /path/to/binary
Prelinking /<product>/lib/lib<product>common.so.1.0.0
Prelinking /usr/local/Qt-5.3.1/lib/libQt5Qml.so.5.3.1 
[..]

ライブラリがロードされると、少なくとも libQt5Qml.so と libproductcommon.so が prelink によって設定された優先ロード アドレスにロードされるように見えます。

$ cat /proc/`pidof binary`/maps
2ab49000-2ab4a000 r--p 0001e000 07:00 9357       /roroot/lib/ld-2.17.so
2ab4a000-2ab4b000 rw-p 0001f000 07:00 9357       /roroot/lib/ld-2.17.so
2b0fd000-2b223000 r-xp 00000000 07:00 9730       /roroot/lib/libc-2.17.so
2b223000-2b22a000 ---p 00126000 07:00 9730       /roroot/lib/libc-2.17.so
2b22a000-2b22c000 r--p 00125000 07:00 9730       /roroot/lib/libc-2.17.so
2b22c000-2b22d000 rw-p 00127000 07:00 9730       /roroot/lib/libc-2.17.so
41030000-41ce7000 r-xp 00000000 07:00 9305       /roroot/<product>/lib/lib<product>common.so.1.0.0
41ce7000-41cef000 ---p 00cb7000 07:00 9305       /roroot/<product>/lib/lib<product>common.so.1.0.0
41cef000-41cf1000 rw-p 00cb7000 07:00 9305       /roroot/<product>/lib/lib<product>common.so.1.0.0
434f0000-437f8000 r-xp 00000000 07:00 1355       /roroot/usr/local/Qt-5.3.1/lib/libQt5Qml.so.5.3.1
437f8000-437ff000 ---p 00308000 07:00 1355       /roroot/usr/local/Qt-5.3.1/lib/libQt5Qml.so.5.3.1
437ff000-4380e000 rw-p 00307000 07:00 1355       /roroot/usr/local/Qt-5.3.1/lib/libQt5Qml.so.5.3.1
[..]

さて、私は移転の数がいくらか減少することを期待していました:

$ LD_DEBUG=statistics /path/to/binary
    20453:                      number of relocations: 66379
    20453:           number of relocations from cache: 38995
    20453:             number of relative relocations: 21690

$ LD_USE_LOAD_BIAS=0 LD_DEBUG=statistics /path/to/binary
    20478:                      number of relocations: 66379
    20478:           number of relocations from cache: 38995
    20478:             number of relative relocations: 62981

これは、プレリンクによって相対的な 再配置のみが減少したことを示していますが、通常の再配置 (おそらくシンボル ルックアップが必要) は減少していません。他の移転はおそらくより高価なものであるため、私は特に他の移転を減らすことに興味があります.

今私の質問:

  1. プレリンクは通常の再配置を減らすことさえできますか? LWNの記事では、プレリンク後の通常の再配置が 0 であることを示しているので、それは可能であると思います。
  2. 非相対的な再配置が事前にリンクされないようにするには、何が間違っている可能性がありますか? どこからデバッグを開始すればよいですか?
4

2 に答える 2

3

OK、問題は、私の元の質問に見られるように、一部のライブラリが正しく prelink されていないことであることが判明しました。たとえば、libc.so が正しいロード アドレスにロードされていませんでした。

事前リンクは全か無かのアプローチのようです: 実行可能ファイルの依存関係の 1 つが正しく事前リンクされていないか、優先アドレスにロードできない場合、実行可能ファイルもライブラリもそれを利用できません。事前にリンクされたシンボルの再配置、および事前にリンクされた相対再配置のみを利用します。

ライブラリが正しく事前リンクされているかどうかは、上記に加えて、次の方法で確認する必要があります。

# readelf --dynamic usr/lib/someLibrary.so 
[..]
0x6ffffdf5 (GNU_PRELINKED)              2014-12-15T14:16:56
[..]

# readelf --program-headers usr/lib/someLibrary.so
Program Headers:
  Type           Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align
  [..]
  LOAD           0x000000 0x44bf0000 0x44bf0000 0xb56d4 0xb56d4 R E 0x8000
  [..]

によって出力されるアドレスはprelink --verbose、一致する必要がありますreadelf --program-headerscat /proc/PID/maps

私の間違いは、チェックしなかったことです。確認しreadelfていれば、ビルドシステムのエラーにより、プリリンクされたバージョンがプリリンクされていないバージョンで上書きされたため、ターゲットデバイス上の一部のライブラリがプリリンクされていないことに気付いたでしょう。 ...

ビルドシステムの問題を修正した後、通常の再配置は実際に 0 になりました。

# LD_DEBUG=statistics /path/to/binary
  5089:                      number of relocations: 0
  5089:           number of relocations from cache: 19477
  5089:             number of relative relocations: 0
于 2014-12-15T15:33:30.643 に答える
2

一部のリンクされたライブラリは、プレリンク情報が古くなっているか、割り当てられたアドレスに競合があるため、プレリンクされていないようです。

それか、不運に見舞われてhttp://lwn.net/Articles/341313/のようなものに苦しむ可能性があります。

i686 では、約 10% から 50% の確率で、linux-gate.so としても知られる [vdso] の配置のランダム化によって、プレリンクのこの利点が失われます。カーネルが [vdso] 用に選択したページが、事前にリンクされた必要な共有ライブラリと重複する場合、ld-linux はそのライブラリの再配置の処理を回避できません。多くの場合、事前にリンクされたページを取得しないライブラリが移動され、後続のライブラリに干渉するため、雪だるま式にコストがかかります。[x86_64 では、vdso は競合できない特別な固定アドレスにあります。]

https://bugzilla.redhat.com/show_bug.cgi?id=162797からこの例を試してください。

    for i in 0 1 2 3 4 5 6 7 8 9; do
      for j in 0 1 2 3 4 5 6 7 8 9; do
        for k in 0 1 2 3 4 5 6 7 8 9; do
          ldd /bin/cat
        done
      done 
    done  |  grep libc  |  sort  |  uniq -c

i686 上の現在の Fedora 11 では、ld-linux、libc、および [vdso] のみが関与する約 10% の時間で競合が発生します。これは、glibc が事前にリンクされていて、共有ライブラリの使用が /bin/cat で最小限に近い場合でも、とにかく glibc を時間の約 10% で動的に再配置する必要があることを意味します。この件に関する別のスレッドで主張されているように、GNOME アプリが 50 以上のリンク済み共有ライブラリを使用する場合、実行時の競合と費用がさらに発生する可能性が高くなります。

arm には [vdso] はありませんが、ここに文書化されたユーティリティ関数でいっぱいのコード ページがあることに注意してください https://www.kernel.org/doc/Documentation/arm/kernel_user_helpers.txtそれらは [vectors] ffff0000 内にあります。 ffff1000。

prelink ステージをプラットフォーム上で直接実行してみますが、これは読み取り専用の fs を備えた組み込みのもののようですが、試してみる価値があると思います。

これらの再配置は、プログラムの起動時間にのみ影響することに注意してください。

于 2014-12-03T13:01:14.983 に答える