[英]Understanding gcc behaviour regarding AAPCS (on STM32)
編輯:我完全知道函數asmCopy可能不是functionnal,我的問題更多是關於gcc的有關在寄存器中傳遞的參數的行為。
我正在使用構建器為arm-none-eabi-gcc的STM32CubeIDE開發STM32H7
優化級別為-Os
我看到以下無法解釋的行為。 我進行了屏幕截圖,以獲取並行的asm和C代碼。
我的C代碼正在調用3個函數。 第一個和第三個具有完全相同的參數。
第二個不帶參數。 這是它的代碼:
static void Reset_Cycle_Counter(void)
{
volatile unsigned long *DWT_CYCCNT = (unsigned long *)0xE0001004;
volatile unsigned long *DWT_CONTROL = (uint32_t *)0xE0001000;
// Reset cycle counter
*DWT_CONTROL = *DWT_CONTROL & ~0x00000001 ;
*DWT_CYCCNT = 0;
*DWT_CONTROL = *DWT_CONTROL | 1 ;
}
第三個功能很特別:我正在嘗試編寫一些匯編代碼(現在可能很錯誤)。
static void __attribute__((noinline)) asmCopy(void *dst, void *src, uint32_t bytes)
{
while (bytes--)
{
asm("ldrb r12,[r1], #1"); // src param is stored in r1, r12 can be modified without being restored after
asm("strb r12,[r0], #1"); // dst paramis stored in r0
}
}
在第一個函數調用(對memcpy)之前,向r0,r1和r2加載正確的值。
然后,在調用第三個函數之前,您可以在下面看到r1和r2中的參數錯誤(qspi_addr應該為0x90000000)。
我對AAPCS(ARM上的過程調用標准)的理解是,在調用子例程之前,應將函數的參數(如果有的話)裝入寄存器r0至r3。 並且子例程不需要保留或還原這些寄存器。 然后,第二個函數修改r1和r2是正常的。 因此,我希望編譯器在第三個調用之前更新r0,r1和r2。
如果將優化代碼更改為-O0,則確實可以達到預期的效果。
你怎么看 ?
您不能只打開一個內聯匯編塊並假定r0和r1仍然包含函數參數。 對此沒有任何保證。 如果需要使用參數,則需要正確地將其作為輸入和/或輸出操作數傳遞
static void __attribute__((noinline))
myAsmCopy(void* dst, void* src, uint32_t bytes) {
asm volatile("1: cbz %[bytes], 1f \n"
"ldrb r12, [%[src]], #1 \n"
"strb r12, [%[dst]], #1 \n"
"subs %[bytes], #1 \n"
"b 1b \n"
"1: \n"
: [dst] "+&r"(dst), [src] "+&r"(src), [bytes] "+&r"(bytes)
:
: "cc", "memory", "r12");
}
GCC在此處提供了有關內聯匯編的大量文檔: https : //gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html
由於您顯然從未使用過任何一種方法,因此我必須對此提出嚴重建議。 如果“ C包含腳槍”,則內聯匯編會將6發左輪手槍放5枚子彈到您的頭部。
如果您嘗試詢問編譯器如何對其進行存檔,一切將變得更加容易
void __attribute__((noinline)) asmCopy(void *dst, void *src, uint32_t bytes)
{
while (bytes--)
{
asm("ldrb r12,[r1], #1"); // src param is stored in r1, r12 can be modified without being restored after
asm("strb r12,[r0], #1"); // dst paramis stored in r0
}
}
void __attribute__((noinline)) asmCopy1(void *dst, void *src, uint32_t bytes)
{
while (bytes--)
{
*(uint8_t *)dst++ = *(uint8_t *)src++;
}
}
和代碼
asmCopy:
.L2:
adds r2, r2, #-1
bcs .L3
bx lr
.L3:
ldrb r12,[r1], #1
strb r12,[r0], #1
b .L2
asmCopy1:
subs r0, r0, #1
add r2, r2, r1
.L5:
cmp r1, r2
bne .L6
bx lr
.L6:
ldrb r3, [r1], #1 @ zero_extendqisi2
strb r3, [r0, #1]!
b .L5
我想我找到了答案。
在我正在測試的函數中(無論是我實現的最糟糕的函數,還是來自@Vinci的更好的函數),傳遞給函數的某些參數是全局變量(用於執行某些測試的虛擬數據數組)。
我的理解是,編譯器“修改”函數的原型以僅使用一個參數來構建函數。 其他參數被視為常量,僅在函數開始時相對加載了PC。
因此,我修改了代碼以調用完全相同的函數,但使用了本地易失性指針,問題消失了:我可以看到寄存器r0,r1和r2加載了預期的參數。
是否有意義 ?
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.