ラベル _start
を使用 main
の代わりに ELF エントリ ポイント用。 main
C main
のようなものであることを意味します 関数ですが、これは関数でさえありません (たとえば、ret
はできません ).
あなたは言いませんが、エラー メッセージとコードから、nasm -felf32 hello32.asm && ld -melf_i386 -o hello32 hello32.o
で 32 ビット コードをビルドしていると思います。
(実際に 64 ビット コードをビルドしている場合、たまたま動作することは幸運ですが、esp
で何かを行うとすぐに壊れます。 rsp
の代わりに .)
エラーメッセージは ld
からのものです 、nasm
からではありません .メッセージにそう書いてあります。ティムのコメントは正しいです:ld
_start
を探します リンクするファイル内の記号ですが、テキスト セグメントが見つからない場合はエントリ ポイントをテキスト セグメントの先頭に設定します。
定義する他のグローバル/外部シンボルは関係ありません。 main
ここではまったく関係がなく、好きな場所を指すことができます。逆アセンブル出力などにのみ役立ちます。 global main
を削除しても、コードはまったく同じように機能します。 / main:
行、またはそれらを他の名前に変更しました。
それを main
とラベル付けする ELF エントリ ポイントは関数ではないため、賢明ではありません . 違う main()
、および argc
を受け取りません と argv
ret
できません。 ESP が argc
を指しているため 返信先住所の代わりに。
main
のみを使用してください main
を探す gcc / glibc の CRT スタートアップ コードとリンクする場合 libc の初期化後に呼び出します。 (そのため、printf のような関数が機能します。技術的に動的リンカ フックを使用すると、libc は _start
の前に自分自身を初期化できます。 リンクした場合、しかし、自分が何をしているのかを正確に理解していない限り、通常はそうしないでください)。関連:64 ビット システムでの 32 ビット バイナリのアセンブル (GNU ツールチェーン)
例えばgcc -m32 -no-pie -o hello main.o
main:
を定義する場合
gcc -m32 -static -nostdlib -o hello start.o
の代わりに
(これは素の ld
と同等です ).
(過去数年間、Linux ディストリビューションは -pie
で GCC を構成してきました デフォルトでは、位置に依存しないコードが必要です。しかし、これは RIP 相対アドレッシングのない 32 ビット モードでは本当に不便です (たとえば、GCC asm 出力を見てください)。これは ld
を意味します。 call printf
を変換しません call [email protected]
に あなたのために。そのため、ほとんどのチュートリアルに従うほとんどの手書きの asm では、従来の非 PIE 実行可能ファイルが必要になるため、テキストの再配置は必要ありません)。
gcc
を使用してオブジェクト ファイル (生成方法に関係なく) をリンクすることをお勧めします。 、ld
ではありません .
gcc
ld
を呼び出します 適切なオプションを使用して、ソースコードについて詳しく知っており、ld
という仮定に必要なものを作成するためです。