diff --git a/llvm/tools/llvm-libgcc/CMakeLists.txt b/llvm/tools/llvm-libgcc/CMakeLists.txt new file mode 100644 --- /dev/null +++ b/llvm/tools/llvm-libgcc/CMakeLists.txt @@ -0,0 +1,49 @@ +cmake_minimum_required(VERSION 3.13.4) + +# If we are not building as a part of LLVM, build llvm-libgcc as a standalone +# project, using compiler-rt and libunwind external libraries. +if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR) + project(LLVM_LIBGCC) + if(NOT LLVM_LIBGCC_LIBUNWIND_DIR) + message(FATAL_ERROR + "We're building llvm-libgcc as a standalone project, but we didn't " + " supply a path to LLVM_LIBGCC_LIBUNWIND_DIR. It's not possible to build " + "llvm-libgcc without this path!") + endif() +elseif(NOT LLVM_ENABLE_LIBGCC) + return() +endif() + +list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}") + +message(STATUS "LLVM_LIBGCC_TARGET set to ${LLVM_LIBGCC_TARGET}") +set(LLVM_LIBGCC_VERSION_SCRIPT_PATH + "${CMAKE_CURRENT_SOURCE_DIR}/version-scripts/gcc_s-${LLVM_LIBGCC_TARGET}.ver") +set(LLVM_LIBGCC_SYSROOT "${CMAKE_INSTALL_PREFIX}" CACHE PATH + "Assumes this path as the root directory when setting symlinks.") + +set(LLVM_LIBGCC_COMPILER_RT_DIR "" CACHE PATH + "Absolute path to a pre-existing compiler-rt builtins.") +find_package(CompilerRT REQUIRED) +string(REGEX REPLACE "^${LLVM_LIBGCC_SYSROOT}/lib${LLVMLIB_DIR_SUFFIX}/*" "" + LLVM_LIBGCC_COMPILER_RT "${LLVM_LIBGCC_COMPILER_RT}") + +set(LLVM_LIBGCC_LIBUNWIND_DIR "" CACHE PATH + "Absolute path to a pre-existing libunwind.a.") +find_package(LLVMLibunwind REQUIRED) +string(REGEX REPLACE "^${LLVM_LIBGCC_SYSROOT}/lib${LLVMLIB_DIR_SUFFIX}/*" "" + LLVM_LIBGCC_UNWIND_STATIC "${LLVM_LIBGCC_UNWIND_STATIC}") + +if(NOT EXISTS "${LLVM_LIBGCC_VERSION_SCRIPT_PATH}") + message(SEND_ERROR + "We can't synthesise libgcc_s for '${LLVM_LIBGCC_TARGET}' because " + "'${LLVM_LIBGCC_VERSION_SCRIPT_PATH}' doesn't exist. If this target is the " + "target that you're after, then we probably need to first generate the " + "version script, then re-run CMake.") +endif() + +set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/lib${LLVMLIB_DIR_SUFFIX}") +set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/lib${LLVMLIB_DIR_SUFFIX}") +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/lib${LLVMLIB_DIR_SUFFIX}") + +add_subdirectory(lib) diff --git a/llvm/tools/llvm-libgcc/FindCompilerRT.cmake b/llvm/tools/llvm-libgcc/FindCompilerRT.cmake new file mode 100644 --- /dev/null +++ b/llvm/tools/llvm-libgcc/FindCompilerRT.cmake @@ -0,0 +1,101 @@ +include(FindPackageHandleStandardArgs) +include(CheckLibraryExists) + +function(building_compiler_rt) + if(LLVM_LIBGCC_COMPILER_RT_DIR) + return() + endif() + + list(FIND LLVM_ENABLE_PROJECTS compiler-rt LLVM_LIBGCC_HAS_COMPILER_RT) + if(NOT LLVM_LIBGCC_HAS_COMPILER_RT) + return() + endif() + + if(NOT COMPILER_RT_BUILD_BUILTINS) + message(SEND_ERROR + "When building llvm-libgcc alongside compiler-rt, we need to set " + "-DCOMPILER_RT_BUILD_BUILTINS=On so we can export all the necessary " + "symbols.") + return() + endif() + + if(NOT COMPILER_RT_BUILTINS_HIDE_SYMBOLS) + message(SEND_ERROR + "When building llvm-libgcc alongside compiler-rt, we need to set " + "-DCOMPILER_RT_BUILTINS_HIDE_SYMBOLS=Off so we can export all the " + "necessary symbols.") + return() + endif() + + set(LLVM_LIBGCC_COMPILER_RT builtins) + set(CompilerRT_FOUND ON) + message(STATUS "llvm-libgcc is using in-tree compiler-rt") +endfunction() + +function(find_external_compiler_rt) + if(NOT ${CMAKE_CHECK_CXX_COMPILER_ID} MATCHES Clang AND + NOT LLVM_LIBGCC_COMPILER_RT_DIR) + message(STATUS + "When building llvm-libgcc without compiler-rt (e.g. as a standalone " + "project), we either need to be using Clang, or " + "'LLVM_LIBGCC_COMPILER_RT_INSTALL_DIRECTORY' must be set to a directory.") + return() + endif() + + if(LLVM_LIBGCC_COMPILER_RT_DIR) + set(LLVM_LIBGCC_PATH_TO_RTLIB + "${LLVM_LIBGCC_COMPILER_RT_DIR}/libclang_rt.builtins-${LLVM_LIBGCC_TARGET}.a") + + check_library_exists("${LLVM_LIBGCC_PATH_TO_RTLIB}" emutls_key_destructor + LLVM_LIBGCC_HAS_EXTERNAL_RTLIB) + if (NOT LLVM_LIBGCC_HAS_EXTERNAL_RTLIB) + message(SEND_ERROR + "When using LLVM_LIBGCC_COMPILER_RT_DIR='${LLVM_LIBGCC_COMPILER_RT_DIR}', " + "we couldn't path '${LLVM_LIBGCC_PATH_TO_RTLIB}'. There could be a few " + "reasons for this (e.g. typo in path or wrong permissions for file), " + "and a manual inspection is necessary.") + return() + endif() + + set(LLVM_LIBGCC_COMPILER_RT "${LLVM_LIBGCC_PATH_TO_RTLIB}" PARENT_SCOPE) + return() + endif() + + execute_process(COMMAND "${CMAKE_CXX_COMPILER}" + ${CMAKE_CXX_FLAGS} + --rtlib=compiler-rt + --print-libgcc-file-name + RESULT_VARIABLE HAD_ERROR + OUTPUT_VARIABLE LLVM_LIBGCC_COMPILER_RT) + string(STRIP "${LLVM_LIBGCC_COMPILER_RT}" LLVM_LIBGCC_COMPILER_RT) + + if(HAD_ERROR) + message(STATUS "llvm-libgcc unable to find compiler-rt builtins: got return code ${HAD_ERROR}") + unset(LLVM_LIBGCC_COMPILER_RT) + return() + endif() + + if(NOT EXISTS "${LLVM_LIBGCC_COMPILER_RT}") + message(STATUS "llvm-libgcc unable to find path '${LLVM_LIBGCC_COMPILER_RT}'") + unset(LLVM_LIBGCC_COMPILER_RT) + endif() + + set(LLVM_LIBGCC_COMPILER_RT "${LLVM_LIBGCC_COMPILER_RT}" PARENT_SCOPE) +endfunction() + +set(CompilerRT_FOUND OFF) +if(NOT CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR) + building_compiler_rt() +endif() + +if(NOT CompilerRT_FOUND) + find_external_compiler_rt() + if(LLVM_LIBGCC_COMPILER_RT) + string(REGEX REPLACE "^${LLVM_LIBGCC_SYSROOT}/lib${LLVMLIB_DIR_SUFFIX}/*" "" + LLVM_LIBGCC_COMPILER_RT "${LLVM_LIBGCC_COMPILER_RT}") + message(STATUS "llvm-libgcc is using a pre-installed compiler-rt: ${LLVM_LIBGCC_COMPILER_RT}") + set(CompilerRT_FOUND ON) + endif() +endif() + +find_package_handle_standard_args(CompilerRT REQUIRED_VARS CompilerRT_FOUND) diff --git a/llvm/tools/llvm-libgcc/FindLLVMLibunwind.cmake b/llvm/tools/llvm-libgcc/FindLLVMLibunwind.cmake new file mode 100644 --- /dev/null +++ b/llvm/tools/llvm-libgcc/FindLLVMLibunwind.cmake @@ -0,0 +1,56 @@ +include(FindPackageHandleStandardArgs) + +function(building_libunwind) + list(FIND LLVM_ENABLE_PROJECTS libunwind LLVM_LIBGCC_HAS_LIBUNWIND) + if(NOT LLVM_LIBGCC_HAS_LIBUNWIND) + return() + endif() + + if(NOT LIBUNWIND_USE_COMPILER_RT) + message(SEND_ERROR + "When we're building llvm-libgcc alongside libunwind, we need to set " + "'-DLIBUNWIND_USE_COMPILER_RT=On'.") + endif() + + if(LIBUNWIND_INSTALL_SHARED_LIBRARY) + message(SEND_ERROR + "When we're building llvm-libgcc alongside libunwind, llvm-libgcc will " + "be the owner of libunwind.so. To prevent the projects from clashing, we " + "need to set '-DLIBUNWIND_INSTALL_SHARED_LIBRARY=Off'.") + endif() + + if(NOT (LIBUNWIND_SUPPORTS_FNO_EXCEPTIONS_FLAG AND + LIBUNWIND_SUPPORTS_FUNWIND_TABLES_FLAG)) + message(SEND_ERROR + "Compiler doesn't support generation of unwind tables if exception " + "support is disabled. Building libunwind DSO with runtime dependency " + "on C++ ABI library is not supported.") + endif() + + set(LLVM_LIBGCC_UNWIND_STATIC unwind_static PARENT_SCOPE) + set(LLVMLibunwind_FOUND ON PARENT_SCOPE) + message(STATUS "llvm-libgcc is using in-tree libunwind") +endfunction() + +function(find_external_libunwind) + if (NOT EXISTS "${LLVM_LIBGCC_LIBUNWIND_DIR}/libunwind.a") + message(SEND_ERROR + "When using LLVM_LIBGCC_LIBUNWIND_DIR='${LLVM_LIBGCC_LIBUNWIND_DIR}', we " + "couldn't find '${LLVM_LIBGCC_LIBUNWIND_DIR}/libunwind.a'. There could " + "be a few reasons for this (e.g. typo in path or wrong permissions for " + "file), and a manual inspection is necessary.") + endif() + + set(LLVM_LIBGCC_UNWIND_STATIC "${LLVM_LIBGCC_LIBUNWIND_DIR}/libunwind.a" PARENT_SCOPE) + set(LLVMLibunwind_FOUND ON PARENT_SCOPE) +endfunction() + +set(LLVMLibunwind_FOUND OFF) +if(NOT CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR) + building_libunwind() +else() + find_external_libunwind() + message(STATUS "llvm-libgcc is using a pre-built libunwind: ${LLVM_LIBGCC_UNWIND_STATIC}") +endif() + +find_package_handle_standard_args(LLVMLibunwind REQUIRED_VARS LLVMLibunwind_FOUND) diff --git a/llvm/tools/llvm-libgcc/docs/LLVMLibgcc.rst b/llvm/tools/llvm-libgcc/docs/LLVMLibgcc.rst new file mode 100644 --- /dev/null +++ b/llvm/tools/llvm-libgcc/docs/LLVMLibgcc.rst @@ -0,0 +1,213 @@ +.. llvm-libgcc: + +=========== +llvm-libgcc +=========== + +.. contents:: + :local: + +**Note that these instructions assume a Linux and bash-friendly environment. +YMMV if you’re on a non Linux-based platform.** + +.. _introduction: + +Motivation +============ + +Enabling libunwind as a replacement for libgcc on Linux has proven to be +challenging since libgcc_s.so is a required dependency in the [Linux standard +base][5]. Some software is transitively dependent on libgcc because glibc makes +hardcoded calls to functions in libgcc_s. For example, the function +``__GI___backtrace`` eventually makes its way to a [hardcoded dlopen to libgcc_s' +_Unwind_Backtrace][1]. Since libgcc_{eh.a,s.so} and libunwind have the same ABI, +but different implementations, the two libraries end up [cross-talking, which +ultimately results in a segfault][2]. + +To solve this problem, libunwind needs libgcc "front" that is, link the +necessary functions from compiler-rt and libunwind into an archive and shared +object that advertise themselves as ``libgcc.a``, ``libgcc_eh.a``, and +``libgcc_s.so``, so that glibc’s baked calls are diverted to the correct objects +in memory. Fortunately for us, compiler-rt and libunwind use the same ABI as the +libgcc family, so the problem is solvable at the llvm-project configuration +level: no program source needs to be edited. Thus, the end result is for a +distro manager to configure their LLVM build with a flag that indicates they +want to archive compiler-rt/unwind as libgcc. We achieve this by compiling +libunwind with all the symbols necessary for compiler-rt to emulate the libgcc +family, and then generate symlinks named for our "libgcc" that point to their +corresponding libunwind counterparts. + +.. _alternatives + +Alternatives +============ + +We alternatively considered patching glibc so that the source doesn't directly +refer to libgcc, but rather _defaults_ to libgcc, so that a system preferring +compiler-rt/libunwind can point to these libraries at the config stage instead. +Even if we modified the Linux standard base, this alternative won't work because +binaries that are built using libgcc will still end up having cross-talk between +the differing implementations. + +.. _target audience: + +Target audience +=============== + +llvm-libgcc is not for the casual LLVM user. It is intended to be used by distro +managers who want to replace libgcc with compiler-rt and libunwind, but cannot +fully abandon the libgcc family (e.g. because they are dependent on glibc). Such +managers must have worked out their compatibility requirements ahead of using +llvm-libgcc. + +.. _cmake options: + +CMake options +============= + +.. option:: `LLVM_LIBGCC_TARGET` + + **Required** + + The target for which llvm-libgcc is being built. This can't be inferred from + ``LLVM_TARGETS_TO_BUILD``, and presently only supports one target at a time. + +.. option:: `LLVM_LIBGCC_SYSROOT` + + **Default value**: ``${CMAKE_INSTALL_PREFIX}`` + + Transforms an absolute path into a relative path starting from the specified + directory. This variable is only used when performing an out-of-tree build. + +.. option:: `LLVM_LIBGCC_COMPILER_RT_INSTALL_DIRECTORY` + + Path to compiler-rt. Overrides building compiler-rt in-tree, and is required + when building out-of-tree when ``CMAKE_CXX_COMPILER`` isn't Clang. + +The following CMake options are not used by llvm-libgcc but are required when +building in-tree. + +.. option:: `COMPILER_RT_BUILD_BUILTINS=On` + +.. option:: `COMPILER_RT_BUILTINS_HIDE_SYMBOLS=Off` + + Necessary for exposing symbols that libgcc_s exposes, but compiler-rt doesn't + by default. This variable should be set when building libunwind out-of-tree + too. + +.. option:: `LIBUNWIND_USE_COMPILER_RT=On` + +.. option:: `LIBUNWIND_INSTALL_SHARED_LIBRARY` + + llvm-libgcc generates both `libunwind.so` and `libgcc_s.so`, so we want to + avoid having libunwind generate this too (otherwise there would be a clash). + This variable should be set when building libunwind out-of-tree too. + +.. _building llvm-libgcc out of tree + +Building llvm-libgcc out of tree +================================ + +Building llvm-libgcc out of tree requires a compiler that supports compiler-rt +when its builtin symbols are exported. This usually means having two build trees +instead of the usual one. + +.. code-block:: bash + + # Assumes $(PWD) is /path/to/llvm-project + $ mkdir -p build + $ cd build + +.. _Building Clang + +Building Clang +-------------- + +The first build tree is a mostly conventional build tree and gets you a Clang +build with these compiler-rt symbols exposed. + +.. code-block:: bash + # Assumes $(PWD) is /path/to/llvm-project + $ cmake -GNinja -S llvm -B build-primary \ + -DCMAKE_BUILD_TYPE=Release \ + -DCMAKE_INSTALL_PREFIX=/tmp/llvm-libgcc-experiment \ + -DLLVM_ENABLE_PROJECTS='clang;compiler-rt' \ + -DLLVM_ENABLE_RUNTIMES='libcxx;libcxxabi;libunwind' \ + -DCOMPILER_RT_BUILTINS_HIDE_SYMBOLS=Off \ + -DLIBUNWIND_INSTALL_SHARED_LIBRARY=Off \ + -DLIBUNWIND_ENABLE_SHARED=Off \ + -DLIBUNWIND_USE_COMPILER_RT=On \ + -DLIBUNWIND_HAS_COMMENT_LIB_PRAGMA=Off \ + -DLIBUNWIND_HAS_DL_LIB=Off \ + -DLIBUNWIND_HAS_PTHREAD_LIB=Off + $ ninja -C build-primary install + +``LIBUNWIND_HAS_COMMENT_LIB_PRAGMA``, ``LIBUNWIND_HAS_DL_LIB``, and +``LIBUNWIND_HAS_PTHREAD_LIB`` are not strictly necessary, but are useful to +prevent requiring your libunwind dependents to also link with libdl and +libpthread. + +.. _Building llvm-libgcc + +Building llvm-libgcc +------------------ + +Now that we've built the prerequisites, we can build llvm-libgcc in a second +tree. We build llvm-libgcc for x86_64 in this example, but it's possible to +replicate for any architecture that has a `version script`_ in the +``version-scripts`` directory (presently i686, x86_64, armhf, and aarch64). + +.. _version script: https://sourceware.org/binutils/docs/ld/VERSION.html + +.. code-block:: bash + + # Assumes $(PWD) is /path/to/llvm-project + $ export LLVM_LIBGCC_SYSROOT=/tmp/llvm-libgcc-experiment + $ export CC="${LLVM_LIBGCC_SYSROOT}/bin/clang" CXX="${LLVM_LIBGCC_SYSROOT}/bin/clang++" + $ cmake -GNinja -S llvm/tools/llvm-libgcc -B build-libgcc \ + -DCMAKE_BUILD_TYPE=Release \ + -DCMAKE_INSTALL_PREFIX="${LLVM_LIBGCC_SYSROOT}" \ + -DLLVM_LIBGCC_TARGET=x86_64 \ + -DLLVM_LIBGCC_LIBUNWIND_DIR="${LLVM_LIBGCC_SYSROOT}/lib/x86_64-unknown-linux-gnu" + $ ninja -C build-libgcc install + +``${LLVM_LIBGCC_SYSROOT}/lib/x86_64-unknown-linux-gnu`` is the path to +``libunwind.a``. The target triple is determined by setting the flag +``LLVM_RUNTIME_TARGETS`` in the Clang build: make sure they match. +``LLVM_LIBGCC_TARGET`` is usually only the first part of the triple: ``x86_64``, +``armv7a``, ``aarch64``, etc. + +## Verifying your results + +This gets you a copy of libunwind with the libgcc symbols. You can verify this +using ``readelf``. + +.. code-block:: bash + + $ readelf -W --dyn-syms "${LLVM_LIBGCC_SYSROOT}/lib/libunwind.so" | grep FUNC | grep GCC_3.0 + + +Roughly sixty symbols should appear, all suffixed with ``@@GCC_3.0``. You can +replace ``GCC_3.0`` with any of the supported version names in the version +script you’re exporting to verify that the symbols are exported. + +Generating a new version script +=============================== + +To generate a new version script, we need to generate the list of symbols that exist in the set +(compiler-rt builtins ∪ ``libunwind.a``) ∩ ``libgcc_s.so.1``. The prerequisites for generating +a version script are a binaries for the three aforementioned libraries targeting your architecture +(without having built llvm-libgcc). + +Once these libraries are in place, to generate a new version script, run the following command. + +.. code-block:: bash + + /path/to/llvm-project $ llvm/tools/llvm-libgcc/generate_version_script.py \ + --compiler_rt=/path/to/libclang_rt.builtins-${ARCH}.a \ + --libunwind=/path/to/libunwind.a \ + --libgcc_s=/path/to/libgcc_s.so.1 \ + --output=${ARCH} + +This will generate a new version script called ``gcc_s-${ARCH}.ver`` in the ``version-scripts`` +directory. diff --git a/llvm/tools/llvm-libgcc/generate_version_script.py b/llvm/tools/llvm-libgcc/generate_version_script.py new file mode 100755 --- /dev/null +++ b/llvm/tools/llvm-libgcc/generate_version_script.py @@ -0,0 +1,127 @@ +#!/usr/bin/python + +from collections import defaultdict +from itertools import chain +import argparse, subprocess, sys, os + + +def split_suffix(symbol): + """ + Splits a symbol such as `__gttf2@GCC_3.0` into a triple representing its + function name (__gttf2), version name (GCC_3.0), and version number (300). + + The version number acts as a priority. Since earlier versions are more + accessible and are likely to be used more, the lower the number is, the higher + its priortiy. A symbol that has a '@@' instead of '@' has been designated by + the linker as the default symbol, and is awarded a priority of -1. + """ + if '@' not in symbol: + return None + data = [i for i in filter(lambda s: s, symbol.split('@'))] + _, version = data[-1].split('_') + version = version.replace('.', '') + priority = -1 if '@@' in symbol else int(version + '0' * + (3 - len(version))) + return data[0], data[1], priority + + +def invert_mapping(symbol_map): + """Transforms a map from Key->Value to Value->Key.""" + store = defaultdict(list) + for symbol, (version, _) in symbol_map.items(): + store[version].append(symbol) + result = [] + for k, v in store.items(): + v.sort() + result.append((k, v)) + result.sort(key=lambda x: x[0]) + return result + + +def intersection(llvm, gcc): + """ + Finds the intersection between the symbols extracted from compiler-rt.a/libunwind.a + and libgcc_s.so.1. + """ + common_symbols = {} + for i in gcc: + suffix_triple = split_suffix(i) + if not suffix_triple: + continue + + symbol, version_name, version_number = suffix_triple + if symbol in llvm: + if symbol not in common_symbols: + common_symbols[symbol] = (version_name, version_number) + continue + if version_number < common_symbols[symbol][1]: + common_symbols[symbol] = (version_name, version_number) + return invert_mapping(common_symbols) + + +def find_function_names(path): + """ + Runs readelf on a binary and reduces to only defined functions. Equivalent to + `readelf -su --wide ${path} | grep 'FUNC' | grep -v 'UND' | awk '{print $8}'`. + """ + result = subprocess.run(args=['readelf', '-su', '--wide', path], + capture_output=True) + + if result.returncode != 0: + print(result.stderr.decode('utf-8'), file=sys.stderr) + sys.exit(1) + + stdout = result.stdout.decode('utf-8') + stdout = filter(lambda x: "FUNC" in x and "UND" not in x, + stdout.split('\n')) + stdout = chain( + map(lambda x: filter(None, x), (i.split(' ') for i in stdout))) + + return [list(i)[7] for i in stdout] + + +def to_file(suffix, versioned_symbols): + path = f'{os.path.dirname(os.path.realpath(__file__))}/version-scripts/gcc_s-{suffix}.ver' + with open(path, 'w') as f: + for version, symbols in versioned_symbols: + f.write(f'{version} {{\n') + for i in symbols: + f.write(f' {i};\n') + f.write('};\n\n') + + +def read_args(): + parser = argparse.ArgumentParser() + parser.add_argument('--compiler_rt', + type=str, + help='Path to `libclang_rt.builtins-${ARCH}.a`.', + required=True) + parser.add_argument('--libunwind', + type=str, + help='Path to `libunwind.a`.', + required=True) + parser.add_argument( + '--libgcc_s', + type=str, + help= + 'Path to `libgcc_s.so.1`. Note that unlike the other two arguments, this is a dynamic library.', + required=True) + parser.add_argument( + '--suffix', + type=str, + help='The suffix of the version script file. It should match ${ARCH}.', + required=True) + return parser.parse_args() + + +def main(): + args = read_args() + llvm = find_function_names(args.compiler_rt) + find_function_names( + args.libunwind) + gcc = find_function_names(args.libgcc_s) + versioned_symbols = intersection(llvm, gcc) + to_file(args.suffix, versioned_symbols) + + +if __name__ == "__main__": + main() diff --git a/llvm/tools/llvm-libgcc/lib/CMakeLists.txt b/llvm/tools/llvm-libgcc/lib/CMakeLists.txt new file mode 100644 --- /dev/null +++ b/llvm/tools/llvm-libgcc/lib/CMakeLists.txt @@ -0,0 +1,59 @@ +include(CheckLibraryExists) + +add_library(unwind_shared SHARED blank.cpp) +set_target_properties(unwind_shared + PROPERTIES + LINKER_LANGUAGE C + OUTPUT_NAME "unwind" + VERSION "1.0" + SOVERSION "1" + POSITION_INDEPENDENT_CODE ON) +target_link_options( + unwind_shared PRIVATE + -Wl,-nostdlib + -Wl,--whole-archive + -Wl,--version-script,${LLVM_LIBGCC_VERSION_SCRIPT_PATH} + -Wl,${LLVM_LIBGCC_SYSROOT}/lib${LLVMLIB_DIR_SUFFIX}/${LLVM_LIBGCC_COMPILER_RT} + -Wl,${LLVM_LIBGCC_SYSROOT}/lib${LLVMLIB_DIR_SUFFIX}/${LLVM_LIBGCC_UNWIND_STATIC} + -Wl,--no-whole-archive +) +check_library_exists(m sin "" LLVM_LIBGCC_HAS_LIBM) +check_library_exists(c printf "" LLVM_LIBGCC_HAS_LIBC) +target_link_libraries( + unwind_shared PRIVATE + $<$:m> + $<$:c> +) + +add_custom_target(synth_libgcc ALL + DEPENDS "${LLVM_LIBGCC_SYSROOT}/lib${LLVMLIB_DIR_SUFFIX}/${LLVM_LIBGCC_COMPILER_RT}" unwind_shared + COMMAND ${CMAKE_COMMAND} -E create_symlink + "${LLVM_LIBGCC_COMPILER_RT}" "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/libgcc.a") +add_custom_target(synth_libgcc_eh ALL + COMMAND ${CMAKE_COMMAND} -E create_symlink + "${LLVM_LIBGCC_UNWIND_STATIC}" "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/libgcc_eh.a") +add_custom_target(synth_libgcc_s ALL + DEPENDS unwind_shared + COMMAND ${CMAKE_COMMAND} -E create_symlink + "libunwind.so" "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/libgcc_s.so") +add_custom_target(synth_libgcc_s1 ALL + DEPENDS unwind_shared + COMMAND ${CMAKE_COMMAND} -E create_symlink + "libunwind.so.1" "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/libgcc_s.so.1") + +add_custom_target(unwind + DEPENDS + unwind_shared + synth_libgcc + synth_libgcc_eh + synth_libgcc_s + synth_libgcc_s1) +set(LLVM_LIBGCC_INSTALL_LIBRARY_DIR lib${LLVM_LIBDIR_SUFFIX} CACHE PATH "") +install(TARGETS unwind_shared + LIBRARY DESTINATION "${LLVM_LIBGCC_INSTALL_LIBRARY_DIR}" COMPONENT unwind + ARCHIVE DESTINATION "${LLVM_LIBGCC_INSTALL_LIBRARY_DIR}" COMPONENT unwind + RUNTIME DESTINATION bin COMPONENT unwind) +install(FILES "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/libgcc.a" TYPE LIB) +install(FILES "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/libgcc_eh.a" TYPE LIB) +install(FILES "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/libgcc_s.so" TYPE LIB) +install(FILES "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/libgcc_s.so.1" TYPE LIB) diff --git a/llvm/tools/llvm-libgcc/lib/blank.cpp b/llvm/tools/llvm-libgcc/lib/blank.cpp new file mode 100644 --- /dev/null +++ b/llvm/tools/llvm-libgcc/lib/blank.cpp @@ -0,0 +1,2 @@ +// This file is required to exist because CMake needs a source file to create a +// target. Sincethere's nothing to do, this file is intentionally blank. diff --git a/llvm/tools/llvm-libgcc/version-scripts/gcc_s-aarch64.ver b/llvm/tools/llvm-libgcc/version-scripts/gcc_s-aarch64.ver new file mode 100644 --- /dev/null +++ b/llvm/tools/llvm-libgcc/version-scripts/gcc_s-aarch64.ver @@ -0,0 +1,146 @@ +GCC_3.0 { + _Unwind_DeleteException; + _Unwind_Find_FDE; + _Unwind_ForcedUnwind; + _Unwind_GetDataRelBase; + _Unwind_GetGR; + _Unwind_GetIP; + _Unwind_GetLanguageSpecificData; + _Unwind_GetRegionStart; + _Unwind_GetTextRelBase; + _Unwind_RaiseException; + _Unwind_Resume; + _Unwind_SetGR; + _Unwind_SetIP; + __absvdi2; + __absvsi2; + __addtf3; + __addvdi3; + __addvsi3; + __ashlti3; + __ashrti3; + __clear_cache; + __cmpti2; + __divtf3; + __divti3; + __eqtf2; + __extenddftf2; + __extendsftf2; + __ffsdi2; + __ffsti2; + __fixdfti; + __fixsfti; + __fixtfdi; + __fixtfsi; + __fixtfti; + __fixunsdfdi; + __fixunsdfti; + __fixunssfdi; + __fixunssfti; + __fixunstfdi; + __fixunstfsi; + __fixunstfti; + __floatditf; + __floatsitf; + __floattidf; + __floattisf; + __floattitf; + __getf2; + __gttf2; + __letf2; + __lshrti3; + __lttf2; + __modti3; + __multf3; + __multi3; + __mulvdi3; + __mulvsi3; + __negti2; + __negvdi2; + __negvsi2; + __netf2; + __subtf3; + __subvdi3; + __subvsi3; + __trunctfdf2; + __trunctfsf2; + __ucmpti2; + __udivmodti4; + __udivti3; + __umodti3; +}; + +GCC_3.3 { + _Unwind_Backtrace; + _Unwind_FindEnclosingFunction; + _Unwind_GetCFA; + _Unwind_Resume_or_Rethrow; +}; + +GCC_3.3.1 { + __gcc_personality_v0; +}; + +GCC_3.4 { + __clzdi2; + __clzti2; + __ctzdi2; + __ctzti2; + __paritydi2; + __parityti2; + __popcountdi2; + __popcountti2; +}; + +GCC_3.4.2 { + __enable_execute_stack; +}; + +GCC_3.4.4 { + __absvti2; + __addvti3; + __mulvti3; + __negvti2; + __subvti3; +}; + +GCC_4.0.0 { + __divdc3; + __divsc3; + __divtc3; + __muldc3; + __mulsc3; + __multc3; + __powidf2; + __powisf2; + __powitf2; +}; + +GCC_4.2.0 { + _Unwind_GetIPInfo; + __floatunditf; + __floatunsitf; + __floatuntidf; + __floatuntisf; + __floatuntitf; +}; + +GCC_4.3.0 { + __bswapdi2; + __bswapsi2; + __emutls_get_address; +}; + +GCC_4.5.0 { + __unordtf2; +}; + +GCC_7.0.0 { + __divmodti4; +}; + +GLIBC_2.0 { + __deregister_frame; + __register_frame; +}; + diff --git a/llvm/tools/llvm-libgcc/version-scripts/gcc_s-armhf.ver b/llvm/tools/llvm-libgcc/version-scripts/gcc_s-armhf.ver new file mode 100644 --- /dev/null +++ b/llvm/tools/llvm-libgcc/version-scripts/gcc_s-armhf.ver @@ -0,0 +1,208 @@ +GCC_3.0 { + _Unwind_DeleteException; + _Unwind_ForcedUnwind; + _Unwind_GetDataRelBase; + _Unwind_GetLanguageSpecificData; + _Unwind_GetRegionStart; + _Unwind_GetTextRelBase; + _Unwind_RaiseException; + _Unwind_Resume; + __absvdi2; + __absvsi2; + __adddf3; + __addsf3; + __addvdi3; + __addvsi3; + __ashldi3; + __ashrdi3; + __clear_cache; + __cmpdi2; + __divdf3; + __divsf3; + __divsi3; + __eqdf2; + __eqsf2; + __extendsfdf2; + __ffsdi2; + __fixdfdi; + __fixdfsi; + __fixsfdi; + __fixsfsi; + __fixunsdfdi; + __fixunsdfsi; + __fixunssfdi; + __fixunssfsi; + __floatdidf; + __floatdisf; + __floatsidf; + __floatsisf; + __gedf2; + __gesf2; + __gtdf2; + __gtsf2; + __ledf2; + __lesf2; + __lshrdi3; + __ltdf2; + __ltsf2; + __modsi3; + __muldf3; + __muldi3; + __mulsf3; + __mulvdi3; + __mulvsi3; + __nedf2; + __negdf2; + __negdi2; + __negsf2; + __negvdi2; + __negvsi2; + __nesf2; + __subdf3; + __subsf3; + __subvdi3; + __subvsi3; + __truncdfsf2; + __ucmpdi2; + __udivmoddi4; + __udivsi3; + __umodsi3; +}; + +GCC_3.3 { + _Unwind_GetCFA; + _Unwind_Resume_or_Rethrow; +}; + +GCC_3.3.1 { + __gcc_personality_v0; +}; + +GCC_3.3.4 { + __unorddf2; + __unordsf2; +}; + +GCC_3.4 { + __clzdi2; + __clzsi2; + __ctzdi2; + __ctzsi2; + __paritydi2; + __paritysi2; + __popcountdi2; + __popcountsi2; +}; + +GCC_3.4.2 { + __enable_execute_stack; +}; + +GCC_3.5 { + _Unwind_Complete; + _Unwind_VRS_Get; + _Unwind_VRS_Pop; + _Unwind_VRS_Set; + __aeabi_cdcmpeq; + __aeabi_cdcmple; + __aeabi_cdrcmple; + __aeabi_cfcmpeq; + __aeabi_cfcmple; + __aeabi_cfrcmple; + __aeabi_d2f; + __aeabi_d2iz; + __aeabi_d2lz; + __aeabi_d2uiz; + __aeabi_d2ulz; + __aeabi_dadd; + __aeabi_dcmpeq; + __aeabi_dcmpge; + __aeabi_dcmpgt; + __aeabi_dcmple; + __aeabi_dcmplt; + __aeabi_dcmpun; + __aeabi_ddiv; + __aeabi_dmul; + __aeabi_dneg; + __aeabi_drsub; + __aeabi_dsub; + __aeabi_f2d; + __aeabi_f2iz; + __aeabi_f2lz; + __aeabi_f2uiz; + __aeabi_f2ulz; + __aeabi_fadd; + __aeabi_fcmpeq; + __aeabi_fcmpge; + __aeabi_fcmpgt; + __aeabi_fcmple; + __aeabi_fcmplt; + __aeabi_fcmpun; + __aeabi_fdiv; + __aeabi_fmul; + __aeabi_fneg; + __aeabi_frsub; + __aeabi_fsub; + __aeabi_i2d; + __aeabi_i2f; + __aeabi_idiv; + __aeabi_idiv0; + __aeabi_idivmod; + __aeabi_l2d; + __aeabi_l2f; + __aeabi_lasr; + __aeabi_lcmp; + __aeabi_ldiv0; + __aeabi_ldivmod; + __aeabi_llsl; + __aeabi_llsr; + __aeabi_lmul; + __aeabi_ui2d; + __aeabi_ui2f; + __aeabi_uidiv; + __aeabi_uidivmod; + __aeabi_ul2d; + __aeabi_ul2f; + __aeabi_ulcmp; + __aeabi_uldivmod; + __aeabi_unwind_cpp_pr0; + __aeabi_unwind_cpp_pr1; + __aeabi_unwind_cpp_pr2; + __gnu_unwind_frame; +}; + +GCC_4.0.0 { + __divdc3; + __divsc3; + __muldc3; + __mulsc3; + __powidf2; + __powisf2; +}; + +GCC_4.2.0 { + __floatundidf; + __floatundisf; + __floatunsidf; + __floatunsisf; +}; + +GCC_4.3.0 { + _Unwind_Backtrace; + __bswapdi2; + __bswapsi2; + __emutls_get_address; + __ffssi2; +}; + +GCC_7.0.0 { + __divmoddi4; +}; + +GLIBC_2.0 { + __divdi3; + __moddi3; + __udivdi3; + __umoddi3; +}; + diff --git a/llvm/tools/llvm-libgcc/version-scripts/gcc_s-i386.ver b/llvm/tools/llvm-libgcc/version-scripts/gcc_s-i386.ver new file mode 100644 --- /dev/null +++ b/llvm/tools/llvm-libgcc/version-scripts/gcc_s-i386.ver @@ -0,0 +1,124 @@ +GCC_3.0 { + _Unwind_DeleteException; + _Unwind_Find_FDE; + _Unwind_ForcedUnwind; + _Unwind_GetDataRelBase; + _Unwind_GetGR; + _Unwind_GetIP; + _Unwind_GetLanguageSpecificData; + _Unwind_GetRegionStart; + _Unwind_GetTextRelBase; + _Unwind_RaiseException; + _Unwind_Resume; + _Unwind_SetGR; + _Unwind_SetIP; + __absvdi2; + __absvsi2; + __addvdi3; + __addvsi3; + __ashldi3; + __ashrdi3; + __clear_cache; + __cmpdi2; + __deregister_frame_info_bases; + __ffsdi2; + __fixdfdi; + __fixsfdi; + __fixunsdfdi; + __fixunsdfsi; + __fixunssfdi; + __fixunssfsi; + __fixunsxfdi; + __fixunsxfsi; + __fixxfdi; + __floatdidf; + __floatdisf; + __floatdixf; + __lshrdi3; + __muldi3; + __mulvdi3; + __mulvsi3; + __negdi2; + __negvdi2; + __negvsi2; + __register_frame_info_bases; + __register_frame_info_table_bases; + __subvdi3; + __subvsi3; + __ucmpdi2; + __udivmoddi4; +}; + +GCC_3.3 { + _Unwind_Backtrace; + _Unwind_FindEnclosingFunction; + _Unwind_GetCFA; + _Unwind_Resume_or_Rethrow; +}; + +GCC_3.3.1 { + __gcc_personality_v0; +}; + +GCC_3.4 { + __clzdi2; + __clzsi2; + __ctzdi2; + __ctzsi2; + __paritydi2; + __paritysi2; + __popcountdi2; + __popcountsi2; +}; + +GCC_3.4.2 { + __enable_execute_stack; +}; + +GCC_4.0.0 { + __divdc3; + __divsc3; + __divxc3; + __muldc3; + __mulsc3; + __mulxc3; + __powidf2; + __powisf2; + __powixf2; +}; + +GCC_4.2.0 { + _Unwind_GetIPInfo; + __floatundidf; + __floatundisf; + __floatundixf; +}; + +GCC_4.3.0 { + __bswapdi2; + __bswapsi2; + __emutls_get_address; + __ffssi2; +}; + +GCC_4.8.0 { + __cpu_indicator_init; +}; + +GCC_7.0.0 { + __divmoddi4; +}; + +GLIBC_2.0 { + __deregister_frame; + __deregister_frame_info; + __divdi3; + __moddi3; + __register_frame; + __register_frame_info; + __register_frame_info_table; + __register_frame_table; + __udivdi3; + __umoddi3; +}; + diff --git a/llvm/tools/llvm-libgcc/version-scripts/gcc_s-x86_64.ver b/llvm/tools/llvm-libgcc/version-scripts/gcc_s-x86_64.ver new file mode 100644 --- /dev/null +++ b/llvm/tools/llvm-libgcc/version-scripts/gcc_s-x86_64.ver @@ -0,0 +1,131 @@ +GCC_3.0 { + _Unwind_DeleteException; + _Unwind_Find_FDE; + _Unwind_ForcedUnwind; + _Unwind_GetDataRelBase; + _Unwind_GetGR; + _Unwind_GetIP; + _Unwind_GetLanguageSpecificData; + _Unwind_GetRegionStart; + _Unwind_GetTextRelBase; + _Unwind_RaiseException; + _Unwind_Resume; + _Unwind_SetGR; + _Unwind_SetIP; + __absvdi2; + __absvsi2; + __addvdi3; + __addvsi3; + __ashlti3; + __ashrti3; + __clear_cache; + __cmpti2; + __deregister_frame; + __deregister_frame_info; + __deregister_frame_info_bases; + __divti3; + __ffsdi2; + __ffsti2; + __fixdfti; + __fixsfti; + __fixunsdfdi; + __fixunsdfti; + __fixunssfdi; + __fixunssfti; + __fixunsxfdi; + __fixunsxfti; + __fixxfti; + __floattidf; + __floattisf; + __floattixf; + __lshrti3; + __modti3; + __multi3; + __mulvdi3; + __mulvsi3; + __negti2; + __negvdi2; + __negvsi2; + __register_frame; + __register_frame_info; + __register_frame_info_bases; + __register_frame_info_table; + __register_frame_info_table_bases; + __register_frame_table; + __subvdi3; + __subvsi3; + __ucmpti2; + __udivmodti4; + __udivti3; + __umodti3; +}; + +GCC_3.3 { + _Unwind_Backtrace; + _Unwind_FindEnclosingFunction; + _Unwind_GetCFA; + _Unwind_Resume_or_Rethrow; +}; + +GCC_3.3.1 { + __gcc_personality_v0; +}; + +GCC_3.4 { + __clzdi2; + __clzti2; + __ctzdi2; + __ctzti2; + __paritydi2; + __parityti2; + __popcountdi2; + __popcountti2; +}; + +GCC_3.4.2 { + __enable_execute_stack; +}; + +GCC_3.4.4 { + __absvti2; + __addvti3; + __mulvti3; + __negvti2; + __subvti3; +}; + +GCC_4.0.0 { + __divdc3; + __divsc3; + __divxc3; + __muldc3; + __mulsc3; + __mulxc3; + __powidf2; + __powisf2; + __powixf2; +}; + +GCC_4.2.0 { + _Unwind_GetIPInfo; + __floatuntidf; + __floatuntisf; + __floatuntixf; +}; + +GCC_4.3.0 { + __bswapdi2; + __bswapsi2; + __divtc3; + __emutls_get_address; + __multc3; +}; + +GCC_4.8.0 { + __cpu_indicator_init; +}; + +GCC_7.0.0 { + __divmodti4; +}; +