簡體   English   中英

`bash: ./a.out: 在運行由 `ld` 生成的可執行文件時沒有這樣的文件或目錄

[英]`bash: ./a.out: No such file or directory` on running executable produced by `ld`

這是一個 C 語言的 Hello World 代碼:

// a.c
#include <stdio.h>

int main() {
    printf("Hello world\n");
    return 0;
}

我將它編譯為gcc ac ,它按預期生成a.out並且./a.out打印Hello world ... 按預期。

現在,如果我分別進行編譯和鏈接: gcc -c ac; ld -lc ao gcc -c ac; ld -lc ao ,它運行生成為./a.outa.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 ac生成a.out可以正確運行。

ld -lc ao

這個命令行有幾個問題:

  1. 通常,用戶級代碼永遠不應該直接使用ld ,而始終使用適當的編譯器前端(此處為gcc )來執行鏈接。

    如您gccgcc構建的鏈接命令行非常復雜,您在 Joan Esteban 的回答中接受的命令行是錯誤的。

    如果您想查看實際的鏈接命令,請檢查gcc -v ao輸出。

    另請注意,當您僅稍微更改gcc命令時,鏈接命令會發生顯着變化(例如,某些操作系統需要不同的crt1.o具體取決於您是否鏈接多線程可執行文件),並且命令行始終是特定於操作系統的(這是一個永遠不要直接使用ld更多理由)。

  2. 庫應該在命令行上遵循目標文件。 所以ld -lc ao永遠不會正確,應該總是(變體) ld ao -lc 解釋

使用gcc foo.o鏈接動態可執行文件(為 CRT 和 libc 使用正確的路徑,以及動態鏈接器/ELF 解釋器ld-linux-x86-64.so.2 )。
或者gcc -nostartfiles foo.o用於 libc 而不是 CRT _start ,如果你有一個手寫的_start

(對於沒有 libc 或 CRT 的靜態可執行文件,您可以直接使用ldgcc -nostdlib -static 。)

gcc -v foo.o將顯示您系統上使用的實際 GCC 路徑。


其他答案只解決如何避免這個問題1 ,而不是發生了什么實際問題

gcc -c ac; ld -lc ao 您給出的gcc -c ac; ld -lc ao命令會產生一個非常明顯的警告:

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

如您所見,此錯誤消息的常見原因是在未安裝正確動態鏈接器和動態庫的系統上運行 ELF 二進制文件(例如,未安裝 32 位支持的 64 位系統)。 在您的情況下,這是因為您使用了錯誤的鏈接命令並使用錯誤的解釋器路徑制作了動態可執行文件。


我在 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 的評論指出這一點。)

使用那個:

  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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM