7

C プログラムをコンパイルすると、プリプロセッサ、コンパイラ、アセンブラ、リンカの順に処理されます。の主なタスクの 1 つは、linkerライブラリ関数のコードをプログラムで使用できるようにすることです。リンカーは、静的または動的の 2 つの方法でそれらをリンクできます。

stdio.h宣言のみを含み、定義は存在しません。stdio.h戻り値の型と関数の名前についてコンパイラを言うためにプログラムに含めるだけです では、以下のサンプルプログラムでeg(printf(),scanf(),getc(),putc()...).. どのようprintf()scanf()リンクされていますか?

  • 動的にリンクしている場合、どの「DLL」がリンクを担当していますか??
  • 総「C」ライブラリはプログラムに動的にリンクされていますか??
    #include "stdio.h"
 
    int main()
    {
      int n;
 
       printf("Enter an integer\n");
       scanf("%d", &n);
 
       if (n%2 == 0)
           printf("Even\n");
       else
           printf("Odd\n");
 
       return 0;
    } 
4

4 に答える 4

16

あなたが尋ねようとしている質問は次のようなものだと思いprintfますscanf。しかし、コンパイラや IDE にプログラムを C ランタイム ライブラリにリンクするように指示しなくても、それらを使用できます。なぜ私はそれをする必要がないのですか?」</p>

その質問に対する答えは次のとおりです。ライブラリ関数を明示的に使用しない場合でも、起動コードが必要であり、コンパイラは内部でmemcpy、浮動小数点エミュレーション関数などの呼び出しを発行する可能性があります。したがって、便宜上、コンパイラーは、ユーザーがそうしないように指示しない限り、プログラムを C ランタイム・ライブラリーに自動的にリンクします」</p>

C ランタイム ライブラリにリンクしないようにコンパイラに指示する方法については、コンパイラのドキュメントを参照する必要があります。GCC は-nostdlibコマンドライン オプションを使用します。以下では、それを機能させるためにジャンプしなければならないフープを示します...

$ cat > test.c
#include <stdio.h>
int main(void) { puts("hello world"); return 0; }
^D
$ gcc -nostdlib test.c && { ./a.out; echo $?; } 
/usr/bin/ld: warning: cannot find entry symbol _start
/tmp/cc8svIx5.o: In function ‘main’:
test.c:(.text+0xa): undefined reference to ‘puts’
collect2: error: ld returned 1 exit status

putsは明らかに C ライブラリにありますが、この謎の「エントリ シンボル_start」も同様です。Cライブラリをオフにすると、それも自分で提供する必要があります...

$ cat > test.c
int _start(void) { return 0; }
^D
$ gcc -nostdlib test.c && { ./a.out; echo $?; }
Segmentation fault
139

現在はリンクしていますが、_start戻る場所がないため、セグメンテーション違反が発生します! オペレーティング システムは、それが を呼び出すことを期待しています_exit。よし、そうしよう...

$ cat > test.c
extern void _exit(int);
void _start(void) { _exit(0); }
^D
$ gcc -nostdlib test.c && { ./a.out; echo $?; }
/tmp/ccuDrMQ9.o: In function `_start':
test.c:(.text+0xa): undefined reference to `_exit'
collect2: error: ld returned 1 exit status

...ナッツ、_exitCランタイムライブラリの関数でもあります! 生のシステムコール時間...

$ cat > test.c
#include <unistd.h>
#include <sys/syscall.h>
void _start(void) { syscall(SYS_exit, 0); }
^D
$ gcc -nostdlib test.c && { ./a.out; echo $?; }
/tmp/cchtZnbP.o: In function `_start':
test.c:(.text+0x14): undefined reference to `syscall'
collect2: error: ld returned 1 exit status

...いや、C ランタイムの関数でsyscallあります。アセンブリを使用する必要があると思います。

$ cat > test.S
#include <sys/syscall.h>
.text
.globl _start
.type _start, @function
_start:
        movq $SYS_exit, %rax
        movq $0, %rdi
        syscall
$ gcc -nostdlib test.S && { ./a.out; echo $?; }
0

そして、それは最終的に機能します。私のコンピューターで。システムコールのアセンブリレベルの規則が異なる別のオペレーティングシステムでは機能しません。

-nostdlibシステム コールを実行するためだけにアセンブリ言語を使用する必要があるとしたら、いったい何の役に立つのだろうかと疑問に思うかもしれません。これは、ブートローダー、カーネル、および C ランタイム自体 (の一部) など、完全に自己完結型の低レベル システム プログラムをコンパイルするときに使用することを目的としています

ゼロからやり直す必要がある場合、syscall ラッパー、言語に依存しないプロセスの起動コード、および任意の言語のコンパイラが使用する可能性がある関数だけを使用して、低レベルの言語に依存しないランタイムを分離することは理にかなっています。 「ボンネットの下」(、、、そのようなもの)を呼び出す必要があります。そのアイデアの問題点は、急速にミッション クリープが発生すること です。ジェネリック スレッド プリミティブ? (どれが、どのセマンティクスで?) 動的リンカ? の実装で、上記のもののどれが必要ですか? Windowsはこの概念として始まり、Windows 10 ではディスク上で 1.8MB であり、 +よりも(わずかに)大きいmemcpy_Unwind_RaiseException__muldi3errnomallocntdll.dlllibc.sold.so私のLinuxパーティションで。また、Microsoft であっても、のみを使用するプログラムを作成することはまれであり、困難ntdll.dllです (私が確信している唯一の例は でありcsrss.exe、これはカーネル コンポーネントである可能性もあります)。

于 2015-10-29T19:19:15.623 に答える
5

通常、標準 C ライブラリは動的にリンクされます。これは主に、プログラムが静的にリンクされると、プログラム内のコードが永久に固定されるためです。誰かがprintfまたはのバグを見つけて修正した場合、修正scanfされたコードを取得するために、すべてのプログラムを再度リンクする必要があります。

動的リンクの場合、実行可能ファイル (リンク後に作成される) には、printfまたはのコードのコピーは含まれませんscanf。の新しい修正済みバージョンprintfが利用可能な場合は、実行時に取得されます。

于 2015-10-29T19:50:28.463 に答える
4
-static-libstdc++

g++ プログラムを使用して C++ プログラムをリンクすると、通常は libstdc++ に対して自動的にリンクされます。libstdc++ が共有ライブラリとして利用可能で、-static オプションが使用されていない場合、これは libstdc++ の共有バージョンに対してリンクされます。それは通常問題ありません。ただし、完全に静的なリンクに至ることなく、プログラムで使用される libstdc++ のバージョンをフリーズすると便利な場合があります。-static-libstdc++ オプションは、g++ ドライバーに libstdc++ を静的にリンクするように指示しますが、必ずしも他のライブラリーを静的にリンクする必要はありません。

詳細については、このスレッドを確認してください。 標準ライブラリを C++ プログラムに静的にリンクするにはどうすればよいですか?

于 2015-10-29T19:05:30.813 に答える
-3

それらは静的にリンクされているため、プログラムを実行する前にコンパイルエラーがあるかどうかをプログラムが判断できます。

于 2015-10-29T18:59:26.580 に答える