これがCのHelloWorldコードです。
// a.c
#include <stdio.h>
int main() {
printf("Hello world\n");
return 0;
}
私はそれをgcc a.c
としてコンパイルします。これにより、予想どおりa.out
が生成され、予想どおり./a.out
がHello world
...を出力します。
コンパイルとリンクを別々に行う場合:gcc -c a.c; ld -lc a.o
は、a.out
として生成された./a.out
を実行します。メッセージが表示されます。
bash: ./a.out: No such file or directory
そのエラーをグーグルで検索したところ、生成された実行可能ファイルが32ビットELFで、マシンアーキテクチャが64ビットの場合に発生するようです。
私は64ビットマシンを実行していて、file a.out
を実行すると次のようになります。
a.out: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), not stripped
なぜこれが起こるのですか?
編集:
uname -m
の出力
$ uname -m
x86_64
ldd a.out
の出力
$ ldd a.out
linux-vdso.so.1 => (0x00007ffeeedfb000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fa13a7b8000)
/lib64/ld-linux-x86-64.so.2 (0x00007fa13abab000)
gcc a.c
は、正しく実行されるa.out
を生成します。
他の回答は、これを回避する方法のみを扱っており、何が起こったのかについての実際の質問ではありません。
指定した_gcc -c a.c; ld -lc a.o
_コマンドは、非常に明白な警告を生成します。
_ld: warning: cannot find entry symbol _start; defaulting to 0000000000400260
_
したがって、このファイルを実行できたとしても、おそらくすぐにクラッシュします。 @ EmployedRussianの回答を参照何をすべきかを説明します。
_$ strace ./a.out
execve("./a.out", ["./a.out"], [/* 72 vars */]) = -1 ENOENT (No such file or directory)
_
execve(2)
は、インタプリタが見つからないためENOENTを返します(これはfile
などからわかりました。以下を参照してください)。で始まるファイルを実行しようとすると同じエラーが発生します
_#!/usr/non-existant-path/bin/bash
_
ご存知のとおり、このエラーメッセージの通常の理由は、適切なダイナミックリンカーとダイナミックライブラリがインストールされていないシステム(32ビットサポートがインストールされていない64ビットシステムなど)でELFバイナリを実行している場合です。あなたの場合、それはあなたが悪いリンクコマンドを使用し、悪いインタプリタパスで動的実行可能ファイルを作成したためです。
私はUbuntu15.10を使用していますが、GNU file
バージョン5.22のレポート:
_a.out: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib/ld64.so.1, not stripped
_
私のシステムには_/lib/ld64.so.1
_がありません。 ldd
は、バイナリで指定されたものではなく、デフォルトのELFインタープリターを使用するため、ldd
の出力は混乱を招きます。
_$ ldd a.out
linux-vdso.so.1 => (0x00007ffc18d2b000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f0e0a79f000)
/lib/ld64.so.1 => /lib64/ld-linux-x86-64.so.2 (0x0000559dbc9d2000)
_
したがって、ldd
が使用したものに解決されたバイナリのランタイムインタプリタがそれ自体を使用したと想定しています。
ldd
の出力は、その行の_/lib64/ld-linux-x86-64.so.2
_を示しているだけなので、おそらく古いバージョンのものでもあります。このような奇妙なケースでは、悪い推測をしない方がおそらく良い動作ですが、バイナリに奇妙なインタプリタパスがあることを確認するのに役立ちません。
_readelf -l a.out
_
インタプリタパスを含むELFヘッダーをデコードします。 (これを指摘してくれた@EmployedRussianのコメントに感謝します。)
ld -lc a.o
このコマンドラインにはいくつかの問題があります。
一般に、ユーザーレベルのコードは決してld
を直接使用するべきではなく、常に適切なコンパイラフロントエンド(ここではgcc
)を使用してリンクを実行します。
ご存知のように、gcc
が構築するリンクコマンドラインは非常に複雑であり、JoanEstebanの回答で受け入れたコマンドラインは間違っています。
actualリンクコマンドを確認したい場合は、gcc -v a.o
からの出力を調べてください。
また、gcc
コマンドをわずかに変更するとlinkコマンドが大幅に変更されます(たとえば、一部のOSでは、マルチスレッド実行可能ファイルをリンクするかどうかによって、異なるcrt1.o
が必要になります)。コマンドラインは常にOS固有(これは、決してld
を直接使用しないもう1つの理由です)。
ライブラリは、コマンドラインでオブジェクトファイルに従う必要があります。したがって、ld -lc a.o
は決して正しくなく、常にである必要があります(の変形)ld a.o -lc
。 説明 。
それを使用してください:
ld -o a.out -dynamic-linker /lib/ld-linux.so.2 /usr/lib/crt1.o /usr/lib/crti.o -lc c.o /usr/lib/crtn.o