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

时间:2012-08-04 22:04:21

标签: c++ gcc assembly arm

我有以下代码可以在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], %r0\n\t"
             "mov %[__run], %r5\n\t"
             "mov %[__stack], %%sp\n\t"
             "blx %r5\n\t"
             : /* no output operands */
             : [__stack] "r" (_stack), 
               [__this] "r" (_this), 
               [__run] "r" (_run)
             : /* no clobbers */);

问:在x86 asm中,使用thiscall调用约定,“this”指针进入ecx。 它在哪里?

修改

答: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

它在visual studio中完美运行,但我无法让它在XCode / iOS中正常工作

5 个答案:

答案 0 :(得分:3)

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

答案 1 :(得分:2)

对于来自gcc内联汇编程序的call任何东西都不是特别安全,因为没有办法告诉编译器它(没有约束到gcc内联asm指令可以表达“这个东西包含函数调用,执行所有必要的操作来保存/恢复保存在寄存器中的任何内容,这些寄存器在进行函数调用时可能会发生变化“。

理论上你可以通过给出一个clobber列表来“手动”执行该操作,该列表指定在根据平台ABI进行函数调用时可能更改的所有寄存器(在ARM上相当多,我认为它是几乎所有这些都不包括sp ...)。但是这样做经常会导致gcc告诉你无法满足约束的情况(即它没有留下任何寄存器来填充“需要保留的东西”),具体取决于使用内联asm的上下文。 / p>

为什么需要从内联汇编中调用函数?您是否可以使用static inline函数将普通C代码(执行函数调用)与内联汇编相结合,以执行只能在内联汇编中执行的操作?

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

答案 2 :(得分:0)

看看this。虽然它使用x86组件,但同样适用于臂组件。

答案 3 :(得分:0)

我不太确定你在那里使用堆栈指针做什么 - 这是你在ARM上不需要的x86成语还是你故意尝试设置一个新的堆栈指​​针?

在任何情况下,堆栈指针都在r13中 - 程序计数器为r15 - LDRMOV进入PC会影响分支。在函数序言之外,SP已经指向堆栈上的下一个位置,因此如果由于寄存器r0-r3不够而需要在堆栈上传递参数,则只需要修改它 - 这是不是这里的情况。

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

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

如果您在iOS上这样做,ISTR会对寄存器的使用情况产生微妙的变化。

答案 4 :(得分:0)

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