Enable -mno-direct-extern-access and ELF protected visibility

The -mno-direct-extern-access tells the compiler and linker that
references to symbols outside this ELF module mustn't be direct and must
instead always go through the GOT or PLT (the PLT can additionally be
disabled with -fno-plt). The ELF protected visibility tells the compiler
and linker that this symbol is present in the dynamic symbol table as an
export, but it cannot be interposed by another ELF module.

This option is required for user code to link properly to Qt, otherwise
they will get linker errors (assuming GNU binutils >= 2.39) or runtime
failures (glibc >= 2.35). Both versions of glibc and binutils are older
than GCC 12, so it's a safe assumption they are in use and downgrading
the toolchain or libc is not supported. Adding this option to the
compilation is assured for CMake and qmake-based projects.

For example, all accessess to QCoreApplication::self in QtCore, after
this change and with GCC 12 are relocation-free and direct:

000000000013ebf0 <QCoreApplicationPrivate::checkInstance(char const*)>:
  13ebf0:       cmpq   $0x0,0x4f73d0(%rip)        # 635fc8 <QCoreApplication::self>
  13ebf8:       setne  %al
  13ebfb:       je     a90fe <QCoreApplicationPrivate::checkInstance(char const*) [clone .cold]>
  13ec01:       ret

Meanwhile, accesses to the same variable in other modules are indirect
via the GOT:

   66650:       mov    0x876e1(%rip),%rax        # edd38 <QCoreApplication::self@Qt_6>
   66657:       cmpq   $0x0,(%rax)

This replaces the -Bsymbolic and -Bsymbolic-functions (broken)
functionality that Qt has been using or attempting to use since ~2006.

See https://gitlab.com/x86-psABIs/x86-64-ABI/-/issues/8#note_606975128

Change-Id: Iad4b0a3e5c06570b9f5f571b26ed564aa0811e47
Reviewed-by: Alexandru Croitor <alexandru.croitor@qt.io>
Reviewed-by: Lars Knoll <lars.knoll@qt.io>
This commit is contained in:
Thiago Macieira 2012-01-23 11:46:58 -02:00
parent 1818d6682d
commit 19b7f854a2
9 changed files with 40 additions and 7 deletions

View File

@ -202,7 +202,8 @@ function(qt_internal_add_module target)
qt_internal_get_framework_info(fw ${target})
endif()
if(QT_FEATURE_reduce_relocations AND UNIX AND NOT is_interface_lib)
if(NOT QT_FEATURE_no_extern_direct_access AND QT_FEATURE_reduce_relocations AND
UNIX AND NOT is_interface_lib)
# On x86 and x86-64 systems with ELF binaries (especially Linux), due to
# a new optimization in GCC 5.x in combination with a recent version of
# GNU binutils, compiling Qt applications with -fPIE is no longer

View File

@ -30,6 +30,9 @@ function(qt_internal_setup_public_platform_target)
target_compile_options(Platform INTERFACE "-stdlib=libc++")
target_link_options(Platform INTERFACE "-stdlib=libc++")
endif()
if (QT_FEATURE_no_extern_direct_access)
target_compile_options(Platform INTERFACE "-mno-direct-extern-access")
endif()
qt_set_msvc_cplusplus_options(Platform INTERFACE)

View File

@ -189,6 +189,11 @@ qt_config_compiler_supports_flag_test(optimize_debug
FLAG "-Og"
)
qt_config_compiler_supports_flag_test(no_extern_direct_access
LABEL "-mno-direct-extern-access support"
FLAG "-mno-direct-extern-access"
)
qt_config_linker_supports_flag_test(enable_new_dtags
LABEL "new dtags support"
FLAG "--enable-new-dtags"
@ -695,7 +700,13 @@ qt_feature("reduce_exports" PRIVATE
)
qt_feature_definition("reduce_exports" "QT_VISIBILITY_AVAILABLE")
qt_feature_config("reduce_exports" QMAKE_PUBLIC_QT_CONFIG)
qt_feature("reduce_relocations" PRIVATE
qt_feature("no_extern_direct_access" PRIVATE
LABEL "Use protected visibility and -mno-direct-extern-access"
CONDITION NOT WIN32 AND TEST_no_extern_direct_access
)
qt_feature_definition("no_extern_direct_access" "QT_USE_PROTECTED_VISIBILITY")
qt_feature_config("no_extern_direct_access" QMAKE_PUBLIC_QT_CONFIG)
qt_feature("reduce_relocations" PUBLIC
LABEL "Reduce amount of relocations"
CONDITION NOT WIN32 AND TEST_reduce_relocations
)

View File

@ -45,7 +45,7 @@ QMAKE_CFLAGS_RELEASE_WITH_DEBUGINFO += $$QMAKE_CFLAGS_OPTIMIZE -g
QMAKE_CFLAGS_DEBUG += -g
QMAKE_CFLAGS_SHLIB += $$QMAKE_CFLAGS_PIC
QMAKE_CFLAGS_STATIC_LIB += $$QMAKE_CFLAGS_PIC
QMAKE_CFLAGS_APP += $$QMAKE_CFLAGS_PIC
QMAKE_CFLAGS_APP +=
QMAKE_CFLAGS_YACC += -Wno-unused -Wno-parentheses
QMAKE_CFLAGS_HIDESYMS += -fvisibility=hidden
QMAKE_CFLAGS_EXCEPTIONS_OFF += -fno-exceptions

View File

@ -58,6 +58,13 @@ qaxserver {
!force_import_plugins:!contains(TEMPLATE, ".*app"):!if(contains(TEMPLATE, ".*lib"):dll): \
CONFIG -= import_plugins
unix {
contains(QT_CONFIG, no_extern_direct_access): CONFIG += mno_extern_direct_access
else:contains(QT_CONFIG, reduce_relocations):!contains(TEMPLATE, .*lib): {
QMAKE_CFLAGS += $$QMAKE_CFLAGS_PIC
QMAKE_CXXFLAGS += $$QMAKE_CFLAGS_PIC
}
}
# qmake variables cannot contain dashes, so normalize the names first
CLEAN_QT = $$replace(QT, -private$, _private)

View File

@ -0,0 +1,2 @@
QMAKE_CFLAGS += -mno-direct-extern-access
QMAKE_CXXFLAGS += -mno-direct-extern-access

View File

@ -214,7 +214,12 @@
# define Q_DECL_EXPORT __declspec(dllexport)
# define Q_DECL_IMPORT __declspec(dllimport)
# elif defined(QT_VISIBILITY_AVAILABLE)
# define Q_DECL_EXPORT __attribute__((visibility("default")))
# define Q_DECL_EXPORT_OVERRIDABLE __attribute__((visibility("default"), weak))
# ifdef QT_USE_PROTECTED_VISIBILITY
# define Q_DECL_EXPORT __attribute__((visibility("protected")))
# else
# define Q_DECL_EXPORT __attribute__((visibility("default")))
# endif
# define Q_DECL_IMPORT __attribute__((visibility("default")))
# define Q_DECL_HIDDEN __attribute__((visibility("hidden")))
# endif
@ -1151,6 +1156,9 @@
#ifndef Q_DECL_EXPORT
# define Q_DECL_EXPORT
#endif
#ifndef Q_DECL_EXPORT_OVERRIDABLE
# define Q_DECL_EXPORT_OVERRIDABLE Q_DECL_EXPORT
#endif
#ifndef Q_DECL_IMPORT
# define Q_DECL_IMPORT
#endif

View File

@ -1289,8 +1289,9 @@ inline int qIntCast(float f) { return int(f); }
#define QT_MODULE(x)
#if !defined(QT_BOOTSTRAPPED) && defined(QT_REDUCE_RELOCATIONS) && defined(__ELF__) && \
(!defined(__PIC__) || (defined(__PIE__) && defined(Q_CC_GNU) && Q_CC_GNU >= 500))
#if defined(QT_BOOTSTRAPPED) || defined(QT_USE_PROTECTED_VISIBILITY) || !defined(__ELF__) || defined(__PIC__)
// this is fine
#elif defined(QT_REDUCE_RELOCATIONS)
# error "You must build your code with position independent code if Qt was built with -reduce-relocations. "\
"Compile your code with -fPIC (and not with -fPIE)."
#endif

View File

@ -255,7 +255,7 @@ void QCoreApplicationPrivate::processCommandLineArguments()
// Support for introspection
extern "C" void Q_CORE_EXPORT qt_startup_hook()
extern "C" void Q_DECL_EXPORT_OVERRIDABLE qt_startup_hook()
{
}