Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/67.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/assembly/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何从ARM组件调用C函数?_C_Assembly_Arm_Gnu Assembler_Cortex A8 - Fatal编程技术网

如何从ARM组件调用C函数?

如何从ARM组件调用C函数?,c,assembly,arm,gnu-assembler,cortex-a8,C,Assembly,Arm,Gnu Assembler,Cortex A8,我正在编写针对Android设备上的ARM Cortex-A的代码(使用GNU汇编程序和编译器),并尝试在汇编和C之间进行接口。特别是,我对从汇编调用用C编写的函数感兴趣。我尝试了很多方法,包括.extern指令,用asm和\uuuuuasm\uuuuu声明C函数等等,但都不起作用,所以我正在寻找一个这样做的最小示例。同样欢迎参考此类示例。您需要armeabi-v7a的规范,描述调用堆栈、寄存器(被调用方与调用方)等。然后查看编译的C代码的汇编输出,了解语法,等等。当试图调用共享库或可重定位对象

我正在编写针对Android设备上的ARM Cortex-A的代码(使用GNU汇编程序和编译器),并尝试在汇编和C之间进行接口。特别是,我对从汇编调用用C编写的函数感兴趣。我尝试了很多方法,包括
.extern
指令,用
asm
\uuuuuasm\uuuuu
声明C函数等等,但都不起作用,所以我正在寻找一个这样做的最小示例。同样欢迎参考此类示例。

您需要armeabi-v7a的规范,描述调用堆栈、寄存器(被调用方与调用方)等。然后查看编译的C代码的汇编输出,了解语法,等等。当试图调用共享库或可重定位对象中的函数时,事情就更复杂了。

正如Brett所说,您真正需要做的就是将正确的值放入正确的寄存器中,并通过指向函数地址的链接进行分支。您需要知道编译后的函数将覆盖哪些寄存器,以及在返回之前将恢复哪些寄存器——这些都写在infocenter.arm.com上的ABI文档中。您还需要确保堆栈寄存器设置为编译器期望的值,也可能设置其他寄存器(对于PIC模式?)

但是,您真的需要在汇编文件中编写代码吗

如果您使用GCC的“asm”特性,那么您可以将汇编程序片段(只要您愿意)嵌入到常规的C函数中,并在更方便的时候返回到C中

在有些情况下,有C gubbins是不行的,但是如果你能调用C函数,我猜你不在其中


说到这里,为什么你需要使用汇编程序呢。。。。无论如何,C基本上是高级汇编程序?

您需要阅读ARM和/或了解指令集的全部内容,通常您会希望执行类似的操作

asm:

bl cfun

c:
void cfun ( void )
{

}
你可以自己试试。对于gnu-as和gcc,这很好,如果您使用clang将c代码发送到对象,而gnu-as用于汇编器,它也应该很好。不知道你在用什么

上述问题是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)
因此,如果你让你的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

当然,您需要另一个寄存器来执行此操作,如果您想保留链接寄存器和另一个寄存器,请记住在调用C之前和之后按下并弹出链接寄存器和另一个寄存器。

最小可运行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上的示例和通用的样板:

@user606723我考虑过这一点,但C使用带有函数声明的头文件在不同文件之间进行通信。这不是完全不同的情况吗?编译器查看头文件中函数的声明来编译调用。您需要手动执行同样的操作。例如,如果您还不知道调用约定以了解用于传递参数的寄存器,请执行以下两种操作之一,编写一些C代码来调用您的函数,然后反汇编以查看编译器执行了什么操作。正确的答案是查找其他人给你指出的调用约定。你是对的,我只演示了如何让ARM指令调用函数,而不是让thumb指令调用C函数,我可以编辑答案,并向你演示如何做……你提到了cortex a,所以我假设你正在运行ARM指令绝大多数情况下都不是拇指,利用你的马力,而不是一些总线限制的东西。正如Brett提到的可重新定位对象可能会使其变得更复杂,你需要使cfun_addr全局化,任何加载可重新定位对象的人都需要在使用它之前修改cfun_addr。尊重老定时器!哇,那是不受欢迎的。。。但没人说为什么?OP不是问如何输出hello world。他想调用一个
C
函数。@Samhammay不是
put
C函数吗?:-)
push {ip, lr}
push {lr}