【问题标题】:How to call a c++ member function from gcc inline arm7 assembly如何从 gcc 内联 arm7 程序集中调用 c++ 成员函数
【发布时间】:2012-08-04 22:04:20
【问题描述】:

我有以下在 x86 上工作的代码,我需要将其转换为 gcc/arm7 内联汇编。

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

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 中正常运行

【问题讨论】:

    标签: c++ gcc assembly arm


    【解决方案1】:

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

    【讨论】:

      【解决方案2】:

      call 来自 gcc 内联汇编器的任何东西都不是特别安全,因为没有办法告诉编译器它(没有 约束 到 gcc 内联 asm 指令可以表示“这个东西包含一个函数调用,做所有必要的事情来保存/恢复你保存在寄存器中的任何东西,这些东西在进行函数调用时可能会改变”)。

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

      为什么你需要从内联程序集中调用一个函数?难道你不能使用 static inline 函数来代替普通的 C 代码(执行函数调用)和内联汇编来完成只能在内联汇编中完成的事情吗?

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

      【讨论】:

      • 我正在尝试从程序集中调用该函数,因为我的主要目标是覆盖堆栈指针。因此,在调用函数之前,我需要将任何我想要保留的内容移出堆栈,并放入寄存器中。
      • @al bundy:有系统接口——UN*X 下的setcontext()(包括Android/iOS)和Windows 下的SetThreadContext()(包括WinCE / WinPhone)。只有在编写自己的操作系统时才需要手动重新实现它。
      • 实际上,ucontext 似乎已被弃用完成......不知道为什么它在任何地方都不受支持.. Windows 有光纤,但除此之外,真的不支持用户级线程。我试图组合一些我可以用来实现协程/协作多任务处理的东西,但这种事情结果证明有点不合我意。 Boost 最近接受了 Boost::Context,但它还没有正式发布 =/ 所以我想我现在只能坚持使用线程。
      • 不确定您所说的已弃用是什么意思。 struct ucontext 存在于最新的 UNIX 规范中,pubs.opengroup.org/onlinepubs/009696799/basedefs/… - 只是通用规范留下了有趣的部分,mcontext_t,未指定/特定于系统。您可以在 UNIX 中通过信号和 sigaltstack() 实现协程 - 比完整的 setcontext() 稍微轻一些。不确定许多人是否还在研究协作式多任务……Sun 在 2002 年从他们的 Solaris libthread 中放弃了这一点,本机线程性能变得更好,没有任何东西可以证明其复杂性。
      • 也就是说……线程与协程……区别主要在于设置开销。如果您只在想要进行切换时创建线程,那么它肯定会比makecontext()/setcontext()(或他们自己开发的等价物)慢。如果协程的线程(池)已经存在,那么使用信号量作为触发器并让操作系统为您进行上下文切换应该给出与协程/手动上下文切换相同的大致数字。这是 DrDobbs 文章中使用的技术:drdobbs.com/cpp/cross-platform-coroutines-in-c/184404529
      【解决方案3】:

      看看this。虽然它使用 x86 汇编,但同样适用于 arm 汇编。

      【讨论】:

        【解决方案4】:

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

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

        如果你修改了堆栈指针,你需要在函数调用之后恢复它,否则你会在函数退出时遇到一个不错的小崩溃。

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

        如果您在 iOS 上执行此操作,ISTR 会在寄存器使用方面存在细微差异。

        【讨论】:

        • 我实际上是在尝试实现协程。我正在尝试为该函数设置一个新的堆栈指​​针,然后将longjmp退出该函数以恢复原始堆栈。然后我可以 longjmp 回到函数中,新的堆栈仍然存在。我没有指定被破坏的寄存器,因为我认为如果我立即调用新函数,然后在它之后立即执行 longjmp,那么这些寄存器的内容将无关紧要。
        • 这更有意义 - 因此,您的堆栈已经在对象中分配,并且算法会为您提供递减堆栈的指针 - 您希望它足够大!被破坏的寄存器列表是编译器必须假定在 asm 块末尾修改的所有寄存器。如果您从不打算返回,那真的不是问题 - 分支和链接 (blx) 指令的存在表明您可能是。但是,如果返回是可能的,那么 longjmp 会浪费很多东西!
        【解决方案5】:

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

        【讨论】:

        • 我实际上一直在尝试这样做......但是在 Visual Studio 会给我一个近乎完美的代码翻译的地方,xcode 会生成一些非常奇怪的程序集......例如,在 vs12 中,“ mov esp, _stack" 就是这样翻译的,在 xcode 中 "mov %[__stack], %%sp\n\t" 翻译成大约 4 行.. 在将其移入寄存器之前似乎添加了一些奇怪的偏移量 = /
        猜你喜欢
        • 2012-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-06-28
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-02-15
        相关资源
        最近更新 更多