0

私はアセンブリ言語を理解していません。私の学校では、アセンブリ言語とは何か、コンパイル方法を示すためだけにこれを行っています。

tccasm で実行できるアセンブリ言語を使用した基本的な Hello World の例を教えてください。

任意の助けをいただければ幸いです

4

1 に答える 1

2

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 では必要ありません。

これで始められるはずです。

于 2013-11-19T15:37:33.060 に答える