`bash: ./a.out: Aucun fichier ou répertoire sur l’exécutable en cours d’exécution produit par` ld`

Voici un code Hello World en C:

// ac #include  int main() { printf("Hello world\n"); return 0; } 

Je le comstack en tant que gcc ac , qui produit a.out comme prévu et ./a.out Hello world … comme prévu.

Maintenant, si je comstack et lie séparément: gcc -c ac; ld -lc ao gcc -c ac; ld -lc ao , il exécute l’ a.out produit sous la forme ./a.out Je reçois le message:

 bash: ./a.out: No such file or directory 

J’ai googlé cette erreur et il semble que cela se produise lorsque l’exécutable produit est un ELF 32 bits et que l’architecture de la machine est 64 bits.

J’exécute une machine 64 bits et le file a.out cours d’exécution file a.out donne:

 a.out: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), not ssortingpped 

Pourquoi cela arrive-t-il?

MODIFIER:

Sortie de uname -m

 $ uname -m x86_64 

Sortie 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 produit a.out qui fonctionne correctement.

Les autres réponses n’abordent que la manière d’éviter cela, pas la question de savoir ce qui s’est passé .

Le gcc -c ac; ld -lc ao gcc -c ac; ld -lc ao commandes gcc -c ac; ld -lc ao vous avez données produisent un avertissement assez évident:

 ld: warning: cannot find entry symbol _start; defaulting to 0000000000400260 

Donc, même si ce fichier pouvait être exécuté, il va probablement se bloquer immédiatement. Voir la réponse de @ EmployedRussian pour une explication de ce que vous auriez dû faire.


La question de savoir pourquoi cela ne peut même pas être exécuté est toujours intéressante:

 $ strace ./a.out execve("./a.out", ["./a.out"], [/* 72 vars */]) = -1 ENOENT (No such file or directory) 

execve(2) renvoie ENOENT car il ne trouve pas l’interpréteur (ce que j’ai découvert à partir d’un file , etc., voir ci-dessous). Vous obtiendrez la même erreur d’essayer d’exécuter un fichier qui a commencé avec

 #!/usr/non-existant-path/bin/bash 

Comme vous l’avez découvert, la raison habituelle de ce message d’erreur est l’exécution d’un fichier binary ELF sur un système sur lequel l’éditeur de liens dynamic et les bibliothèques dynamics ne sont pas installés (par exemple, un système 64 bits sans le support 32 bits installé). Dans votre cas, c’est parce que vous avez utilisé une commande de liaison incorrecte et créé un exécutable dynamic avec un chemin d’interpréteur incorrect.


Je suis sur Ubuntu 15.10, où file version de file GNU 5.22 rapporte:

 a.out: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib/ld64.so.1, not ssortingpped 

Il n’y a pas /lib/ld64.so.1 sur mon système. ldd sortie de ldd est source de confusion, car ldd utilise son interpréteur ELF par défaut, et non celui spécifié par le 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) 

Donc, cela suppose que l’interpréteur d’exécution du binary résolu comme celui que ldd lui-même utilisé, je suppose.

Votre sortie de ldd provient probablement d’une ancienne version également, puisqu’elle affiche simplement /lib64/ld-linux-x86-64.so.2 pour cette ligne. Ne pas prendre une mauvaise hypothèse est probablement un meilleur comportement, pour un cas aussi étrange que celui-ci, mais ne vous aide pas à voir que votre binary a un chemin interpréteur étrange.

 readelf -l a.out 

décodera les en-têtes ELF pour vous, y compris le chemin de l’interprète. (Merci au commentaire de @ EmployedRussian pour l’avoir signalé.)

ld -lc ao

Il y a plusieurs problèmes avec cette ligne de commande:

  1. En général, le code de niveau utilisateur ne doit jamais utiliser directement ld , et toujours utiliser le frontal approprié du compilateur ( gcc ici) pour effectuer le lien.

    Comme vous l’avez découvert, la ligne de commande de lien que gcc construit est assez compliquée et la ligne de commande que vous avez acceptée dans la réponse de Joan Esteban est fausse.

    Si vous voulez voir la commande de lien réelle , examinez la sortie de gcc -v ao .

    Notez également que la commande link change de manière significative lorsque vous ne modifiez que légèrement la commande gcc (par exemple, certains systèmes d’exploitation requièrent un crt1.o différent, selon que vous crt1.o un exécutable multithread ou non), et la ligne de commande est toujours spécifique à votre système d’exploitation (qui plus de raison de ne jamais utiliser ld directement).

  2. Les bibliothèques doivent suivre les fichiers d’objects en ligne de commande. Donc, ld -lc ao n’est jamais correct, et devrait toujours être (une variante de) ld ao -lc . Explication

Utiliser ça:

  ld -o a.out -dynamic-linker /lib/ld-linux.so.2 /usr/lib/crt1.o /usr/lib/crti.o -lc co /usr/lib/crtn.o