web-dev-qa-db-ja.com

libc staticとその他のライブラリを動的にリンクするGCCの再検討

以下の質問は関連していますが、私の質問には答えません。

GCCで部分的に静的および部分的に動的にリンクする

他の静的ライブラリにリンクする静的ライブラリへの動的ライブラリのリンク

GCC:一部のライブラリのみを静的リンク

gccの共有ライブラリ関数の静的リンク

私は以前に非常に似た質問をしましたが、私が始めた前の質問はコメントセクションで幾分乱雑になり、完全に答えられませんでした(しかし、それは良い努力であり、少なくとも部分的に答えたので答えたとしてフラグを立てました)新しい質問をします。問題は、libcを静的としてリンクする方法と、他のライブラリ(libmなど)を動的にリンクする方法です。これは最初の質問ではできないと示唆されましたが、本当ですか?もしそうなら、なぜそうでないかを知ることは非常に興味深いでしょう。

これを行うことさえ可能ですか?誰かがコメントをしました(何らかの理由で削除されました、間違っているかもしれませんか?)、それは可能ですが、動的にリンクされたalsoが存在する必要があります動的ライブラリに必要となるため、libcのバージョン(たとえば、動的libmには動的libc(?)が必要)。

これは私にとっては問題ありませんが、GCCにこれを行う方法、つまりlibcを静的および動的の両方としてリンクする方法は明らかではありません。これを行うにはどうすればよいですか(いくつかの試みを行いましたが、いくつかは質問の後半に示されています)。または、私がやりたいことをする他の方法はありますか?

まず、gcc test.c -lmを実行するだけで、次のようにすべてが動的にリンクされることがわかります。

$ gcc test.c -lm
$ ldd a.out 
        linux-vdso.so.1 (0x00007fffb37d1000)
        libm.so.6 => /lib64/libm.so.6 (0x00007f3b0eeb6000)
        libc.so.6 => /lib64/libc.so.6 (0x00007f3b0eb10000)
        /lib64/ld-linux-x86-64.so.2 (0x00007f3b0f1b0000)

Libcのみを静的としてリンクし、libcを動的のままにするには、次のようにします(前述の質問の1つでZ bosonが指摘したように)。

$ gcc test.c /usr/lib/gcc/x86_64-pc-linux-gnu/4.7.3/../../../../lib64/libm.a

$ ldd a.out 
        linux-vdso.so.1 (0x00007fff747ff000)
        libc.so.6 => /lib64/libc.so.6 (0x00007f09aaa0c000)
        /lib64/ld-linux-x86-64.so.2 (0x00007f09aadb2000)

ただし、同じ手順でlibc staticとlibm dynamicをリンクしようとしても、うまくいかないようです:

$ gcc test.c /usr/lib/gcc/x86_64-pc-linux-gnu/4.7.3/../../../../lib64/libc.a -lm
/usr/lib/gcc/x86_64-pc-linux-gnu/4.7.3/../../../../x86_64-pc-linux-gnu/bin/ld: dynamic STT_GNU_IFUNC symbol `strcmp' with pointer equality in `/usr/lib/gcc/x86_64-pc-linux-gnu/4.7.3/../../../../lib64/libc.a(strcmp.o)' can not be used when making an executable; recompile with -fPIE and relink with -pie
collect2: error: ld returned 1 exit status

このエラーメッセージはどういう意味ですか?

他のいくつかの試み(ほとんどが私の最初の質問にも含まれていました):

$ gcc test.c /usr/lib64/libc.a
linux-gnu/4.7.3/../../../../x86_64-pc-linux-gnu/bin/ld: dynamic STT_GNU_IFUNC symbol `strcmp' with pointer equality in `/usr/lib64/libc.a(strcmp.o)' can not be used when making an executable; recompile with -fPIE and relink with -pie
urned 1 exit status
$ gcc test.c -Wl,-Bdynamic -lm -Wl,-Bstatic -lc
/usr/lib/gcc/x86_64-pc-linux-gnu/4.7.3/../../../../x86_64-pc-linux-gnu/bin/ld: cannot find -lgcc_s
/usr/lib/gcc/x86_64-pc-linux-gnu/4.7.3/../../../../x86_64-pc-linux-gnu/bin/ld: cannot find -lgcc_s
collect2: error: ld returned 1 exit status
$ gcc -Wl,-Bdynamic -lm -Wl,-Bstatic -lc test.c
/usr/lib/gcc/x86_64-pc-linux-gnu/4.7.3/../../../../x86_64-pc-linux-gnu/bin/ld: cannot find -lgcc_s
/usr/lib/gcc/x86_64-pc-linux-gnu/4.7.3/../../../../x86_64-pc-linux-gnu/bin/ld: cannot find -lgcc_s
collect2: error: ld returned 1 exit status
$ gcc -Wl,-Bstatic -lc -Wl,-Bdynamic -lm test.c
/usr/lib/gcc/x86_64-pc-linux-gnu/4.7.3/../../../../x86_64-pc-linux-gnu/bin/ld: dynamic STT_GNU_IFUNC symbol `strcmp' with pointer equality in `/usr/lib/gcc/x86_64-pc-linux-gnu/4.7.3/../../../../lib64/libc.a(strcmp.o)' can not be used when making an executable; recompile with -fPIE and relink with -pie
collect2: error: ld returned 1 exit status
$ gcc test.c /usr/lib/gcc/x86_64-pc-linux-gnu/4.7.3/../../../../lib64/libc.a /usr/lib/gcc/x86_64-pc-linux-gnu/4.7.3/../../../../lib64/libc.so -lm
/usr/lib/gcc/x86_64-pc-linux-gnu/4.7.3/../../../../x86_64-pc-linux-gnu/bin/ld: dynamic STT_GNU_IFUNC symbol `strcmp' with pointer equality in `/usr/lib/gcc/x86_64-pc-linux-gnu/4.7.3/../../../../lib64/libc.a(strcmp.o)' can not be used when making an executable; recompile with -fPIE and relink with -pie
collect2: error: ld returned 1 exit status
$ gcc test.c /usr/lib/gcc/x86_64-pc-linux-gnu/4.7.3/../../../../lib64/libc.so /usr/lib/gcc/x86_64-pc-linux-gnu/4.7.3/../../../../lib64/libc.a -lm

最後のものが正常にコンパイル/リンクされたことに注意してください。ただし、libcは静的にリンクされておらず、動的にリンクされているだけなので、別の失敗した試みです。

テストプログラムは次のとおりです。

$ cat test.c 
#include <stdio.h>
#include <math.h>

int main(int argc, char **argv)
{
        int i;
        int result;

        for(i = 0; i < 65535; i++) {
                result = sin(i);
        }

        return 0;
}

編集:

この質問で提案されているように、私はまた、修飾子とアーミンを試しました:

gccの共有ライブラリ関数の静的リンク

どちらも動作しません。

16

基本的に、最初のアプローチはこれを行う正しい方法です。

gcc test.c libc.a -lm

Gccが暗黙的なライブラリを追加すると、(概念的に)次のようになります。

gcc crt1.o test.c libc.a -lm -lc -lgcc -lc

つまり、crt1.oまたはtest.cのいずれかによって呼び出されたlibc関数は、libc.aから取り込まれ、静的にリンクされますが、solelyと呼ばれる関数はlibmまたはlibgccは動的にリンクされます(ただし、libmが既に引き込まれたものを呼び出す場合は、静的関数を再利用します)。

リンカは常に左端のファイル/ライブラリから始まり、右方向に動作します。二度と戻りません。 .cおよび.oファイルは無条件でリンクされますが、.aファイルおよび-lオプションは、既に参照されているがまだ定義されていない関数を見つけるためにのみ使用されます。したがって、左側のライブラリは無意味です(-lc-lcに依存し、-lgcc-lgccに依存するため、-lcは2回出現する必要があります)。 リンクの順序が重要です!

残念ながら、あなたはstrcmp(またはstrcmpを含むlibc)のバグに悩まされているように見えます:STT_GNU_IFUNC事は、含まれる関数の複数のバージョン、および利用可能なハードウェアに基づいて、実行時に選択される最適なバージョン。よくわかりませんが、この機能はPIE(Position Independent Executable)または共有ライブラリビルドでのみ使用できるようです。

なぜそれが静的なlibc.aにあるのかは私には謎ですが、簡単な回避策があります:独自のstrcmp(基本的な遅い実装はCのほんの数行です)とリンクbeforelibc.aにあります。

gcc test.c mystrcmp.c libc.a -lm

または、libc.aから本当に必要な関数を抽出し、静的にのみ関数をリンクすることもできます。

ar x libc.a
gcc test.c somefile.o -lm

ar.aファイルに対するもので、tar.tarファイルに対するものですが、コマンドの使用法は少し異なるため、この例では.oファイルを抽出します.aファイルから、それらを明示的にリンクします。

23
ams

Amsの答えに基づいて、私は次のことをしました

mystrcmp.c

int strcmp(const char *s1, const char *s2) {
}

コンパイル

gcc -c test.c
gcc -c mystrcmp.c

設定ファイル

ln -s `gcc -print-file-name=crt1.o`
ln -s `gcc -print-file-name=crti.o`
ln -s `gcc -print-file-name=crtn.o`
ln -s `gcc -print-file-name=libgcc_eh.a`
ln -s `gcc -print-file-name=libc.a`
ln -s `gcc -print-file-name=libm.so`

リンク

ld -m elf_x86_64 -o math crt1.o crti.o test.o mystrcmp.o libc.a libgcc_eh.a libc.a libm.so -dynamic-linker /lib64/ld-linux-x86-64.so.2 crtn .o

これは正しくリンクして実行されます。ただし、ldd

linux-vdso.so.1 =>  (0x00007fff51911000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f8182470000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f81820a9000)
/lib64/ld-linux-x86-64.so.2 (0x00007f8182793000)

動的libmには動的libcが必要なようです。実際、それは簡単に表示できます

ldd libm.soレポート

linux-vdso.so.1 =>  (0x00007fff20dfe000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fcaf74fe000)
/lib64/ld-linux-x86-64.so.2 (0x00007fcaf7bed000)

したがって、libcに依存せずにlibmをコンパイルできなければ、libc.soをリンクせずにlibm.soにリンクすることはできません。

5
Z boson