Multi Project Linker Silent Failure

Sysprogs forums Forums VisualGDB Multi Project Linker Silent Failure

Tagged: 

This topic contains 11 replies, has 2 voices, and was last updated by  codex653 4 weeks, 1 day ago.

Viewing 12 posts - 1 through 12 (of 12 total)
  • Author
    Posts
  • #27188

    codex653
    Participant

    Hello! I have been recently revamping my personal tooling workflow to allow compiling various VisualGDB solutions into static libraries, then linking them all together in a large project to produce a flashable binary for an STM32F4 device. I have commonly used subsystems that I was tired of regenerating the build tooling for on each new project, so I wanted standalone solutions I could include in larger VisualGDB projects as a component.

    I’ve been following the examples shown in https://visualgdb.com/tutorials/porting/multiplatform/ to help create a platform in Visual Studio for my chip. I’ve got everything compiling and linking successfully, but when I start debugging, I find that the chip has jumped off into the weeds and gotten completely lost. I have a feeling that somehow the isr vector table got messed up in the linking process and is not placed at the correct location in the binary. I cannot hit the breakpoint inside of the Reset_Handler function. Each sub component project is using the same linker script that comes default with my chip in VisualGDB (STM32F446RE_flash.lds).

    Any thoughts on what I might be doing wrong here? Disassembly output did not show the expected isr jump table at the reset address (0x08000000), but rather a function that I did not recognize. My understanding of the STM32F4 resets is likely flawed though.

    Edit: I should mention I am compiling 3 sub-projects as static libraries and linking them into one larger project.

    • This topic was modified 1 month ago by  codex653.
    #27190

    support
    Keymaster

    Hi,

    It looks like your support period has expired. Please renew it here and will be happy to help you.

    #27191

    codex653
    Participant

    Whoops! I didn’t realize it had expired. I’ve purchased the support renewal as of a few moments ago.

    #27192

    support
    Keymaster

    Thanks for renewing your support.

    If the firmware doesn’t start completely, we would advise checking the following points:

    1. Using Embedded Memory Explorer, check that the interrupt vector is present at the correct address (double-check the address in the device datasheet, or compare it with a working file).
    2. Double-check that the interrupt vector points to the correct Reset handler function. You can dump the contents of the section containing the interrupt vector by running arm-none-eabi-objdump or do it at runtime by evaluating *((void *)0xADDRESS) via the Watch window.
    3. You can configure VisualGDB to stop at the Reset handler via VisualGDB Project Properties – >Embedded Debug Tweaking and then starting debugging with F10 instead of F5.
    4. If nothing helps, you can also try hardcoding a breakpoint in the reset handler (asm(“bkpt 255”)) and issuing a manual reset via the GDB Session window (mon reset).
    #27197

    codex653
    Participant

    I was able to verify that the isr vector table is located at the correct address with both #1 & #2, but I noticed that the .text section was also located at the same address (0x08000000). As a test, I compiled the HAL blinky example project from the project wizard and objdump-ing the output showed me that the .text and .isr_vector symbols are located at two different addresses. Further inspection of the blinky binary shows the expected Reset_Handler address in the second word of the image and the stack address in the first word, as expected…my project shows essentially garbage data.

    I’ve attached an image of the objdump output for an example. This seems to be leading me down the right path…

    • This reply was modified 1 month ago by  codex653.
    Attachments:
    You must be logged in to view attached files.
    #27204

    codex653
    Participant

    I ended up solving the problem. My chip’s startup code is compiled into one of the static libraries that is linked into the larger project. Despite verifying that the vector table IS in there and was compiled with the “__attribute__( ( section( “.isr_vector” ), used ) )” GCC annotation to prevent removal, it’s still being thrown out during linking. In order to fix this, I had to include the startup file in the larger project, which goes against my goal of modularizing the code base.

    Is there a way for me to inject --whole-archive/--no-whole-archive into the linker step? I’d rather not have to explicitly reference the interrupt vector in the main project in order to keep that part of the code from the static library.

    For reference, I’ve been looking at this tutorial: https://visualgdb.com/tutorials/arm/linkerscripts/

    and this StackOverflow question: https://stackoverflow.com/questions/1202494/why-doesnt-attribute-constructor-work-in-a-static-library

    • This reply was modified 1 month ago by  codex653.
    • This reply was modified 1 month ago by  codex653.
    #27207

    support
    Keymaster

    No problem, we can add an option for wrapping library references with –whole-archive. Just to double-check, are you using MSBuild and referencing the libraries using the regular References window in VS?

    #27208

    codex653
    Participant

    I’m using MSBuild, but I was explicitly referencing the libraries via the Linker options in the project properties settings. Is there an easier way to do it through references?

    #27209

    support
    Keymaster

    Hi,

    If you are using the Linker Options->Command Line to specify the libraries anyway, you can simply put -Wl,–whole-archive before the library names and -Wl,–no-whole-archive after them.

    That said, the recommended way to reference libraries would be to right-click on the executable project in Solution Explorer and select Add->Reference. This will automatically add the libraries to the linker inputs and will also make sure that the libraries are built before the main application. If it helps, we could add a per-library option that will let VisualGDB automatically wrap its name with the –whole-archive/–no-whole-archive when building the linker command line for the main project.

    #27248

    codex653
    Participant

    Adding the references worked a treat. Thanks for the new trick! I wasn’t using the command line to specify the library inputs because it can’t parse Visual Studio macros like $(OutDir), which limits the portability of the solution. So personally I would love having the ability to wrap with -whole-archive/-no-whole-archive! 🙂

    #27251

    support
    Keymaster

    No problem, please try this build: VisualGDB-5.5.3.3461.msi

    We have added the following option: VS Project Properties -> Exported Settings-> Link as Whole Archive (needs to be set for the library). After you set it, next time you build the main project, VisualGDB will automatically inject the –whole-archive option into the linker command line (see the .link.rsp file). Note that if you don’t change any other files after applying this option, it won’t trigger a rebuild of the main project.

    #27262

    codex653
    Participant

    Thanks so much! That behaves exactly as I hoped and it saved me a ton of headache. I went to debug a project and realized my customized hardfault handler wasn’t being linked in due to the same issue. Turning on the flag linked everything properly and I was able to get to the correct handler! Very very handy flag.

Viewing 12 posts - 1 through 12 (of 12 total)

You must be logged in to reply to this topic.