This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

Linker generates wrong call from thumb to arm in blx instruction

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)