0

I am trying to do a very simple exercise as shown below

  1. Compiler a simple C program using arm-none-eabi-gcc compiler for a Cortex-R5 MCU target.
  2. Link it with the respective linker file and create a executable so I can load it and debug.

What have I tried?

  1. I was able to successfully compiler the below C code using the below mentioned command
#include<stdio.h>

int main()
{
    int a = 1;
    for(int i=0;i<10;i++)
    {
        a++;
    }
    return 0;
}

gcc Command used - arm-none-eabi-gcc -mcpu=cortex-r5 -mthumb -mfloat-abi=hard -mfpu=vfpv3-d16 --specs=nosys.specs -ffunction-sections -fdata-sections -c main.c -o hi.o

This has properly created a object file.

Where am I stuck?

When I tried to use the below linker and link command I am receiving a warning where the vector table is improperly placed in the memory (It is placed in the 0x10260000 (RAM) instead of 0x0 where it has to be)

Linker command used - arm-none-eabi-gcc -mcpu=cortex-r5 -mthumb -mfloat-abi=hard -mfpu=vfpv3-d16 -Wl,-Map=output.map -Wl,-I/home/kowshik/ti/mcu_plus_sdk_am273x_08_05_00_24/source/kernel/nortos/lib/ -Wl,-Lnortos.am273x.r5f.ti-arm-clang.debug.lib -nostdlib -nostartfiles --specs=nosys.specs -T linker.ld hi.o -o hi.elf

Linker file used

/* This is the stack that is used by code running within main()
 * In case of NORTOS,
 * - This means all the code outside of ISR uses this stack
 * In case of FreeRTOS
 * - This means all the code until vTaskStartScheduler() is called in main()
 *   uses this stack.
 * - After vTaskStartScheduler() each task created in FreeRTOS has its own stack
 */
__stack_size = 16384;
/* This is the heap size for malloc() API in NORTOS and FreeRTOS
 * This is also the heap used by pvPortMalloc in FreeRTOS
 */
__heap_size = 32768;
ENTRY(_vectors)/* This is the entry of the application, _vector MUST be placed at starting address 0x0 */

/* This is the size of stack when R5 is in IRQ mode
 * In NORTOS,
 * - Here interrupt nesting is enabled
 * - This is the stack used by ISRs registered as type IRQ
 * In FreeRTOS,
 * - Here interrupt nesting is disabled
 * - This is stack that is used initially when an IRQ is received
 * - But then the mode is switched to SVC mode and SVC stack is used for all user ISR callbacks
 * - Hence in FreeRTOS, IRQ stack size is less and SVC stack size is more
 */
__IRQ_STACK_SIZE = 256;
/* This is the size of stack when R5 is in IRQ mode
 * - In both NORTOS and FreeRTOS, nesting is disabled for FIQ
 */
__FIQ_STACK_SIZE = 256;
__SVC_STACK_SIZE = 4096; /* This is the size of stack when R5 is in SVC mode */
__ABORT_STACK_SIZE = 256;  /* This is the size of stack when R5 is in ABORT mode */
__UNDEFINED_STACK_SIZE = 256;  /* This is the size of stack when R5 is in UNDEF mode */

MEMORY
{
    R5F_VECS : ORIGIN = 0x00000000, LENGTH = 0x00000040
    R5F_TCMA : ORIGIN = 0x00000040, LENGTH = 0x00003FC0
    R5F_TCMB : ORIGIN = 0x00080000, LENGTH = 0x00004000

    /* when using multi-core application's i.e more than one R5F active, make sure
     * this memory does not overlap with other R5F's
     */
    MSS_L2 : ORIGIN = 0x10260000, LENGTH = 0x40000

    /* This is typically used to hold data IO buffers from accelerators like CSI, HWA, DSP */
    DSS_L3 : ORIGIN = 0x88000000, LENGTH = 0x00390000

    /* shared memories that are used by RTOS/NORTOS cores */
    /* On R5F,
     * - make sure there are MPU entries which map below regions as non-cache
     */
    USER_SHM_MEM : ORIGIN = 0x102E8000, LENGTH = 0x00004000
    LOG_SHM_MEM : ORIGIN = 0x102EC000, LENGTH = 0x00004000
    /* MSS mailbox memory is used as shared memory, we dont use bottom 32*6 bytes, since its used as SW queue by ipc_notify */
    RTOS_NORTOS_IPC_SHM_MEM : ORIGIN = 0xC5000000, LENGTH = 0x1F40
    MAILBOX_HSM : ORIGIN = 0x44000000, LENGTH = 0x000003CE
    MAILBOX_R5F : ORIGIN = 0x44000400, LENGTH = 0x000003CE
}


SECTIONS
{
    /* This has the R5F entry point and vector table, this MUST be at 0x0 */
    
    .vectors :
    {
        KEEP(*(.vectors)) /* Keep the vectors section */
    } > R5F_VECS

    /* This is rest of code. This can be placed in MSS_L2 */
    .text :
    {
        *(.text) /* Code resides here */
    } > MSS_L2

    /* This is rest of initialized data. This can be placed in MSS_L2 */
    .rodata :
    {
        *(.rodata) /* Consts go here */
    } > MSS_L2

    /* This is rest of uninitialized data. This can be placed in MSS_L2 */
    .data :
    {
        *(.data) /* Initialized globals and statics go here */
    } > MSS_L2

    /* This is where the uninitialized data goes */
    .bss :
    {
        *(.bss) /* Uninitialized globals go here */
        __bss_start__ = .; /* Symbol for BSS start address */
        *(.sysmem) /* Malloc heap goes here */
        *(.stack) /* Main stack goes here */
        __bss_end__ = .; /* Symbol for BSS end address */
    } > MSS_L2

    /* This is where the stacks for different R5F modes go */
    .irqstack :
    {
        . = ALIGN(8);
        __IRQ_STACK_START = .;
        BYTE(0); /* Reserve space for IRQ stack */
        __IRQ_STACK_END = .; /* Symbol for IRQ stack end address */
    }

    .fiqstack :
    {
        . = ALIGN(8);
        __FIQ_STACK_START = .;
        BYTE(0); /* Reserve space for FIQ stack */
        __FIQ_STACK_END = .; /* Symbol for FIQ stack end address */
    }

    .svcstack :
    {
        . = ALIGN(8);
        __SVC_STACK_START = .;
        BYTE(0); /* Reserve space for SVC stack */
        __SVC_STACK_END = .; /* Symbol for SVC stack end address */
    }

    .abortstack :
    {
        . = ALIGN(8);
        __ABORT_STACK_START = .;
        BYTE(0); /* Reserve space for ABORT stack */
        __ABORT_STACK_END = .; /* Symbol for ABORT stack end address */
    }

    .undefinedstack :
    {
        . = ALIGN(8);
        __UNDEFINED_STACK_START = .;
        BYTE(0); /* Reserve space for UNDEFINED stack */
        __UNDEFINED_STACK_END = .; /* Symbol for UNDEFINED stack end address */
    }

    /* Sections needed for C++ projects */
    .ARM.exidx :
    {
        *(.ARM.exidx) /* Needed for C++ exception handling */
    } > MSS_L2

    .init_array :
    {
        KEEP(*(SORT(.init_array.*))) /* Contains function pointers called before main */
    } > MSS_L2

    .fini_array :
    {
        KEEP(*(SORT(.fini_array.*))) /* Contains function pointers called after main */
    } > MSS_L2

    /* any data buffer needed to be put in L3 can be assigned this section name */
    .bss.dss_l3 :
    {
        *(.bss.dss_l3)
    } > DSS_L3

    /* General purpose user shared memory, used in some examples */
    .bss.user_shared_mem (NOLOAD) :
    {
        *(.bss.user_shared_mem)
    } > USER_SHM_MEM

    /* this is used when Debug log's to shared memory are enabled, else this is not used */
    .bss.log_shared_mem  (NOLOAD) :
    {
        *(.bss.log_shared_mem)
    } > LOG_SHM_MEM

    /* this is used only when IPC RPMessage is enabled, else this is not used */
    .bss.ipc_vring_mem   (NOLOAD) :
    {
        *(.bss.ipc_vring_mem)
    } > RTOS_NORTOS_IPC_SHM_MEM

    /* this is used only when Secure IPC is enabled */
    .bss.sipc_hsm_queue_mem   (NOLOAD) :
    {
        *(.bss.sipc_hsm_queue_mem)
    } > MAILBOX_HSM

    .bss.sipc_r5f_queue_mem   (NOLOAD) :
    {
        *(.bss.sipc_r5f_queue_mem)
    } > MAILBOX_R5F
}

Warning I received - warning: cannot find entry symbol _vectors; defaulting to 0000000010260000

I am using AM273x Texas Instrument's MCU, here's the link to Technial reference manual (TRM)

I also opened the map file generated by this command I still see no section is allocated to the vectors alone.

I can definitely assure that the _vectors symbol is defined properly in a file that is already present in the nortos.am273x.r5f.ti-arm-clang.debug.lib static library. I can provide more details about this if you require.

Please help me here to properly locate the vector table in the binary so I can run my applications properly.

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
kowshik
  • 1
  • 1

1 Answers1

0

The vector table is normally application specific (and in the startup file, but you have defined -nostartfiles). It seems strange to include the vector table in a .lib file.

The linker will only link symbols in a static library object if they are explicitly referenced in any preceding object file. You do not normally reference the default vector table at 0x0 on Cortex-M because the hardware expects it to be there.

To force the vector table to link, it will either need to be a standalone object file (normally the startup file), or you will need to explicitly reference it, by for example explicitly setting the vector table address to _vectors even though it is at the default in any case.

Clifford
  • 88,407
  • 13
  • 85
  • 165
  • Thanks Clifford for the answer. Can you tell me how to do this "you will need to explicitly reference it, by for example explicitly setting the vector table address to _vectors even though it is at the default in any case." ?? – kowshik May 28 '23 at 18:56
  • By writing it to the the VTOR register: https://developer.arm.com/documentation/dui0662/b/The-Cortex-M0--Processor/Exception-model/Vector-table, but any reference will force it to be linked I would imagine. – Clifford May 28 '23 at 19:04
  • There is no such VTOR register in my MCU. – kowshik May 29 '23 at 04:27
  • Please note that my MCU is no cortex-M. It's cortex-r5 and we don't have any vtor register. I manually place it at 0x0 through linker. – kowshik May 29 '23 at 09:24
  • @kowshik. Apologies - oversight in my part. Even more reason not to put the vector table in the library - how are you going to implement application specific interrupts? Or does the library include all the device drivers you will ever use? – Clifford May 29 '23 at 14:35
  • You're absolutely correct. The lib which I'm trying to use has the exception and abort handlers implemented along with. – kowshik May 29 '23 at 15:27
  • Any idea about this? Thanks – kowshik May 30 '23 at 18:22
  • About what? If you are asking about an alternative to referencing `_vectors` as I said, you simply need a dummy reference that won't be optimised out. `volatile uint32_t* dummy = _vectors ;` perhaps. With respect to vectors being in the library, that is workable if all vectors point to a handler that jumps to an address defined elsewhere. i.e. the library could take a pointer to an user vector table, and each handler would redirect to an address in this table. Imposing a small overhead c.f. Cortex-M. – Clifford May 30 '23 at 22:09