Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

__isr_vectors variable not found when placed inside a static library

As a spin-off of a previous question (sbrk function not found when placed in a static library): I'm creating a bare-metal application for the stm32f407 microcontroller, which has an ARM Cortex M4 core. I'm trying to create a static library containing basic stuff like cmsis, the HAL functions, and the interrupt vector table, and link that static library to my main application. However, when the interrupt vector table (which is a variable named __isr_vectors) is placed inside the static library, the variable does not survive linking.

I can piece together what happens: The linker has an object main.o, and a few libraries. It takes all symbols found in main.o, and it takes all symbols out of the libraries that are used by main.o or that are used by other symbols that are already deemed necessary. The __isr_vectors variable is not yet needed at this stage, since no one references this variable explicitly, so it is thrown out by the linker. Then, the linker searches for all input sections named .isr_vector in order to create the output section .isr_vector. However, no symbols survived up to this moment, so that output section is left empty, and my binary is left without an interrupt table.

I know of one trick to get the __isr_vector to survive: reference it in a dummy function in main.c. However, this is kinda ugly and error-prone (you can forget to do that when building a new application against the same static library). So here's my question: Is there another way to make the __isr_vector survive, so that I can just link in my static library and be done with it?

These are the files and steps to reproduce the problem:

vectors.c:

__ attribute__ ((section(".isr_vector"), used)) void* __isr_vectors = 0;

main.c:

void _start(void) {}

link.ld:

MEMORY { FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 1024K }

ENTRY(_start)

SECTIONS { .isr_vector : ALIGN(4) { KEEP(*(.isr_vector)) } >FLASH

   .text : ALIGN(4)
   {
       *(.text .text.*)
   } >FLASH

}

Commands:

"C:\Program Files (x86)\GNU Tools ARM Embedded\4.9 2014q4\bin\arm-none-eabi-gcc.exe" -g -mcpu=cortex-m4 -mfpu=fpv4-sp-d16 -mfloat-abi=softfp -mthumb -ffunction-sections -std=gnu11 -o main.c.obj -c main.c "C:\Program Files (x86)\GNU Tools ARM Embedded\4.9 2014q4\bin\arm-none-eabi-gcc.exe" -g -mcpu=cortex-m4 -mfpu=fpv4-sp-d16 -mfloat-abi=softfp -mthumb -ffunction-sections -std=gnu11 -o vectors.c.obj -c vectors.c

"C:\Program Files (x86)\GNU Tools ARM Embedded\4.9 2014q4\bin\arm-none-eabi-gcc.exe" -g -mcpu=cortex-m4 -mfpu=fpv4-sp-d16 -mfloat-abi=softfp -mthumb -ffunction-sections -std=gnu11 -g -mcpu=cortex-m4 -mfpu=fpv4-sp-d16 -mfloat-abi=softfp -mthumb -Wl,--gc-sections -nostartfiles -Wl,-Tlink.ld -Wl,-Map=test_linker.without_library.map main.c.obj vectors.c.obj -o test_linker.without_library.elf

"C:\Program Files (x86)\GNU Tools ARM Embedded\4.9 2014q4\bin\arm-none-eabi-ar.exe cq libtest_linker.lib.a vectors.c.obj

"C:\Program Files (x86)\GNU Tools ARM Embedded\4.9 2014q4\bin\arm-none-eabi-ranlib.exe" libtest_linker.lib.a

"C:\Program Files (x86)\GNU Tools ARM Embedded\4.9 2014q4\bin\arm-none-eabi-gcc.exe" -g -mcpu=cortex-m4 -mfpu=fpv4-sp-d16 -mfloat-abi=softfp -mthumb -ffunction-sections -std=gnu11 -g -mcpu=cortex-m4 -mfpu=fpv4-sp-d16 -mfloat-abi=softfp -mthumb -Wl,--gc-sections -nostartfiles -Wl,-Tlink.ld -Wl,-Map=test_linker.with_library.map main.c.obj -o test_linker.with_library.elf libtest_linker.lib.a

like image 465
Richard Avatar asked Mar 09 '15 18:03

Richard


People also ask

Is it possible to use a volatile variable in ISR?

In fact volatile doesn't matter if you're using that variable in ISR only: volatile just says to the compiler it can't optimise usage of that variable.

Can I use C instead of ISRs?

In fact you can place some important and often used variables in registers (registers of emulated processor and so on) and not load them from memory everytime an ISR is called. In order to use C in this situation is probably only one: not use ISRs, use pooling. This may be faster in fact as pooling tends to use cache better.

When LD links against a library it only picks that function?

When ld links against a library, it will only pick those functions which are required at that time (because of references to functions from translation units which have been linked in before ). The linker will forget all other functions (and the library won't be considered later).


Video Answer


3 Answers

I have made two changes to your files:

In the linker script, I have changed the ENTRY from

ENTRY(_start)

to

ENTRY(Reset_Handler)

and in vectors.c I have added this function:

void Reset_Handler(void) {
}

The trick is that Reset_Handler is a function in the translation unit vectors.c wheras _start is somewhere else.

Now when Reset_Handler is linked in (enforced by ENTRY), __isr_vectors seems to be considered as well! So it seems that another function in that translation unit must be linked in order to "drag along" that variable.


For completeness sake:

  • Normally the Reset_Handler is referenced in the __isr_vectors, and Reset_Handler calls main eventually (in your case it's _start). So this is not just a workaround, you probably need that anyway.

  • I have added -fdata-sections to the compile commands

like image 118
Beryllium Avatar answered Nov 26 '22 16:11

Beryllium


I got this problem in the same kind of environment (arm-none-eabi-gcc-cs-5.2.0-3.fc23.x86_64, arm-none-eabi-binutils-cs-2.25-2.fc23.x86_64 on Fedora 23).

It seems the linker does not try to read content of the archive as it has already all the symbols it needs. it's probably a kind of optimization or a bug.

An alternative solution to force the archive to be read for "used" symbols, is to force the linker ld to consider __isr_vectors as undefined, with -u __isr_vectors.

As gcc option, -Xlinker -u -Xlinker __isr_vectors or -Wl,-u,__isr_vectors.

like image 20
FredG Avatar answered Nov 26 '22 18:11

FredG


This is more of a follow-on to the posted answer: I suggest that you only need to change the ENTRY in the linker script to: ENTRY(g_pfnVectors) I submit that this is less work, and does not require change to the original source file. If g_pfnVectors does not exist in your source file, it is the name of the vector table itself in our file. Modify as appropriate.

like image 35
Stephen Munnings Avatar answered Nov 26 '22 18:11

Stephen Munnings