17

cプログラムがどのように機能するか、およびプログラムがlibcを使用できるようにするために必要な最小レベルのコンテンツをより正確に学習するための演習として、私は主にgasとldを使用してx86アセンブリでプログラミングを試みることにしました。

楽しい小さな挑戦として、私はさまざまな自作のダイナミックライブラリにリンクされたいくつかのプログラムを正常に組み立ててリンクしましたが、gccを直接使用せずにlibc関数呼び出しを使用するようにプログラムを最初からコーディングすることはできませんでした。

個々のcライブラリ関数の呼び出し規約を理解し、objdumpとreadelfを使用してgccからコンパイルされたプログラムを徹底的に検査しましたが、ガスアセンブリファイルに含める情報と呼び出すパラメーターについてはどこにも到達していません。 ldでlibcに正常にリンクします。誰かがこれについて何か洞察を持っていますか?

x86マシンでLinuxを実行しています。

4

4 に答える 4

23

ダイナミックリンクでlibcを正常に使用するには、少なくとも3つのことを行う必要があります。

  1. リンク。これには、ELFバイナリのエントリポイントとなるが/usr/lib/crt1.o含まれます。_start
  2. リンク/usr/lib/crti.o(libcの前)と/usr/lib/crtn.o(後)。初期化と最終化のコードを提供します。
  3. バイナリがダイナミックリンカを使用することをリンカに伝えます/lib/ld-linux.so

例えば:

$ cat hello.s
 .text
 .globl main
main:
 push %ebp
 mov %esp, %ebp
 pushl $hw_str
 call puts
 add $4, %esp
 xor %eax, %eax
 leave
 ret

 .data
hw_str:
 .asciz "Hello world!"

$ as -o hello.o hello.s
$ ld -o hello -dynamic-linker /lib/ld-linux.so.2 /usr/lib/crt1.o /usr/lib/crti.o -lc hello.o /usr/lib/crtn.o
$ ./hello
Hello world!
$
于 2010-08-26T23:56:02.367 に答える
5

mainアセンブリで定義する場合

マシューの答えは、最小要件を伝えるのに最適です。

システム内でこれらのパスを見つける方法を紹介します。走る:

gcc -v hello_world.c |& grep 'collect2' | tr ' ' '\n'

次に、マシューが言及したファイルをピックアップします。

gcc -vGCCが使用する正確なリンカーコマンドを提供します。

collect2は、GCCがリンカーフロントエンドとして使用する内部実行可能ファイルであり、と同様のインターフェイスを備えていますld

Ubuntu 14.04 64ビット(GCC 4.8)では、次のようになりました。

ld -dynamic-linker /lib64/ld-linux-x86-64.so.2 \
  /usr/lib/x86_64-linux-gnu/crt1.o \
  /usr/lib/x86_64-linux-gnu/crti.o \
  -lc hello_world.o \
  /usr/lib/x86_64-linux-gnu/crtn.o

とが必要な場合もあり-lgccます-lgcc_s。参照:本当にlibgccが必要ですか?

_startアセンブリで定義する場合

を定義した場合_start、glibcのhelloworldは次のように機能します。

ld -dynamic-linker /lib64/ld-linux-x86-64.so.2 -lc hello_world.o

これが堅牢であるかどうか、つまりcrt初期化を安全にスキップしてglibc関数を呼び出すことができるかどうかはわかりません。参照:アセンブリプログラムがcrt1.o crti.oおよびcrtn.oとリンクされている場合にのみ機能するのはなぜですか?

于 2015-06-08T09:40:18.453 に答える
1

私はこのようなものがうまくいくはずだと思います:

  1. 簡単なCプログラムを作成する
  2. gcc -S file.c
  3. ファイルを編集します。
  4. ガスファイル.s
  5. ld file.o -lc crt1.o -o myprog
于 2010-08-26T19:26:22.327 に答える
1

_start(上記のコメントのいくつかで述べたように)代わりに使用する場合はmain、プログラムの終了方法も変更する必要があります。そうしないと、セグメンテーション違反が発生します。

            .text
            .globl    _start
_start:     
            mov       $hw_str, %rdi
            call      puts
            movl      $0,%ebx   # first argument: exit code.
            movl      $1,%eax   # system call number: sys_exit.
            int       $0x80     # call kernel.

            .data
hw_str:     .asciz "Hello world!"

Kubuntu 18.04.2(gcc(Ubuntu 7.3.0-27ubuntu1〜18.04)7.3.0):

$ as -o hello.o hello.s
$ ld -dynamic-linker /lib64/ld-linux-x86-64.so.2 -o hello hello.o -lc

また、システム上でダイナミックリンカーが何であるかを確認する簡単な方法の1つは、小さなCプログラムをコンパイルしてからldd、バイナリで実行することです。

test.c:

int main() { return 0; }

実行可能ファイルに対してlddをコンパイルして実行します。

$ gcc -o test test.c
$ ldd test
    linux-vdso.so.1 (0x00007ffd0a182000)
    libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007ff24d8e6000)
    /lib64/ld-linux-x86-64.so.2 (0x00007ff24ded9000)
于 2019-02-26T00:36:52.693 に答える