[libc] Basic implementation of crt0 (#146863)
In order to run hermetic tests downstream (#145349), we need startup
code. This is based on the crt0 that is present in Arm Toolchain:
5446a3cbf4/arm-software/embedded/llvmlibc-support/crt0
.
Note that some tests do fail due to lack of hardware setup, which will
be implemented at a later time.
Most of the CMake/structure is a copy from the existing code in both
`libc/startup/linux` and `libc/startup/gpu`. It is required to build an
object file to be linked with.
Also add header files for init/fini such that crt0 can use the provided
symbols.
---------
Co-authored-by: Michael Jones <michaelrj@google.com>
This commit is contained in:
parent
35a4d8206b
commit
8c9863eb1e
@ -1,3 +1,34 @@
|
||||
# TODO: Use generic "add_startup_object" https://github.com/llvm/llvm-project/issues/133156
|
||||
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
|
||||
@ -5,6 +36,8 @@ add_entrypoint_object(
|
||||
DEPENDS
|
||||
libc.hdr.stdint_proxy
|
||||
libc.src.__support.common
|
||||
HDRS
|
||||
init.h
|
||||
)
|
||||
|
||||
add_entrypoint_object(
|
||||
@ -14,4 +47,29 @@ add_entrypoint_object(
|
||||
DEPENDS
|
||||
libc.hdr.stdint_proxy
|
||||
libc.src.__support.common
|
||||
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(fq_target_name libc.startup.baremetal.${LIBC_TARGET_ARCHITECTURE}.crt1)
|
||||
add_dependencies(libc-startup ${fq_target_name})
|
||||
install(FILES $<TARGET_OBJECTS:${fq_target_name}>
|
||||
DESTINATION ${LIBC_INSTALL_LIBRARY_DIR}
|
||||
RENAME $<TARGET_PROPERTY:${fq_target_name},OUTPUT_NAME>
|
||||
COMPONENT libc)
|
||||
|
16
libc/startup/baremetal/arm/CMakeLists.txt
Normal file
16
libc/startup/baremetal/arm/CMakeLists.txt
Normal file
@ -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
|
||||
-Wno-global-constructors # To allow vector table initialization
|
||||
)
|
92
libc/startup/baremetal/arm/start.cpp
Normal file
92
libc/startup/baremetal/arm/start.cpp
Normal file
@ -0,0 +1,92 @@
|
||||
//===-- 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 <stdint.h>
|
||||
|
||||
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.
|
||||
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"
|
||||
|
||||
namespace LIBC_NAMESPACE_DECL {
|
||||
[[noreturn]] void do_start() {
|
||||
// FIXME: set up the QEMU test environment
|
||||
|
||||
// Perform the equivalent of scatterloading
|
||||
LIBC_NAMESPACE::memcpy(__data_start, __data_source, (uintptr_t)__data_size);
|
||||
LIBC_NAMESPACE::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));
|
||||
}
|
@ -6,17 +6,13 @@
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "hdr/stdint_proxy.h"
|
||||
#include "startup/baremetal/fini.h"
|
||||
|
||||
#include "src/__support/macros/config.h"
|
||||
#include <stddef.h>
|
||||
|
||||
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) {
|
||||
|
16
libc/startup/baremetal/fini.h
Normal file
16
libc/startup/baremetal/fini.h
Normal file
@ -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 "hdr/stdint_proxy.h"
|
||||
|
||||
extern "C" {
|
||||
extern uintptr_t __fini_array_start[];
|
||||
extern uintptr_t __fini_array_end[];
|
||||
|
||||
void __libc_fini_array(void);
|
||||
} // extern "C"
|
@ -6,19 +6,13 @@
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "hdr/stdint_proxy.h"
|
||||
#include "startup/baremetal/init.h"
|
||||
|
||||
#include "src/__support/macros/config.h"
|
||||
#include <stddef.h>
|
||||
|
||||
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) {
|
||||
|
18
libc/startup/baremetal/init.h
Normal file
18
libc/startup/baremetal/init.h
Normal file
@ -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 "hdr/stdint_proxy.h"
|
||||
|
||||
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"
|
Loading…
x
Reference in New Issue
Block a user