Putting a pointer to a struct in a certain linker section

Hi! I have a question I was hoping to get some help with! We (https://github.com/bitcraze) make open source'd nano quadcopters. They are sort of flying Arduinos and it is possible to construct decks for them, in the same way you can construct shields for Arduino.

When you do, you write a deck driver. I am attempting to write a deck driver in Rust (this is in STM32/FreeRTOS land). One thing I am having problem getting around is that the interface for deck drivers in our C API is that you fill out a struct DeckDriver and then call a magic macro DECK_DRIVER that is defined as (struct deck_driver is typedef'd to DeckDriver):

#define DECK_DRIVER(NAME) const struct deck_driver * driver_##NAME __attribute__((section(".deckDriver." #NAME), used)) = &(NAME)

Putting a pointer to the deck_driver structure at a special place so that the code later can iterate over all registered deck drivers.

So that the basic register driver part of the driver looks like:

static const DeckDriver helloDriver = {
  .name = "myHello",
  .init = helloInit,
  .test = helloTest,
};
DECK_DRIVER(helloDriver);

(Making your first Deck driver | Bitcraze)

Now :slight_smile: How would I best interface this to Rust? I've used bindgen to get binding to the DeckDriver structure, how do I make it so a pointer to that structure end up in the .deckDriver section?

This is my naive attempt that does not work (cannot be shared between threads safely):

#[no_mangle]
static example_driver: DeckDriver = DeckDriver {
    name: b"RustExampleDriver\0".as_ptr() as *mut u8,
    init: Some(rustExampleInit),
    test: Some(rustExampleTest),
    usedPeriph: 0,
    usedGpio: 0,
    requiredEstimator: 0,
    requiredLowInterferenceRadioMode: false,
    vid: 0,
    pid: 0,
    memoryDef: core::ptr::null(),
};
#[no_mangle]
#[link_section = ".deckDriver"]
static driver_rustExampleDriver: *const DeckDriver = &example_driver;
1 Like

Based on the attribute portion of the C macro you posted:

__attribute__((section(".deckDriver." #NAME), used))

You appear to be missing the rest of the link_section name (might be irrelevant) and the used attribute:

#[used]
#[no_mangle]
#[link_section = ".deckDriver.rustExampleDriver"]
static driver_rustExampleDriver: *const DeckDriver = &example_driver;

A macro would likely be ideal here in order to ensure that the names of the variables and attribute strings end up the same. This would only bring the code up to parity with the posted C code, however. A global pointer variable is not going to be thread-safe on the C side either, you'd want to use thread_local or something similar in that case.

Thanks camden-smallwood!

A macro was what I was going for once I got this to work! Changing the C API is unfortunately not an option because we have people using it already for their deck-drivers and they need to continue to work.

So, as I see it, I need a way of getting an address of this struct to the correct place in the elf-file. Safe or unsafe, in order to bridge this gap and enable Rust in drivers.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.