How to write a C "static const" in Rust?

Hi,

I was wondering how to translate this to Rust:

typedef struct {
    int32_t x;
    uint64_t y;
    bool z;
} foo_t;

static const foo_t foo = {
    .x = 0,
    .y = 0,
    .z = false,
};

This code would put foo in the .rodata memory region. How does one achieve this in Rust? static const does not seem to be valid Rust, and if I understand correctly, a const in Rust is more like a #define in C.

The most simple way possible ?

struct Foo {
    x: i32,
    y: u64,
    z: bool,
}

static FOO: Foo = Foo {
    x: 0,
    y: 0,
    z: false,
};

Unless your Foo type is more complex than what you presented.

1 Like

To clarify, a static const in C is equivalent to a static in Rust[1], since static variables are immutable unless declared with static mut:

Non-mut static items that contain a type that is not interior mutable may be placed in read-only memory.


  1. if interior mutability is not used ↩︎

3 Likes

Wouldn't a static in Rust be placed in RAM? If that's not the case, how do I declare a static in RAM?

static in Rust allocates data in .data. Having data in .text is really not ok, so perhaps you meant .rodata?
P.S. There’s link_section attribute.

UPD: In some cases, static can allocate data in .bss.

2 Likes

Everything would be placed in RAM, even your code.

1 Like

Having data in .text is really not ok, so perhaps you meant .rodata ?

Yes, you're right, sorry :slight_smile:

My understanding is that const basically copies the contents of the const variable everywhere you use it.

For example

const X: i32 = 0;

let x = X;
let y = X;

would be like

#define X 0

int32_t x = X;
int32_t y = X;

Edit: maybe "copy" isn't the right word, maybe substitution or replacement or something like that would be a better fit

To give some context, I'm working on a driver for a XIP flash (eXecute In Place) for a microcontroller.

The MCU has a peripheral to read data from flash on the fly, but it needs an address to a lookup table that defines the commands needed to interface the particular flash IC on your board. This lookup table must be in RAM, since the peripheral can't read it from flash before it knows how to read from flash. The peripheral can access the lookup table if it's located in the on-chip RAM though.

I'm not a Rust expert but that doesn't sound right to me. The reference specifically states that const items are not associated with any specific memory locations.

If your program's instructions are loaded in memory, static data should also be in memory.

That's not correct. const values are instantiated freshly at every usage - that's why it's possible to have a non-Copy consts.

Put another way: I have a function that takes an address to where the lookup table is located. The address is an 32-bit unsigned integer, as this is what needs to be written to the peripheral register.

fn set_lookup_table(address: u32);

What can I pass to that function if I have this?

const FLASH_LOOKUP_TABLE: [u32; 128] = [0; 128];

EDIT: I want a single instance of the lookup table in memory. I don't want different references to FLASH_LOOKUP_TABLE to point to different places in memory.

For real. The part about Copy and .rodata was wrong.

If you pass &FLASH_LOOKUP_TABLE as u32 to the function, it will receive the address of some instantiation of FLASH_LOOKUP_TABLE as a static variable. The compiler generally tries not to duplicate it, but to entirely rule out duplication, you'd have to make it a static. If you want to control exactly where the constant data is placed by the linker, you can use the link_section attribute. What exact target triple are you using to compile your program?

1 Like

So if I use static, I can achieve what I want, but it is up to the compiler/optimizer to decide where to put the variable, so it's up to me to tell the compiler where I want it?

arm-none-eabi? Not sure if that's what you're asking.

If you use a static with no interior mutability, then it will be placed in a section designated for read-only non-executable data. It is very likely the same section that a static const in C would end up in. Whether the data ends up in RAM or in flash is up to the linker for that particular embedded target; it would make sense if it was placed next to the .text section, but I haven't tested it myself.

Overall, it would probably be a good idea to test a regular static first, and if that doesn't do what you want, then you can start playing with link_section tricks.

3 Likes

Thanks, I think that's a good enough summary for me.

My take-away is that I need to always double-check the memory map in the build artifacts when such particular variable placements are necessary, and use the link_section attribute to be explicit.