簡體   English   中英

在ARM上將參數從asm傳遞到C

[英]Passing arguments from asm to C in on 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函數:

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

但我的表現並不好。 那么,如何訪問C代碼中的寄存器?

可以肯定的是,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之類的東西。

displayRegistersValue(int registers[number_of_registers])

這是一個數組,而不是結構,並作為指向某些對象(而不是一長串項目)的指針傳遞。 順便說一句,結構順便說一句。

通常最簡單的方法是構造一個C函數,該函數在asm中執行您想要的操作,然后查看編譯器生成的內容,然后從那里開始(使用ABI文檔進行確認,等等)。

#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)

您將需要執行類似的操作,通過添加到堆棧指針來在堆棧上騰出空間,保存lr,以便不將其與分支鏈接一起丟棄,將寄存器復制到該內存(堆棧)中,將r0指向起始地址。要傳遞的內存/數組,然后調用該函數(r0是要傳遞給該函數的第一個也是唯一的參數)。

push {lr} 
mov lr,sp 
stmdb sp!,{r0-r12} 
mov r0,lr 
bl displayRegistersValue
add sp,sp,#52
pop {lr}

數組作為指針傳遞到單個寄存器中。 如果要5個寄存器,則需要5個參數(int i1,int i2等)。

引用ARM APCS文檔:

“前四個寄存器r0-r3(a1-a4)用於將參數值傳遞給子程序並從函數返回結果值。它們也可用於在例程中保存中間值(但一般來說,只在子程序調用之間。)“

因此,如果要將超過4個值傳遞給C函數,則需要傳遞堆棧上的其余值。 更好的主意是將寄存器值放在已靜態分配的內存區域中,並將內存(指針)的地址傳遞給C函數。 函數可以取消引用指針以獲取寄存器值。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM