在ARM上将参数从asm传递到C

在ARM上将参数从asm传递到C,c,assembly,arm,C,Assembly,Arm,我在这个论坛上读了很多话题,找到了很多关于这个话题的答案。我实现了从汇编代码向C函数传递5个参数。为此,我使用了以下说明: mov r0, #0 mov r1, #1 mov r2, #2 mov r3, #3 mov r4, #4 STR r4, [sp, #-4]! BL displayRegistersValue 但是今天我试图将整个寄存器传递给C函数,以将它们保存在C结构中。我试着用这个指令: STMDB sp!, {registers that i want to save} 我的

我在这个论坛上读了很多话题,找到了很多关于这个话题的答案。我实现了从汇编代码向C函数传递5个参数。为此,我使用了以下说明:

mov r0, #0
mov r1, #1
mov r2, #2
mov r3, #3
mov r4, #4
STR r4, [sp, #-4]!
BL displayRegistersValue
但是今天我试图将整个寄存器传递给C函数,以将它们保存在C结构中。我试着用这个指令:

STMDB sp!, {registers that i want to save}
我的C函数:

displayRegistersValue(int registers[number_of_registers])
char printable = registers[0] + (int)'0'; // Convert in a printable character
print_uart0(&printable);

但是我的表现不好。那么,如何在C代码中访问寄存器呢?

数组作为指针在单个寄存器中传递。如果需要5个寄存器,则需要有5个参数(int i1、int i2等)。

非常确定ARM标准只允许R0-R3通过值传递,因此最大值为4。如果需要更多值,则将它们推到堆栈上,并以这种方式访问它们-就像编译器那样。或者创建一个结构并传递其地址

好的,双重检查,我是对的,这是一个到ARM调用约定的链接-向下一点页面

要执行所需操作,请将某个内存位置(数组)的地址传递到汇编例程中。一旦你有了这个地址,可能在r0之内,你就可以使用stmdb了!在该位置中,所有寄存器值和内存都可以在C级别查看

小心,这可能不会像你认为的那样。根据上面的调用约定链接,这些值可以更改很多。如果这是为了调试,最好使用调试器并以这种方式查看寄存器

好了,你还是不明白:


{
    int registerValues[14];

    myAsmRoutine(registerValues);

    print_uart0(& registerValues);
}

myAsmRoutine:
    stmia  r0!, {r1-r14}
    blx   lr


我跳过了R0和PC,但你明白了。此外,您还需要做一些稍微复杂的事情来将值更改为可打印的格式—sprintf或itoa os之类的格式。

引用ARM APCS文档:

前四个寄存器r0-r3(a1-a4)用于将参数值传递给子例程,并从函数返回结果值。它们也可用于保存例程内的中间值(但通常仅在子例程调用之间)

因此,如果要向C函数传递4个以上的值,则需要传递堆栈上的其余值。更好的方法是将寄存器值放在静态分配的内存区域中,并将内存地址(指针)传递给C函数。该函数可以取消对指针的引用,以获取寄存器值

displayRegistersValue(int registers[number_of_registers])
这是一个数组而不是一个结构,作为指向某个对象的指针传递,而不是作为一个长的项目列表传递。顺便说一句,结构也是如此

通常最简单的方法是构造一个在asm中实现所需功能的C函数,然后查看编译器生成的内容,然后从那里开始(使用ABI文档进行确认,等等)


好的,如果我理解了,我需要在我的C函数中有13个参数,如果我想传递13个寄存器?还有别的办法吗?您说过数组作为指针在单个寄存器中传递。因此它假设指针存储在r0中。但是存储了什么呢?指针的地址或值?好的,所以我必须将函数参数的数量设置为我要保存的寄存器的数量?传递第1个参数-一个内存地址。该地址存储在寄存器中,用于保存您的值。在
STMDB
之前/之后,您需要
mov r0,sp
。这将传递指向“C”例程的指针作为第一个参数。那你的代码应该能用,我不指望。您永远不知道编译器想要保存到堆栈中的内容。这个,其他垃圾,等等。只给它自己的地址更安全。尽管如此,我认为OP不理解指针,这是一个障碍;它不应该覆盖以前的堆栈帧。
sp表示保存后更新堆栈指针。他似乎在使用EABI.+1的正确堆栈方向来提及
objdump
objdump
是了解汇编程序的人诊断许多问题的绝佳工具。谢谢大家,今晚我将尝试你们所有的解决方案。
#define NUMREGS 13
void displayRegistersValue(unsigned int registers[NUMREGS]);
void outer ( void )
{
    unsigned int regs[NUMREGS];
    displayRegistersValue(regs);
}

> arm-none-linux-gnueabi-gcc -O2 -c fun.c -o fun.o
> arm-none-linux-gnueabi-objdump -D fun.o

fun.o:     file format elf32-littlearm


Disassembly of section .text:

00000000 <outer>:
   0:   e52de004    push    {lr}        ; (str lr, [sp, #-4]!)
   4:   e24dd03c    sub sp, sp, #60 ; 0x3c
   8:   e28d0004    add r0, sp, #4
   c:   ebfffffe    bl  0 <displayRegistersValue>
  10:   e28dd03c    add sp, sp, #60 ; 0x3c
  14:   e49df004    pop {pc}        ; (ldr pc, [sp], #4)
push {lr} 
mov lr,sp 
stmdb sp!,{r0-r12} 
mov r0,lr 
bl displayRegistersValue
add sp,sp,#52
pop {lr}