This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

MCU-PLUS-SDK-AM263PX: Using GCC with AM263PX SDK causes "undefined address" with mixed C/Assembly code

Part Number: MCU-PLUS-SDK-AM263PX
Other Parts Discussed in Thread: MCU-PLUS-SDK-AM263X

Tool/software:

We found an issue when porting TI example: "uart echo interrupt lld no rtos" to our environment.
- using the MCU-PLUS-SDK-AM263X SDK (9.2.0.56). Compiling source code. Not linking in library.
- compiler flags are the same:
- using arm-none-eabi-gcc and ld for toolchain
- compiler flags: -mcpu=cortex-r5 -mfloat-abi=hard -mfpu=vfpv3-d16 -mlittle-endian -mthumb -DSOC_AM263PX -D_DEBUG_=1 -g
- Linker flags: -mcpu=cortex-r5 -mfloat-abi=hard -mfpu=vfpv3-d16 -mlittle-endian -mthumb -DSOC_AM263PX -D_DEBUG_=1 -g


This example runs on CCS and the AM263P-CC eval board successfully. But when ported to our environment, unmodified causes the SoC to jump to an unexpected address and eventually generating an "undefined address" interrupt.

The code in question is uart_echo_interrupt_lld.c ln 161.
void UART_lld_writeCompleteCallback(void *args)
{
unlock_mutex(gUartObject[CONFIG_UART_CONSOLE].writeTransferMutex);
return;
}


Mutex_armv7r_asm.S ln 94

// unlock_mutex
unlock_mutex:
mov r1, #0
dmb // Required before releasing protected resource
str r1, [r0] // Unlock mutex
signal_update
bx lr

During uart interrupt UART_lld_writeCompleteCallback calls unlock_mutex. And when stepping into unlock_mutex, the core jumps to a unexpected address during the dmb instruction.


Our developer found the problem and fixed it using .type directive. Here is his comment.

===============================================================
There’s a problem when mixing assembly code with C. Typically, the assembly code is compiled in ARM mode, but the rest of the C code is compiled in Thumb mode. The gist of it is that the wrong instruction is used to call ARM mode from C code. For example, a C function calling “unlock_mutex” (in mcu_plus_sdk_am263x_09_02_00_56\source\kernel\nortos\dpl\r5\Mutex_armv7r_asm.S) get compiled as “bl <unlock_mutex>”, which is wrong; the processor would stay in Thumb mode and start to misinterpret ARM code as Thumb.

However, we found out that curiously, functions in this file do not have the “.type %function” directive declaring them as functions, and other assembly files (ex: PmuP_armv7r_asm.S) have those properly applied to functions. If we add those directives to functions in Mutex_armv7r_asm.S (ex: “.type unlock_mutex, %function”), then the generated code is good (the function call gets compiled to “blx <unlock_mutex>”) and the code works correctly.

Compiler used: arm-none-eabi-gcc (xPack GNU Arm Embedded GCC x86_64) 11.2.1 20220111 with linker arm-none-eabi-ld (xPack GNU Arm Embedded GCC x86_64) 2.37.20220122, but it seems to be independent of the version used; we observed the same issues with arm-none-eabi-gcc (Arch Repository) 14.1.0 and linker arm-none-eabi-ld (GNU Binutils) 2.42.

===============================================================


Please provide assistance in regards to the following questions:
1. TI/CCS somehow manages to build/link this properly. How does TI's toolchain handle this? It is using the same code and same flags as our GCC environment?

2. What are TI's suggestion to mitigate this in our environment? Edit the SDK and add .type directive to all assembly functions?

3. Can TI update the SDK to support GCC?

Thanks for the support

  • I can't answer much.  But I can shed some light on this question ...

    How does TI's toolchain handle this?

    Here is what the tiarmclang compiler does.  For a thumb function, the compiler emits the directive ...

    .thumb_func

    This causes the associated function symbol to be at an odd address.  That is, 1 is or'd into the least significant bit (LSB) of the address.  That is how the linker knows whether a function is in thumb state or arm state.  The compiler always uses the BL instruction to call a function.  When the linker sees that a BL instruction causes a change in state (from thumb to arm, or vice versa), it changes the BL instruction to BLX.  The instructions used for return (BX LR, or a pop that restores the saved LR from the stack into the PC) rely on the LSB of the return address to know whether the function being returned to is in thumb state (LSB = 1) or arm state (LSB = 0).  

    For the rest of your questions, I have changed responsibility for this thread to the team that supports the SDK for your device.

    Thanks and regards,

    -George

  • Thank you for the explanation. 

    Just as a clarity, it makes sense tiarmclang would add .thumb_func when generating assembly from C functions.  But will it do this for assembly functions as well?   

    Is there documentation regarding how tiarmclang does this so we can replicate it when using GNU gcc? 

  • Posting more information here to help with discussion and others to recognize this issue:

    The mutex_unlock arm mode instructions generated by the assembler

    CCS toolchain generates proper assembly using blx instruction to call <unlock mutex>.

    GNU toolchain generates improper assembly using bl instruction to call <unlock mutex>

    GNU toolchain only generates proper assembly using blx instruction to call <unlock_mutex> only when modifying the SDK.

    kernel/nortos/dpl/r5/Mutex_arm7r_asm.S by adding the .type directive.

  • Hi Huey

    Please refer to https://software-dl.ti.com/codegen/docs/tiarmclang/rel4_0_0_LTS/ for all documentation on armclang.

    We don't support GCC for AM263x devices as of now, and recommend using ti-arm-clang.

    Regards,
    Akshit