Getting “error: redefinition” when trying to override weak functions in C

151 views Asked by At

I’m trying to write some C library code to create the system and device interrupt vector tables for a RV32EC microcontroller, the CH32V003. It’s almost identical to how an ARM Cortex-M vector table is laid out: an array of function pointers that are weakly defined to point to a default handler unless otherwise specified. Then when either I or some future user of the library wants to define their own interrupt handler, just create it and it will override the default entry. I’m getting an “error: redefinition” when I try to override the default functions.

I’m using the xpack-riscv-none-elf-gcc-13.2.0-2 GCC toolchain on MacOS Sonoma. I’ve written dozens of other small programs for these chips that used either no interrupts or some of the other interrupt handling schemes available on the CH32V003, e.g., Vector-table-free and uniform interrupts, with success.

Near the top of my main.c file I have this code:

// system vectors

// these are function prototypes that are supposed to be in the main.h header file

__attribute__ ((weak, interrupt)) void system_vector_default(void); // reserved slot(s) in system vector table
__attribute__ ((weak, interrupt, alias("system_vector_default"))) void system_vector_NMI(void); // non-maskable interrupt handler
__attribute__ ((weak, interrupt, alias("system_vector_default"))) void system_vector_HardFault(void); // hard fault handler
__attribute__ ((weak, interrupt, alias("system_vector_default"))) void system_vector_SysTick(void); // SysTick interrupt handler
__attribute__ ((weak, interrupt, alias("system_vector_default"))) void system_vector_SW(void); // software interrupt

void system_vector_default(void) { // reserved slot(s) in system vector table

    // note: this definition is required, as all the other weakly-linked functions point to it
}

void system_vector_NMI(void) {} // non-maskable interrupt handler
//void system_vector_HardFault(void) {} // hard fault handler
//void system_vector_SysTick(void) {} // SysTick interrupt handler
//void system_vector_SW(void) {} // software interrupt

__attribute__ ((section(".system_vector"))) void (* const system_vector_table[]) (void) = { // system vector table, skipping vector 0 (reserved)
    system_vector_default,              // 1 - reserved
    system_vector_NMI,                  // 2 - non-maskable interrupt handler
    system_vector_HardFault,            // 3 - hard fault interrupt handler
    system_vector_default,              // 4 - reserved
    system_vector_default,              // 5 - reserved
    system_vector_default,              // 6 - reserved
    system_vector_default,              // 7 - reserved
    system_vector_default,              // 8 - reserved
    system_vector_default,              // 9 - reserved
    system_vector_default,              // 10 - reserved
    system_vector_default,              // 11 - reserved
    system_vector_SysTick,              // 12 - SysTick interrupt handler
    system_vector_default,              // 13 - reserved
    system_vector_SW,                   // 14 - software interrupt handler
    system_vector_default,              // 15 - reserved
};

When I define the “system_vector_default()” function and none of the other functions, the code compiles perfectly and produces a vector table containing only pointers to the “system_default_vector()” function. This is exactly what I wanted.

When I un-comment the definition of the "system_vector_NMI()” function (as above), or any of the other “system_vector_*()” functions, I get the following error message:

main.c:22:6: error: redefinition of 'system_vector_NMI'
   22 | void system_vector_NMI(void) {} // non-maskable interrupt handler
      |      ^~~~~~~~~~~~~~~~~
main.c:12:72: note: previous definition of 'system_vector_NMI' with type 'void(void)'
   12 | __attribute__ ((weak, interrupt, alias("system_vector_default"))) void system_vector_NMI(void); // non-maskable interrupt handler
      |                                                                        ^~~~~~~~~~~~~~~~~
make: *** [J4-weak.elf] Error 1

The compiler is telling me exactly what it finds objectionable: the “prototype” of the “system_vector_NMI()” function. Maybe I don’t understand what a function prototype is or how to use one: I thought it was a “function signature”, i.e., return type and parameter types, with no function body definition.

Searching here and elsewhere on the internet for this error brings me nothing but shame. It’s a common beginner problem, especially when you accidentally & recursively include some header file with a declaration in it. I’ve diligently added “#include guards” to all my header files. For this example, I brought all of the code directly into the single source file for clarity. I’ve even tried putting all the vector-related stuff into its own vector.c/vector.h file and the same compiler error occurs.

So what I’m expecting the compiler to do is to create my table of system vectors, using default values for undefined functions, but substituting the addresses of any functions that are supplied by the library user.

So I’m doing “something wrong” and I’m sure at this point it’s based on either my ignorance of how these things are supposed to work or some incorrect assumptions I have made along the way.

0

There are 0 answers