Gunakan label _start
bukannya main
untuk titik masuk ELF. main
menyiratkan itu seperti C main
fungsi, tetapi ini bahkan bukan fungsi (mis. Anda tidak dapat ret
).
Anda tidak mengatakannya, tetapi dari pesan kesalahan dan kode saya menganggap Anda sedang membuat kode 32bit Anda dengan nasm -felf32 hello32.asm && ld -melf_i386 -o hello32 hello32.o
(Jika Anda benar-benar membuat kode 64bit, Anda beruntung kode itu berhasil, tetapi akan rusak segera setelah Anda melakukan apa pun dengan esp
bukannya rsp
.)
Pesan kesalahan berasal dari ld
, bukan dari nasm
. Dikatakan begitu tepat di pesan. Komentar Tim benar:ld
mencari _start
simbol dalam file yang ditautkan, tetapi menyetel titik masuk ke awal segmen teks jika tidak menemukannya.
Tidak masalah simbol global/eksternal apa pun yang Anda tentukan. main
tidak memiliki relevansi sama sekali di sini, dan dapat menunjuk ke mana saja yang Anda inginkan. Ini hanya berguna untuk keluaran pembongkaran dan hal-hal seperti itu. Kode Anda akan bekerja persis sama jika Anda mengeluarkan global main
/ main:
baris, atau mengubahnya menjadi nama lain.
Memberi label sebagai main
tidak bijaksana karena titik masuk ELF bukan fungsi . Ini tidak main()
, dan tidak menerima argc
dan argv
argumen, dan tidak bisa ret
karena ESP menunjuk ke argc
bukannya alamat pengirim.
Hanya gunakan main
jika Anda menautkan dengan kode startup CRT gcc / glibc yang mencari main
simbol dan memanggilnya setelah menginisialisasi libc. (Jadi fungsi seperti printf berfungsi. Kait linker yang dinamis secara teknis biarkan libc menginisialisasi dirinya sendiri sebelum _start
Anda jika Anda menautkannya, tetapi umumnya jangan lakukan itu kecuali Anda benar-benar mengerti apa yang Anda lakukan). Terkait:Merakit binari 32-bit pada sistem 64-bit (rangkaian alat GNU)
misalnya gcc -m32 -no-pie -o hello main.o
jika Anda mendefinisikan main:
bukannya gcc -m32 -static -nostdlib -o hello start.o
(yang setara dengan ld
kosong Anda ).
(Selama beberapa tahun terakhir, distro Linux telah mengonfigurasi GCC dengan -pie
sebagai default, yang menginginkan kode yang tidak bergantung pada posisi. Tapi itu benar-benar merepotkan dalam mode 32-bit tanpa pengalamatan relatif RIP (lihat keluaran asm GCC misalnya), dan berarti ld
tidak akan mengonversi call printf
ke dalam call [email protected]
untukmu. Jadi untuk sebagian besar asm tulisan tangan yang mengikuti sebagian besar tutorial, Anda menginginkan executable non-PIE tradisional sehingga tidak diperlukan relokasi teks.)
Saya menyarankan agar Anda menautkan file objek Anda (bagaimanapun itu diproduksi) dengan gcc
, bukan ld
.
gcc
akan memanggil ld
dengan opsi yang sesuai, karena ia mengetahui lebih banyak tentang kode sumber dan akan membuat apa pun yang diperlukan untuk asumsi bahwa ld
membuat.