Bug 1643258 - Avoid the use of the __cxa_thread_atexit_impl symbol. r=froydnj

When linking a weak symbol in an object against a library where the
symbol is provided with a version, the final binary get a weak versioned
symbol reference.

It turns out weak versioned symbols still make the dynamic linker need
the symbol version, even if all symbols needed with that version are
weak.

Practically speaking, that means with bug 1634204, we now end up with
a weak versioned symbol reference to __cxa_thread_atexit_impl with
version GLIBC_2.18, and glibcs without the symbol can't fulfil that
version, even though the weak symbol is the only thing we need from that
version.

This means the check_binary changes in bug 1634204 are too
relaxed, so we revert them (although we keep the easier to read
conditions in check_dep_versions).

We also introduce a hack in stdc++compat.cpp (although it's not
technically entirely about libstdc++ compat) so that we avoid the weak
symbol reference while keeping the intended baseline for libstdc++ and
glibc.

Differential Revision: https://phabricator.services.mozilla.com/D79773
This commit is contained in:
Mike Hommey 2020-06-18 11:02:43 +00:00
Родитель 09750d5dab
Коммит 9d26424253
2 изменённых файлов: 27 добавлений и 12 удалений

Просмотреть файл

@ -8,6 +8,7 @@
#include <stdarg.h>
#include <stdio.h>
#include <mozilla/Assertions.h>
#include <cxxabi.h>
/* GLIBCXX_3.4.16 is from gcc 4.6.1 (172240)
GLIBCXX_3.4.17 is from gcc 4.7.0 (174383)
@ -144,6 +145,12 @@ namespace std {
* depending on optimization level */
template basic_ios<char, char_traits<char>>::operator bool() const;
} // namespace std
/* operator delete with size is only available in CXXAPI_1.3.9, equivalent to
* GLIBCXX_3.4.21. */
void operator delete(void* ptr, size_t size) noexcept(true) {
::operator delete(ptr);
}
#endif
#if MOZ_LIBSTDCXX_VERSION >= GLIBCXX_VERSION(3, 4, 23)
@ -154,3 +161,18 @@ template basic_string<char, char_traits<char>, allocator<char>>::basic_string(
const basic_string&, size_t, const allocator<char>&);
} // namespace std
#endif
/* The __cxa_thread_atexit_impl symbol is only available on GLIBC 2.18, but we
* want things to keep working on 2.17. It's not actually used directly from
* C++ code, but through __cxa_thead_atexit in libstdc++. The problem we have,
* though, is that rust's libstd also uses it, introducing a dependency we
* don't actually want. Fortunately, we can fall back to libstdc++'s wrapper
* (which, on systems without __cxa_thread_atexit_impl, has its own compatible
* implementation).
* The __cxa_thread_atexit symbol itself is marked CXXABI_1.3.7, which is
* equivalent to GLIBCXX_3.4.18.
*/
extern "C" int __cxa_thread_atexit_impl(void (*dtor)(void*), void* obj,
void* dso_handle) {
return __cxxabiv1::__cxa_thread_atexit(dtor, obj, dso_handle);
}

Просмотреть файл

@ -23,6 +23,7 @@ from mozpack.executables import (
STDCXX_MAX_VERSION = Version('3.4.19')
CXXABI_MAX_VERSION = Version('1.3.7')
GLIBC_MAX_VERSION = Version('2.17')
LIBGCC_MAX_VERSION = Version('4.8')
@ -96,11 +97,8 @@ def iter_symbols(binary):
continue
addr = int(m.group(0), 16)
# The second "column" is 7 one-character items that can be
# whitespaces.
flags = line[m.end():][:7]
# We're only interested whether the symbol might be weak.
weak = 'w' in flags
# whitespaces. We don't have use for their value, so just skip
# those.
rest = line[m.end() + 9:].split()
# The number of remaining colums will vary between ELF and MACHO.
# On ELF, we have:
@ -119,7 +117,6 @@ def iter_symbols(binary):
'size': int(rest[1], 16) if ty == ELF else 0,
'name': name,
'version': ver or None,
'weak': weak,
}
else:
export_table = False
@ -147,7 +144,6 @@ def iter_symbols(binary):
'size': 0,
'name': name,
'version': None,
'weak': None,
}
@ -169,11 +165,6 @@ def check_dep_versions(target, binary, lib, prefix, max_version):
if sym['addr'] != 0:
continue
# Versions for weak symbols don't matter, since the code must
# handle the case where they're not defined.
if sym['weak']:
continue
# No version to check
if not sym['version']:
continue
@ -195,6 +186,8 @@ def check_dep_versions(target, binary, lib, prefix, max_version):
def check_stdcxx(target, binary):
check_dep_versions(
target, binary, 'libstdc++', 'GLIBCXX', STDCXX_MAX_VERSION)
check_dep_versions(
target, binary, 'libstdc++', 'CXXABI', CXXABI_MAX_VERSION)
def check_libgcc(target, binary):