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

__cxa_get_globals is not a member of abi #59

Closed
Johnnyxy opened this issue Jun 12, 2019 · 15 comments

Comments

@Johnnyxy
Copy link

commented Jun 12, 2019

Hi there,
when building Boost for QNX SDP 7.0 (QCC 5.4.0) I get an error in the uncaught_exceptions.hpp file.

error

In file included from ./boost/log/detail/format.hpp:26:0,
from libs\log\src\format_parser.cpp:25:
./boost/core/uncaught_exceptions.hpp: In function 'unsigned int boost::core::uncaught_exceptions()':
./boost/core/uncaught_exceptions.hpp:109:66: error: '__cxa_get_globals' is not a member of 'abi'
std::memcpy(&count, reinterpret_cast< const unsigned char* >(::abi::__cxa_get_globals()) + sizeof(void*), sizeof(count)); // __cxa_eh_globals::uncaughtExceptions, x32 offset - 0x4, x64 - 0x8

background

QNX 7.0 actually has a __cxa_get_globals function but does not expose it through cxxabi.h like some systems, according to the code docs:

// At least on MinGW and Linux, only GCC since 4.7 declares __cxa_get_globals() in cxxabi.h. Older versions of GCC do not expose this function but it's there.

In the QNX compiler cxxabi.h source it is defined at line 605 (see attachment).
cxxabi.h.txt

compile fix

I fixed compilation by patching the uncaught_exceptions.hpp at line 62, adding the QNX Neutrino macro __QNXNTO__ (this is defined for QNX versions > 4).
from:

#if !defined(__FreeBSD__) && \
    ( \
        (defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__) < 407) || \
        defined(__OpenBSD__) || \
        defined(_LIBCPPABI_VERSION) \
    )

to:

#if !defined(__FreeBSD__) && \
    ( \
        (defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__) < 407) || \
        defined(__OpenBSD__) || \
        defined(__QNXNTO__) || \
        defined(_LIBCPPABI_VERSION) \
    )

I will test this a little bit more but until now this does the trick.

@Lastique

This comment has been minimized.

Copy link
Member

commented Jun 12, 2019

I'm not sure I understand. In the file you attached, __cxa_get_globals is defined, so it should be accessible. The preprocessor workaround in uncaught_exceptions.hpp is there for systems that don't declare __cxa_get_globals in cxxabi.h. Are you sure you're including the right cxxabi.h in your project?

@Johnnyxy

This comment has been minimized.

Copy link
Author

commented Jun 12, 2019

The problem is that even building Boost log does not work. My code does not even get compiled yet.

It was odd for me too that __cxa_get_globals it is declared in the cxxabi.h but while building Boost log it still does get the mentioned error.

@Lastique

This comment has been minimized.

Copy link
Member

commented Jun 12, 2019

Try looking at the preprocessed output and track what headers are included. It is also possible that there is some sort of macro collision that causes __cxa_get_globals to disappear.

You can see full command lines used to build Boost if you add -d+2 to the b2 command line. Use that command line for the failing file and modify it to produce preprocessed output.

@Johnnyxy

This comment has been minimized.

Copy link
Author

commented Jun 13, 2019

Hi,
I did modify the compiler execution to only preprocess and output the preprocessed code to a file gcc-compiler-variant ... -E -P ... > preprocessed.cpp.

What I found was that cxxabi.h was actually included. This would mean that the code had to be included but it was not. Now after a little investigation I found out that there are two (for QNX SDP 7.0) in the future maybe more cxxabi.h variants (not only of this file, serval others too). These variants depend on the libcxx one links against.

For QNX SDP 7.0 there are by default two C++ libraries available (see docs) "GNU C++ library" (QNX abbr. name: gpp) and "LLVM C++ library" (QNX abbr. name: cxx) which is the default.
The GNU C++ library comes with a cxxabi.h that defines the __cxa_get_globals as one can see here while the LLVM C++ library does not (see attachment).
QNX SDP 7.0 cxx cxxabi.h.txt

I did a text search for __cxa_get_globals and it is not provided in any other file except for the GNU C++ library variant.

conclusion

This means only for the LLVM library boost needs to provide its own definition of __cxa_get_globals, maybe additionally with others that are needed.
At the moment I do not know if it is possible to detect the library by some macro as the include path is already set by the QNX "compiler" which is a GCC wrapper with target specific parameters.

@Lastique

This comment has been minimized.

Copy link
Member

commented Jun 13, 2019

Right, and they commented _LIBCPPABI_VERSION define just to make life more fun to the developers. Oh, joy. You should really report this bug to QNX developers.

@Johnnyxy

This comment has been minimized.

Copy link
Author

commented Jun 13, 2019

For the LLVM variant there is a __config header file. This header file only exists in the LLVM variant.
Also there is a macro #define _LIBCPP_VERSION 3700 as well as #define _LIBCPP_ABI_VERSION 1 (see attachment).
__config.txt

I will try to do a workaround to detect if the __cxa_get_globals has to be included by Boost.

@Lastique Lastique closed this in 420dff8 Jun 13, 2019

@Lastique

This comment has been minimized.

Copy link
Member

commented Jun 13, 2019

Thank you for your investigation, I've committed 420dff8 as a tentative fix. Could you verify if it works?

@Lastique

This comment has been minimized.

Copy link
Member

commented Jun 13, 2019

Regarding __config, I don't see it being included by LLVM's cxxabi.h. Can you confirm it is being included indirectly?

@Lastique

This comment has been minimized.

Copy link
Member

commented Jun 13, 2019

Although, nevermind. __config is part of libc++, not libc++abi, which is considered a separate library. libc++ can be used with glibcxx, so it can't be used to detect libc++abi.

@Johnnyxy

This comment has been minimized.

Copy link
Author

commented Jun 13, 2019

The output of the preprocessed code shows that the __config has been included serval times.
So to answer your question, yes the __config gets included directly.

# 1 "./boost/config/compiler/gcc.hpp" 1
# 165 "./boost/config/compiler/gcc.hpp"
# 1 "c:\\qnx700\\target\\qnx7\\usr\\include\\c++\\v1\\cstddef" 1 3 4
# 36 "c:\\qnx700\\target\\qnx7\\usr\\include\\c++\\v1\\cstddef" 3 4
# 1 "c:\\qnx700\\target\\qnx7\\usr\\include\\c++\\v1\\__config" 1 3 4
# 15 "c:\\qnx700\\target\\qnx7\\usr\\include\\c++\\v1\\__config" 3 4
       
# 16 "c:\\qnx700\\target\\qnx7\\usr\\include\\c++\\v1\\__config" 3
# 25 "c:\\qnx700\\target\\qnx7\\usr\\include\\c++\\v1\\__config" 3
# 1 "c:\\qnx700\\target\\qnx7\\usr\\include\\unistd.h" 1 3 4
# 27 "c:\\qnx700\\target\\qnx7\\usr\\include\\unistd.h" 3 4
# 1 "c:\\qnx700\\target\\qnx7\\usr\\include\\confname.h" 1 3 4
# 28 "c:\\qnx700\\target\\qnx7\\usr\\include\\unistd.h" 2 3 4

additionally

I just did a quick search and it gets included by all std header files as first include command #include <__config>.

  • array
  • atomic
  • bitset
  • cassert
  • cctype
  • cerrno
  • cfenv
  • cfloat
  • chrono
  • cinttypes
  • ...

EDIT:
I will try the fix tomorrow.

@Johnnyxy

This comment has been minimized.

Copy link
Author

commented Jun 18, 2019

@Lastique
I used your proposal an added some additional checks to it. With this change it works for QNX SDP 6.5 (GNU C++), QNX SDP 7.0 (GNU C++; LLVM C++).

The background for those checks is that only with the LLVM backend it is necessary to declare __cxa_get_globals. As I know the LLVM backend is integrated since QNX SDP 7.0 that wraps the execution of GCC 5.4. The next older version of QNX SDP is 6.6 and that shipped with GCC 4.7 and had no LLVM included. So the check has to ensure that the Boost declaration of __cxa_get_globals gets only used when using QNX SDP 7.0 or higher.
As 7.0 it is the current version at the moment and the version (4.4, 4.7, 5.4.) steps of the used GCC shipped with each QNX SDP version (6.5, 6.6, 7.0) can be larger, in the next QNX SDP release this "bug" could be resolved already. Thus my proposed solution is to check the QNX version if it is 7 and if _LIBCPP_VERSION is 3700 (as currently declared in the header files) or lower. If the next QNX SDP still needs this declaration we can increase the version numbers.

Have a look at the patch file in the attachment:
boost_core_qnx70_cxx_provide___cxa_get_globals.patch.txt

@Lastique

This comment has been minimized.

Copy link
Member

commented Jun 18, 2019

Thanks.

I don't think checking for libc++ version is correct. As I said earlier, it is not tied to libc++abi, so the latter may get updated without the former and vice versa.

I will add an open check for _NTO_VERSION though. If a future QNX version is known to fix libc++abi so that it defines _LIBCPPABI_VERSION as it normally should, that check can be updated and converted to a closed one. But it won't hurt if we don't. To my knowledge, no version of libc++abi declares __cxa_get_globals, I don't think this is going to change.

@Lastique

This comment has been minimized.

Copy link
Member

commented Jun 18, 2019

On the second thought, do we have to check for _NTO_VERSION? If older QNX versions don't ship libc++abi, the existing checks for __GLIBCXX__ and __GLIBCPP__ should be working. Can you verify that my original checks in commit 420dff8 do work in all cases?

@Johnnyxy

This comment has been minimized.

Copy link
Author

commented Jun 18, 2019

I tested the tentative fix with QNX SDP 6.5 (GNU C++, Dinkum C++), QNX SDP 7.0 (GNU C++, LLVM C++). All variants compiled successfully.

All in all it worked.

Additionally

If I may: The comment you put into the fix is not 100% correct.

On QNX SDP 7.0 (QCC 5.4.0), there are multiple cxxabi.h, one from glibcxx from gcc and another from libc++abi from LLVM. The latter is included first by qcc.

As the different variants of the header files are not included in sequence or in any order at all.
The QNX SDP compiler wrapper invokes a GCC variant for a specific target depending on command line arguments. In this call the GCC frontend gets passed the library to use (GNU C++ or LLVM C++). Thus only one set of files are included specific for the target and library.

q++ -Vgcc_ntoaarch64le_cxx ... (compile for arch aarch64le with LLVM C++ library)
will execute something like that
ntoaarch64-gcc.exe -Ic:/.../LLVM_INCLUDE_PATH

q++ -Vgcc_ntoaarch64le_gpp ... (compile for arch aarch64le with GNU C++ library)
will execute something like that
ntoaarch64-gcc.exe -Ic:/.../GNU_INCLUDE_PATH

I would change the comment you made in the fix to the following to clarify this:

// On QNX SDP 7.0 (QCC 5.4.0), there are multiple cxxabi.h, one from glibcxx from gcc and another from libc++abi from LLVM. Which one is included will be determined by the qcc
// command line arguments (-V and/or -Y; http://www.qnx.com/developers/docs/7.0.0/#com.qnx.doc.neutrino.utilities/topic/q/qcc.html). The LLVM libc++abi is missing the declaration
// of __cxa_get_globals but it is also patched by QNX developers to not define _LIBCPPABI_VERSION. #59

The tested patch code I have been using is (including your fix and my modified comments):
boost_core_qnx70_cxx_provide___cxa_get_globals.patch.txt

@Lastique

This comment has been minimized.

Copy link
Member

commented Jun 18, 2019

Thanks, I already updated the comment in 7e1d028.

Johnnyxy pushed a commit to Johnnyxy/conan-boost that referenced this issue Jun 25, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
2 participants
You can’t perform that action at this time.