我想使用 <Button
android:id="@+id/apply"
style="?android:attr/borderlessButtonStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/md_cyan_A700"
android:text="Cancel"/>
branch
到特定地址(不是标签),而不修改ARM assembly
寄存器。所以我选择LR
代替B
或BL
。
我希望在BX
中完成此操作。
Here是文档,这是我尝试过的:
GCC inline asm
这是一个C宏,可以用#define JMP(addr) \
__asm__("b %0" \
: /*output*/ \
: /*input*/ \
"r" (addr) \
);
调用。当我运行它时,我收到以下错误:
address
错误是因为error: undefined reference to 'r3'
的使用。我调查了一下,我发现它可能是gcc 4.9。*版本的错误。
BTW,我在"r"
上使用Android/Linux Gcc 4.9 cross compiler
。
另外,我不知道我应该在OSX
装载什么东西。
干杯!
修改
我将宏更改为此,我仍然得到Rm
:
undefined reference to r3 and r4
说明: 将变量的地址加载到r5,然后将该地址的值加载到r4。然后将1加到LSB(ARM规范要求的emm?)。最后转到那个地址。
答案 0 :(得分:4)
您无法分支到寄存器,只能分支到标签。如果要跳转到寄存器中的地址,则需要将其移入PC寄存器(r15)。
#define JMP(addr) \
__asm__("mov pc,%0" \
: /*output*/ \
: /*input*/ \
"r" (addr) \
);
答案 1 :(得分:4)
由于您使用C编程,您可以使用简单的C方法而不使用任何程序集:只需将指向您要跳转的地址的指针转换为函数指针并调用它程:
((void (*)(void)) addr)();
只是对这个括号丛林的解释:
使用此代码,您将addr
转换为指针(由星号(*)
表示)到不带参数的函数(第二个void
表示没有参数)并且还返回没事(第一void
)。最后两个括号是该函数的实际调用。
Google for&#34; C函数指针&#34;有关该方法的更多信息。
但是,如果这对你不起作用,而你仍然想要采用汇编方法,那么你正在寻找的指令实际上是BX
(不知道为什么你最初将它排除在外。但是我可以猜到名称&#34;分支和交换&#34;误导你相信寄存器参数与程序计数器交换(从而改变),这是 NOT 的情况,但它在开始时也让我感到困惑。)
为此,只需简单回顾一下说明:
B
会将标签作为参数。实际上,跳转将被编码为当前位置的偏移量,这会告诉处理器向前或向后跳转许多指令(通常编译器,汇编器或链接器将负责为您计算该偏移量)。在执行期间,控制流将简单地转移到的位置,而不用更改任何寄存器(这意味着链接寄存器LR
也将保持不变)。BX R0
将从寄存器中获取绝对(因此不偏移量)地址,在本例中为R0
,并继续在该地址执行。这也是在没有更改任何其他寄存器的情况下完成的。BL
和BLX R0
是前两条指令的对应部分。他们将在控制流方面做同样的事情,但最重要的是保存链接寄存器LR
中的当前程序计数器。如果被调用的函数应该稍后返回,则需要这样做。所以从本质上讲,你需要做的是:
asm("BX %0" : : "r"(addr));
指示编译器确保变量addr
位于寄存器(r
)中,您承诺只读取而不更改。最重要的是,在返回时你不会改变(破坏)任何其他注册。
见这里 https://gcc.gnu.org/onlinedocs/gcc/Constraints.html 有关内联汇编约束的更多信息。
为了帮助您理解为什么还有其他解决方案,这里有一些关于ARM架构的内容:
PC
用于许多可作为常规寄存器R15
访问的指令。它只是该确切寄存器号的别名。BX LR
完全符合您的要求:获取链接寄存器的内容(LR
是R14
的别名)并跳转到该位置,有效地返回到呼叫者POP {R4-R11, PC}
恢复调用者保存的寄存器并跳回调用者。这几乎肯定会在函数开头有PUSH {R4-R11, LR}
的对应部分:你正在将链接寄存器的内容(返回地址)推送到堆栈上,但是将它存回到程序计数器中,有效地返回给调用者结束B
分支到不同的函数,如果此函数以尾调用结束并将其留给该函数返回原始调用者。希望有所帮助, 马丁