Files
Konstantin BogdanovandClaude Fable 5 c169dcbcb5 Link musl CRT startup files in the canonical order
The AI reviewer correctly noted that the startup files must be linked as
crt1, crti, [program objects], crtn: crti/crtn provide the prologue and
epilogue of the .init/.fini sections and must wrap every other
contribution to them. Reordering source lists cannot express this:
CMake's Ninja generator always emits $<TARGET_OBJECTS:...> before the
target's own object files, so crtn.o preceded the program objects
regardless of its position in add_executable or target_sources.

Wire the startup files through the link line instead: the objects are
copied to stable paths in contrib/musl-cmake, crt1.o and crti.o are
passed via CMAKE_EXE_LINKER_FLAGS (placed before all object files) and
crtn.o at the end of DEFAULT_LIBS (placed after all libraries). This
covers every executable uniformly, so the per-target special cases in
clickhouse_add_executable, contrib and test CMake files are removed.

The order is not hypothetical: OpenSSL contributes a .init fragment
calling OPENSSL_cpuid_setup, which previously landed after crtn's
epilogue (unreachable, so it never ran at startup); a binary whose .init
lacks the crtn epilogue altogether segfaults in __libc_start_init,
because musl calls _init. With this change, .init of the clickhouse
binary disassembles to the complete push/call/pop/ret sequence.

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-07-03 01:38:56 +02:00

75 lines
3.0 KiB
CMake

# Set standard, system and compiler libraries explicitly.
# This is intended for more control of what we are linking.
set (DEFAULT_LIBS "-nodefaultlibs")
# Wire compiler-rt runtimes (builtins/sanitizers/XRay) into the link flags.
include (cmake/compiler_rt_link.cmake)
# `libllvmlibc` supplies both the math functions and the SIMD memory functions
# (`memcpy`/`memmove`/`memset`/`memcmp`/`bcmp`/`memmem`). Disabling it on
# x86_64/aarch64 reverts all of them to the system libc, including `memcpy` —
# which then carries a versioned glibc symbol again (no portability shim).
option (ENABLE_LLVM_LIBC_MATH "Use math and memory functions from llvm-libc instead of glibc" ON)
if (NOT (ARCH_AMD64 OR ARCH_AARCH64))
set(ENABLE_LLVM_LIBC_MATH OFF)
endif()
if (ENABLE_LLVM_LIBC_MATH)
link_directories("${CMAKE_BINARY_DIR}/contrib/libllvmlibc-cmake")
target_link_libraries(global-libs INTERFACE libllvmlibc)
set (DEFAULT_LIBS "${DEFAULT_LIBS} -llibllvmlibc")
if (NOT SANITIZE)
set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-u,memcpy -Wl,-u,memmove -Wl,-u,memset -Wl,-u,memcmp")
endif()
endif()
if (OS_ANDROID)
# pthread and rt are included in libc
set (DEFAULT_LIBS "${DEFAULT_LIBS} -lc -lm -ldl")
elseif (USE_MUSL)
# musl itself is linked in cmake/musl.cmake. -nostartfiles: don't use glibc's crt*.o
# from the sysroot; musl's own startup files (copied to stable paths in
# contrib/musl-cmake) are wired here in the canonical order: crt1.o and crti.o go
# through CMAKE_EXE_LINKER_FLAGS, which the link line places before all object
# files, and crtn.o goes at the end of DEFAULT_LIBS, after all libraries — crti and
# crtn provide the prologue/epilogue of the `.init`/`.fini` sections and must wrap
# every other contribution to them.
set (MUSL_CRT_DIR "${CMAKE_BINARY_DIR}/contrib/musl-cmake")
set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${MUSL_CRT_DIR}/crt1.o ${MUSL_CRT_DIR}/crti.o")
set (DEFAULT_LIBS "${DEFAULT_LIBS} -static -nostartfiles ${MUSL_CRT_DIR}/crtn.o")
else ()
set (DEFAULT_LIBS "${DEFAULT_LIBS} -lc -lm -lrt -lpthread -ldl")
endif ()
message(STATUS "Default libraries: ${DEFAULT_LIBS}")
set(CMAKE_CXX_STANDARD_LIBRARIES ${DEFAULT_LIBS})
set(CMAKE_C_STANDARD_LIBRARIES ${DEFAULT_LIBS})
add_library(Threads::Threads INTERFACE IMPORTED)
if (USE_MUSL)
# musl provides pthread in libc.
set_target_properties(Threads::Threads PROPERTIES INTERFACE_LINK_LIBRARIES musl)
else ()
set_target_properties(Threads::Threads PROPERTIES INTERFACE_LINK_LIBRARIES pthread)
endif ()
include (cmake/unwind.cmake)
include (cmake/cxx.cmake)
if (USE_MUSL)
include (cmake/musl.cmake)
endif()
if (NOT OS_ANDROID)
if (NOT USE_MUSL)
disable_dummy_launchers_if_needed()
# Our compatibility layer doesn't build under Android, many errors in musl.
add_subdirectory(base/glibc-compatibility)
enable_dummy_launchers_if_needed()
endif ()
add_subdirectory(base/harmful)
endif ()