diff --git a/libc/startup/baremetal/CMakeLists.txt b/libc/startup/baremetal/CMakeLists.txt index 4faced93fabe5..c5c74a0de5c3a 100644 --- a/libc/startup/baremetal/CMakeLists.txt +++ b/libc/startup/baremetal/CMakeLists.txt @@ -1,11 +1,71 @@ +function(add_startup_object name) + cmake_parse_arguments( + "ADD_STARTUP_OBJECT" + "ALIAS" # Option argument + "SRC" # Single value arguments + "DEPENDS;COMPILE_OPTIONS" # Multi value arguments + ${ARGN} + ) + + get_fq_target_name(${name} fq_target_name) + if(ADD_STARTUP_OBJECT_ALIAS) + get_fq_deps_list(fq_dep_list ${ADD_STARTUP_OBJECT_DEPENDS}) + add_library(${fq_target_name} ALIAS ${fq_dep_list}) + return() + endif() + + add_object_library( + ${name} + SRCS ${ADD_STARTUP_OBJECT_SRC} + COMPILE_OPTIONS ${ADD_STARTUP_OBJECT_COMPILE_OPTIONS} + ${ADD_STARTUP_OBJECT_UNPARSED_ARGUMENTS} + DEPENDS ${ADD_STARTUP_OBJECT_DEPENDS} + ) + set_target_properties( + ${fq_target_name} + PROPERTIES + OUTPUT_NAME ${name}.o + ) +endfunction() + add_entrypoint_object( init SRCS init.cpp + HDRS + init.h ) add_entrypoint_object( fini SRCS fini.cpp + HDRS + fini.h +) + +if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${LIBC_TARGET_ARCHITECTURE}) + add_subdirectory(${LIBC_TARGET_ARCHITECTURE}) +else() + message(WARNING "Cannot build 'crt1.o' for ${LIBC_TARGET_ARCHITECTURE} yet.") + return() +endif() + +add_startup_object( + crt1 + ALIAS + DEPENDS + .${LIBC_TARGET_ARCHITECTURE}.crt1 ) + +add_custom_target(libc-startup) +set(startup_components crt1) +foreach(target IN LISTS startup_components) + set(fq_target_name libc.startup.baremetal.${target}) + add_dependencies(libc-startup ${fq_target_name}) + install(FILES $ + DESTINATION ${LIBC_INSTALL_LIBRARY_DIR} + RENAME $ + COMPONENT libc) +endforeach() + diff --git a/libc/startup/baremetal/arm/CMakeLists.txt b/libc/startup/baremetal/arm/CMakeLists.txt new file mode 100644 index 0000000000000..3f6c4041341f4 --- /dev/null +++ b/libc/startup/baremetal/arm/CMakeLists.txt @@ -0,0 +1,16 @@ +add_startup_object( + crt1 + SRC + start.cpp + DEPENDS + libc.src.stdlib.atexit + libc.src.stdlib.exit + libc.src.string.memcpy + libc.src.string.memset + libc.startup.baremetal.init + libc.startup.baremetal.fini + COMPILE_OPTIONS + -ffreestanding # To avoid compiler warnings about calling the main function. + -fno-builtin +) +get_fq_target_name(crt1 fq_name) diff --git a/libc/startup/baremetal/arm/start.cpp b/libc/startup/baremetal/arm/start.cpp new file mode 100644 index 0000000000000..b40e7116c4001 --- /dev/null +++ b/libc/startup/baremetal/arm/start.cpp @@ -0,0 +1,95 @@ +//===-- Implementation of crt for arm -------------------------------------===// +// +// 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 "src/__support/macros/config.h" +#include "src/stdlib/atexit.h" +#include "src/stdlib/exit.h" +#include "src/string/memcpy.h" +#include "src/string/memset.h" +#include "startup/baremetal/fini.h" +#include "startup/baremetal/init.h" + +#include + +extern "C" { +int main(int argc, char **argv); +void _start(); + +// Semihosting library initialisation if applicable. Required for printf, etc. +[[gnu::weak]] void _platform_init() {} + +// These symbols are provided by the linker. The exact names are not defined by +// a standard. +extern uintptr_t __stack; +extern uintptr_t __data_source[]; +extern uintptr_t __data_start[]; +extern uintptr_t __data_size[]; +extern uintptr_t __bss_start[]; +extern uintptr_t __bss_size[]; + +// Based on +// https://developer.arm.com/documentation/107565/0101/Use-case-examples/Generic-Information/What-is-inside-a-program-image-/Vector-table +void NMI_Handler() {} +void HardFault_Handler() { LIBC_NAMESPACE::exit(1); } +void MemManage_Handler() { LIBC_NAMESPACE::exit(1); } +void BusFault_Handler() { LIBC_NAMESPACE::exit(1); } +void UsageFault_Handler() { LIBC_NAMESPACE::exit(1); } +void SVC_Handler() {} +void DebugMon_Handler() {} +void PendSV_Handler() {} +void SysTick_Handler() {} + +// Architecturally the bottom 7 bits of VTOR are zero, meaning the vector table +// has to be 128-byte aligned, however an implementation can require more bits +// to be zero and Cortex-M23 can require up to 10, so 1024-byte align the vector +// table. +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wglobal-constructors" +using HandlerType = void (*)(void); +const HandlerType vector_table[] + __attribute__((section(".vectors"), aligned(1024), used)) = { + (HandlerType)&__stack, // SP + _start, // Reset + NMI_Handler, // NMI Handler + HardFault_Handler, // Hard Fault Handlerß + MemManage_Handler, // MPU Fault Han`dler + BusFault_Handler, // Bus Fault Handler + UsageFault_Handler, // Usage Fault Handler + 0, // Reserved + 0, // Reserved + 0, // Reserved + 0, // Reserved + SVC_Handler, // SVC Handler + DebugMon_Handler, // Debug Monitor Handler + 0, // Reserved + PendSV_Handler, // PendSV Handler + SysTick_Handler, // SysTick Handler + // Unused +}; +} // extern "C" +#pragma clang diagnostic pop + +namespace LIBC_NAMESPACE_DECL { +[[noreturn]] void do_start() { + // FIXME: set up the QEMU test environment + + // Perform the equivalent of scatterloading + memcpy(__data_start, __data_source, (uintptr_t)__data_size); + memset(__bss_start, '\0', (uintptr_t)__bss_size); + __libc_init_array(); + + _platform_init(); + LIBC_NAMESPACE::atexit(&__libc_fini_array); + LIBC_NAMESPACE::exit(main(0, 0)); +} +} // namespace LIBC_NAMESPACE_DECL + +extern "C" void _start() { + asm volatile("mov sp, %0" : : "r"(&__stack)); + asm volatile("bl %0" : : "X"(LIBC_NAMESPACE::do_start)); +} diff --git a/libc/startup/baremetal/fini.cpp b/libc/startup/baremetal/fini.cpp index 263d7192cc607..5532512117ea6 100644 --- a/libc/startup/baremetal/fini.cpp +++ b/libc/startup/baremetal/fini.cpp @@ -6,17 +6,14 @@ // //===----------------------------------------------------------------------===// +#include "startup/baremetal/fini.h" + #include "src/__support/macros/config.h" #include #include namespace LIBC_NAMESPACE_DECL { -extern "C" { -extern uintptr_t __fini_array_start[]; -extern uintptr_t __fini_array_end[]; -} - using FiniCallback = void(void); extern "C" void __libc_fini_array(void) { diff --git a/libc/startup/baremetal/fini.h b/libc/startup/baremetal/fini.h new file mode 100644 index 0000000000000..c3d53601d92cc --- /dev/null +++ b/libc/startup/baremetal/fini.h @@ -0,0 +1,16 @@ +//===-- Implementation header of __libc_fini_array ------------------------===// +// +// 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 + +extern "C" { +extern uintptr_t __fini_array_start[]; +extern uintptr_t __fini_array_end[]; + +void __libc_fini_array(void); +} // extern "C" diff --git a/libc/startup/baremetal/init.cpp b/libc/startup/baremetal/init.cpp index ce387017c4972..98cca18102fef 100644 --- a/libc/startup/baremetal/init.cpp +++ b/libc/startup/baremetal/init.cpp @@ -6,19 +6,14 @@ // //===----------------------------------------------------------------------===// +#include "startup/baremetal/init.h" + #include "src/__support/macros/config.h" #include #include namespace LIBC_NAMESPACE_DECL { -extern "C" { -extern uintptr_t __preinit_array_start[]; -extern uintptr_t __preinit_array_end[]; -extern uintptr_t __init_array_start[]; -extern uintptr_t __init_array_end[]; -} - using InitCallback = void(void); extern "C" void __libc_init_array(void) { diff --git a/libc/startup/baremetal/init.h b/libc/startup/baremetal/init.h new file mode 100644 index 0000000000000..2b294e33c98e6 --- /dev/null +++ b/libc/startup/baremetal/init.h @@ -0,0 +1,18 @@ +//===-- Implementation header of __libc_init_array ------------------------===// +// +// 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 + +extern "C" { +extern uintptr_t __preinit_array_start[]; +extern uintptr_t __preinit_array_end[]; +extern uintptr_t __init_array_start[]; +extern uintptr_t __init_array_end[]; + +void __libc_init_array(void); +} // extern "C"