[英]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.