簡體   English   中英

STM32 相同的while 循環代碼但編譯為不同的匯編代碼

[英]STM32 same while loop code but compiled to different assembly code

我正在 stm32F411RE 板(Cortex-M4)上學習 RTOS。 我使用 MDK uVision v5。 我遇到了 C 代碼while loop的問題。 下面的代碼在我的項目和講師的項目(在 Udemy 上)完全相同,但是,在編譯這兩個項目(在我的 PC 上)后,匯編代碼看起來不同。 我想問一下是什么讓這不同。 謝謝你。

void osSignalWait(int32_t *semaphore)
{
    __disable_irq();
    while(*semaphore <=0)
    {       
            __disable_irq();        
            __enable_irq();
    }
    *semaphore -= 0x01;
    __enable_irq();
}

在調試視圖(見圖)中,如果條件不匹配,則不會去加載實際值LDR r1,[r0, #0x00]然后進行比較。 相反,它比較並在 while 循環內執行命令。 我的代碼編譯調試視圖 我的代碼編譯如下

   100: void osSignalWait(int32_t *semaphore) 
   101: { 
0x08001566 4770      BX            lr
   102:         __disable_irq(); 
   103:         while(*semaphore <=0) 
   104:         {               
0x08001568 B672      CPSID         I
   101: { 
   102:         __disable_irq(); 
   103:         while(*semaphore <=0) 
   104:         {               
0x0800156A 6801      LDR           r1,[r0,#0x00]
0x0800156C E001      B             0x08001572
   105:                         __disable_irq();                 
0x0800156E B672      CPSID         I
   106:                         __enable_irq(); 
   107:         } 
   108:         *semaphore -= 0x01; 
0x08001570 B662      CPSIE         I
0x08001572 2900      CMP           r1,#0x00
0x08001574 DDFB      BLE           0x0800156E
0x08001576 1E49      SUBS          r1,r1,#1
   109:         __enable_irq(); 
0x08001578 6001      STR           r1,[r0,#0x00]
0x0800157A B662      CPSIE         I
   110: } 

如果我編譯講師(在 Udemy 上)的代碼(在我的 PC 上使用他的項目),匯編代碼看起來會有所不同(while 循環代碼完全相同)。 它會再次加載實際值並進行比較。 教師代碼編譯調試視圖 下面編譯的講師代碼(在我的電腦上編譯)

100: void osSignalWait(int32_t *semaphore) 
   101: { 
0x08000CDE 4770      BX            lr
   102:         __disable_irq(); 
0x08000CE0 B672      CPSID         I
   103:         while(*semaphore <=0) 
   104:         { 
0x08000CE2 E001      B             0x08000CE8
   105:                         __disable_irq();                         
0x08000CE4 B672      CPSID         I
   106:                         __enable_irq();   
   107:         } 
0x08000CE6 B662      CPSIE         I
0x08000CE8 6801      LDR           r1,[r0,#0x00]
0x08000CEA 2900      CMP           r1,#0x00
0x08000CEC DDFA      BLE           0x08000CE4
   108:         *semaphore -= 0x01; 
0x08000CEE 6801      LDR           r1,[r0,#0x00]
0x08000CF0 1E49      SUBS          r1,r1,#1
0x08000CF2 6001      STR           r1,[r0,#0x00]
   109:         __enable_irq(); 
   110:          
   111:          
0x08000CF4 B662      CPSIE         I
   112: } 

由於您沒有告訴編譯器semaphore在此函數執行期間可以更改,因此您的編譯器決定優化您的代碼並僅加載一次信號量的值並在 while 循環中使用其副本,然后僅將結果寫入結尾。 正如現在所寫,編譯器沒有理由認為這可能是有害的。

要通知編譯器一個變量可以在函數外更改,在該函數執行期間,請使用volatile關鍵字,請參閱: https : //en.cppreference.com/w/c/language/volatile

在這種情況下,您的代碼將變為:

void osSignalWait(volatile int32_t *semaphore)
{
    __disable_irq();
    while(*semaphore <=0)
    {       
        __disable_irq();        // Note: I think the order is wrong...
        __enable_irq();
    }
    *semaphore -= 0x01;
    __enable_irq();
}

順便說一句,調用__disable_irq兩次(一次在 while 循環之前,然后在循環內的開始處)然后__enable_irq似乎有點__enable_irq ,您的意思是啟用(並執行某些操作)然后在 while 循環中禁用嗎?

這是眾所周知的keil over優化錯誤。 多次舉報。 擁有內存破壞器,它應該每次都讀取內存。

這是clobbers如何工作的示例

#include <stdint.h>

unsigned x;
volatile unsigned y;


int foo()
{
    while(x < 1000);
}

int bar()
{
    while(x < 1000) asm("":::"memory");
}
foo:
        ldr     r3, .L5
        ldr     r3, [r3]
        cmp     r3, #1000
        bxcs    lr
.L3:
        b       .L3
.L5:
        .word   x
bar:
        ldr     r1, .L11
        ldr     r2, .L11+4
        ldr     r3, [r1]
        cmp     r3, r2
        bxhi    lr
.L9:
        ldr     r3, [r1]
        cmp     r3, r2
        bls     .L9
        bx      lr
.L11:
        .word   x
        .word   999

暫無
暫無

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

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