直接跳转到另一个C++函数

ori*_*ena 6 c++ assembly systems-programming

我正在将一个小型学术操作系统从TriCore移植到ARM Cortex(Thumb-2指令集).为了使调度程序工作,我有时需要将JUMP直接转换为另一个函数,而无需修改堆栈或链接寄存器.

在TriCore上(或者更确切地说,在tricore-g ++上),这个包装器模板(用于任何三个参数函数)可以工作:

template< class A1, class A2, class A3 > 
inline void __attribute__((always_inline)) 
JUMP3( void (*func)( A1, A2, A3), A1 a1, A2 a2, A3 a3 ) {
    typedef void (* __attribute__((interrupt_handler)) Jump3)( A1, A2, A3);
    ( (Jump3)func )( a1, a2, a3 );
}

//example for using the template:
JUMP3( superDispatch, this, me, next );
Run Code Online (Sandbox Code Playgroud)

这将生成汇编程序指令J(又名JUMP),而不是CALL在跳转到(否则正常)C++函数时保持堆栈和CSA不变superDispatch(SchedulerImplementation* obj, Task::Id from, Task::Id to).

现在我需要ARM Cortex上的等效行为(或者更确切地说,对于arm-none-linux-gnueabi-g ++),即生成B(又称BRANCH)指令而不是BLX(又称带有链接和交换的BRANCH).但是没有interrupt_handlerarm-g ++的属性,我找不到任何等效属性.

所以我试图asm volatile直接使用和编写asm代码:

template< class A1, class A2, class A3 > 
inline void __attribute__((always_inline)) 
JUMP3( void (*func)( A1, A2, A3), A1 a1, A2 a2, A3 a3 ) {
    asm volatile (
                  "mov.w r0, %1;"
                  "mov.w r1, %2;"
                  "mov.w r2, %3;"
                  "b %0;"
                            :
                            : "r"(func), "r"(a1), "r"(a2), "r"(a3)
                            : "r0", "r1", "r2"
                  );
}
Run Code Online (Sandbox Code Playgroud)

到目前为止,至少在我的理论中这么好.Thumb-2要求函数参数在寄存器中传递,即在这种情况下为r0..r2,因此它应该可以工作.

但随后链接器就死了

undefined reference to `r6'
Run Code Online (Sandbox Code Playgroud)

在asm声明的结束时......我不知道该怎么做.好吧,我不是C++的专家,asm语法也不是很简单......所以有人给我一个暗示吗?__attribute__对arm-g ++ 的正确提示将是一种方式,修复asm代码的提示将是另一种方式.另一种方法可能是告诉编译器a1..a3r0..r2输入asm语句时应该已经在寄存器中(我查了一下,但没有找到任何提示).

ori*_*ena 0

好吧,我现在知道出了什么问题了。

直接跳转到另一个函数的整个概念在 ARM Cortex 上是没有意义的,因为每次调用另一个函数时,TriCore 使用上下文保存区域 (CSA) 来保存整个 CPU 上下文。将其视为第二个独立堆栈,随每个堆栈一起增长CALL并随每个堆栈缩小RET。每个CSA块都有恒定的大小。

另一方面,ARM Cortex 使用一个简单的标准堆栈(好吧,它知道系统堆栈和线程堆栈,但这在这里并不重要)——而 GCC 只是保存每个函数所需的内容,因此每个帧都有一个不同的尺寸。因此,简单地跳转到另一个函数是不可能的,因为一旦跳转到的函数开始保存它使用的非易失性寄存器,堆栈就会损坏。

关于对 r6 的未定义引用的链接器错误......好吧,我应该更仔细地阅读指令集文档。是到立即B地址的无条件分支,是期望寄存器中的分支地址的指令。我被手册中的指令列表愚弄了,它被简短地描述为“带有交换的分支”。我不想交换任何东西,我想要一个简单的跳转,所以我没有继续阅读。BXBX

所以,在代码中B交换后,代码就编译好了。但是,正如上面指出的,整个概念无法按预期发挥作用。也许其他人可以找到该代码的用例,我现在必须求助于经典函数调用......BXasm volatile