如何从gcc内联arm7程序集中调用c++成员函数

How to call a c++ member function from gcc inline arm7 assembly

本文关键字:调用 集中 c++ 成员 函数 程序集 程序 gcc 内联 arm7      更新时间:2023-10-16

我有以下一段在x86上工作的代码,我需要将其转换为gcc/arm7内联程序集。

替换堆栈似乎很简单,只需将堆栈指针移动到r15而不是esp,但我不知道如何调用该函数,或将实际变量放入arm汇编代码中。

Object *c;
unsigned long _stack = (unsigned long)c->stack + 65535;
void (Object::*_run)() = &Object::_run;
__asm
{
    mov ecx, _this // store pointer to this Object
    mov edx, _run  // store address of _run() function
    mov esp, stack // replace stack pointer with Object's internal stack
    call edx       // call the _run() function
}


编辑:

到目前为止,我有这个:

unsigned long _stack = (unsigned long)c->stack + 65535;
void (Object::*_run)() = &Object::_run;
asm volatile("mov %[__this], %r0nt"
             "mov %[__run], %r5nt"
             "mov %[__stack], %%spnt"
             "blx %r5nt"
             : /* no output operands */
             : [__stack] "r" (_stack), 
               [__this] "r" (_this), 
               [__run] "r" (_run)
             : /* no clobbers */);

Q: 在x86 asm中,使用thiscall调用约定,"this"指针进入ecx。它的手臂在哪里?

编辑:

A: For C++, an implicit this parameter is passed as an extra argument that immediately precedes the first user argument. Other rules for marshalling C++ arguments are described in CPPABI.

编辑:

我想做的事情的全面实施如下:http://pastebin.com/6mrUC7td

它在visualstudio中运行得很好,但我无法使它在XCode/iOS 中正常运行

arm abi指定寄存器r0r3用于参数传递。this指针总是在第一个寄存器中,这将是r0

从gcc内联汇编程序中call的任何东西都不是特别安全,因为没有办法告诉编译器这一点(gcc内联asm指令的约束可以表示"这件事包含一个函数调用,执行所有必要的操作来保存/恢复寄存器中的任何内容,这些内容在进行函数调用时可能会更改")。

理论上,你可以通过给出一个clobber列表来"手动"实现这一点,该列表指定在根据平台ABI进行函数调用时可能更改的所有寄存器(在ARM上有很多,我认为几乎所有寄存器都不包括sp…)(即,它没有任何寄存器来填充"需要保存的东西"),这取决于使用内联asm的上下文。

为什么需要从内联程序集中调用函数?难道你不能用一个static inline函数来代替它,它将普通的C代码(函数调用它)与内联汇编结合起来,来做只能在内联汇编中完成的事情吗?

如果整个函数仅为内联汇编,则ARM上的gcc提供了一种解决方案,即__attribute__((naked))选项。这告诉编译器不要为其创建函数序言/结束语,您有义务自己编写这些,即添加保存/恢复此函数使用但由EABI声明保留的寄存器的代码。通过将执行函数调用的内联程序集"外包"到static inline __attribute__((naked))函数中,您可以避免指定大量的clobber列表,因为编译器会识别出这是一个函数调用(并根据需要保留/恢复它,即使在内联代码时也是如此)。

看看这个。尽管它使用x86程序集,但同样适用于arm程序集。

我不太确定你在用堆栈指针做什么——这是ARM上不需要的x86习惯用法,还是你有意设置一个新的堆栈指针?

在任何情况下,堆栈指针都在r13中-程序计数器是r15-LDRMOVPC中会影响分支。在函数prolog之外,SP已经指向堆栈上的下一个位置,因此只有当由于寄存器r0-r3不够而需要在堆栈上传递参数时,才需要修改它——这里的情况并非如此。

若您确实修改了堆栈指针,您需要在函数调用后恢复它,否则在函数退出时会出现一个很好的小崩溃。

最后,您需要将ARM[E]ABI允许被调用者在函数调用时修改的所有寄存器声明为clobbered。这是r0-r3r9{可能}和r12

如果你在iOS上这样做,ISTR在注册使用方面会有细微的变化。

获取ABI所需信息的简单解决方案(比如在哪些寄存器中获取传递的值):只需在调用c++方法的地方写几行伪代码,然后反汇编结果(在目标平台上)。