3

GasNASM、およびYASMでマルチプラットフォームの Hello World コードを動作させています。基本的な Hello World C プログラムが80KB の実行可能ファイルであり、アセンブリははるかに小さいはずです。実行可能ファイルの大部分は、リンカー オプションからのジャンクで満たされていると思います。

痕跡:

LIBS=c:/strawberry/c/i686-w64-mingw32/lib/crt2.o -Lc:/strawberry/c/i686-w64-mingw32/lib -lmingw32 -lmingwex -lmsvcrt

ld ld -o $(EXECUTABLE) hello.o $(LIBS)

hello.exe
Hello World!

コード:

.data

msg: .ascii "Hello World!\0"

.text

.global _main

_main:

pushl $msg
call _puts

leave
movl $0, %eax
ret

LIBS のオプションのいずれかを削除すると、リンク プロセスが失敗するか、結果の実行可能ファイルを実行すると Windows エラーが発生します。したがって、行うべき論理的なことは、puts呼び出しを sys_write のような単純なものに置き換えることですが、この multiplatform を行う方法がわかりません。オンラインの小さなドキュメントint 0x80には、カーネルへの呼び出しを実行するために使用するように書かれていますが、これは Linux でのみ機能し、Windows では機能しないため、アセンブリ コードをマルチプラットフォームにしたいと考えています。

4

5 に答える 5

2

プログラムの肥大化は、ほとんどが C ランタイム ライブラリに由来します。Windows では、独自の「小さな」CRT を作成すると、単純な hello world プログラムが 5K 未満になることがあります。これは、EXEを可能な限り最小のサイズに縮小する方法に関するすべての詳細を説明するプロジェクトへのリンクです。

http://www.codeproject.com/Articles/15156/Tiny-C-Runtime-Library

于 2012-09-21T14:41:54.900 に答える
1

GetStdHandle()Windows の場合、ネイティブの Win32 API 関数 (やなど) を呼び出して、WriteFile()stdout に直接書き込むことができます。

Unix ライクなシステムの場合write()、stdout のファイル記述子 1 を使用して syscall を呼び出すことができます。

これらのそれぞれをどのように行うかの詳細は、使用しているアセンブラと OS によって異なります。

于 2012-09-20T20:46:59.970 に答える
0

アセンブラの肥大化は、特にputs. C 呼び出しを使用せずに Hello World を出力するようにコードをリファクタリングするには、OS 固有のアセンブリ コードが必要になる可能性が高くなります。これは、Unix 標準にはカーネルへの呼び出しを行う割り込みが含まれており、Windows にはそのようなタスク用の独自の VB に似た API があるためです。

プラットフォームにとらわれずに小さな実行可能ファイルを作成するソリューションを見つけることができました。通常、C プリプロセッサ ディレクティブでうまくいきますが、どのアセンブリ言語にプリプロセッサ構文があるのか​​さえわかりません。ただし、制御されたインクルード アセンブリ コード ファイルを使用することで、同様の効果を得ることができます。ラッパー コード ファイルのコレクションは、OS 固有のアセンブリ コードを処理できますが、含まれているアセンブリ ファイルが残りの処理を行います。また、単純な Makefile は、それぞれのビルド コンソール コマンドを実行して、目的のプラットフォーム上のそれぞれのラッパー コードを参照できます。

たとえば、このように機能するFASMコードをすばやく作成することができました。(ただし、実際にバイパスするように通知していませんが、puts肥大化の少ないもので。) とにかく、それは進歩です。

于 2012-09-22T00:39:09.493 に答える
0

C ランタイム ライブラリを静的に含めるのではなく、動的にリンクできるはずです。Linux でのやり方はわかりませんが、Windows ではmsvcrt.dll.

于 2012-09-21T01:50:08.710 に答える
0

ほとんどすべての C 関数は、呼び出し先 (関数) ではなく呼び出し元がスタックを調整する CDECL 呼び出し規約を使用するためです。

物事を正しく行う方法を今すぐ学ばないと、トラブルに巻き込まれます。バグを追跡するためにもっとよく読んでください。

これを試して:

    push    szLF
    push    esp
    push    fmtint2
    call    printf
    add     esp, 4 * 3

    push msg
    call puts 

    push    szLF
    push    esp
    push    fmtint2
    call    printf
    add     esp, 4 * 3

それを実行して、プットへのコールの前後の数字に注目してください。彼らは違いますか?まあ、それらは同じはずです。追加します:

    add     esp, 4

puts を呼び出して再度実行した後..数値は同じになりましたか? つまり、バランスの取れたスタック ポインターがあり、関数は CDECL 呼び出し規約を使用します。

于 2012-09-23T20:52:21.457 に答える