2011-11-05 210 views
1

我需要從ARM彙編語言例程中調用printf。我寫了一個可以執行相同操作的c程序(printf("%d.%d",1,2))。我反編譯了編譯器的輸出,但是如何傳遞格式字符串並不明顯。你們有沒有一個代碼的例子來做到這一點?從ARM彙編語言中調用c函數printf

這是我用來測試如何調用printf的測試c例程。

#include <stdio.h> 
#include <stdlib.h> 

int main(void) { 
     printf("%d.%d\n",1,2); 
     return EXIT_SUCCESS; 
} 

我的主程序如下所示拆卸:

000081c4 <main>: 
81c4:  e1a0c00d  mov  ip, sp 
81c8:  e92dd800  stmdb sp!, {fp, ip, lr, pc} 
81cc:  e24cb004  sub  fp, ip, #4  ; 0x4 
81d0:  e59f0014  ldr  r0, [pc, #20] ; 81ec <.text+0x11c> 
81d4:  e3a01001  mov  r1, #1 ; 0x1 
81d8:  e3a02002  mov  r2, #2 ; 0x2 
81dc:  eb000212  bl  8a2c <_IO_printf> 
81e0:  e3a03000  mov  r3, #0 ; 0x0 
81e4:  e1a00003  mov  r0, r3 
81e8:  e89da800  ldmia sp, {fp, sp, pc} 
81ec:  00060120  andeq r0, r6, r0, lsr #2 

我看到跳轉到_IO_printf套路,但我不明白如何將它傳遞的格式字符串。

+0

如果你附加了反彙編的相關部分,它會更容易解釋(我們也可以確定我們說的是相同的語言方言)。 – user786653

+0

請看我更新的問題。 – ziggle314

+0

看起來格式字符串位於'00060120'。請注意,最後解碼的指令實際上並不意味着被解釋爲指令。 – user786653

回答

0

在C中,一個字符串存儲爲一個字節序列。當你將一個字符串傳遞給一個函數時,你實際上是在字符串中傳遞了第一個字符的地址。

當您調用printf()(沒有編譯器優化)時,參數將以相反的順序(即從右到左)推入堆棧。然後printf()彈出第一個參數,它是(指向)格式字符串的指針。它分析格式字符串以確定每個連續參數要彈出多少個字節,以及如何根據它們表示的數據類型(int,string等)來解釋它們。

更新:正如其他人指出的,ARM處理器使用不同的調用約定。它不是使用堆棧,而是傳遞寄存器中的第一個參數。但是這些參數的內容與它們在堆棧中傳遞時的內容相同。 R0將包含一個指向格式字符串的指針,下面的等效代碼仍然是準確的。

感謝那些提供更正的人。

所以,至少至於printf()而言,你的代碼是相同的:

const char formatString[] = "%d.%d"; 
printf(&formatString[0], 1, 2); 
+0

請跟我來!我想你知道我需要知道什麼。看到我更新的問題。 – ziggle314

+3

ARM調用約定不會將參數堆棧用於參數,除非您的參數超過4個。 –

+0

請參閱dwelch的答案,該答案非常清晰和完整。 +1給你! –

0

我看到跳轉到_IO_printf套路,但我不明白怎麼傳它是格式字符串。

清潔你的眼鏡。寄存器R0是字符串的地址,R1是「1」,R2是「2」。 Adam Liss是錯誤的,在ARM中,您使用R0-R4作爲前4個函數參數。

81d0: e59f0014 ldr r0, [pc, #20] ; 81ec <.text+0x11c>

加載這個地址存儲在返回到R0背後的功能的「尾巴」。

2
#include <stdio.h> 
#include <stdlib.h> 

int main(void) { 
     printf("%d.%d\n",1,2); 
     return EXIT_SUCCESS; 
} 

編譯和拆機:

0000842c <main>: 
    842c: e92d4008 push {r3, lr} 
    8430: e3a01001 mov r1, #1 
    8434: e3a02002 mov r2, #2 
    8438: e59f0008 ldr r0, [pc, #8] ; 8448 <main+0x1c> 
    843c: ebffffcc bl 8374 <_init+0x44> 
    8440: e3a00000 mov r0, #0 
    8444: e8bd8008 pop {r3, pc} 
    8448: 00008524 andeq r8, r0, r4, lsr #10 

r0是第一參數,格式字符串,R 1是所述第二參數A 1,R 2,第三參數A 2.格式字符串是一個字符串,一個指向字節數組的指針。 r0加載該指針,即一個字節字符串的地址。在這種情況下,該地址是0x8524。

,如果你很好奇,你可以去看看0x8524,看看你的字符串,

8524: 252e6425 strcs r6, [lr, #-1061]! ; 0xfffffbdb 
8528: 00000a64 andeq r0, r0, r4, ror #20 

0x25,0x64,0x2E之間,0x25,0x64,的0x0A,爲0x00

同樣,在你的拆裝地址你的字符串是

81d0:  e59f0014  ldr  r0, [pc, #20] ; 81ec <.text+0x11c> 
... 
81ec:  00060120  andeq r0, r6, r0, lsr #2 

如果你看看你的反彙編地址0x60120你會看到你的字符串。