我在Android设备上编写针对ARM Cortex-A的代码(使用GNU汇编程序和编译器),我试图在汇编和C之间进行接口。特别是,我对调用汇编中用C编写的函数很感兴趣。我尝试了很多东西,包括.extern指令、用asm和__asm__声明C函数等等,但是它们都没有工作,所以我想找一个这样做的最小例子。提及这类例子同样值得欢迎。
发布于 2011-12-07 22:44:27
您需要阅读手臂和/或知道指令集是全部,通常您会想要这样做
asm:
bl cfun
c:
void cfun ( void )
{
}你自己试试吧。对于gnu和gcc,如果您使用clang将c代码获取到一个对象,而gnu作为汇编程序,它也应该工作得很好。不知道你在用什么。
上面提到的问题是bl的范围有限,
if ConditionPassed(cond) then
if L == 1 then
LR = address of the instruction after the branch instruction
PC = PC + (SignExtend_30(signed_immed_24) << 2)知道bl指令将链接寄存器设置为bl指令之后的指令,那么如果您读到程序计数器寄存器:
For an ARM instruction, the value read is the address of the instruction
plus 8 bytes. Bits [1:0] of this
value are always zero, because ARM instructions are always word-aligned.所以如果你让你的asm看起来像这样:
mov lr,pc
ldr pc,=cfun你会得到
d6008034: e1a0e00f mov lr, pc
d6008038: e51ff000 ldr pc, [pc, #-0] ; d6008040
...
d6008040: d60084c4 strle r8, [r0], -r4, asr #9汇编程序将保留一个内存位置,在ldr pc的范围内,指令(如果可能的话,生成错误),其中它将放置指令的完整32位地址。链接器稍后将使用外部地址填充此地址。这样,您就可以到达地址空间中的任何地址。
如果您不想玩这样的汇编程序游戏,并且想要控制,那么您可以创建一个位置来保存该函数的地址,并自己将其加载到pc中:
mov lr,pc
ldr pc,cfun_addr
...
cfun_addr:
.word cfun汇编:
d6008034: e1a0e00f mov lr, pc
d6008038: e51ff000 ldr pc, [pc, #-0] ; d6008040 <cfun_addr>
...
d6008040 <cfun_addr>:
d6008040: d60084c4 strle r8, [r0], -r4, asr #9最后,如果你想进入现代的手臂世界,手臂和拇指是混合的,或者可以(例如,使用bx lr而不是mov pc,lr),那么您将需要使用bx。
add lr,pc,#4
ldr r1,cfun_addr
bx r1
...
cfun_addr:
.word cfun当然,您需要另一个寄存器才能做到这一点,如果您想要保存链接寄存器,请记住在调用C之前和之后推动和弹出链接寄存器和其他寄存器。
发布于 2016-10-14 12:00:40
最小可运行armv7示例
这个问题归结为“什么是ARM呼叫约定(AAPCS)”。一个例子a.S
/* Make the glibc symbols visible. */
.extern exit, puts
.data
msg: .asciz "hello world"
.text
.global main
main:
/* r0 is the first argument. */
ldr r0, =msg
bl puts
mov r0, #0
bl exit然后在Ubuntu 16.04上:
sudo apt-get install gcc-arm-linux-gnueabihf qemu-user-static
# Using GCC here instead of as + ld without arguments is needed
# because GCC knows where the C standard library is.
arm-linux-gnueabihf-gcc -o a.out a.S
qemu-arm-static -L /usr/arm-linux-gnueabihf a.out输出:
hello world在更复杂的例子中最容易犯的错误是忘记堆栈必须是8字节对齐的。例如,你想:
push {ip, lr}而不是:
push {lr}GitHub上的推广样板:https://github.com/cirosantilli/arm-assembly-cheat/blob/82e915e1dfaebb80683a4fd7bba57b0aa99fda7f/c_from_arm.S的例子
发布于 2011-12-07 21:01:59
您需要armeabi-v7a的规范,描述调用堆栈、寄存器(被调用者和调用者)等等。然后查看编译的C代码的程序集输出的语法等等。当尝试在共享库或可重定位的对象中调用函数时,事情要复杂得多。
https://stackoverflow.com/questions/8422287
复制相似问题