私はアセンブリ言語を理解していません。私の学校では、アセンブリ言語とは何か、コンパイル方法を示すためだけにこれを行っています。
tccasm で実行できるアセンブリ言語を使用した基本的な Hello World の例を教えてください。
任意の助けをいただければ幸いです
32 ビット Windows の Hello World は次のとおりです。
.global main
.section .text
main:
leal message, %eax
pushl %eax // the C convention is params are pushed onto the stack
call printf
popl %eax // and the caller is responsible for cleanup
pushl $0
call exit
hlt // never reached
.data
message:
.string "Hello, world!\n\0"
これでビルドします: tcc test.s -lmsvcrt
(ファイル名は、tcc が asm ファイルとして認識するために .s で終わる必要があります)
これは、C 関数を呼び出して作業を行います。Windows 関数のみを使用することもできます。
.global main
.section .text
main:
pushl $-11 // STD_OUTPUT_HANDLE
call GetStdHandle // the return value will be in eax
// now we'll call WriteFile. Args are pushed from right to left
pushl $0 // lpOverlapped == null, don't want async
pushl $0 // lpNumberOfBytesWritten == null, we don't care
pushl $14 // nNumberOfBytesToWrite, our hello world has 14 chars.
leal message, %ebx // load address for lpBuffer, pointer to the string to write
pushl %ebx // and push it to the stack
pushl %eax // the return value we got from GetStdHandle
call WriteFile // and write the file
// unlike the C convention, the Windows functions clean up their own stack
// so we don't have to pop that stuff
// and now we'll call ExitProcess to get out
pushl $0 // our main's return value of 0 == success
call ExitProcess
hlt // never reached
.data
message:
.string "Hello, world!\n\0"// so we don't have to pop that stuff
// and now we'll call ExitProcess to get out
pushl $0
call ExitProcess
hlt // never reached
.data
message:
.string "Hello, world!\n\0"
ここでは C ライブラリは必要ないので、単純な .xml でビルドしtcc test.s
ます。コンソールから実行すると、そこにメッセージが表示されるはずです。
豆知識: Windows の機能は使いやすく、メッセージ ボックスを簡単に表示できます。
.global main
.section .text
main:
pushl $0 // MB_OK
pushl $0 // title = null (will use the default of "Error")
leal message, %eax // load our message
pushl %eax // and push the string pointer to the argument list
pushl $0 // hwnd == null, no owning window
call MessageBoxA // and pop up the message box
pushl $0
call ExitProcess
hlt // never reached
.data
message:
.string "Hello, world!\n\0" // don't forget the zero terminator!
MessageBoxA は user32 にあるので、 でビルドしてtcc test.s -luser32
実行すると、それが得られます。
私は多くの win64 を知らないので、これはすべて win32 ですが、32 ビット プログラムでも問題なく動作するはずです。tcc は AT&T アセンブラー構文を使用しますが、これは一般的ではありませんが、nasm または他のほとんどのアセンブラーの Intel 構文をそれに変換するために、次のことを覚えておいてください。
命令に長さサフィックスが必要です。そのため、長い別名 32 ビット値をプッシュするpushl
代わりに。push
数値リテラルである即値には、$ のプレフィックスが付きます。pushl $message
実際、これを書いている今、2 ステップの代わりに上記のように書くこともできたことに気付きleal message, %eax pushl %eax
ました。まあ、両方の方法が機能します。しかし、$ を忘れると、それをポインターとして使用しようとするため、読み込み時に小さなメモリ アドレスで不正な読み取り/書き込みが行われる可能性があります。
レジスタ名には % 接頭辞が必要です
これは、Intel 構文の宛先であるソースの反対であるソース、宛先になります。(私は新参者として Intel の方法を学んだので、AT&T の構文は私には後ろ向きに感じられます!)
しかし、これら 4 つの違いを覚えていれば、インテルの構文コードを tcc 用の AT&T の構文コードに簡単に変換できます。マイナーな変更は、tcc が C スタイルのコメント ( // comment
) を使用することです。; command
tcc のもう 1 つの点は、extern 関数を宣言したり、引数の長さのサフィックスやアンダースコアのプレフィックスを使用したりする必要がないことです。ほぼ C と同じように記述しますが、ASCII またはワイド サフィックスが必要です (これらは C のマクロです。#define MessageBox MessageBoxA
したがって、Windows ヘッダーで、Unicode サポートを使用してコンパイルしている場合は A を W に変更します。違いは次のとおりです。 A バージョンは ASCII 文字列を使用します - 1 文字あたり 8 ビットで、すべての文字にアクセスすることはできません。W バージョンは 16 ビットの Unicode 文字列を使用します)。
補足: Win32 関数の実際の修飾名は、_MessageBoxA@16 のようなものです。先ほど述べたように、サンプル コードで「A」を使用していることがわかりますが、_ や @16 は使用していません。名前のこれらのビットは C から隠され、間違った数の引数をキャッチするために使用されます。@16 は、16 バイトの引数が必要であることを意味します。32 ビットのメッセージ ボックスでは、hwnd (4, HWND)、メッセージへのポインター ( 4, char*)、タイトルへのポインター (4, char*)、およびフラグ (4, int)。これらの変更を伴う関数呼び出しのサンプル コードがインターネット上にある場合は、それがそこにある理由であり、tcc では必要ありません。
これで始められるはずです。