Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
BlueAndi opened this issue Dec 23, 2019 · 7 comments
Open

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

BlueAndi opened this issue Dec 23, 2019 · 7 comments
Assignees

Comments

@BlueAndi
Copy link

Environment

  • Development Kit: [ESP32-DevKitC]
  • Kit version (for WroverKit/PicoKit/DevKitC): [v1|v2|v3|v4]
  • Module or chip used: [ESP32]
  • IDF version: v3.2.3-105-g65db2bf87
  • Build System: [PlatformIO]
  • Compiler version: 1.22.0-80-g6c4433a5
  • Operating System: [Windows]
  • Power Supply: [external 5V]

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
...
@github-actions github-actions bot changed the title IRAM_ATTR ignored for templated function IRAM_ATTR ignored for templated function (IDFGH-2429) Dec 23, 2019
@Alvin1Zhang
Copy link
Collaborator

@BlueAndi Thanks for reporting.

@BlueAndi
Copy link
Author

BlueAndi commented Jan 6, 2020

@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
Copy link

atlaste commented Feb 6, 2022

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
Copy link
Contributor

0xjakob commented Feb 7, 2022

@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...

@0xjakob 0xjakob self-assigned this Feb 7, 2022
@atlaste
Copy link

atlaste commented Feb 8, 2022

@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:

  • float's and ISR's didn't mix,
  • vtables didn't mix,
  • switches didn't mix, (I hope they are not generated implicitly by the compiler) and now
  • templates don't seem to mix.

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
Copy link
Author

BlueAndi commented Feb 8, 2022

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

dhebbeker added a commit to dhebbeker/robot-control that referenced this issue May 19, 2022
dhebbeker added a commit to dhebbeker/robot-control that referenced this issue May 19, 2022
This is necessary as:

 - C++11 is used and there max() is not declared constexpr
 - C++11 is used because the compiler version supporting C++14 has a bug (see espressif/esp-idf#4542)
 - function must be declared in a namespace, as Arduino.h declares std::max in global namespace 😠 esp8266/Arduino@dfcaa1b#diff-3d1fc8ffad5bc435eea7c0970e45f03a0cd0c8c95bb3840b939251d2a877ee95R251
 - code copied from https://en.cppreference.com/w/cpp/algorithm/max#Possible_implementation
@malachib
Copy link

malachib commented Mar 7, 2023

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...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants