1. ホーム
  2. c

[解決済み] `bash: ./a.out: ld` が生成した実行ファイルを実行する際に、そのようなファイルやディレクトリはありません`。

2022-02-26 15:49:41

質問

以下はC言語によるHello Worldのコードです。

// 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

ググってみたら、生成された実行ファイルが32bitのELFで、マシンのアーキテクチャが64bitの場合にこのエラーが発生するようです。

私は64ビットマシンで file a.out が与える。

a.out: ELF 64-bit LSB  executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), not stripped

なぜ、このようなことが起こるのでしょうか?

EDIT

の出力 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 foo.o (CRTとlibcに正しいパスを使用し、ダイナミックリンカー/ELFインタープリターに ld-linux-x86-64.so.2 ).
または gcc -nostartfiles foo.o libc の場合ですが、CRT ではありません。 _start があれば、手書きの _start

(libcやCRTのない静的な実行ファイルの場合は ld を直接使用するか gcc -nostdlib -static .)

gcc -v foo.o は、あなたのシステムでGCCが実際に使用したパスを表示します。


他の回答は、これを回避する方法のみを取り上げています 1 ではなく 何が起こったのか、実際の問題 .

は、以下の通りです。 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バイナリを実行したときです。 あなたの場合は、間違ったリンクコマンドを使用し、間違ったインタープリターパスで動的実行ファイルを作成したことが原因です。


私はUbuntu 15.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 の出力は紛らわしいです。 ldd はバイナリで指定されたものではなく、デフォルトのELFインタープリタを使用します。

$ 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 のコメントによる指摘に感謝します)。