Can't run executable linked with libc
The immediate problem is that ld
uses /lib/ld64.so.1
as interpreter by default and you may be missing that (it can be a symlink to /lib64/ld-linux-x86-64.so.2
or whatever is appropriate):
$ readelf -l a.out | grep interpreter
[Requesting program interpreter: /lib/ld64.so.1]
$ ls -l /lib/ld64.so.1
ls: cannot access /lib/ld64.so.1: No such file or directory
You can work around this by setting the interpreter explicitly by passing -dynamic-linker /lib64/ld-linux-x86-64.so.2
option to your ld
invocation:
$ ld -s -dynamic-linker /lib64/ld-linux-x86-64.so.2 test.o -lc
$ readelf -l a.out | grep interpreter
[Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]
$ ./a.out
$
The simple rule of thumb however is to use gcc
for linking if you need libc, it will do everything right for you. Also make sure you use main
as entry point so that normal libc startup code has a chance of initializing. Similarly, just return from your main
at the end and do not use exit
syscall directly (you may use the exit
function from libc if you really want). In general, using syscalls is not recommended.
`bash: ./a.out: No such file or directory` on running executable produced by `ld`
Link dynamic executables with gcc foo.o
(to use the right paths for CRT and libc, and the dynamic linker / ELF interpreter ld-linux-x86-64.so.2
).
Or gcc -nostartfiles foo.o
for libc but not CRT _start
, if you have a hand-written _start
(For static executables without libc or CRT, you can use ld
directly or gcc -nostdlib -static
.)
gcc -v foo.o
will show you the actual paths GCC used on your system.
The other answers only address how to avoid this1, not the actual question of what happened.
The gcc -c a.c; ld -lc a.o
commands you gave produce a pretty obvious warning:
ld: warning: cannot find entry symbol _start; defaulting to 0000000000400260
So even if this file could be executed, it will probably crash right away. See @EmployedRussian's answer for an explanation of what you should have done.
The question of why it can't even be executed is still interesting:
$ strace ./a.out
execve("./a.out", ["./a.out"], [/* 72 vars */]) = -1 ENOENT (No such file or directory)
execve(2)
returns ENOENT because it can't find the interpreter (which I figured out from file
and so on, see below). You'd get the same error from trying to run a file that started with
#!/usr/non-existant-path/bin/bash
As you discovered, the usual reason for this error message is when running an ELF binary on a system without the right dynamic linker and dynamic libraries installed (e.g. a 64bit system without 32bit support installed). In your case, it's because you used a bad link command and made a dynamic executable with a bad interpreter path.
I'm on Ubuntu 15.10, where GNU file
version 5.22 reports:
a.out: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib/ld64.so.1, not stripped
There is no /lib/ld64.so.1
on my system. ldd
output is confusing, because ldd
uses its default ELF interpreter, not the one specified by the binary.
$ 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)
So it assumes that the runtime interpreter in the binary resolved to the one ldd
used itself, I guess.
Your ldd
output is probably from an old version too, since it just shows /lib64/ld-linux-x86-64.so.2
for that line. Not taking a bad guess is probably better behaviour, for a weird case like this, but doesn't help you see that your binary has a weird interpreter path.
readelf -l a.out
will decode the ELF headers for you, including the interpreter path. (Thanks to @EmployedRussian's comment for pointing this out.)
Link explicitly to libc (-lc)
Should I explicitly link my program or library against libc, when using libc symbols?
No. From POSIX cc:
The standard C-language library is automatically available to the C-language program.
what if I don't use any libc symbols at all?
Then still do not link explicitly against libc and let compiler link with it automatically.
Is there any situation in which doing so or not doing it can be problematic?
When you are writing a kernel, bare-metal software, or other low-level program specific to some environment you are working with, and you do not want to link the standard library. Also, when you do not accept the license of the library.
linking mess with libc
Perhaps someone will find it useful if I share what the problem was:
The library was not compiled for the same OS version as the main program, so it was expecting a different libc than what it found when running.
Linking a C program directly with ld fails with undefined reference to `__libc_csu_fini`
I found another post which contained a clue: -dynamic-linker /lib/ld-linux.so.2
.
Try this:
$ gcc hello.c -S -masm=intel
$ as -o hello.o hello.s
$ ld -o hello -dynamic-linker /lib/ld-linux.so.2 /usr/lib/crt1.o /usr/lib/crti.o hello.o -lc /usr/lib/crtn.o
$ ./hello
hello, world
$
Valid ARM executable doesn't find libraries
Your ld-linux.so.3
appears to be in a nonstandard location (/opt/lib
), and it's possible that your gcc
is specifying a different program interpreter. You can use readelf -l <program>
to check what program interpreter your binary is expecting (under PT_INTERP
, "Requesting program interpreter").
If the binary's program interpreter is wrong for your platform, you can specify it manually by passing -Wl,--dynamic-linker=/opt/lib/ld-linux.so.3
to gcc
.
Related Topics
Less Gets Keyboard Input from Stderr
How to Print a Single Ascii Char
How to Write a Linux Bash Script That Tells Me Which Computers Are on in My Lan
Differencebetween Ld_Library_Path and -L at Link Time
How to Remove Duplicate Words from a Plain Text File Using Linux Command
Handling Input Confirmations in Linux Shell Scripting
Recursively Kill R Process with Children in Linux
How to Install The Ncursesw Development Libraries
Rsync Over Ssh Preserve Ownership Only for Www-Data Owned Files
Bash 'Swallowing' Sub-Shell Children Process When Executing a Single Command
What Does a Hexadecimal Number, with a Register in Parenthesis Mean in Assembly
Dropping of Connections with Tcp_Tw_Recycle
What Is a Way to Read Man Pages in Vim Without Using Temporary Files
Hadoop: «Error:Java_Home Is Not Set»
Linux Memory Reporting Discrepancy
How to Build and Compile Cross Platform Xamarin Apps on Linux