espressif / esp-idf

Espressif IoT Development Framework. Official development framework for Espressif SoCs.
Apache License 2.0
13.63k stars 7.28k forks source link

IRAM_ATTR ignored for templated function (IDFGH-2429) #4542

Open BlueAndi opened 4 years ago

BlueAndi commented 4 years ago

Environment

Problem Description

IRAM_ATTR is ignored for templated function, like https://gcc.gnu.org/bugzilla/show_bug.cgi?id=70435

Expected Behavior

IRAM_ATTR is considered.

Code to reproduce this issue

#include <Arduino.h>

template <typename Type>
class TestClass
{
public:
    TestClass(Type value) :
        m_value(value)
    {
    }

    Type m_value;

    Type IRAM_ATTR add(Type value) const _NOINLINE
    {
        return m_value + value;
    }
};

static TestClass<int> myTest(5);

void setup()
{
}

void loop()
{
    Serial.println(myTest.add(random(10)));
}

Debug Logs

Check via xtensa-esp32-elf-nm.exe

...
400e8710 W TestClass<int>::add(int) const
...
Alvin1Zhang commented 4 years ago

@BlueAndi Thanks for reporting.

BlueAndi commented 4 years ago

@Alvin1Zhang You are welcome. :-) It looks like a lot of 3rd party libs are not aware of this problem. I am curious about a solution.

atlaste commented 2 years ago

We encountered this issue as well in our firmware. Specifically while using templates of function pointers. We used to attach ISR's by using a template that gives us type safety. It works by using a helper function:

    template <typename ThisType, void (ThisType::*Callback)()>
    struct InterruptCallbackHelper {
        static void IRAM_ATTR callback(void* ptr) { (static_cast<ThisType*>(ptr)->*Callback)(); }
    };

Apparently the callback is not stored in IRAM, and when it is triggered while flash is accessed, the esp crashes. We actually found this out by objdump'ing the binary in question and checking if it was in flash or IRAM.

This appears to be the case for all templates. It's quite a nasty bug - consider using std::atomic<T> for example in an ISR!

0xjakob commented 2 years ago

@atlaste Currently, we don't have an automatic way to place template functions into IRAM. You can still do it manually, though.

Besides, there might be mitigations available depending on the circumstances:

If that doesn't help, there are ways to manually place the functions into flash via the linker. Not convenient but it should work. I did this a long time ago but don't have the information at hand right now. Need to find this again...

atlaste commented 2 years ago

@atlaste Currently, we don't have an automatic way to place template functions into IRAM. You can still do it manually, though.

Could you elaborate this further? What's missing and why is this not simply working?

Besides, there might be mitigations available depending on the circumstances:

If that doesn't help, there are ways to manually place the functions into flash via the linker. Not convenient but it should work. I did this a long time ago but don't have the information at hand right now. Need to find this again...

Most of our interrupts are very timing critial; I'm a collaborator of FluidNC, the frequently used CNC firmware, used by thousands of people. We use ISR's for things like probes, endstops and motor stepping. We are well aware of the possibilities to offload things to tasks via a queue and handling it in a task, but most of what we need here is very time critical. If we don't catch a probe or endstop in time, things will simply be destroyed. As for the C3, we wanted to make the leap to the S3 at some point because it seems like a better match - but so far I haven't been able to obtain one (out of stock). Regardless of that, there will still be a lot of people using the firmware with normal ESP's.

Most of the crashes we had in the past seemed to originate from ISR's. Apparently:

My main issue is: where does it stop and what are we still missing? Now it's just guessing... We've been adding things to a custom linker script to place them in IRAM manually. It's a bit of a pain, and as a result we have to put way more in IRAM than we really need to get vtables and switches working. I attempted to get rid of switches with templates, but apparently that's out of the window too... Obviously there's a limit here.

This template case got me concerned. Atomic is just one case. Vectors come to mind. And many, many more hidden templates that are used in the STL for template specialization to who knows what, even in different compilation units...

I hope you see my concern, so I'd rather work towards getting this solved in the compiler if possible, or at the very least have a list of what will and what will not work in an ISR, so I can do an extensive review of all the relevant code.

BlueAndi commented 2 years ago

Note, the root cause seems this bug, as I mentioned in the issue description.: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=70435

malachib commented 1 year ago

I observe that with a linker script, one might be specify their own name convention and pick them up into IRAM with the help of wildcards (ala https://stackoverflow.com/questions/36279162/section-attribute-of-a-function-template-is-silently-ignored-in-gcc)

Is there a way to accomplish this (including the wildcards) with esp-idf linker fragments? I am smacking face first into this issue, never did I anticipate I wouldn't be able to use my templated functions in this scenario...