Hi,
I have a "test_fun1()" function call to a inline ASM "test_fun2()". I found that the caller, "test_fun1()" did not keep the R3 before jump to "test_fun2()", which cause the result of the "test_fun1()" is not correct (inline ASM "test_fun2()" use R3).
The same code works fine with Keil MDK-ARM. It also works when I change the Core from M3 to M0.
Does the "test_fun2()" have any problem/violation?
I will be appreciated if anyone can give some suggestions. Thanks.
Following are some information and the code (It has some differences from the original application code, I create a simple ASM version to reproduces the issue).
GNU Arm Version: 9 2020-q2-update (gcc-arm-none-eabi-9-2020-q2-update-win32.exe)
ARM_CORE = cortex-m3ARCH_OPTION = -mcpu=$(ARM_CORE) -mthumb -mthumb-interworkC_OPTION = -gdwarf-2 -MD -Wall -Os -mapcs-frame -ffunction-sections -fdata-sectionsL_OPTION = -Wl,-Map=$(TARGET_NAME).map -Wl,--gc-sections --specs=nano.specs
Caller_R3_source_code.zip
main.c
int result; int main(void) { extern int test_fun1(int a, int b, int c, int d); extern int gTest; result = test_fun1(1, 2, 3, 4); if (gTest != 4) { while (1); // R3 Error here } while (1) // OK { } }
test.c
void test_fun2(int a, int b, int c); int gTest = 0; int test_fun1(int a, int b, int c, int d) { int uStart; uStart = gTest; if (a > 0) { test_fun2(uStart, uStart + c, 5); } uStart += d; gTest = uStart; return 1; } #if defined (__CC_ARM) __asm void test_fun2(int a, int b, int c) { PUSH {R4-R6, LR} MOV R4, R0 LDR R3, =0x1234 ADD R1, R1, R3 POP {R4-R6, PC} } #endif #if defined (__GNUC__) void test_fun2(int a, int b, int c) { __asm volatile("PUSH {R4-R6, LR}"); __asm volatile("MOV R4, R0"); __asm volatile("LDR R3, =0x1234"); __asm volatile("ADD R1, R1, R3"); __asm volatile("POP {R4-R6, PC}"); } #endif
disasm.txt
$t main 0x00000198: b508 .. PUSH {r3,lr} 0x0000019a: 2203 ." MOVS r2,#3 0x0000019c: 2304 .# MOVS r3,#4 0x0000019e: 2102 .! MOVS r1,#2 0x000001a0: 2001 . MOVS r0,#1 0x000001a2: f000f815 .... BL test_fun1 ; 0x1d0 0x000001a6: 4b04 .K LDR r3,[pc,#16] ; [0x1b8] = 0x20000020 0x000001a8: 6018 .` STR r0,[r3,#0] 0x000001aa: 4b04 .K LDR r3,[pc,#16] ; [0x1bc] = 0x2000001c 0x000001ac: 681b .h LDR r3,[r3,#0] 0x000001ae: 2b04 .+ CMP r3,#4 0x000001b0: d000 .. BEQ 0x1b4 ; main + 28 0x000001b2: e7fe .. B 0x1b2 ; main + 26 0x000001b4: e7fe .. B 0x1b4 ; main + 28 0x000001b6: bf00 .. NOP $d 0x000001b8: 20000020 .. DCD 536870944 0x000001bc: 2000001c ... DCD 536870940 $t test_fun2 0x000001c0: b570 p. PUSH {r4-r6,lr} 0x000001c2: 4604 .F MOV r4,r0 0x000001c4: f2412334 A.4# MOV r3,#0x1234 0x000001c8: 4419 .D ADD r1,r1,r3 0x000001ca: bd70 p. POP {r4-r6,pc} 0x000001cc: 4770 pG BX lr 0x000001ce: 0000 .. MOVS r0,r0 $t test_fun1 0x000001d0: b538 8. PUSH {r3-r5,lr} 0x000001d2: 4d07 .M LDR r5,[pc,#28] ; [0x1f0] = 0x2000001c 0x000001d4: 2800 .( CMP r0,#0 0x000001d6: 4611 .F MOV r1,r2 0x000001d8: 682c ,h LDR r4,[r5,#0] 0x000001da: dd04 .. BLE 0x1e6 ; test_fun1 + 22 0x000001dc: 2205 ." MOVS r2,#5 0x000001de: 4620 F MOV r0,r4 0x000001e0: 4421 !D ADD r1,r1,r4 0x000001e2: f7ffffed .... BL test_fun2 ; 0x1c0 0x000001e6: 441c .D ADD r4,r4,r3 0x000001e8: 2001 . MOVS r0,#1 0x000001ea: 602c ,` STR r4,[r5,#0] 0x000001ec: bd38 8. POP {r3-r5,pc} 0x000001ee: bf00 .. NOP $d 0x000001f0: 2000001c ... DCD 536870940
I believe you need to define r3 as being 'clobbered' by the inline assembly function:gcc.gnu.org/.../Extended-Asm.html