具有非内联汇编的 Qt C++ 项目

Posted

技术标签:

【中文标题】具有非内联汇编的 Qt C++ 项目【英文标题】:Qt C++ Project with non-inline assembly 【发布时间】:2012-03-15 20:40:25 【问题描述】:

我使用的是 Windows XP,以及带有 QtSDK 和内置 gcc 编译器的最新 Qt Creator。

问题是,如何在 C++ Qt 项目中使用完整的程序集。 我知道如何使用内联汇编,但我不知道如何在 Qt C++ 项目中进行非内联(编写在单独的 .asm 文件中)完整汇编。

Qt C++ 项目是否可以实现,如果可以,如何实现?

编辑:

*专业文件

TEMPLATE = app
CONFIG += console
CONFIG -= qt

SOURCES += \
    calc.S

calc.S

section .data
        hello: db 'Hello world!', 10
        helloLen: equ $-hello

section .text
        global _start

_start:
        mov eax, 4
        mov ebx, 1
        mov ecx, hello
        mov edx, helloLen
        int 80h

proexit:
        mov eax, 1
        mov ebx, 0
        int 80h

编译错误

..\plain_cpp\calc.S: Assembler messages:
..\plain_cpp\calc.S:1: Error: no such instruction: `section .data'
..\plain_cpp\calc.S:2: Error: no such instruction: `db 72ello world!4410'
..\plain_cpp\calc.S:3: Error: no such instruction: `equ $-hello'
..\plain_cpp\calc.S:5: Error: no such instruction: `section .text'
..\plain_cpp\calc.S:6: Error: no such instruction: `global _start'
..\plain_cpp\calc.S:9: Error: too many memory references for `mov'
..\plain_cpp\calc.S:10: Error: too many memory references for `mov'
..\plain_cpp\calc.S:11: Error: too many memory references for `mov'
..\plain_cpp\calc.S:12: Error: too many memory references for `mov'
..\plain_cpp\calc.S:13: Error: junk `h' after expression
..\plain_cpp\calc.S:13: Error: suffix or operands invalid for `int'
..\plain_cpp\calc.S:16: Error: too many memory references for `mov'
..\plain_cpp\calc.S:17: Error: too many memory references for `mov'
..\plain_cpp\calc.S:18: Error: junk `h' after expression
..\plain_cpp\calc.S:18: Error: suffix or operands invalid for `int'

编辑 2 - AT&T 风格

专业档案

TEMPLATE = app
CONFIG += console
CONFIG -= qt

SOURCES += \
    calc.S

calc.S

.data
hello:
    .string "Hello World\n"

.globl  main
main:
    movl $4, %eax
    movl $1, %ebx
    movl $hello,%ecx
    movl $12,%edx
    int $0x80

    ret

错误

undefined reference to `WinMain@16'
collect2: ld returned 1 exit status

【问题讨论】:

这是一个链接器错误。您需要在链接时提供正确的 -l 选项。 【参考方案1】:

虽然 @karlphillip 方法通常是正确的,但您应该记住一些 windows 指定的东西:

    当您编译 @karlphillip 的代码时,您会收到由MinGw 标准库文件产生的链接器错误:

    c:/mingw/bin/../lib/gcc/mingw32/4.6.1/../../../libmingw32.a(main.o): In function `main':
    C:\MinGW\msys\1.0\src\mingwrt/../mingw/main.c:73: undefined reference to `WinMain@16'
    

    那不是你的main,那是libmingw32.a的主要。它期望WinMain 作为你的 代码的入口点。问题是WinMain 是 Microsoft 定义的 Windows 应用程序的默认入口点。 libmingw32.a 定义了实际的 main,即从实际入口点调用。那个 main 做了一些事情,然后打电话给WinMain。但是你显然没有定义WinMain

    在这个简单的例子中你实际上不需要标准库,那么你可以删除标准库并用命令行编译上面的代码

    gcc -Wl,-subsystem,console 1.S -nostdlib
    

    应该相当于Qt设置QMAKE_CXXFLAGS+=-nostdlib

    然后上面的代码编译,并且... segfaults。然后转到第2点:

    int 80h 是特定的 linux 系统调用。似乎它不适用于Windows。您应该在 Windows 上调用 WriteConsole 以写入 stdin。但作为“概念证明”,您可以运行以下代码:

    .text
    .globl  main
    main:
        movl $1, %eax
    ret
    

    这会将程序的退出代码设置为 1。

编辑 如果你想要 Hello world 例子,编译时包含标准库,你可以试试这个:

.data
hello:
    .string "Hello World\n"

.text
.global _WinMain@16
_WinMain@16:
    push $hello
    call _puts
    add $4, %esp

    ret

使用gcc 1.S编译

【讨论】:

是否可以在不使用 WinMain 的情况下使用标准库调用(例如 puts)?我想将startmain 定义为入口点。我试图通知链接器使用main 作为入口点(-emain),但它不起作用:它仍然需要WinMain@16。而当我添加-nostdlib 时,另一方面它无法识别puts ;-/ puts 位于哪里?我应该链接什么库? @SasQ,即使你重新定义入口点,你仍然链接到标准库,它需要在你的代码中定义int main()。如果你重新定义入口点,这个 main 将永远不会被调用。您可以只创建空的main()。但是我认为您在尝试使用带有自定义入口点的标准库时正在寻找麻烦:自定义入口点意味着不会运行初始化代码,不会创建全局对象,可能标准库函数会拒绝工作 我发现我做错了什么:链接器没有看到我的puts,因为我使用了_puts(名称重整),但似乎在 x86_64 目标 GCC 上默认不使用重整(以及其他 ABI 损坏,例如使用寄存器传递参数等)。我的代码是为 x86(32 位)编写的,它使用不同的调用约定(名称修改、在堆栈上推送参数等)。出于同样的原因,它没有看到我的main 函数,我称之为_main。在这些更改之后,它起作用了。嗯...一个人需要终生学习... :-P【参考方案2】:

我建议您阅读 this tutorial 以正确设置 Qt Creator 以进行组装。

编辑:

您的问题是 qmake 将调用 gcc 来编译您的汇编代码,而您使用的是 Intel Syntax。您需要将汇编代码转换为使用 AT&T 语法

calc.S

.data
hello:
    .string "Hello World\n"

.globl  main
main:
    movl $4, %eax
    movl $1, %ebx
    movl $hello,%ecx
    movl $12,%edx
    int $0x80

    ret

calc.pro

TEMPLATE = app
CONFIG += console
CONFIG -= qt

SOURCES += \
    calc.S

将这两个文件粘贴到同一目录中,然后执行qmake,然后执行make

输出:

$ ./calc 
Hello World

【讨论】:

谢谢。 I c 杀死了所有 QT 和 C++ 构建步骤。因此只允许纯组装的项目。我认为它混合了完整的程序集 src 文件,而 Qt 项目中的 C++/Qt src 文件是不可能的? 更新了答案。问题是您使用的是 Intel 语法。检查我的例子。 谢谢,所以我需要在 GCC 中使用 AT&T 风格吗?我尝试了您的建议,原始帖子中的代码,出错了。 我添加了完整的示例。它使用 gcc/g++ 在我的 Linux 上运行。如果您有任何问题,您必须在此处粘贴错误。我建议你创建一个新文件夹来执行上面的测试。 不起作用。我看到你在 Linux 上。有趣的。在这里使用 Win XP。 `WinMain@16' 错误。【参考方案3】:

您是否在 *.pro 文件中尝试过 SOURCES += yourfile.asm

【讨论】:

不清楚,这里用哪个编译器来汇编? gcc/g++?这就是 Qt 附带的,也是我选择的。这仅支持内联汇编权限(不支持标签和 .data 部分等许多内容)? @L123 错误。 gcc 确实支持将汇编文件 (*.s) 转换为目标代码。它确实支持内联汇编,它甚至可能包含像“.data”这样的伪操作并跳转到内联汇编中定义的本地标签。只有你不知道,请阅读 gcc 在线文档和关于内联汇编的章节。

以上是关于具有非内联汇编的 Qt C++ 项目的主要内容,如果未能解决你的问题,请参考以下文章

纯 C++ 代码比内联汇编程序快 10 倍。为啥?

使用 C++ 中的内联汇编对缓冲区中的数字求和

如何在 Visual C++ 6.0 中编写以下内联汇编代码?

GNU g++ 内联汇编块,如 Apple g++/Visual C++?

内联汇编中的子数组。 C++

如何使用 Visual C++ 的内联汇编器插入重复的 NOP 语句?