diff --git a/compiler-rt/cmake/Modules/AddCompilerRT.cmake b/compiler-rt/cmake/Modules/AddCompilerRT.cmake --- a/compiler-rt/cmake/Modules/AddCompilerRT.cmake +++ b/compiler-rt/cmake/Modules/AddCompilerRT.cmake @@ -375,7 +375,7 @@ if(APPLE) # Ad-hoc sign the dylibs add_custom_command(TARGET ${libname} - POST_BUILD + POST_BUILD COMMAND codesign --sign - $ WORKING_DIRECTORY ${COMPILER_RT_OUTPUT_LIBRARY_DIR} ) diff --git a/llvm-libgcc/CMakeLists.txt b/llvm-libgcc/CMakeLists.txt new file mode 100644 --- /dev/null +++ b/llvm-libgcc/CMakeLists.txt @@ -0,0 +1,45 @@ +cmake_minimum_required(VERSION 3.13.4) + +if (NOT IS_DIRECTORY "${CMAKE_CURRENT_LIST_DIR}/../libunwind") + message(FATAL_ERROR "llvm-libgcc requires being built in a monorepo layout with libunwind available") +endif() + +set(LLVM_COMMON_CMAKE_UTILS "${CMAKE_CURRENT_SOURCE_DIR}/../cmake") + +# Add path for custom modules +list(INSERT CMAKE_MODULE_PATH 0 + "${CMAKE_CURRENT_SOURCE_DIR}/cmake" + "${CMAKE_CURRENT_SOURCE_DIR}/cmake/Modules" + "${LLVM_COMMON_CMAKE_UTILS}" + "${LLVM_COMMON_CMAKE_UTILS}/Modules" + ) + +project(llvm-libgcc LANGUAGES C CXX ASM) + +if(NOT LLVM_LIBGCC_EXPLICIT_OPT_IN) + message(FATAL_ERROR + "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. If you want to build llvm-libgcc, please add -DLLVM_LIBGCC_EXPLICIT_OPT_IN=Yes " + "to your CMake invocation and try again.") +endif() + +list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}") + +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}/bin") + +set(COMPILER_RT_BUILD_BUILTINS On) +set(COMPILER_RT_BUILTINS_HIDE_SYMBOLS Off) +add_subdirectory("../compiler-rt" "compiler-rt") + +set(LIBUNWIND_ENABLE_STATIC On) +set(LIBUNWIND_ENABLE_SHARED Off) +set(LIBUNWIND_HAS_COMMENT_LIB_PRAGMA Off) +set(LIBUNWIND_USE_COMPILER_RT On) +add_subdirectory("../libunwind" "libunwind") + +add_subdirectory(lib) diff --git a/llvm-libgcc/docs/LLVMLibgcc.rst b/llvm-libgcc/docs/LLVMLibgcc.rst new file mode 100644 --- /dev/null +++ b/llvm-libgcc/docs/LLVMLibgcc.rst @@ -0,0 +1,182 @@ +.. 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_EXPLICIT_OPT_IN` + + **Required** + + Since llvm-libgcc is such a fundamental, low-level component, we have made it + difficult to accidentally build, by requiring you to set an opt-in flag. + +.. _Building llvm-libgcc + +Building llvm-libgcc +-------------------- + +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_CROSSCOMPILING=On \ + -DCMAKE_INSTALL_PREFIX=/tmp/aarch64-unknown-linux-gnu \ + -DLLVM_ENABLE_PROJECTS='clang' \ + -DLLVM_ENABLE_RUNTIMES="libcxx;libcxxabi;llvm-libgcc" \ + -DLLVM_TARGETS_TO_BUILD=AArch64 \ + -DLLVM_DEFAULT_TARGET_TRIPLE=aarch64-unknown-linux-gnu \ + -DLLVM_LIBGCC_EXPLICIT_OPT_IN=Yes + $ ninja -C build-primary install + +It's very important to notice that neither `compiler-rt`, nor `llvm-libgcc`, are +listed in `LLVM_ENABLE_RUNTIMES`. llvm-libgcc makes these subprojects, and adding +them to this list will cause you problems. + +## Verifying your results + +This gets you a copy of libunwind with the libgcc symbols. You can verify this +using ``readelf``. + +.. code-block:: bash + + $ llvm-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. + + +.. _supported platforms: + +Supported platforms +=================== + +llvm-libgcc currently supports the following target triples: + +* ``aarch64-*-*-*`` +* ``armv7a-*-*-gnueabihf`` +* ``i386-*-*-*`` +* ``x86_64-*-*-*`` + +If you would like to support another triple (e.g. ``powerpc64-*-*-*``), you'll +need to generate a new version script, and then edit ``lib/gcc_s.ver``. + +.. _Generating a new version script + +Generating a new version script +------------------------------- + +To generate a new version script, we need to generate the list of symbols that +exist in the set (``clang-builtins.a`` ∪ ``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 + $ export ARCH=powerpc64 + $ 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 a la +``/path/to/llvm-project/llvm/tools/llvm-libgcc/gcc_s-${ARCH}.ver``, which we use +in the next section. + +.. _Editing ``lib/gcc_s.ver`` + +Editing ``lib/gcc_s.ver`` +------------------------- + +Our freshly generated version script is unique to the specific architecture that +it was generated for, but a lot of the symbols are shared among many platforms. +As such, we don't check in unique version scripts, but rather have a single +version script that's run through the C preprocessor to prune symbols we won't +be using in ``lib/gcc_s.ver``. + +Working out which symbols are common is largely a manual process at the moment, +because some symbols may be shared across different architectures, but not in +the same versions of libgcc. As such, a symbol appearing in ``lib/gcc_s.ver`` +doesn't guarantee that the symbol is available for our new architecture: we need +to verify that the versions are the same, and if they're not, add the symbol to +the new version section, with the appropriate include guards. + +There are a few macros that aim to improve readability. + +* ``ARM_GNUEABIHF``, which targets exactly ``arm-*-*-gnueabihf``. +* ``GLOBAL_X86``, which should be used to target both x86 and x86_64, regardless + of the triple. +* ``GLOBAL_32BIT``, which is be used to target 32-bit platforms. +* ``GLOBAL_64BIT``, which is be used to target 64-bit platforms. diff --git a/llvm-libgcc/generate_version_script.py b/llvm-libgcc/generate_version_script.py new file mode 100755 --- /dev/null +++ b/llvm-libgcc/generate_version_script.py @@ -0,0 +1,128 @@ +#!/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 + `llvm-readelf --wide ${path} | grep 'FUNC' | grep -v 'UND' | awk '{print $8}'`. + """ + result = subprocess.run(args=['llvm-readelf', '-su', 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(versioned_symbols): + path = f'{os.path.dirname(os.path.realpath(__file__))}/new-gcc_s-symbols' + with open(path, 'w') as f: + f.write('Do not check this version script in: you should instead work ' + 'out which symbols are missing in `lib/gcc_s.ver` and then ' + 'integrate them into `lib/gcc_s.ver`. For more information, ' + 'please see `doc/LLVMLibgcc.rst`.\n') + 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) + 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) + # TODO(cjdb): work out a way to integrate new symbols in with the existing + # ones + to_file(versioned_symbols) + + +if __name__ == '__main__': + main() diff --git a/llvm-libgcc/lib/CMakeLists.txt b/llvm-libgcc/lib/CMakeLists.txt new file mode 100644 --- /dev/null +++ b/llvm-libgcc/lib/CMakeLists.txt @@ -0,0 +1,95 @@ +include(CheckLibraryExists) +include(GNUInstallDirs) +string(REPLACE "-Wl,-z,defs" "" CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS}") + +add_custom_target(gcc_s_ver ALL DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/gcc_s.ver") +set(LLVM_LIBGCC_GCC_S_VER "${CMAKE_CURRENT_BINARY_DIR}/gcc_s.ver") + +add_custom_command( + OUTPUT gcc_s.ver + DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/gcc_s.ver" + COMMAND + "${CMAKE_C_COMPILER}" + "-E" + "-xc" "${CMAKE_CURRENT_SOURCE_DIR}/gcc_s.ver" + "-o" "${CMAKE_CURRENT_BINARY_DIR}/gcc_s.ver" +) +add_custom_target(gcc_s_version_script DEPENDS gcc_s.ver) +set_target_properties( + gcc_s_version_script PROPERTIES + OUTPUT_PATH "${CMAKE_CURRENT_BINARY_DIR}/gcc_s.ver") + +add_library(libgcc_s SHARED blank.c) +add_dependencies(libgcc_s gcc_s_ver) +set_target_properties(libgcc_s + PROPERTIES + LINKER_LANGUAGE C + OUTPUT_NAME "unwind" + VERSION "1.0" + SOVERSION "1" + POSITION_INDEPENDENT_CODE ON) +string(REGEX MATCH "[^-]+" LLVM_LIBGCC_TARGET_ARCH ${CMAKE_C_COMPILER_TARGET}) +target_link_options( + libgcc_s PRIVATE + -nostdlib) +target_link_libraries( + libgcc_s PRIVATE + $ + $ +) +target_link_options( + libgcc_s PRIVATE + -Wl,--version-script,$) + +check_library_exists(m sin "" LLVM_LIBGCC_HAS_LIBM) +target_link_libraries( + libgcc_s PRIVATE + $<$:m> + c +) + +#add_custom_target(synth_libgcc ALL +# DEPENDS builtins libgcc_s +# COMMAND +# ${CMAKE_COMMAND} -E create_symlink builtins "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/libgcc.a") + +set(LLVM_LIBGCC_INSTALL_LIBRARY_DIR lib${LLVM_LIBDIR_SUFFIX} CACHE PATH "") +install(TARGETS libgcc_s + LIBRARY DESTINATION "${LLVM_LIBGCC_INSTALL_LIBRARY_DIR}" COMPONENT unwind + ARCHIVE DESTINATION "${LLVM_LIBGCC_INSTALL_LIBRARY_DIR}" COMPONENT unwind + RUNTIME DESTINATION bin COMPONENT unwind) +get_filename_component(LLVM_LIBGCC_LIBUNWIND_STATIC_ROOT "${CMAKE_INSTALL_PREFIX}/${LIBUNWIND_INSTALL_LIBRARY_DIR}" ABSOLUTE) +string(REPLACE "${CMAKE_INSTALL_FULL_LIBDIR}/" "" LLVM_LIBGCC_LIBUNWIND_STATIC_ROOT "${LLVM_LIBGCC_LIBUNWIND_STATIC_ROOT}") + +get_compiler_rt_install_dir(${LLVM_LIBGCC_TARGET_ARCH} install_dir_builtins) +string(REGEX REPLACE "^lib/" "" install_dir_builtins "${install_dir_builtins}") +string(FIND "${install_dir_builtins}" "${LLVM_DEFAULT_TARGET_TRIPLE}" install_path_contains_triple) +if(install_path_contains_triple EQUAL -1) + set(builtins_suffix "-${LLVM_LIBGCC_TARGET_ARCH}") +endif() +install(CODE "execute_process( + COMMAND \"\${CMAKE_COMMAND}\" -E + create_symlink ${install_dir_builtins}/libclang_rt.builtins${builtins_suffix}.a libgcc.a + WORKING_DIRECTORY \"\$ENV{DESTDIR}${CMAKE_INSTALL_FULL_LIBDIR}\")" + COMPONENT unwind) + +install(CODE "execute_process( + COMMAND \"\${CMAKE_COMMAND}\" -E + create_symlink ${LLVM_LIBGCC_LIBUNWIND_STATIC_ROOT}/libunwind.a libgcc_eh.a + WORKING_DIRECTORY \"\$ENV{DESTDIR}${CMAKE_INSTALL_FULL_LIBDIR}\")" + COMPONENT unwind) +install(CODE "execute_process( + COMMAND \"\${CMAKE_COMMAND}\" -E + create_symlink libunwind.so libgcc_s.so.1.0 + WORKING_DIRECTORY \"\$ENV{DESTDIR}${CMAKE_INSTALL_FULL_LIBDIR}\")" + COMPONENT unwind) +install(CODE "execute_process( + COMMAND \"\${CMAKE_COMMAND}\" -E + create_symlink libgcc_s.so.1.0 libgcc_s.so.1 + WORKING_DIRECTORY \"\$ENV{DESTDIR}${CMAKE_INSTALL_FULL_LIBDIR}\")" + COMPONENT unwind) +install(CODE "execute_process( + COMMAND \"\${CMAKE_COMMAND}\" -E + create_symlink libgcc_s.so.1 libgcc_s.so + WORKING_DIRECTORY \"\$ENV{DESTDIR}${CMAKE_INSTALL_FULL_LIBDIR}\")" + COMPONENT unwind) diff --git a/llvm-libgcc/lib/blank.c b/llvm-libgcc/lib/blank.c new file mode 100644 diff --git a/llvm-libgcc/lib/gcc_s.ver b/llvm-libgcc/lib/gcc_s.ver new file mode 100644 --- /dev/null +++ b/llvm-libgcc/lib/gcc_s.ver @@ -0,0 +1,167 @@ +// Detect if we're using arm-*-*-gnueabihf +#if defined(__arm__) && \ + defined(__ARM_ARCH_7A__) && defined(__ARM_EABI__) && \ + defined(__ARM_FP) && (__ARM_FP >= 0x04) + #define ARM_GNUEABIHF +#endif + +#if !defined(__x86_64__) && \ + !defined(__aarch64__) && \ + !defined(__i386__) && \ + !defined(ARM_GNUEABIHF) + #error The only platforms that are currently supported are x86_64, i386, arm-gnueabihf, and aarch64. +#endif + +#if defined(__x86_64__) || defined(__i386__) + #define GLOBAL_X86 +#endif + +#if __SIZEOF_POINTER__ >= 8 + #define GLOBAL_64BIT +#else + #define GLOBAL_32BIT +#endif + +GCC_3.0 { + __absvdi2; __absvsi2; __addvdi3; __addvsi3; __clear_cache; __ffsdi2; + __fixunsdfdi; __fixunssfdi; __mulvdi3; __mulvsi3; __negvdi2; __negvsi2; + __subvdi3; __subvsi3; + _Unwind_DeleteException; + _Unwind_ForcedUnwind; + _Unwind_GetDataRelBase; + _Unwind_GetLanguageSpecificData; + _Unwind_GetRegionStart; + _Unwind_GetTextRelBase; + _Unwind_RaiseException; + _Unwind_Resume; +}; + +GCC_3.3 { _Unwind_GetCFA; _Unwind_Resume_or_Rethrow; }; +GCC_3.3.1 { __gcc_personality_v0; }; +GCC_3.4 { __clzdi2; __ctzdi2; __paritydi2; __popcountdi2; }; +GCC_3.4.2 { __enable_execute_stack; }; +GCC_4.0.0 { __divdc3; __divsc3; __muldc3; __mulsc3; __powidf2; __powisf2; }; +GCC_4.3.0 { __bswapdi2; __bswapsi2; __emutls_get_address; }; + +#if defined(GLOBAL_32BIT) + GCC_3.0 { + __ashldi3; __ashrdi3; __cmpdi2; __fixdfdi; __fixsfdi; __fixunsdfsi; + __fixunssfsi; __floatdidf; __floatdisf; __lshrdi3; __muldi3; __negdi2; + __ucmpdi2; __udivmoddi4; + }; + + GCC_3.4 { __clzsi2; __ctzsi2; __paritysi2; __popcountsi2; }; + GCC_4.2.0 { __floatundidf; __floatundisf; }; + GCC_4.3.0 { __ffssi2; }; + GCC_7.0.0 { __divmoddi4; }; + GLIBC_2.0 { __divdi3; __moddi3; __udivdi3; __umoddi3; }; +#elif defined(GLOBAL_64BIT) + GCC_3.0 { + __ashlti3; __ashrti3; __cmpti2; __divti3; __ffsti2; __fixdfti; + __fixsfti; __fixunssfti; __floattidf; __lshrti3; __modti3; __multi3; + __negti2; __ucmpti2; __udivmodti4; __udivti3; __umodti3; __fixunsdfti; + __floattisf; + }; + + GCC_3.4 { __clzti2; __ctzti2; __parityti2; __popcountti2; }; + GCC_3.4.4 { __absvti2; __addvti3; __mulvti3; __negvti2; __subvti3; }; + GCC_4.2.0 { __floatuntidf; __floatuntisf; }; + GCC_7.0.0 { __divmodti4; }; +#endif + +#if defined(GLOBAL_X86) + GCC_3.0 { + __deregister_frame_info_bases; __fixunsxfdi; __register_frame_info_bases; + __register_frame_info_table_bases; + }; + + GCC_4.0.0 { __divxc3; __mulxc3; __powixf2; }; + GCC_4.8.0 { __cpu_indicator_init; }; +#endif + +#if !defined(ARM_GNUEABIHF) + GCC_3.0 { + _Unwind_Find_FDE; _Unwind_GetGR; _Unwind_GetIP; _Unwind_SetGR; _Unwind_SetIP; + }; + + GCC_3.3 { _Unwind_Backtrace; _Unwind_FindEnclosingFunction; }; + GCC_4.2.0 { _Unwind_GetIPInfo; }; +#else // defined(ARM_GNUEABIHF) + GCC_3.0 { + __adddf3; __addsf3; __divdf3; __divsf3; __divsi3; __eqdf2; + __eqsf2; __extendsfdf2; __fixdfsi; __fixsfsi; __floatsidf; __floatsisf; + __gedf2; __gesf2; __gtdf2; __gtsf2; __ledf2; __lesf2; + __ltdf2; __ltsf2; __modsi3; __muldf3; __mulsf3; __nedf2; + __negdf2; __negsf2; __nesf2; __subdf3; __subsf3; __truncdfsf2; + __udivsi3; __umodsi3; + }; + + GCC_3.3.4 { __unorddf2; __unordsf2; }; + + GCC_3.5 { + __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; + _Unwind_Complete; + _Unwind_VRS_Get; + _Unwind_VRS_Pop; + _Unwind_VRS_Set; + }; + + GCC_4.2.0 { __floatunsidf; __floatunsisf; }; + GCC_4.3.0 { _Unwind_Backtrace; }; +#endif + +#if defined(__aarch64__) + GCC_3.0 { + __addtf3; __divtf3; __eqtf2; __extenddftf2; __extendsftf2; + __fixtfdi; __fixtfsi; __fixtfti; __fixunstfdi; __fixunstfsi; + __fixunstfti; __floatditf; __floatsitf; __floattitf; __getf2; + __gttf2; __letf2; __lttf2; __multf3; __netf2; + __subtf3; __trunctfdf2; __trunctfsf2; + }; + + GCC_4.0.0 { __powitf2; __divtc3; __multc3; }; + GCC_4.2.0 { __floatunditf; __floatunsitf; __floatuntitf; }; + GCC_4.5.0 { __unordtf2; }; +#endif + +#if defined(__aarch64__) || defined(__i386__) + GLIBC_2.0 { __deregister_frame; __register_frame; }; +#endif + +#if defined(__i386__) + GCC_3.0 { __fixunsxfsi; __fixxfdi; __floatdixf; }; + GCC_4.2.0 { __floatundixf; }; + + GLIBC_2.0 { + __register_frame_info; __register_frame_info_table; __register_frame_table; + __deregister_frame_info; + }; +#endif + +#if defined(__x86_64__) + GCC_3.0 { + __register_frame_info; __register_frame_info_table; __register_frame_table; + __deregister_frame; __deregister_frame_info; __register_frame; + __fixunsxfti; __fixxfti; __floattixf; + }; + + GCC_4.2.0 { __floatuntixf; }; + GCC_4.3.0 { __divtc3; __multc3; }; +#endif diff --git a/runtimes/CMakeLists.txt b/runtimes/CMakeLists.txt --- a/runtimes/CMakeLists.txt +++ b/runtimes/CMakeLists.txt @@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.13.4) project(Runtimes C CXX ASM) -set(LLVM_ALL_RUNTIMES "compiler-rt;libc;libcxx;libcxxabi;libunwind;openmp") +set(LLVM_ALL_RUNTIMES "compiler-rt;libc;libcxx;libcxxabi;libunwind;llvm-libgcc;openmp") set(LLVM_ENABLE_RUNTIMES "" CACHE STRING "Semicolon-separated list of runtimes to build (${LLVM_ALL_RUNTIMES}), or \"all\".") if(LLVM_ENABLE_RUNTIMES STREQUAL "all" ) @@ -178,6 +178,27 @@ set(LLVM_LIT_ARGS "${LIT_ARGS_DEFAULT}" CACHE STRING "Default options for lit") endif() +# llvm-libgcc incorporates both compiler-rt and libunwind as subprojects with very +# specific flags, which causes clashes when they're independently built too. +list(FIND "${runtimes}" "llvm-libgcc" RUNTIMES_HAS_LLVM_LIBGCC) +if(NOT RUNTIMES_HAS_LLVM_LIBGCC EQUAL -1) + list(FIND "${runtimes}" "compiler-rt" RUNTIMES_HAS_COMPILER_RT) + list(FIND "${LLVM_ENABLE_PROJECTS}" "compiler-rt" RUNTIMES_PROJECTS_HAS_COMPILER_RT) + if(NOT RUNTIMES_HAS_COMPILER_RT EQUAL -1 OR NOT RUNTIMES_PROJECTS_HAS_COMPILER_RT EQUAL -1) + message(FATAL_ERROR + "Attempting to build both compiler-rt and llvm-libgcc will cause irreconcilable " + "target clashes. Please choose one or the other, but not both.") + endif() + + list(FIND "${runtimes}" "libunwind" RUNTIMES_HAS_LIBUNWIND) + if(NOT RUNTIMES_HAS_LIBUNWIND EQUAL -1) + message( + FATAL_ERROR + "Attempting to build both libunwind and llvm-libgcc will cause irreconcilable " + "target clashes. Please choose one or the other, but not both.") + endif() +endif() + # We do this in two loops so that HAVE_* is set for each runtime before the # other runtimes are added. foreach(entry ${runtimes})