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文件名必须以 .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

// and now we'll call ExitProcess to get out
    pushl   $0
    call    ExitProcess
    hlt // never reached
.data
message:
    .string  "Hello, world!\n\0"

这里不需要 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!

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 语法对我来说感觉倒退了!)

但是,如果您还记得这四个差异,您就可以相当轻松地将 Intel 语法代码转换为 tcc 的 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, an int)。如果您在 Internet 上看到带有这些更改的调用函数的示例代码,这就是它存在的原因,而 tcc 不需要它。

那应该让你开始!

于 2013-11-19T15:37:33.060 回答