这是 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"
Run Code Online (Sandbox Code Playgroud)
使用此构建:(tcc test.s -lmsvcrt文件名必须以 .s 结尾,以便 tcc 将其识别为 asm 文件)
这会调用 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
Run Code Online (Sandbox Code Playgroud)
这里不需要 C 库,因此使用一个简单的构建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!
Run Code Online (Sandbox Code Playgroud)
MessageBoxA 在 user32 中找到,因此使用 构建tcc test.s -luser32,运行,您就会得到它。
这都是win32,因为我不太了解win64,但是32位程序应该仍然可以正常工作,你可以使用它。tcc 使用 AT&T 汇编器语法,这并不常见,但要将 nasm 或大多数其他汇编器的 Intel 语法转换为它,请记住:
它需要指令上的长度后缀。因此pushl,不要push推送长整型值(又名 32 位值)。
立即数、数字文字,以 $ 为前缀。实际上,现在我写了这篇文章,我意识到我可以写pushl $message上面而不是两步leal message, %eax pushl %eax。哦,好吧,两种方法都有效。但是,如果您忘记了 $,它会尝试将其用作指针,并且在加载内容时您可能会在看起来很小的内存地址处看到非法读/写。
寄存器名称需要 % 前缀
它转到源、目的地,这与英特尔语法的目的地、源相反。(我作为新手学习了 intel 方式,所以 AT&T 语法对我来说感觉很落后!)
但如果您记住这四个差异,您就可以相当轻松地将 tcc 的 Intel 语法代码转换为 AT&T 语法代码。一个小的变化是 tcc 使用 C 风格注释 ( // comment),而大多数其他汇编器使用; command
tcc 的另一件事是您不必声明 extern 函数,也不必使用参数长度后缀或下划线前缀。您几乎可以像在 C 中一样编写它,尽管需要有 ASCII 或 Wide 后缀(这些是 C 中的宏;#define MessageBox MessageBoxA因此在 Windows 标头中,如果您使用 unicode 支持进行编译,请将 A 更改为 W。区别在于A 版本采用 ascii 字符串 - 每个字符 8 位,无法访问所有字符,W 版本采用 16 位 unicode 字符串。)。
旁注:Win32 函数的实际损坏名称类似于 _MessageBoxA@16。您可以看到我们确实在示例代码中使用了“A”,正如我刚才提到的,但没有使用 _ 也没有使用 @16。名称的这些位对 C 来说是隐藏的,用于帮助捕获错误数量的参数 - @16 意味着它需要 16 个字节的参数,对于 32 位的消息框,这就是 hwnd (4, HWND),指向消息的指针 ( 4, char*)、指向标题的指针 (4, char*) 和标志 (4, int)。如果您在互联网上看到具有这些更改的调用函数的示例代码,这就是它存在的原因,并且您不需要使用 tcc 来使用它。
这应该可以帮助你开始!
| 归档时间: |
|
| 查看次数: |
2282 次 |
| 最近记录: |