Použijte štítek _start
místo main
pro vstupní bod ELF. main
znamená, že je to jako C main
funkce, ale to ani není funkce (např. nemůžete ret
).
Neříkáte, ale z chybových zpráv a kódu předpokládám, že vytváříte svůj 32bitový kód s nasm -felf32 hello32.asm && ld -melf_i386 -o hello32 hello32.o
(Pokud skutečně vytváříte 64bitový kód, máte štěstí, že to náhodou funguje, ale porouchá se, jakmile s esp
něco uděláte místo rsp
.)
Chybová zpráva pochází z ld
, nikoli z nasm
. Píše to přímo ve zprávě. Timův komentář je správný:ld
hledá _start
symbol v souborech, na které odkazuje, ale nastaví vstupní bod na začátek textového segmentu, pokud žádný nenajde.
Nezáleží na tom, jaké další globální/externí symboly definujete. main
zde nemá vůbec žádný význam a může ukazovat kamkoli chcete. Je to užitečné pouze pro výstup na demontáž a podobné věci. Váš kód by fungoval úplně stejně, kdybyste vyjmuli global main
/ main:
řádky nebo je změnil na jakýkoli jiný název.
Označení jako main
je nerozumné, protože vstupní bod ELF není funkcí . Není main()
a neobdrží argc
a argv
argumenty a nemůže ret
protože ESP ukazuje na argc
místo zpáteční adresy.
Používejte pouze main
pokud propojíte spouštěcí kód CRT gcc / glibc, který hledá main
symbol a volá jej po inicializaci knihovny libc. (Funkce jako printf tedy fungují. Technicky dynamické háky linkeru umožňují, aby se knihovna libc inicializovala před vaším _start
pokud jste to propojili, ale obecně to nedělejte, pokud přesně nerozumíte tomu, co děláte). Související:Sestavení 32bitových binárních souborů na 64bitovém systému (GNU toolchain)
např. gcc -m32 -no-pie -o hello main.o
pokud definujete main:
místo gcc -m32 -static -nostdlib -o hello start.o
(což je ekvivalentní vašemu holému ld
).
(V posledních několika letech distribuce Linuxu konfigurovaly GCC s -pie
jako výchozí, který vyžaduje kód nezávislý na pozici. Ale to je opravdu nepohodlné v 32bitovém režimu bez adresování relativního RIP (podívejte se například na výstup GCC asm) a znamená to ld
nepřevede call printf
do call [email protected]
pro tebe. Takže pro většinu ručně psaných asm po většině tutoriálů chcete tradiční spustitelné soubory bez PIE, takže není potřeba žádné přemístění textu.)
Navrhoval bych, abyste propojili své objektové soubory (bez ohledu na to, jak jsou vytvořeny) s gcc
, nikoli ld
.
gcc
zavolá ld
s příslušnými možnostmi, protože ví více o zdrojovém kódu a vytvoří vše potřebné pro předpoklady, že ld
dělá.