Can't Run Executable Linked with Libc

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



Leave a reply



Submit