2013-04-10 116 views
2

我正在裸機ARM上編寫sdram測試程序。我用C編寫它,但現在我想修改生成的程序集以防止程序使用sdram,這意味着除其他外,沒有堆棧。瞭解彙編堆棧操作

我最近開始學習ARM程序集,並且我不明白編譯器生成的程序集是如何在以下代碼中使用堆棧的(並且我沒有通過閱讀ARM ARM:/找到答案)。 32位變量值被放置在堆棧上,但爲什麼在功能開始時保持3次32位?有人可以在這裏解釋堆棧操作嗎?

C代碼:

/* ugly to have it as global but it reduces stack usage*/            
unsigned int const led_port[]= {0,0,1,1,2,2,3,3,4,4}; 
unsigned int const led_value_on[]={0x90,0x9,0x90,0x9,0x90,0x9,0x90,0x9,0x90,0x9};      
unsigned int const masks[] = {0xf0,0xf,0xf0,0xf,0xf0,0xf,0xf0,0xf,0xf0,0xf};       
unsigned int const led_value_off[]={0x80,0x8,0x80,0x8,0x80,0x8,0x80,0x8,0x80,0x8};      

void gbe_led_on(int i) 
{       
     unsigned int value = 0;                     
     phy_read(led_port[i], 0x10, &value);                 
     value &= ~masks[i]; 
     value |= led_value_on[i];                    
     phy_write(led_port[i], 0x10, value); 
} 

生成組件(從GCC-臂精靈):

 <gbe_led_off>: 
push {r4, r5, r6, lr}  /* ;reserve space on the stack for 3 32 bits variables + return address */ 
ldr  r5, [pc, #84] ; ffff1578 <gbe_led_off+0x60> /*r5=led_port (array base address) */ 
sub  sp, sp, #8    /* sp = sp-8 (decimal 8) what does it point to??*/ 
ldr  r4, [r5, r0, lsl #2] /* r4 = *(led_port+i)&0x00ff, (shift from 16 bits) */ 
add  r2, sp, #8    /* r2 = sp+8 (decimal 8) why???*/ 
mov  r6, r0     /* r6 = i */ 
mov  r3, #0     /* r3 = 0 */ 
mov  r0, r4     /* r0 = led_port[i]*/ 
str  r3, [r2, #-4]!   /* r3 = *(sp+8-4); update r2, to which value???*/ 
add  r5, r5, r6, lsl #2  /* r5 = led_port[i] & 0x00ff */ 
mov  r1, #16     /* r1 = 16 (decimal) */ 
bl  ffff13f8 <phy_read>  /* call phy_read with arguments on r0, r1, r2*/ 
ldr  r1, [r5, #40] ; 0x28 /* r1 = masks[i] */ 
ldr  r3, [sp, #4]   /* r3 = *(sp+4) ????*/ 
ldr  r2, [r5, #120] ; 0x78 /* r2 = led_value_on[i] */ 
bic  r3, r3, r1    /* value &= masks[i] */ 
orr  r3, r3, r2    /* value |= led_value_on[i] */ 
mov  r0, r4     /* r0 = led_port[i] */ 
mov  r2, r3     /* r2 = value */ 
mov  r1, #16     /* r1 = 16 */ 
str  r3, [sp, #4]   /* *(sp+4) = value; why do we do that???*/    
bl  ffff13cc <phy_write> /* branch to phy_write with arguments on r0,r1,r2*/ 
add  sp, sp, #8    /* sp = sp+8 restore stack pointer before pop? */ 
pop  {r4, r5, r6, pc}  /* remove 4 bytes from the stack and branch to return address */ 
.word 0xffff1a30 

回答

3

推是保存寄存器r4r5r6所有這些必須根據ARM編程模型進行保存。 lr的推動是爲了保存返回地址,因爲您正在調用其他將修改它的函數。堆棧中的sub 8保留另外8個字節的內存用於其他變量使用(value變量) - 稍後用於str r3, [2, #-4]行。此外,分支鏈接blphy_readphy_write也可能正在修改堆棧空間,因此堆棧內存問題可能比您想象的要大。另外,最後一次關於4個字節的流行評論是不正確的 - 它釋放了16個字節的空間。

現在,你將有什麼樣的資源可用RAM方式使用?你需要一些東西,否則你的unsigned int value將不會有任何工作的地方不提及你的電話。你必須有可用的東西。如果你這樣做,你可以通過鏈接器腳本和section指令告訴你的C程序,節省你編譯器的麻煩。

+0

phy_read不使用堆棧(內聯啓用),並且是我的程序中最深的功能。我沒有比寄存器更明確的RAM資源,這就是問題所在:/我打算在修改程序集後刪除內聯函數調用並聲明裸函數。 – 2013-04-11 06:13:51

+0

這是一個具有浮點的ARM芯片嗎?如果是這樣,如果需要,可以將這些寄存器用作「工作RAM」。另外,爲了確保,您正在以ARM模式進行編程,而不是Thumb。最後,在用戶模式和超級用戶模式之間交換時可以使用一堆寄存器。鑑於這一切,你可能可以在沒有RAM的情況下完成這項工作。 – 2013-04-11 15:55:36

+0

沒有可用的浮點數,但是我可以使用寄存器列表(配置寄存器,不是「CPU寄存器」)中的4個32位「通用讀/寫寄存器」。是的,我在ARM模式下編程。 – 2013-04-12 09:11:59