3

次のコードに問題があります。

extern printf
global _main
main:
push msg
call printf
ret
msg db "Hello world",0

これを NASM を使用してアセンブルし、nasm -fwin32 test.asm次に を使用してリンクしld test.objます。そして、それは私に言う " test.obj:test.asm:(text+0x6): undefined reference to 'printf'"

ファイルを標準 C ライブラリにリンクする方法は? 私は最新のMinGWからldを持っています。

4

3 に答える 3

1

あなたのコードにはいくつかの問題があります。まず、 にはアンダースコアがありますが、 にはglobal _mainありませんmain:。これらは一致する必要があります。全体でアンダースコアを使用するか、または-私が行うこと-まったく使用しないでください.Windowsの場合は、nasm -f win32 --prefix _ test.asm. これにより、Linuxの場合、アンダースコアなしでアセンブルされるという点で「移植可能」に--prefix _なります。global Linux はアンダースコアまたはextern記号を使用しません。たまたま、OpenWatcom C を使用していた場合は、--postfix _. ええ、OpenWatcom は末尾のアンダースコアを使用します。ええ、C は標準化されていると彼らが言ったことは知っています。しかし、いったんボンネットの下に入ると、これは実際には真実ではありません。

もう 1 つの大きな問題は、 を呼び出した後、「スタックをクリーンアップする」_printf必要があるadd esp, 4(またはpopダミー レジスタを使用する) ことです。Windows API を使用している場合は、"callee がクリーンアップする" STDCALL 呼び出し規約を使用するため、これを行う必要はありません。C 呼び出し (CDECL 呼び出し規約) と Windows API を混在させると混乱するかもしれませんが、うまくいくはずです。

カールは gcc を使用してリンクするという正しい考えを持っていると思います。「コンパイル」するものは何もありませんが、gcc は ld への適切なコマンド ラインを認識しています。gcc -o test.exe test.objおそらく十分でしょう (-m32最新の MinGW が 64 ビット コードを実行することを期待している場合は、追加することもできます)。これは、を呼び出す「起動コード」にリンクします_main。これにより、実行可能ファイルのサイズがわずかに大きくなり、実行可能ファイルがなくてもうまくいく可能性がありますが、実行する方が簡単です。

Linux では、ld を直接使用できますが (コマンド ラインはひどいものです)、ld はエントリポイントとして_startではなくを探しmainます。ld を伝えることはできます-e mainが、このエントリポイントは呼び出されず (!)、そこretから移動する方法はありません! Windows では状況が異なる可能性があります。最低でも、-lcこれらの C ライブラリが必要であることを ld に伝える必要があります。「gccに任せる」のが最も簡単です-.asmコードには触れません(ただし、その「起動コード」にリンクします)。ハッピーハローワールド!:)

于 2013-09-14T19:36:59.147 に答える