【问题标题】:asm function with c++c++中的asm函数
【发布时间】:2020-04-24 10:47:23
【问题描述】:

我想使用汇编语言向我的班级添加方法。我该怎么做? 示例:

main.cpp

Struct ex {
    int field1;
    asm_method(char*);
}

添加.asm

asm_method: 
    //some asm code

【问题讨论】:

  • cppreference 有一个例子en.cppreference.com/w/cpp/language/asm
  • 我知道 asm() 指令,但我想在两个不同的文件中进行操作
  • 差不多就是这样。您需要在 C++ 代码中声明 asm_method(就像您将前向声明 C++ 方法一样),并将其声明为 extern "C"(这比修改名称以匹配您的编译器更容易),然后组装并将汇编代码与正常的链接步骤链接起来。如果您需要更具体的帮助,能否告诉我们哪个 CPU、操作系统(=> 调用约定)和编译器?
  • @ChurkinAleksey 我分享的链接有一个在程序集中定义函数的示例。这不是您要找的吗?
  • 哦,我错过了你说的“将方法添加到我的类” - 因为在这个方法中应该有一个 this 指针?这将需要更多的工作来设置:您需要使用编译器的名称修改工具来确定应该调用什么 asm_method(对类名、返回值和参数类型进行编码)并找出您需要的调用约定汇编代码。例如Windows __thiscall 在 ECX 中传递 this 指针,方法本身从堆栈中删除其参数(“callee clean”)

标签: c++ assembly


【解决方案1】:

获取编译器为 C++ 成员函数的非内联定义生成的 asm 输出,并将其用作 asm 源文件的起点。这适用于任何 ISA 以及任何可以发出有效 asm 的编译器(这是大多数编译器,尽管显然 MSVC 会发出一堆你必须删除的额外垃圾。)


GCC 示例(适用于 x86-64 GNU/Linux,但适用于任何地方)

也适用于 clang。

例如g++ -O3 -fverbose-asm -masm=intel -S -o foo_func.S foo.cpp (How to remove "noise" from GCC/clang assembly output?)

.S 文件现在是您的 asm 源文件。删除编译器生成的指令行并插入您自己的。

显然您需要知道调用约定和其他类似的东西(例如,对于 x86,请参阅 https://www.agner.org/optimize/#manuals 以获取调用约定指南),但这将使编译器为您执行名称修改,针对特定目标平台的ABI。

struct ex {                 // lower case struct not Struct
    int field1;
    void *asm_method(char*);   // methods need a return type
};     // struct declarations end with a ;

void *ex::asm_method(char*) {
    return this;  // easy way to find out what register `this` is passed in.
}

针对 x86-64 System V 编译如下,使用 g++ -O3 (Godbolt with Linux gcc and Windows MSVC)

# x86-64 System V: GNU/Linux g++ -O3
# This is GAS syntax
        .intel_syntax noprefix
        .text                   # .text section is already the default at top of file

        .align 2
        .p2align 4              # aligning functions by 16 bytes is typical
        .globl  _ZN2ex10asm_methodEPc     # the symbol is global, not private to this file
        .type   _ZN2ex10asm_methodEPc, @function   # (optional) and it's a function.
_ZN2ex10asm_methodEPc:                    # a label defines the symbol
        .cfi_startproc
  ## YOUR CODE GOES HERE ##
  ## RSP-8 is aligned by 16 in x86-64 SysV and Windows ##
        mov     rax, rdi                 # copy first arg (this) to return-value register.
        ret                              # pop into program counter
        .cfi_endproc
        .size   _ZN2ex10asm_methodEPc, .-_ZN2ex10asm_methodEPc    # maybe non-optional for dynamic linking

在叶子函数的手写 asm 中省略 .cfi stack-unwind 指令可能没问题,因为您不会从手写 asm 中抛出 C++ 异常(我希望如此)。

【讨论】:

    【解决方案2】:

    这取决于您的目标平台和编译器/工具链,通常对于 StackOverflow 来说过于宽泛。

    例如,GCC 工具链中的 C++ 编译器实际上是从 C++ 生成程序集,然后从该程序集生成目标文件。然后链接器将多个目标文件链接在一起以生成一个 ELF 模块。

    您可以绕过单个目标文件的 C++ 编译步骤,直接编写 .asm 文件。

    你可以像编译.c:gcc myfile.S -o myfile.o一样编译它。

    尽管您应该考虑平台 ABI,以便您可以接受函数参数并通过正确的寄存器返回值。平台 ABI 还指定调用约定以及应在函数调用之间保留哪些寄存器。最后,您需要根据 C++ 名称修改规则生成正确的函数名称,或者使用 C 命名规则(更简单)并声明您的函数 extern "C"

    有关更多详细信息,请参阅C++ to ASM linkage,对于 Linux ABI,请参阅System V ABI

    对于 Windows,从此处开始:calling conventionscompiling assembly in Visual Studio

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-09-04
      • 2011-11-05
      • 2010-11-25
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多