We are running a survey to help us improve the experience for all of our members. If you see the survey appear, please take the time to tell us about your experience if you can.
Version 11.2-2022.02 of the GNU Toolchain contains a bug in the encoding of calls using blx instruction from thumb to arm instructions. When the size of the jump is exactly 16MB + 2, the jump is encoded as a jump of 2 instead of indirect jump. Next code reveals this error.
__attribute__((target("arm"))) int __attribute__ ((noinline)) f(); #define DIRECT_CALL \ asm ("NOP"); #define ERROR_CALL \ DIRECT_CALL \ asm ("NOP"); \ asm ("NOP"); \ asm ("NOP"); \ asm ("NOP"); #define INDIRECT_CALL \ ERROR_CALL \ asm ("NOP"); \ asm ("NOP"); \ asm ("NOP"); __attribute__((target("thumb"))) int main() { asm ("NOP"); asm ("NOP"); f(); //DIRECT_CALL ERROR_CALL //INDIRECT_CALL int k = f(); return k; } #define SIZE_DATA 0xfffe38 //char x[SIZE_DATA] __attribute__((section(".text"))); // fill in memory to make main() and f() almost 2^24 bytes apart. int x[SIZE_DATA >> 2] __attribute__((section(".text"))); // fill in memory to make main() and f() almost 2^24 bytes apart. __attribute__((target("arm"))) int __attribute__ ((noinline)) f() { x[(SIZE_DATA >> 2) - 1] = 12; static int i = 0; i++; asm ("NOP"); return i + x[(SIZE_DATA >> 2) - 1]; // make sure nothing is optimized }
To reproduce the error the example must be compiled using
arm-none-eabi-g++ -std=gnu++17 -mcpu=cortex-a9 -mfpu=vfpv3 -fdata-sections -ffunction-sections -mfloat-abi=hard -O3 -save-temps=obj -fverbose-asm --specs=nosys.specs $TEST_FILE
and the result must be disassembled using
arm-none-eabi-objdump -d a.out > a.s
In the resulting a.s the first call to function f() is encoded as:
8036: f000 e800 blx 8038 <main+0x8>
just a jump of offset 2 from address 8036. This is wrong.
The test has been compiled with AArch32 bare-metal target (arm-none-eabi)