运行由 `ld` 生成的可执行文件时出现 `bash: ./a.out: 没有该文件或目录`
- 2024-10-28 08:37:00
- admin 原创
- 54
问题描述:
以下是 C 语言中的 Hello World 代码:
// a.c
#include <stdio.h>
int main() {
printf("Hello world
");
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
我用 Google 搜索了该错误,似乎当生成的可执行文件是 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
可正确运行的代码。
解决方案 1:
ld -lc a.o
此命令行有几个错误:
一般来说,用户级代码永远不应该直接使用
ld
,而应该始终使用适当的编译器前端(gcc
此处)来执行链接。
正如您所发现的,构建的链接命令行gcc
非常复杂,并且您在 Joan Esteban 的回答中接受的命令行是错误的。
如果您想查看实际的链接命令,请检查输出gcc -v a.o
。
gcc
还要注意,当您稍微更改命令时,链接命令会发生显着变化(例如,某些操作系统需要不同,具体取决于您是否链接多线程可执行文件),并且命令行始终是特定于操作系统的(这是永远不要直接使用crt1.o
的另一个原因)。ld
库应该在命令行上跟随目标文件。所以永远不
ld -lc a.o
正确,并且应该始终是(的变体)。解释。ld a.o -lc
解决方案 2:
将动态可执行文件链接到gcc foo.o
(使用正确的 CRT 和 libc 路径,以及动态链接器 / ELF 解释器)ld-linux-x86-64.so.2
。
或者,如果您有手写的gcc -nostartfiles foo.o
`_start`_start
(对于没有 libc 或 CRT 的静态可执行文件,可以ld
直接使用 或gcc -nostdlib -static
。)
gcc -v foo.o
将显示系统上 GCC 的实际路径。
其他答案仅解决如何避免这种情况,而不是实际发生了什么的问题。
您给出的命令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
正如您所发现的,出现此错误消息的常见原因是在未安装正确动态链接器和动态库的系统上运行 ELF 二进制文件(例如未安装 32 位支持的 64 位系统)。对于您来说,这是因为您使用了错误的链接命令并使用错误的解释器路径创建了动态可执行文件。
我在 Ubuntu 15.10 上,其中 GNUfile
版本 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 的评论指出这一点。)
解决方案 3:
使用:
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
- 2024年20款好用的项目管理软件推荐,项目管理提效的20个工具和技巧
- 2024年开源项目管理软件有哪些?推荐5款好用的项目管理工具
- 项目管理软件有哪些?推荐7款超好用的项目管理工具
- 项目管理软件哪个最好用?盘点推荐5款好用的项目管理工具
- 项目管理软件有哪些最好用?推荐6款好用的项目管理工具
- 项目管理软件有哪些,盘点推荐国内外超好用的7款项目管理工具
- 2024项目管理软件排行榜(10类常用的项目管理工具全推荐)
- 项目管理软件排行榜:2024年项目经理必备5款开源项目管理软件汇总
- 2024年常用的项目管理软件有哪些?推荐这10款国内外好用的项目管理工具
- 项目管理必备:盘点2024年13款好用的项目管理软件