Utilisez le libellé _start
au lieu de main
pour le point d'entrée ELF. main
implique que c'est comme le C main
fonction, mais ce n'est même pas une fonction (par exemple, vous ne pouvez pas ret
).
Vous ne dites pas, mais d'après les messages d'erreur et le code, je suppose que vous construisez votre code 32 bits avec nasm -felf32 hello32.asm && ld -melf_i386 -o hello32 hello32.o
(Si vous construisez réellement du code 64 bits, vous avez de la chance que cela fonctionne, mais il se cassera dès que vous ferez quoi que ce soit avec esp
au lieu de rsp
.)
Le message d'erreur provient de ld
, pas de nasm
. C'est dit directement dans le message. Le commentaire de Tim est correct :ld
cherche un _start
symbole dans les fichiers qu'il relie, mais définit le point d'entrée au début du segment de texte s'il n'en trouve pas.
Peu importe les autres symboles globaux/externes que vous définissez. main
n'a aucune pertinence ici et pourrait pointer n'importe où. C'est seulement utile pour une sortie de démontage et des trucs comme ça. Votre code fonctionnerait exactement de la même manière si vous retiriez le global main
/ main:
lignes, ou les a remplacés par un autre nom.
Étiqueter cela comme main
n'est pas judicieux car le point d'entrée ELF n'est pas une fonction . Ce n'est pas main()
, et ne reçoit pas argc
et argv
arguments, et ne peut pas ret
car ESP pointe vers argc
au lieu d'une adresse de retour.
Utilisez uniquement main
si vous liez avec le code de démarrage CRT de gcc / glibc qui recherche un main
symbole et l'appelle après avoir initialisé libc. (Donc, les fonctions comme printf fonctionnent. Les crochets de l'éditeur de liens techniquement dynamiques permettent à libc de s'initialiser avant votre _start
si vous l'avez lié, mais ne le faites généralement pas à moins que vous ne compreniez exactement ce que vous faites). En relation :Assemblage de binaires 32 bits sur un système 64 bits (chaîne d'outils GNU)
par exemple. gcc -m32 -no-pie -o hello main.o
si vous définissez un main:
au lieu de gcc -m32 -static -nostdlib -o hello start.o
(ce qui équivaut à votre simple ld
).
(Ces dernières années, les distributions Linux ont configuré GCC avec -pie
par défaut, qui veut un code indépendant de la position. Mais c'est vraiment gênant en mode 32 bits sans adressage relatif au RIP (regardez la sortie asm de GCC par exemple), et signifie ld
ne convertira pas call printf
en call [email protected]
pour toi. Donc, pour la plupart des asm écrits à la main après la plupart des tutoriels, vous voulez des exécutables non-PIE traditionnels afin qu'aucun déplacement de texte ne soit nécessaire.)
Je suggérerais que vous liiez vos fichiers objet (quelle que soit leur production) avec gcc
, pas ld
.
gcc
appellera le ld
avec les options appropriées, car il en sait plus sur le code source et créera tout ce qui est nécessaire pour les hypothèses que ld
fait.