Skip to content

undefined reference to std::__throw_length_error, std::__throw_bad_alloc #39

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

Open
sprintersb opened this issue May 10, 2025 · 16 comments
Open

Comments

@sprintersb
Copy link

Test case:

#include <vector>

std::vector<int> v;

int main (void)
{
    v.push_back (1);
}

Invocation:

$ avr-g++-15 -mmcu=atmega128 -Os main.cpp -I$DIR/include $DIR/examples/common/new.cpp $DIR/examples/common/cxxabi.cpp -fno-exceptions -std=c++17

where $DIR denotes the top_srcdir of avr-libstdcpp. The message from the linker is:

$prefix/bin/../lib/gcc/avr/15.1.1/../../../../avr/bin/ld: main.o: in function `.L2':
main.cpp:(.text.startup+0x48): undefined reference to `std::__throw_length_error(char const*)'
$prefix/bin/../lib/gcc/avr/15.1.1/../../../../avr/bin/ld: new.o: in function `operator new(unsigned int)':
new.cpp:(.text+0x8): undefined reference to `std::__throw_bad_alloc()'
$prefix/bin/../lib/gcc/avr/15.1.1/../../../../avr/bin/ld: new.o: in function `operator new[](unsigned int)':
new.cpp:(.text+0x16): undefined reference to `std::__throw_bad_alloc()'
collect2: error: ld returned 1 exit status

where $prefix denotes the installation path of the toolchain (what has been specified with configure).

Configured with: ../../source/gcc-15/configure --target=avr --disable-nls --with-dwarf2 --with-gnu-as --with-gnu-ld  --with-long-double=64 --disable-libcc1 --disable-shared --enable-languages=c,c++
Thread model: single
Supported LTO compression algorithms: zlib
gcc version 15.1.1 20250430 (GCC)

I see that there is stuff in src/functexcept.cc, other parts of the stdlib like new are located in examples/common.

Isn't there one place for object sources that would be expected in some libstdc++? Concerning the error above, is there a way to avoid using these throw handlers? compiling with -fno-exceptions didn't do the trick.

@sprintersb sprintersb changed the title undefined reference to `std::__throw_length_error, std::__throw_bad_alloc undefined reference to std::__throw_length_error, std::__throw_bad_alloc May 10, 2025
@jwakely
Copy link

jwakely commented May 10, 2025

Compiling with -fno-exceptions means there is no throw or catch, but the library still needs to report errors somehow. That's what the __throw_xxx() functions are for. The definitions of those functions can just abort the program if they're compiled without exceptions.

@sprintersb
Copy link
Author

sprintersb commented May 10, 2025

I am still confused about how to use the new.cpp module. It has several implementations of new with different allocators, some that throw and some that don't. Now when I use an allocator that doesn't throw, there will be also a variant of new that does throw. This is since the new variants are not provided by means of a proper library, but all functions are in one big module, new.cpp so when one function is used, then all the others will get linked as well.

My question is basically about the documentation of how to use that stuff in the absence of exception handling (like with avr-g++ where we don't have exceptions AFAIU). Must I copy the new.cpp unit and ditch all throw variants? How to make modules like <vector> use the non-throwing variant? etc

I didn't try it, but shouldn't the problem be resolved by putting each function in its own module?

@salkinium
Copy link
Member

salkinium commented May 10, 2025

There's more integration code in modm that hasn't made it over here yet.

Most of this is actually shared code between AVR and ARM targets, that's why it hasn't been moved here, since it's a pain to keep in sync.

@sprintersb
Copy link
Author

So if I understand correctly the avr-libstdcpp project is not for stand-alone usage with avr-g++ but rather an appendage of modm?

@salkinium
Copy link
Member

salkinium commented May 10, 2025

Yes correct. The support files in modm provide an opinionated integration, where a decision needs to be made. Like how do you handle __throw_*, do you loop forever (hard to detect), restart (can lead to boot loops), log something (requires a configured UART )? These are things that the integrator needs to provide, in this case that's modm.

Obviously we could improve the situation regarding documentation, however, it's rare for developers on AVRs to use "advanced" C++ features like libstdc++ outside of modm, so we focus our time and motivation on the other (ARM Cortex-M) parts of modm.

@sprintersb
Copy link
Author

sprintersb commented May 10, 2025

A canonical approach is to implement a weak symbol that does the "work" (e.g. infinite loop), and when someone want something else, they can implement the symbol and hook in. That's the approach taken by avr-libgcc's _exit for example.

@ckormanyos
Copy link
Collaborator

So if I understand correctly the avr-libstdcpp project is not for stand-alone usage with avr-g++ but rather an appendage of modm

Yes correct. The support files in modm provide an opinionated integration

Sure that's one way of looking at it. But many clients do, in fact, use only avr-libstdcpp in a standalone mode. It can be used without including any other parts of modm. I consider this to be very valuable. I think we need to clarify what exactly standalone or appendage means. The STL port can be used as a single repo if you like.

@salkinium
Copy link
Member

@sprintersb did the modm files help you to integrate this library?

@sprintersb
Copy link
Author

sprintersb commented May 15, 2025

I am just pondering if it would be feasible / a good idea to use avr-libstdcpp to add more C++ support to an GNU Tools for AVR distribution (avr-gcc + Binutils + AVR-LibC).

The current situation is that in the default configuration, avr-g++ doesn't provide any C++ library support, neither headers nor libs. AVR-LibC has the build infrastructure and deduces multilib layout from gcc, so at first it seems avr-libstdcpp may be a viable route, i.e. to build and distribute avr-libstdcpp as part of AVR-LibC provided some TBD configure options are set. However:

  • Some files seem to be hosted by modm directly, not in the avr-libstdcpp project.
  • Sources seem to be sprinkled all over the place, for example new and friends are located in examples/common.
  • The sources are not in a one-function-per-module configuration as needed for a proper library. For example new.cpp contains more than 10 functions that are not secured by #ifdef's (so you cannot pick one specific function for a translation unit / object file).

The preferred solution would be to provide C++ library support in AVR G++ of course, though noone ever succeeded in getting that to work; not even for libsupc++. Dunno where the libstdc++v3 restistance comes from and what's needed. Maybe Jonathan @jwakely can share some insights what's missing to make C++ + AVR work in GCC.

@ckormanyos
Copy link
Collaborator

ckormanyos commented May 15, 2025

I am just pondering if it would be feasible / a good idea to use avr-libstdcpp to add more C++ support to an GNU Tools for AVR distribution

Indeed, @sprintersb, I have often pondered this also. I believe there could be progress. But there would be some definite challenges.

what's missing to make C++ + AVR work in GCC

Well there could be some very challenging areas. First of all using containers can be done. But I fear that clients could get confused when running out of memory on vector or anything like that.

Another challenge is AVR's somewhat unique stance on the meaning of global const which often lands in RAM.

Some challenging libraries would include <regex> and <thread>.

On the other hand the big freestanding movement which will flow straight into C++26 could/should eliminate or aleviate many problems. I could envision a world having AVR STL in freestanding only.

I'd like to hear @jwakely thoughts on some of this also.

@jwakely
Copy link

jwakely commented May 15, 2025

The preferred solution would be to provide C++ library support in AVR G++ of course, though noone ever succeeded in getting that to work; not even for libsupc++.

That's not true at all, I've built it myself. All of libstdc++, not just libsupc++. I know other people are building it too:
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=115482

Dunno where the libstdc++v3 restistance comes from and what's needed.

There is no resistance. Somebody just needs to do the work.

My employer (Red Hat) has zero interest in 8-bit microcontrollers, so all the work I've done to support avr (e.g. here for avr-libstdcpp, or https://gcc.gnu.org/bugzilla/show_bug.cgi?id=97570 https://gcc.gnu.org/bugzilla/show_bug.cgi?id=115481 https://gcc.gnu.org/bugzilla/show_bug.cgi?id=104870 https://gcc.gnu.org/bugzilla/show_bug.cgi?id=104875 etc.) has been on my own time.

A current blocker (for some versions of avr-libc) is https://gcc.gnu.org/bugzilla/show_bug.cgi?id=111639 but it's a simple matter of programming to get it building again.

@sprintersb
Copy link
Author

sprintersb commented May 15, 2025

all the work I've done to support avr [...] has been on my own time.

Same here :-)

IIUC, PR97570, PR104870, PR104875 have already been fixed some time ago.

For PR115481 "HAVE_ for long double":

Should GCC 14 support older versions of avr-libc? Or can we assume that anybody trying to build
libstdc++ (which requires an explicit --enable-libstdcxx for avr) is using a new avr-libc?

I could simply add a caveat to the GCC Release Notes for the respective release that mentions which minimum AVR-LibC version is required for --enable-libstdcxx.

For PR111639 "HAVE_ACOSF" similar could be done.

What I don't know how is how building the tools is supposed to be done. Currently I am (which is from AVR-LibC's build instructions):

  1. Build + Install avr Binutils
  2. Build + Install avr gcc
  3. Build + Install AVR-LibC

i.e. 2) doesn't know anything about AVR-LibC (and AVR-LibC doesn't support in-tree buils in GCC like for example Newlib does).

To make things more complicated, AVR-LibC configure depends on avr-gcc capabilities (like multilib layout, features like CVT, device support and whatnot), so we have a catch 22?

What's also unclear is whether the backend is missing some bits, like e.g. for exceptions. libc supports longjmp, and __builtin_longjmp should also work, but the internals don't explain what to do next.

@ckormanyos
Copy link
Collaborator

ckormanyos commented May 15, 2025

I've looked into full C++ support on AVR a few times. I don't see any fundamental blockers. But there would be a lot of work to be done. There are some rather tiny architectures out there with full library support. AVR would have a few specific challenges. It's something we could talk about, but it's a long ways off.

To make things more complicated, AVR-LibC configure depends on avr-gcc capabilities

I actually use both GCC as well as AVR-LibC in my action that builds avr-gcc. We even worked together on an issue or two to get architectures like 4809 into the devices of your AVR-LibC. It was maybe a year ago.

I build on MinGW for Win* and Ubuntu for *nix. On msys, I use a standalone version of MinGW from another author. I just released GCC 15.1.0 yesterday, which led to some of the chat content here. So there is how I ended up putting all this together.

I'll keep watching AVR. It's one of those amazing things on the books and it sure would be cool to have more C++ support on that amazing little chip.

@sprintersb
Copy link
Author

sprintersb commented May 15, 2025

my action that builds avr-gcc.

As an aside, GCC has ./contrib/download_prerequisites that downloads GMP, MPFR, MPC and friends, and links them into the source tree. configure and build will take care of all these host lib dependencies like a charm.

  • Will use the version of either host lib as expected by GCC.
  • In-tree builds are much more convenient, in particular in canadian cross builds.
  • Lib versions may be other than these of (potentially) installed libs.
  • Downside is slightly increased build time when you do many (re-)builds of the compiler.

@salkinium
Copy link
Member

salkinium commented May 15, 2025

I would personally be very happy if this work was upstreamed! I personally don't use AVRs anymore, neither do the devs that started this, so it's only reluctantly maintained by me at the moment. Christopher and James have more of less taken over the maintance.

@ckormanyos
Copy link
Collaborator

ckormanyos commented May 16, 2025

I would personally be very happy if this work was upstreamed!

Well we also have #23, which both then and now still seems like a good idea. That echoes exactly the same sentiment.

I personally don't use AVRs anymore, neither do the devs that started this, so it's only reluctantly maintained by me at the moment. Christopher and James have more of less taken over the maintance.

I'm not sure where to go with this work. It is a very nice work, and this library, I believe, has a lot of value. I also use this library with gcc-arm-none-eabi on occasion, even though those compilers have their own complete and excellent standard libraries.

I'm willing to keep working here or elsewhere on this project. Going all-in, however, on a GCC C++ library (plus STL) port for AVR would be a big step. Even getting the tests to compile and run would be a huge effort. Realistically, I see this thing a few years out of full GCC inclusion, which puts me in retirement basically.

I would like to find an intermediate solution between upstreming it and neglecting it. This is because of this library's high value and the sheer distance it probably is away from upstreaming in GCC.

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

No branches or pull requests

4 participants