script - `bash:./a.out: No existe ningún archivo o directorio` en ejecutar ejecutable producido por` ld`
script linux ejemplos (3)
ld -lc ao
Hay varias cosas mal con esta línea de comando:
En general, el código de nivel de usuario nunca debe usar
ld
directamente, y siempre usar el frente de compilación apropiado (gcc
aquí) para realizar el enlace.Como ha descubierto, la línea de comando de enlace que construye
gcc
es bastante complicada, y la línea de comando que ha aceptado en la respuesta de Joan Esteban es incorrecta.Si desea ver el comando de enlace real , examine la salida de
gcc -v ao
.También tenga en cuenta que el comando de enlace cambia significativamente cuando cambia el comando
gcc
solo ligeramente (por ejemplo, algunos sistemas operativos requierencrt1.o
diferente dependiendo de si está vinculando ejecutable de subprocesos múltiples o no), y la línea de comandos siempre es específica del sistema operativo (que es uno más razón para nunca usarld
directamente).Las bibliotecas deben seguir los archivos de objetos en la línea de comandos. Entonces
ld -lc ao
nunca es correcto, y siempre debe ser (una variante de)ld ao -lc
. Explicación
Aquí hay un código Hello World en C:
// a.c
#include <stdio.h>
int main() {
printf("Hello world/n");
return 0;
}
Lo compilo como gcc ac
, que produce a.out
como se esperaba y ./a.out
imprime Hello world
... como se esperaba.
Ahora si hago la compilación y el enlace por separado: gcc -c ac; ld -lc ao
gcc -c ac; ld -lc ao
, ejecuta el a.out
producido como ./a.out
recibo el mensaje:
bash: ./a.out: No such file or directory
Busqué ese error en Google y parece que sucede cuando el ejecutable producido es un ELF de 32 bits y la arquitectura de la máquina es de 64 bits.
Estoy ejecutando un equipo de 64 bits y ejecutando el file a.out
da:
a.out: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), not stripped
¿Por qué pasó esto?
EDITAR:
Salida de uname -m
$ uname -m
x86_64
Salida de 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
produce a.out
que se ejecuta correctamente.
Las otras respuestas solo abordan cómo evitar esto, no la cuestión real de lo que sucedió .
El gcc -c ac; ld -lc ao
gcc -c ac; ld -lc ao
comandos gcc -c ac; ld -lc ao
usted dio produjeron una advertencia bastante obvia:
ld: warning: cannot find entry symbol _start; defaulting to 0000000000400260
Entonces, incluso si este archivo pudiera ejecutarse, probablemente se bloquee de inmediato. Consulte la respuesta de @ EmployedRussian para obtener una explicación de lo que debería haber hecho.
La pregunta de por qué ni siquiera se puede ejecutar sigue siendo interesante:
$ strace ./a.out
execve("./a.out", ["./a.out"], [/* 72 vars */]) = -1 ENOENT (No such file or directory)
execve(2)
devuelve ENOENT porque no puede encontrar el intérprete (que encontré en el file
etc.). Obtendrá el mismo error al intentar ejecutar un archivo que comenzó con
#!/usr/non-existant-path/bin/bash
Como descubrió, el motivo habitual para este mensaje de error es cuando se ejecuta un binario ELF en un sistema sin el enlazador dinámico correcto y las bibliotecas dinámicas instaladas (por ejemplo, un sistema de 64 bits sin soporte de 32 bits instalado). En su caso, es porque utilizó un comando de enlace incorrecto e hizo un ejecutable dinámico con una ruta de intérprete incorrecta.
Estoy en Ubuntu 15.10, donde el file
GNU versión 5.22 informa:
a.out: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib/ld64.so.1, not stripped
No hay /lib/ld64.so.1
en mi sistema. ldd
salida de ldd
es confusa, porque ldd
usa su intérprete de ELF predeterminado, no el especificado por el binario.
$ 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)
Por lo tanto, se supone que el intérprete de tiempo de ejecución en el binario resuelto a la que ldd
utilizó, supongo.
Su salida de ldd
es probablemente también de una versión anterior, ya que solo muestra /lib64/ld-linux-x86-64.so.2
para esa línea. No tomar una mala estimación es probablemente un mejor comportamiento, para un caso raro como este, pero no ayuda a ver que su binario tiene una extraña ruta de interpretación.
readelf -l a.out
decodificará los encabezados ELF para usted, incluida la ruta del intérprete. (Gracias al comentario de @ EmployedRussian para señalar esto).
Usa eso:
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