2013-02-12 73 views
2

我在這個論壇上閱讀了很多主題,並在這個主題上找到了很多答案。我實現了將5個參數從我的彙編代碼傳遞給C函數。這樣做的,我使用的指令如下:將參數從asm傳遞到C上ARM

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代碼中的寄存器呢?

+0

'STMDB'之前/之後,你需要'mov r0,sp'。這將傳遞一個指向'C'例程的指針作爲第一個參數。那麼你的代碼應該工作。 – 2013-02-12 16:54:23

+0

我不會指望它。你永遠不知道編譯器想要保存到堆棧中。這個,其他垃圾等。更安全的就是給它地址本身。不過,我不認爲OP理解指針,這是阻礙。 – 2013-02-12 16:57:47

+0

編譯器會保留它需要在堆棧上的空間;它不應該覆蓋以前的堆棧幀。 'sp!'表示在保存後更新堆棧指針。他似乎正在爲EABI使用正確的堆棧方向。 – 2013-02-12 21:20:00

回答

5

很確定ARM標準只允許R0-R3按值傳遞,所以最大值爲4。如果你需要更多的值,那麼將它們推到堆棧上並以這種方式訪問​​它們 - 就像編譯器一樣。或者創建一個結構並傳遞它的地址。

好吧,加倍了cheked,我是正確的here是一個鏈接到ARM調用約定 - 下了一頁。

要做你想做的事,把一些內存位置(一個數組)的地址傳給你的程序集例程。一旦你有了這個地址,可能在r0之內,你可以stmdb!進入該位置的所有寄存器值,並且該內存將在C級別可見。

請注意,這可能不會做你認爲會的事。根據上述調用約定鏈接,這些值可以改變很多。如果這是爲了調試,最好使用調試器並以這種方式觀察寄存器。

好吧,你仍然不理解這裏:


{ 
    int registerValues[14]; 

    myAsmRoutine(registerValues); 

    print_uart0(& registerValues); 
} 

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

我跳過R0和PC,但你的想法。此外,你需要做一些複雜的事情來將值更改爲可打印的格式 - sprintf或itoa os類似的東西。

+0

好了,所以我不得不把函數的參數的個數設置爲我要保存寄存器的數量? – deletMe 2013-02-12 16:37:25

+0

第1個參數被傳遞 - 一個地址到內存。該地址存儲在寄存器中並用於保存您的值。 – 2013-02-12 16:41:58

+0

分貝,IA - 這個概念是固定的... – 2013-02-12 21:40:29

0

數組作爲指針傳遞到單個寄存器中。如果你想要5個寄存器,那麼你需要有5個參數(int i1,int i2等)。

+0

好了,如果我的理解,我需要在我的C函數13個參數,如果我想通過13個寄存器?有另一種方法嗎?你說過一個數組是作爲一個指針傳遞的,所以在一個寄存器中。所以它假定指針存儲在r0中。但是存儲的是什麼?指針的地址或值? – deletMe 2013-02-12 16:28:35

0

爲了從ARM APCS文檔引用:

「前四個寄存器R0-R3(A1〜A4)被用於參數值傳遞到一個子程序,並返回從函數的結果值它們可以也可用於保存例程中的中間值(但通常只在子例程調用之間)。「

所以,如果你想傳遞超過4個值到一個C函數,你需要傳遞堆棧上的其餘值。更好的辦法是將寄存器值放入靜態分配的內存區域,並將內存地址(指針)傳遞給C函數。指針可以被函數取消引用以獲得寄存器值。

2
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} 
+0

+1一樣:)用於提'objdump'。對於瞭解彙編程序診斷許多問題的人來說,objdump是一個很好的工具。 – 2013-02-12 22:35:15

+0

非常感謝,我會在今晚嘗試所有的解決方案。 – deletMe 2013-02-13 13:52:30