![](/img/trans.png)
[英]unsigned int is not uint32_t when compile to cortex-m0 — possible C compiler flag issue
[英]Why GCC (ARM Cortex-M0) generates UXTB instruction when it should know that data is already uint8
我正在使用 NXP (LPC845) 的 Cortex-M0 MCU,我試圖弄清楚 GCC 想要做什么:)
基本上,C代碼(偽)如下:
volatile uint8_t readb1 = 0x1a; // dummy
readb1 = GpioPadB(GPIO_PIN);
我寫的宏是
(*((volatile uint8_t*)(SOME_GPIO_ADDRESS)))
現在代碼正在運行,但它產生了一些我不明白的額外 UXTB 指令
00000378: ldrb r3, [r3, #0]
0000037a: ldr r2, [pc, #200] ; (0x444 <AppInit+272>)
0000037c: uxtb r3, r3
0000037e: strb r3, [r2, #0]
105 asm("nop");
我的解釋如下:
為什么會這樣?
首先,它應該知道 R3 中的數據只有一個 BYTE 的含義(它已經正確生成了 LDRB)。 其次,STRB 已經可以修整 7..0 LSB 那么為什么要使用 UXTB 呢?
感謝您的澄清,
編輯:編譯器版本:
gcc 版本 9.2.1 20191025(發布)[ARM/arm-9-branch 修訂版 277599](用於 Arm 嵌入式處理器的 GNU 工具 9-2019-q4-major)
我用-O3
看起來像是編譯器留下的額外指令和/或 cortex-m 或更新的內核有一些細微差別(很想知道細微差別是什么)。
#define GpioPadB(x) (*((volatile unsigned char *)(x)))
volatile unsigned char readb1;
void fun ( void )
{
readb1 = 0x1A;
readb1 = GpioPadB(0x1234000);
}
一個apt得到gcc
arm-none-eabi-gcc --version
arm-none-eabi-gcc (15:4.9.3+svn231177-1) 4.9.3 20150529 (prerelease)
Copyright (C) 2014 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
arm-none-eabi-gcc -O2 -c -mthumb so.c -o so.o
arm-none-eabi-objdump -d so.o
00000000 <fun>:
0: 231a movs r3, #26
2: 4a03 ldr r2, [pc, #12] ; (10 <fun+0x10>)
4: 7013 strb r3, [r2, #0]
6: 4b03 ldr r3, [pc, #12] ; (14 <fun+0x14>)
8: 781b ldrb r3, [r3, #0]
a: 7013 strb r3, [r2, #0]
c: 4770 bx lr
e: 46c0 nop ; (mov r8, r8)
10: 00000000 .word 0x00000000
14: 01234000 .word 0x01234000
正如人們所期望的那樣。
arm-none-eabi-gcc -O2 -c -mthumb -march=armv7-m so.c -o so.o
arm-none-eabi-objdump -d so.o
so.o: file format elf32-littlearm
Disassembly of section .text:
00000000 <fun>:
0: 4a03 ldr r2, [pc, #12] ; (10 <fun+0x10>)
2: 211a movs r1, #26
4: 4b03 ldr r3, [pc, #12] ; (14 <fun+0x14>)
6: 7011 strb r1, [r2, #0]
8: 781b ldrb r3, [r3, #0]
a: b2db uxtb r3, r3
c: 7013 strb r3, [r2, #0]
e: 4770 bx lr
10: 00000000 .word 0x00000000
14: 01234000 .word 0x01234000
里面有額外的 utxb 指令
有點新的東西
arm-none-eabi-gcc --version
arm-none-eabi-gcc (GCC) 10.2.0
Copyright (C) 2020 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
對於 armv6m 和 armv7m
00000000 <fun>:
0: 231a movs r3, #26
2: 4a03 ldr r2, [pc, #12] ; (10 <fun+0x10>)
4: 7013 strb r3, [r2, #0]
6: 4b03 ldr r3, [pc, #12] ; (14 <fun+0x14>)
8: 781b ldrb r3, [r3, #0]
a: 7013 strb r3, [r2, #0]
c: 4770 bx lr
e: 46c0 nop ; (mov r8, r8)
10: 00000000 .word 0x00000000
14: 01234000 .word 0x01234000
對於 armv4t
00000000 <fun>:
0: 231a movs r3, #26
2: 4a03 ldr r2, [pc, #12] ; (10 <fun+0x10>)
4: 7013 strb r3, [r2, #0]
6: 4b03 ldr r3, [pc, #12] ; (14 <fun+0x14>)
8: 781b ldrb r3, [r3, #0]
a: 7013 strb r3, [r2, #0]
c: 4770 bx lr
e: 46c0 nop ; (mov r8, r8)
10: 00000000 .word 0x00000000
14: 01234000 .word 0x01234000
並且 utxb 不見了。
我認為這只是一個錯過的優化,窺視孔或其他。
正如已經回答的那樣,當您使用非 gpr 大小的變量時,您可以期望和/或容忍編譯器轉換為寄存器大小。 根據編譯器和目標的不同,它們是在輸入還是輸出時執行(讀取變量時或在寫入或使用之前)。
對於 x86 ,您可以分別訪問寄存器的各個部分(或使用基於 memory 的操作數),您會看到它們不會這樣做(在 gcc 中),即使在明顯需要符號擴展或填充的情況下也是如此。 並在使用該值時將其整理出來。
您可以在 gcc 源中搜索 utxb 並可能查看問題或評論。
編輯
請注意,clang 采用不同的路徑,它會燒掉生成地址的時鍾,但不進行擴展
00000000 <fun>:
0: f240 0000 movw r0, #0
4: f2c0 0000 movt r0, #0
8: 211a movs r1, #26
a: 7001 strb r1, [r0, #0]
c: f244 0100 movw r1, #16384 ; 0x4000
10: f2c0 1123 movt r1, #291 ; 0x123
14: 7809 ldrb r1, [r1, #0]
16: 7001 strb r1, [r0, #0]
18: 4770 bx lr
clang --version
clang version 11.1.0 (https://github.com/llvm/llvm-project.git 1fdec59bffc11ae37eb51a1b9869f0696bfd5312)
Target: armv7m-none-unknown-eabi
Thread model: posix
InstalledDir: /opt/llvm11armv7m/bin
我認為這只是 gcc/gnu 的優化問題。
“volatile”修飾符是罪魁禍首。 它在編寫時不會調用類型擴展,因為它沒有意義。 但是在閱讀時,它總是調用擴展。 因為現在數據存儲在寄存器中,並且必須准備好在可見性限制的整個范圍內進行任何操作。 放棄“volatile”會刪除對數據的任何額外操作,但它也可以刪除使用變量的事實。
首先要知道R3中的data只有一個BYTE的意思
寄存器只有 32 位。 它們沒有任何其他“意義”。 寄存器必須包含與加載字節相同的值 - 因此是 UXTB。 以后的任何其他操作(例如添加一些東西需要整個寄存器包含正確的值。
一般來說,使用比 32 位更短的類型通常會增加一些開銷,因為 Cortex-Mx 處理器不對寄存器的“部分”進行操作。
要解決此問題,您需要在https://gcc.gnu.org/bugzilla/ 提交錯誤。 但是有兩種困難的情況。
我的個人意見: GCC 將 ARM kernel 寄存器視為快速 ZCD69B49357F06CD8E298D7 的一部分。 這個 memory 可以通過物理地址訪問,這只會增加問題。 那么,如果這個是memory,並且尺寸不匹配,那么,根據GCC,需要添加擴展命令。 為什么GCC在簡單訪問時使用正確的命令? - 好吧,他從 memory 到 memory 讀取。 強調 - “從記憶中”。 無論接下來發生什么,您都需要立即閱讀。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.