2

I'm working with some code that targets an unusual embedded system that requires distinct processor instructions to read from its read-only memory.

For variables to be placed in said read-only memory, they must be marked with an attribute that places them in a designated section whose contents will be placed into read-only memory.

It would be useful to be able to programmatically determine which section a variable is stored in so that I can determine, at compile-time, which variables are going to be stored in RAM (and thus can use ordinary pointer dereferencing and reference reading) and which variables are going to be stored in ROM (and thus require specialised access code written in assembly).

Having access to such a feature would allow me to do something like:

template<typename Type>
struct data_pointer
{
    Type * pointer;

    data_pointer(Type * pointer, bool) :
        pointer { pointer } {}

    // Non-const data cannot be readonly
    Type & operator *()
    {
        return *pointer;
    }
};

template<typename Type>
struct data_pointer<const Type>
{
    const Type * pointer;
    bool is_readonly;

    data_pointer(const Type * pointer, bool is_readonly) :
        pointer { pointer },
        is_readonly { is_readonly }
    {}

    // Const data might be in RAM or ROM
    const Type operator *()
    {
        return (is_readonly ? *pointer : readonly_dereference(pointer));
    }
};

#define make_data_pointer(object) \
    (data_pointer(&object, is_in_readonly_section(object)))

Where:

  • readonly_dereference is the mechanism by which a pointer to a value in the read-only memory area is read.
  • is_in_readonly_section(object) is the hypothetical compile-time predicate that would be necessary to make the mechanism seamless.

Does GCC have anything akin to this hypothetical is_in_readonly_section compile-time predicate, or am I out of luck?

I could manage without it, but not having it means that the end user would be responsible for ensuring that their data_pointers point to the right kind of memory, which is liable to be a far more error-prone scenario than if the compiler could be made to bear the burden.

8
  • 2
    AFAIK where things end up is mostly determined by the linker not the compiler. So I would not expect "reflection" at compile time to be able to work. Commented Nov 24, 2024 at 17:34
  • 3
    What if you go the other way around? If you want an object to go in readonly memory, you wrap it in a class. ReadOnly<int> foo; would define an object with the right attribute, with a conversion operator that executes the appropriate instruction. And now you can distinguish read-only objects because they are really a different C++ type. Commented Nov 24, 2024 at 18:36
  • @NateEldredge The trouble there is that the attribute can't be applied to non-static member variables, only to objects with static storage duration (globals, static members, and static locals), so there's no way to make a class that could be its own storage. I think the closest I could get to that would be to do something like const rom<Type> var ROM { value }; and then read the data either with an explicit var.read(), rom_read(var), or (possibly dangerous) by overloading operator Type(). It's a little better, but still error prone... Commented Nov 24, 2024 at 19:43
  • @NateEldredge Specifically, it's reliant upon the user to remember that: rom<Type> can only be used for variables with static storage duration, that it must always be used alongside ROM, and that rom<Type> must never be used as a non-static local variable, non-static member variable, or a parameter, and that only rom<Type> & and rom<Type> * are safe to use in those circumstances. Potentially a macro could alleviate rom<Type> always requiring ROM, but it would look ugly (e.g. ROMDATA(Type, var) { value };). It might also be tricky to initialise e.g. arrays. Commented Nov 24, 2024 at 19:48
  • 1
    @Pharap Yes I appreciate there are cases where hardware (in)capabilities are leading and control over what ends up where is important :) And about compiler intrinsics I would say they're not that bad (as long as they can be implemented for any platform) Commented Nov 26, 2024 at 14:03

1 Answer 1

3

GCC provides __builtin_has_attribute which can do this.

#include <iostream>

int x;
int y __attribute__((section("foobar")));

int main() {
    std::cout << "x:" << __builtin_has_attribute(x, section("foobar")) << "\n";
    std::cout << "y:" << __builtin_has_attribute(y, section("foobar")) << "\n";
}

prints

x: 0
y: 1

Try on godbolt

The result of __builtin_has_attribute behaves as an integer constant expression, so can be used to select alternatives at compile time.

Of course, this only works if a declaration of y with the section("foobar") attribute is in scope.

Sign up to request clarification or add additional context in comments.

4 Comments

Tragically the version of GCC I have to work appears to be too early to support this feature. I'll accept regardless because this does indeed answer the question and is as good an answer as I could have hoped for.
I guess another option is, at least for debugging, put in some runtime asserts that the address is in the correct range.
@Pharap: Looks like it was introduced in GCC 9.x, about five years ago.
"put in some runtime asserts that the address is in the correct range. " Unfortunately that won't work because the addresses are in entirely separate address spaces. Imagine trying to tell apart indices for two separate arrays by examining the indices: 0 is 0 regardless of which array it's intended to index. If it were possible to tell them apart (e.g. via the range), the hardware wouldn't need separate instructions for reading them. "Looks like it was introduced in GCC 9.x, about five years ago." Unfortunately yes, that's too recent for what I'm stuck working with at the moment.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.