Forum Rule: Always post complete source code & details to reproduce any issue!
Results 1 to 9 of 9

Thread: C++ Exceptions

  1. #1
    Junior Member
    Join Date
    Jan 2023
    Posts
    5

    C++ Exceptions

    I am working on porting a project that uses C++ exceptions to Teensy 4.1. The project is large, but at the moment I am not able to get exceptions to work properly at all even on the simplest of projects.

    I am running on Platformio with this configuration:
    Code:
    [env:teensy41-gcc11]
    platform = teensy
    platform_packages = 
        toolchain-gccarmnoneeabi@symlink:///home/perception/.platformio/packages/toolchain-gccarmnoneeabi@1.11.3.1.202208/
        ;platformio/toolchain-gccarmnoneeabi@1.90301.200702
        tool-teensy
    lib_deps = 
    	discord-intech/FreeRTOS-Teensy4@^10.0.5
    board = teensy41
    framework = arduino
    build_unflags = -std=gnu++11 -std=gnu++14 -fno-rtti
    build_flags = -std=c++17 
                  -Wl,-Map,output.map
                  -D_GLIBCXX_HAS_GTHREADS=1 
                  -Isrc/mutex_freertos
                  -D_GLIBCXX_HAVE_DIRENT_H 
                  -fexceptions

    This is my simple code:

    Code:
    #include <iostream>
    #include <chrono>
    #include <filesystem>
    #include <mutex>
    
    #include <Arduino.h>
    #include <string>
    #include <exception>
    
    int led = 13;
    
    void setup() 
    {
      pinMode(led, OUTPUT);
    }
    
    void loop() {
    
      try
      {          
            throw std::runtime_error("exception");       // wait for a second
      }
      catch(...)
      {
        while(true)
        {
            digitalWrite(led, HIGH);   // turn the LED on (HIGH is the voltage level)
            delay(100);               // wait for a second
            digitalWrite(led, LOW);    // turn the LED off by making the voltage LOW
            delay(100);        
        }
      }
    }

    With the default Teensy beta linker script just published for GCC11, the program won't link as soon as I enable exceptions and gives these errors:
    Code:
    .pio/build/teensy41-gcc11/libFrameworkArduino.a(startup.c.o):(.ARM.exidx.startup+0x0): relocation truncated to fit: R_ARM_PREL31 against `.startup'
    .pio/build/teensy41-gcc11/libFrameworkArduino.a(startup.c.o):(.ARM.exidx.startup+0x8): relocation truncated to fit: R_ARM_PREL31 against `.startup'
    .pio/build/teensy41-gcc11/libFrameworkArduino.a(startup.c.o):(.ARM.exidx.startup+0x10): relocation truncated to fit: R_ARM_PREL31 against `.startup'
    .pio/build/teensy41-gcc11/libFrameworkArduino.a(startup.c.o):(.ARM.exidx.flashmem+0x0): relocation truncated to fit: R_ARM_PREL31 against `.flashmem'
    .pio/build/teensy41-gcc11/libFrameworkArduino.a(startup.c.o):(.ARM.exidx.flashmem+0x8): relocation truncated to fit: R_ARM_PREL31 against `.flashmem'
    .pio/build/teensy41-gcc11/libFrameworkArduino.a(startup.c.o):(.ARM.exidx.flashmem+0x10): relocation truncated to fit: R_ARM_PREL31 against `.flashmem'
    .pio/build/teensy41-gcc11/libFrameworkArduino.a(startup.c.o):(.ARM.exidx.flashmem+0x18): relocation truncated to fit: R_ARM_PREL31 against `.flashmem'
    .pio/build/teensy41-gcc11/libFrameworkArduino.a(startup.c.o):(.ARM.exidx.flashmem+0x20): relocation truncated to fit: R_ARM_PREL31 against `.flashmem'
    .pio/build/teensy41-gcc11/libFrameworkArduino.a(startup.c.o):(.ARM.exidx.flashmem+0x28): relocation truncated to fit: R_ARM_PREL31 against `.flashmem'
    .pio/build/teensy41-gcc11/libFrameworkArduino.a(tempmon.c.o):(.ARM.exidx.flashmem+0x0): relocation truncated to fit: R_ARM_PREL31 against `.flashmem'
    .pio/build/teensy41-gcc11/libFrameworkArduino.a(usb.c.o):(.ARM.exidx.flashmem+0x0): additional relocation overflows omitted from the output

    I can fix these errors by modifying the linker script such that the general text AND the .ARM.exidx sections get put into flash:

    Code:
    	.text.progmem : {
    		*(.progmem*)
    		*(.text*)
    		. = ALIGN(4);
    	} > FLASH
    
    	.text.itcm : {
    		. = . + 32; /* MPU to trap NULL pointer deref */
    		*(.fastrun)
    		. = ALIGN(16);
    	} > ITCM  AT> FLASH
    
    	.ARM.exidx : {
    		__exidx_start = .;
    		*(.ARM.exidx* .ARM.extab.text* .gnu.linkonce.armexidx.*)
    		__exidx_end = .;
    	} AT> FLASH

    This will compile, link, and execute but exceptions do not get caught. I don't have a debugger, but considering that the uC seems to reboot, I'm guessing its going to std::terminate(). I have read about issues with previous version of the ARM toolchain, but my understanding is that this was fixed. I have also looked at the map file to ensure that it's not linking the nano versions of newlib.

    I don't know if the .ARM.exidx section needs to be in some kind of RAM to work properly, but if so, I don't know how to also put the startup in RAM (or at least ITCM) as well. I believe that the startup has to run from flash, but if so, the .ARM.exidx would have to be in Flash to to prevent the R_ARM_PREL31 error.

  2. #2
    Junior Member
    Join Date
    Jan 2023
    Posts
    5
    I believe this is due to a bug in the linker script.

    The 1.58 beta linker script has:

    Code:
    	.ARM.exidx : {
    		__exidx_start = .;
    		*(.ARM.exidx* .gnu.linkonce.armexidx.*)
    		*(.ARM.exidx* .ARM.extab.text* .gnu.linkonce.armexidx.*)
    		__exidx_end = .;
    	} > ITCM  AT> FLASH
    I found another script online that does this instead and it seems to fix the exception handling:

    Code:
        
             .ARM.extab : ALIGN(8) 
             {
                 *(.ARM.extab* .gnu.linkonce.armextab.*)
             } > FLASH
    
    	.ARM.exidx : ALIGN(8) {
        __exidx_start = .;
            *(.ARM.exidx* .gnu.linkonce.armexidx.*)
        __exidx_end = .;
    	} > FLASH

  3. #3
    Senior Member+ defragster's Avatar
    Join Date
    Feb 2015
    Posts
    16,863
    Is this with the Beta 3 version of the 1.58 release with the updated tool chain?

    With p#2 edit are the exceptions now properly working as expected?

  4. #4
    Junior Member
    Join Date
    Jan 2023
    Posts
    5
    At the moment, I’m not explicitly using the beta, but I was using the latest linker script from the github repository with the 11.3.1 toolchain (as described above). After I moved the extab section above the rest of the exidx, the exceptions started working properly.

  5. #5
    Senior Member+ defragster's Avatar
    Join Date
    Feb 2015
    Posts
    16,863
    It might be best to confirm with the 1.58 Beta install - currently #3?

    The tool chain is getting updated and if the linker script change is safe and good - and it works with the pending update to the toolchain it might make sense to have it considered.

  6. #6
    Junior Member
    Join Date
    Jan 2023
    Posts
    5
    Quote Originally Posted by defragster View Post
    It might be best to confirm with the 1.58 Beta install - currently #3?

    The tool chain is getting updated and if the linker script change is safe and good - and it works with the pending update to the toolchain it might make sense to have it considered.
    I’ll give it a go tomorrow. In the meantime, here is a related issue that gave me the information to solve the problem. The apparent bug is slightly different here, but I think adding the extab where it currently is breaks whatever data structure the exception handling is using.

    https://community.nxp.com/t5/MCUXpre...on/m-p/1015296

  7. #7
    Senior Member+ defragster's Avatar
    Join Date
    Feb 2015
    Posts
    16,863
    Quote Originally Posted by pionex View Post
    I’ll give it a go tomorrow. In the meantime, here is a related issue that gave me the information to solve the problem. The apparent bug is slightly different here, but I think adding the extab where it currently is breaks whatever data structure the exception handling is using.

    https://community.nxp.com/t5/MCUXpre...on/m-p/1015296
    Great if you can see it work on the Beta of 1.58 so it might get changed and work going forward with the new toolchain.

    Interesting - seems a simple alignment/location issue of a couple of bytes the linker can get right.

    Not sure there has been much interest in, or use of, exceptions but, having them as a working option might be beneficial.

    One test case in p#1, if others are handy to post they might make for good test and usage examples.

  8. #8
    Senior Member+ KurtE's Avatar
    Join Date
    Jan 2014
    Posts
    11,414
    Note: I believe there have been some other threads in the past about this.
    Like: https://forum.pjrc.com/threads/64573...ling-on-Teensy

    There are times it would be great, but not sure as a default as might add lots of overhead to handle the undwinding.

  9. #9
    Junior Member
    Join Date
    Jan 2023
    Posts
    5
    Quote Originally Posted by KurtE View Post
    Note: I believe there have been some other threads in the past about this.
    Like: https://forum.pjrc.com/threads/64573...ling-on-Teensy

    There are times it would be great, but not sure as a default as might add lots of overhead to handle the undwinding.
    I agree with this and given the number of modifications that have to be done, I think this is likely to be limited to manual / platformio compilation for specific projects (although we aren't exactly using a resource limited processor with a Teensy 4.1). There are a lot of c++ libraries that use exceptions however, and I assume this could be a major use case for enabling them. I have looked at the ARM documentation https://github.com/ARM-software/abi-...Q1/ehabi32.pdf and I do think there is a bug in the linker script that can be fixed without causing any other side effects.

    Namely:
    5.4.1 Sections
    An object producer must generate:
    • One fragment of index table for each code section.
    • One exception-handling table entry corresponding to each function that may need to be unwound.
    Each fragment of index table (read-only data) must be generated in its own ELF section. It must contain an index entry
    for each non-leaf function in the associated code section, in the same order as that of the functions in the code
    section. The index table section name must be .ARM.exidx optionally followed by further characters. The section
    type must be SHT_ARM_EXIDX (see [AAELF32]). It must have the SHF_LINK_ORDER flag set in the sh_flags field of
    its section header and be linked to its associated code section via the sh_link field of its section header.
    An object producer may generate exception-handling table entries (read-only data) in one ELF section, or one section
    per function. The name of a section containing an exception table fragment must be .ARM.extab optionally followed
    by further characters. The section type must be SHT_PROGBITS.
    To me, that reads that they should be in different sections and that seems to actually make things work empirically.

    To actually get exceptions working requires more than fixing that issue. For one thing, the compiler flags have to be changed from -fno-exceptions to -fexceptions. The teensy linker script runs all of the code from ITCM but puts the .ARM.exidx section in flash. This will not link because of the 31-bit address issue. I currently run all of the code I'm porting from Flash (also because it's too big for ITCM). That causes an issue when I try to write to the flash using LittleFS and all flash code must be executed from RAM. As a result I have put eeprom.c into ITCM as well as it's exidx data (otherwise it won't link). So far that seems to be running fine.

    .text.itcm : {
    . = . + 32; /* MPU to trap NULL pointer deref */
    *(.fastrun)
    *libFrameworkArduino.a:eeprom.c.o(.text* .ARM.exidx.text* )
    . = ALIGN(16);
    } > ITCM AT> FLASH
    So for the purposes of the beta, I think the only thing that can likely be done is just to continue to verify that moving .ARM.extab to it's on section is the correct thing to do, and provide some external documentation for anyone that wants to enable exceptions.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •