diff options
author | Petr Hosek <phosek@chromium.org> | 2019-04-30 17:21:13 +0000 |
---|---|---|
committer | Petr Hosek <phosek@chromium.org> | 2019-04-30 17:21:13 +0000 |
commit | 2ac8e2003401eef2119ec05c9d596756703d5681 (patch) | |
tree | 888b78e6fc40bdd00f78a37e4ccacc34ac5b1bde /lib/crt | |
parent | 8d158e4bfb63c4792b7135d0625fcc4592dcac7b (diff) | |
download | compiler-rt-2ac8e2003401eef2119ec05c9d596756703d5681.tar.gz |
[compiler-rt] Simple crtbegin.o and crtend.o implementation
Clang relies on existence of certain symbols that are normally
provided by crtbegin.o/crtend.o. However, LLVM does not currently
provide implementation of these files, instead relying on either
libgcc or implementations provided as part of the system.
This change provides an initial implementation of crtbegin.o/crtend.o
that can be used on system that don't provide crtbegin.o/crtend.o as
part of their C library.
Differential Revision: https://reviews.llvm.org/D28791
git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@359576 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/crt')
-rw-r--r-- | lib/crt/CMakeLists.txt | 90 | ||||
-rw-r--r-- | lib/crt/crtbegin.c | 97 | ||||
-rw-r--r-- | lib/crt/crtend.c | 22 |
3 files changed, 209 insertions, 0 deletions
diff --git a/lib/crt/CMakeLists.txt b/lib/crt/CMakeLists.txt new file mode 100644 index 000000000..f0e8118e9 --- /dev/null +++ b/lib/crt/CMakeLists.txt @@ -0,0 +1,90 @@ +add_compiler_rt_component(crt) + +function(check_cxx_section_exists section output) + cmake_parse_arguments(ARG "" "" "SOURCE;FLAGS" ${ARGN}) + if(NOT ARG_SOURCE) + set(ARG_SOURCE "int main() { return 0; }\n") + endif() + + string(RANDOM TARGET_NAME) + set(TARGET_NAME "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/cmTC_${TARGET_NAME}.dir") + file(MAKE_DIRECTORY ${TARGET_NAME}) + + file(WRITE "${TARGET_NAME}/CheckSectionExists.c" "${ARG_SOURCE}\n") + + string(REGEX MATCHALL "<[A-Za-z0-9_]*>" substitutions + ${CMAKE_C_COMPILE_OBJECT}) + + set(try_compile_flags "${ARG_FLAGS}") + if(CMAKE_C_COMPILER_ID MATCHES Clang AND CMAKE_C_COMPILER_TARGET) + list(APPEND try_compile_flags "-target ${CMAKE_C_COMPILER_TARGET}") + endif() + + string(REPLACE ";" " " extra_flags "${try_compile_flags}") + + set(test_compile_command "${CMAKE_C_COMPILE_OBJECT}") + foreach(substitution ${substitutions}) + if(substitution STREQUAL "<CMAKE_C_COMPILER>") + string(REPLACE "<CMAKE_C_COMPILER>" + "${CMAKE_C_COMPILER}" test_compile_command ${test_compile_command}) + elseif(substitution STREQUAL "<OBJECT>") + string(REPLACE "<OBJECT>" "${TARGET_NAME}/CheckSectionExists.o" + test_compile_command ${test_compile_command}) + elseif(substitution STREQUAL "<SOURCE>") + string(REPLACE "<SOURCE>" "${TARGET_NAME}/CheckSectionExists.c" + test_compile_command ${test_compile_command}) + elseif(substitution STREQUAL "<FLAGS>") + string(REPLACE "<FLAGS>" "${CMAKE_C_FLAGS} ${extra_flags}" + test_compile_command ${test_compile_command}) + else() + string(REPLACE "${substitution}" "" test_compile_command + ${test_compile_command}) + endif() + endforeach() + + string(REPLACE " " ";" test_compile_command "${test_compile_command}") + + execute_process( + COMMAND ${test_compile_command} + RESULT_VARIABLE TEST_RESULT + OUTPUT_VARIABLE TEST_OUTPUT + ERROR_VARIABLE TEST_ERROR + ) + + execute_process( + COMMAND ${CMAKE_OBJDUMP} -h "${TARGET_NAME}/CheckSectionExists.o" + RESULT_VARIABLE CHECK_RESULT + OUTPUT_VARIABLE CHECK_OUTPUT + ERROR_VARIABLE CHECK_ERROR + ) + string(FIND "${CHECK_OUTPUT}" "${section}" SECTION_FOUND) + + if(NOT SECTION_FOUND EQUAL -1) + set(${output} TRUE PARENT_SCOPE) + else() + set(${output} FALSE PARENT_SCOPE) + endif() + + file(REMOVE_RECURSE ${TARGET_NAME}) +endfunction() + +check_cxx_section_exists(".init_array" COMPILER_RT_HAS_INITFINI_ARRAY + SOURCE "__attribute__((constructor)) void f() {}\nint main() { return 0; }\n") + +append_list_if(COMPILER_RT_HAS_INITFINI_ARRAY -DCRT_HAS_INITFINI_ARRAY CRT_CFLAGS) +append_list_if(COMPILER_RT_HAS_FPIC_FLAG -fPIC CRT_CFLAGS) + +foreach(arch ${CRT_SUPPORTED_ARCH}) + add_compiler_rt_runtime(clang_rt.crtbegin + OBJECT + ARCHS ${arch} + SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/crtbegin.c + CFLAGS ${CRT_CFLAGS} + PARENT_TARGET crt) + add_compiler_rt_runtime(clang_rt.crtend + OBJECT + ARCHS ${arch} + SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/crtend.c + CFLAGS ${CRT_CFLAGS} + PARENT_TARGET crt) +endforeach() diff --git a/lib/crt/crtbegin.c b/lib/crt/crtbegin.c new file mode 100644 index 000000000..796094f65 --- /dev/null +++ b/lib/crt/crtbegin.c @@ -0,0 +1,97 @@ +//===-- crtbegin.c - Start of constructors and destructors ----------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include <stddef.h> + +__attribute__((visibility("hidden"))) void *__dso_handle = &__dso_handle; + +static void *__EH_FRAME_LIST__[] + __attribute__((section(".eh_frame"), aligned(sizeof(void *)))) = {}; + +extern void __register_frame_info(const void *, void *) __attribute__((weak)); +extern void *__deregister_frame_info(const void *) __attribute__((weak)); + +#ifndef CRT_HAS_INITFINI_ARRAY +typedef void (*fp)(void); + +static fp __CTOR_LIST__[] + __attribute__((section(".ctors"), aligned(sizeof(fp)))) = {(fp)-1}; +extern fp __CTOR_LIST_END__[]; +#endif + +extern void __cxa_finalize(void *) __attribute__((weak)); + +static void __attribute__((used)) __do_init() { + static _Bool __initialized; + if (__builtin_expect(__initialized, 0)) + return; + __initialized = 1; + + static struct { void *p[8]; } __object; + if (__register_frame_info) + __register_frame_info(__EH_FRAME_LIST__, &__object); + +#ifndef CRT_HAS_INITFINI_ARRAY + const size_t n = __CTOR_LIST_END__ - __CTOR_LIST__ - 1; + for (size_t i = n; i >= 1; i--) __CTOR_LIST__[i](); +#endif +} + +#ifdef CRT_HAS_INITFINI_ARRAY +__attribute__((section(".init_array"), + used)) static void (*__init)(void) = __do_init; +#else // CRT_HAS_INITFINI_ARRAY +#if defined(__i386__) || defined(__x86_64__) +asm(".pushsection .init,\"ax\",@progbits\n\t" + "call " __USER_LABEL_PREFIX__ "__do_init\n\t" + ".popsection"); +#elif defined(__arm__) +asm(".pushsection .init,\"ax\",%progbits\n\t" + "bl " __USER_LABEL_PREFIX__ "__do_init\n\t" + ".popsection"); +#endif // CRT_HAS_INITFINI_ARRAY +#endif + +#ifndef CRT_HAS_INITFINI_ARRAY +static fp __DTOR_LIST__[] + __attribute__((section(".dtors"), aligned(sizeof(fp)))) = {(fp)-1}; +extern fp __DTOR_LIST_END__[]; +#endif + +static void __attribute__((used)) __do_fini() { + static _Bool __finalized; + if (__builtin_expect(__finalized, 0)) + return; + __finalized = 1; + + if (__cxa_finalize) + __cxa_finalize(__dso_handle); + +#ifndef CRT_HAS_INITFINI_ARRAY + if (__deregister_frame_info) + __deregister_frame_info(__EH_FRAME_LIST__); + + const size_t n = __DTOR_LIST_END__ - __DTOR_LIST__ - 1; + for (size_t i = 1; i < n; i++) __DTOR_LIST__[i](); +#endif +} + +#ifdef CRT_HAS_INITFINI_ARRAY +__attribute__((section(".fini_array"), + used)) static void (*__fini)(void) = __do_fini; +#else // CRT_HAS_INITFINI_ARRAY +#if defined(__i386__) || defined(__x86_64__) +asm(".pushsection .fini,\"ax\",@progbits\n\t" + "call " __USER_LABEL_PREFIX__ "__do_fini\n\t" + ".popsection"); +#elif defined(__arm__) +asm(".pushsection .fini,\"ax\",%progbits\n\t" + "bl " __USER_LABEL_PREFIX__ "__do_fini\n\t" + ".popsection"); +#endif +#endif // CRT_HAS_INIT_FINI_ARRAY diff --git a/lib/crt/crtend.c b/lib/crt/crtend.c new file mode 100644 index 000000000..ebcc60b89 --- /dev/null +++ b/lib/crt/crtend.c @@ -0,0 +1,22 @@ +//===-- crtend.c - End of constructors and destructors --------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include <stdint.h> + +// Put 4-byte zero which is the length field in FDE at the end as a terminator. +const int32_t __EH_FRAME_LIST_END__[] + __attribute__((section(".eh_frame"), aligned(sizeof(int32_t)), + visibility("hidden"), used)) = {0}; + +#ifndef CRT_HAS_INITFINI_ARRAY +typedef void (*fp)(void); +fp __CTOR_LIST_END__[] + __attribute__((section(".ctors"), visibility("hidden"), used)) = {0}; +fp __DTOR_LIST_END__[] + __attribute__((section(".dtors"), visibility("hidden"), used)) = {0}; +#endif |