0

私は、musl-cross-make (gcc 9.2.0、musl 1.2.0) でビルドされた arm 用の musl ターゲット クロス コンパイラを使用しています。printf を使用して単純な hello world c プログラムをコンパイルすると、標準ライブラリにあるシンボルの未定義の参照が取得されます。

cross-musl/bin/arm-linux-musleabihf-gcc -c hello.c -o hello.o
cross-musl/bin/arm-linux-musleabihf-ld  hello.o -o hello.elf
cross-musl/bin/arm-linux-musleabihf-ld: warning: cannot find entry symbol _start; defaulting to 0000000000010074
cross-musl/bin/arm-linux-musleabihf-ld: hello.o: in function `main':
hello.c:(.text+0x18): undefined reference to `puts'

libc.a と crt1.o をリンカー コマンドに追加すると、エラーは発生しません。

cross-musl/bin/arm-linux-musleabihf-gcc -c hello.c -o hello.o
cross-musl/bin/arm-linux-musleabihf-ld -Lcross-musl/arm-linux-musleabihf/lib -lc cross-musl/arm-linux-musleabihf/lib/crt1.o hello.o -o hello.elf

-nostartfiles、-nostdlib、-nodefaultlibs を使用しない場合は、標準ライブラリと起動ファイルを指定する必要はないと思ったのですが、間違っていますか?

4

2 に答える 2

1

これが GNU ツールの仕組みです gcc は、コンパイラーだけでなく、binutils と C ライブラリーとの相対関係を認識しているリンカを呼び出すために使用される場合に、最もスマートです。 GNU ベースのツールチェーンを構築するとき。gcc からリンカーへの呼び出しを調べて、すべてが指定されていることを確認するのは簡単です。ld は、それがどこにあるのか見当もつかないし、何かがどこにあるかを把握する方法もありません。これがldの設計方法です。Linux プログラムとクロス コンパイラの簡単な例。

#include <stdlib.h>
int main ( void )
{
    exit(1);
}

arm-linux-gnueabi-gcc so.c -o so.o

これは、リンクを機能させるために ld に渡されるものです (実際のバイナリは、arm-whatever-gcc から呼び出されたときに ld という名前が付けられます)。

[1][-plugin]
[2][/usr/lib/gcc-cross/arm-linux-gnueabi/5/liblto_plugin.so]
[3][-plugin-opt=/usr/lib/gcc-cross/arm-linux-gnueabi/5/lto-wrapper]
[4][-plugin-opt=-fresolution=/tmp/ccaUZvi4.res]
[5][-plugin-opt=-pass-through=-lgcc]
[6][-plugin-opt=-pass-through=-lgcc_s]
[7][-plugin-opt=-pass-through=-lc]
[8][-plugin-opt=-pass-through=-lgcc]
[9][-plugin-opt=-pass-through=-lgcc_s]
[10][--sysroot=/]
[11][--build-id]
[12][--eh-frame-hdr]
[13][-dynamic-linker]
[14][/lib/ld-linux.so.3]
[15][-X]
[16][--hash-style=gnu]
[17][--as-needed]
[18][-m]
[19][armelf_linux_eabi]
[20][-z]
[21][relro]
[22][-o]
[23][so.o]
[24][crt1.o]
[25][crti.o]
[26][/usr/lib/gcc-cross/arm-linux-gnueabi/5/crtbegin.o]
[27][-L/usr/lib/gcc-cross/arm-linux-gnueabi/5]
[28][-L/usr/lib/gcc-cross/arm-linux-gnueabi/5/../../../../arm-linux-gnueabi/lib/../lib]
[29][-L/lib/../lib]
[30][-L/usr/lib/../lib]
[31][-L/usr/lib/gcc-cross/arm-linux-gnueabi/5/../../../../arm-linux-gnueabi/lib]
[32][/tmp/ccmlFvlr.o]
[33][-lgcc]
[34][--as-needed]
[35][-lgcc_s]
[36][--no-as-needed]
[37][-lc]
[38][-lgcc]
[39][--as-needed]
[40][-lgcc_s]
[41][--no-as-needed]
[42][/usr/lib/gcc-cross/arm-linux-gnueabi/5/crtend.o]
[43][crtn.o]

自分自身をリンクしたい場合、これは常にすべてを指さなければならない場合です. デフォルトのリンカ スクリプトは例外です。これは、C ライブラリを置き換えたいため、これも絶対に置き換える必要があります。

これまたは、GNU Cライブラリ情報/パスではなく、新しいライブラリ情報をリンカーに渡すための知識/メカニズムをgccに組み込みます...

別の例、x86 ネイティブ:

gcc -O2 so.c -o so
[1][-plugin]
[2][/usr/lib/gcc/x86_64-linux-gnu/5/liblto_plugin.so]
[3][-plugin-opt=/usr/lib/gcc/x86_64-linux-gnu/5/lto-wrapper]
[4][-plugin-opt=-fresolution=/tmp/ccmhqpU9.res]
[5][-plugin-opt=-pass-through=-lgcc]
[6][-plugin-opt=-pass-through=-lgcc_s]
[7][-plugin-opt=-pass-through=-lc]
[8][-plugin-opt=-pass-through=-lgcc]
[9][-plugin-opt=-pass-through=-lgcc_s]
[10][--sysroot=/]
[11][--build-id]
[12][--eh-frame-hdr]
[13][-m]
[14][elf_x86_64]
[15][--hash-style=gnu]
[16][--as-needed]
[17][-dynamic-linker]
[18][/lib64/ld-linux-x86-64.so.2]
[19][-z]
[20][relro]
[21][-o]
[22][so]
[23][/usr/lib/gcc/x86_64-linux-gnu/5/../../../x86_64-linux-gnu/crt1.o]
[24][/usr/lib/gcc/x86_64-linux-gnu/5/../../../x86_64-linux-gnu/crti.o]
[25][/usr/lib/gcc/x86_64-linux-gnu/5/crtbegin.o]
[26][-L/usr/lib/gcc/x86_64-linux-gnu/5]
[27][-L/usr/lib/gcc/x86_64-linux-gnu/5/../../../x86_64-linux-gnu]
[28][-L/usr/lib/gcc/x86_64-linux-gnu/5/../../../../lib]
[29][-L/lib/x86_64-linux-gnu]
[30][-L/lib/../lib]
[31][-L/usr/lib/x86_64-linux-gnu]
[32][-L/usr/lib/../lib]
[33][-L/usr/lib/gcc/x86_64-linux-gnu/5/../../..]
[34][/tmp/ccg1E03e.o]
[35][-lgcc]
[36][--as-needed]
[37][-lgcc_s]
[38][--no-as-needed]
[39][-lc]
[40][-lgcc]
[41][--as-needed]
[42][-lgcc_s]
[43][--no-as-needed]
[44][/usr/lib/gcc/x86_64-linux-gnu/5/crtend.o]
[45][/usr/lib/gcc/x86_64-linux-gnu/5/../../../x86_64-linux-gnu/crtn.o]

同じように、ld は、C ライブラリ、そのブートストラップ、gcc ライブラリなど、どこにあるかを知りません。これはおそらく設計により、すべて gcc に組み込まれています。(もちろん、gcc は複数のプログラムを呼び出して、パーサーと実際のコンパイラー以外のプログラムをコンパイルするラッパーであり、次にアセンブラー、リンカ、そしておそらく他のプログラムもアセンブルするだけでなく、リンクするだけです)。

多くの人はベアメタルに慣れているため、C ライブラリやその他のものを使用しないため、リンカ スクリプトはいくぶん単純です (確かに、ld file.o -o file.elf ほど単純ではありません。そのターゲット)。ライブラリを追加したい場合は、gcc にライブラリを教えるか、必要なすべてをリンカに渡します。

-lgcc は単に、-L が指定されたパスなしで、-L が指定されたパスで libgcc を探すことを意味します。

binutils はユーティリティのセットです。gcc はそれよりも高いレベルであり、binutils (または代替) に依存しています。gcc は binutils なしでは生きられません。bintuils は確かに gcc なしでは生きられません。これと Unix の方法では、明らかに gcc は binutils の外側のすべてを binutils に渡し、gcc のバイナリ ユーティリティになります。

于 2020-06-02T19:43:48.123 に答える
0

@old_timer ありがとうございます。ld の代わりに gcc を起動して実行可能ファイルを生成すると、未解決の外部はありません。

arm-linux-musleabihf-gcc -c hello.c -o hello.o
arm-linux-musleabihf-gcc -o hello.elf  hello.o
于 2020-06-02T20:24:32.863 に答える