Skip to content

Commit 8c9863e

Browse files
[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: https://github.com/arm/arm-toolchain/tree/5446a3cbf4ef73196ccce490fc9fbf87bee093aa/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 <[email protected]>
1 parent 35a4d82 commit 8c9863e

File tree

7 files changed

+204
-14
lines changed

7 files changed

+204
-14
lines changed

libc/startup/baremetal/CMakeLists.txt

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,43 @@
1+
# TODO: Use generic "add_startup_object" https://github.com/llvm/llvm-project/issues/133156
2+
function(add_startup_object name)
3+
cmake_parse_arguments(
4+
"ADD_STARTUP_OBJECT"
5+
"ALIAS" # Option argument
6+
"SRC" # Single value arguments
7+
"DEPENDS;COMPILE_OPTIONS" # Multi value arguments
8+
${ARGN}
9+
)
10+
11+
get_fq_target_name(${name} fq_target_name)
12+
if(ADD_STARTUP_OBJECT_ALIAS)
13+
get_fq_deps_list(fq_dep_list ${ADD_STARTUP_OBJECT_DEPENDS})
14+
add_library(${fq_target_name} ALIAS ${fq_dep_list})
15+
return()
16+
endif()
17+
18+
add_object_library(
19+
${name}
20+
SRCS ${ADD_STARTUP_OBJECT_SRC}
21+
COMPILE_OPTIONS ${ADD_STARTUP_OBJECT_COMPILE_OPTIONS}
22+
${ADD_STARTUP_OBJECT_UNPARSED_ARGUMENTS}
23+
DEPENDS ${ADD_STARTUP_OBJECT_DEPENDS}
24+
)
25+
set_target_properties(
26+
${fq_target_name}
27+
PROPERTIES
28+
OUTPUT_NAME ${name}.o
29+
)
30+
endfunction()
31+
132
add_entrypoint_object(
233
init
334
SRCS
435
init.cpp
536
DEPENDS
637
libc.hdr.stdint_proxy
738
libc.src.__support.common
39+
HDRS
40+
init.h
841
)
942

1043
add_entrypoint_object(
@@ -14,4 +47,29 @@ add_entrypoint_object(
1447
DEPENDS
1548
libc.hdr.stdint_proxy
1649
libc.src.__support.common
50+
HDRS
51+
fini.h
1752
)
53+
54+
if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${LIBC_TARGET_ARCHITECTURE})
55+
add_subdirectory(${LIBC_TARGET_ARCHITECTURE})
56+
else()
57+
message(WARNING "Cannot build 'crt1.o' for ${LIBC_TARGET_ARCHITECTURE} yet.")
58+
return()
59+
endif()
60+
61+
add_startup_object(
62+
crt1
63+
ALIAS
64+
DEPENDS
65+
.${LIBC_TARGET_ARCHITECTURE}.crt1
66+
)
67+
68+
add_custom_target(libc-startup)
69+
70+
set(fq_target_name libc.startup.baremetal.${LIBC_TARGET_ARCHITECTURE}.crt1)
71+
add_dependencies(libc-startup ${fq_target_name})
72+
install(FILES $<TARGET_OBJECTS:${fq_target_name}>
73+
DESTINATION ${LIBC_INSTALL_LIBRARY_DIR}
74+
RENAME $<TARGET_PROPERTY:${fq_target_name},OUTPUT_NAME>
75+
COMPONENT libc)
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
add_startup_object(
2+
crt1
3+
SRC
4+
start.cpp
5+
DEPENDS
6+
libc.src.stdlib.atexit
7+
libc.src.stdlib.exit
8+
libc.src.string.memcpy
9+
libc.src.string.memset
10+
libc.startup.baremetal.init
11+
libc.startup.baremetal.fini
12+
COMPILE_OPTIONS
13+
-ffreestanding # To avoid compiler warnings about calling the main function.
14+
-fno-builtin
15+
-Wno-global-constructors # To allow vector table initialization
16+
)

libc/startup/baremetal/arm/start.cpp

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
//===-- Implementation of crt for arm -------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#include "src/__support/macros/config.h"
10+
#include "src/stdlib/atexit.h"
11+
#include "src/stdlib/exit.h"
12+
#include "src/string/memcpy.h"
13+
#include "src/string/memset.h"
14+
#include "startup/baremetal/fini.h"
15+
#include "startup/baremetal/init.h"
16+
17+
#include <stdint.h>
18+
19+
extern "C" {
20+
int main(int argc, char **argv);
21+
void _start();
22+
23+
// Semihosting library initialisation if applicable. Required for printf, etc.
24+
[[gnu::weak]] void _platform_init() {}
25+
26+
// These symbols are provided by the linker. The exact names are not defined by
27+
// a standard.
28+
extern uintptr_t __stack;
29+
extern uintptr_t __data_source[];
30+
extern uintptr_t __data_start[];
31+
extern uintptr_t __data_size[];
32+
extern uintptr_t __bss_start[];
33+
extern uintptr_t __bss_size[];
34+
35+
// Based on
36+
// https://developer.arm.com/documentation/107565/0101/Use-case-examples/Generic-Information/What-is-inside-a-program-image-/Vector-table
37+
void NMI_Handler() {}
38+
void HardFault_Handler() { LIBC_NAMESPACE::exit(1); }
39+
void MemManage_Handler() { LIBC_NAMESPACE::exit(1); }
40+
void BusFault_Handler() { LIBC_NAMESPACE::exit(1); }
41+
void UsageFault_Handler() { LIBC_NAMESPACE::exit(1); }
42+
void SVC_Handler() {}
43+
void DebugMon_Handler() {}
44+
void PendSV_Handler() {}
45+
void SysTick_Handler() {}
46+
47+
// Architecturally the bottom 7 bits of VTOR are zero, meaning the vector table
48+
// has to be 128-byte aligned, however an implementation can require more bits
49+
// to be zero and Cortex-M23 can require up to 10, so 1024-byte align the vector
50+
// table.
51+
using HandlerType = void (*)(void);
52+
const HandlerType vector_table[]
53+
__attribute__((section(".vectors"), aligned(1024), used)) = {
54+
(HandlerType)&__stack, // SP
55+
_start, // Reset
56+
NMI_Handler, // NMI Handler
57+
HardFault_Handler, // Hard Fault Handlerß
58+
MemManage_Handler, // MPU Fault Han`dler
59+
BusFault_Handler, // Bus Fault Handler
60+
UsageFault_Handler, // Usage Fault Handler
61+
0, // Reserved
62+
0, // Reserved
63+
0, // Reserved
64+
0, // Reserved
65+
SVC_Handler, // SVC Handler
66+
DebugMon_Handler, // Debug Monitor Handler
67+
0, // Reserved
68+
PendSV_Handler, // PendSV Handler
69+
SysTick_Handler, // SysTick Handler
70+
// Unused
71+
};
72+
} // extern "C"
73+
74+
namespace LIBC_NAMESPACE_DECL {
75+
[[noreturn]] void do_start() {
76+
// FIXME: set up the QEMU test environment
77+
78+
// Perform the equivalent of scatterloading
79+
LIBC_NAMESPACE::memcpy(__data_start, __data_source, (uintptr_t)__data_size);
80+
LIBC_NAMESPACE::memset(__bss_start, '\0', (uintptr_t)__bss_size);
81+
__libc_init_array();
82+
83+
_platform_init();
84+
LIBC_NAMESPACE::atexit(&__libc_fini_array);
85+
LIBC_NAMESPACE::exit(main(0, 0));
86+
}
87+
} // namespace LIBC_NAMESPACE_DECL
88+
89+
extern "C" void _start() {
90+
asm volatile("mov sp, %0" : : "r"(&__stack));
91+
asm volatile("bl %0" : : "X"(LIBC_NAMESPACE::do_start));
92+
}

libc/startup/baremetal/fini.cpp

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,13 @@
66
//
77
//===----------------------------------------------------------------------===//
88

9-
#include "hdr/stdint_proxy.h"
9+
#include "startup/baremetal/fini.h"
10+
1011
#include "src/__support/macros/config.h"
1112
#include <stddef.h>
1213

1314
namespace LIBC_NAMESPACE_DECL {
1415

15-
extern "C" {
16-
extern uintptr_t __fini_array_start[];
17-
extern uintptr_t __fini_array_end[];
18-
}
19-
2016
using FiniCallback = void(void);
2117

2218
extern "C" void __libc_fini_array(void) {

libc/startup/baremetal/fini.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
//===-- Implementation header of __libc_fini_array ------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#include "hdr/stdint_proxy.h"
10+
11+
extern "C" {
12+
extern uintptr_t __fini_array_start[];
13+
extern uintptr_t __fini_array_end[];
14+
15+
void __libc_fini_array(void);
16+
} // extern "C"

libc/startup/baremetal/init.cpp

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,13 @@
66
//
77
//===----------------------------------------------------------------------===//
88

9-
#include "hdr/stdint_proxy.h"
9+
#include "startup/baremetal/init.h"
10+
1011
#include "src/__support/macros/config.h"
1112
#include <stddef.h>
1213

1314
namespace LIBC_NAMESPACE_DECL {
1415

15-
extern "C" {
16-
extern uintptr_t __preinit_array_start[];
17-
extern uintptr_t __preinit_array_end[];
18-
extern uintptr_t __init_array_start[];
19-
extern uintptr_t __init_array_end[];
20-
}
21-
2216
using InitCallback = void(void);
2317

2418
extern "C" void __libc_init_array(void) {

libc/startup/baremetal/init.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
//===-- Implementation header of __libc_init_array ------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#include "hdr/stdint_proxy.h"
10+
11+
extern "C" {
12+
extern uintptr_t __preinit_array_start[];
13+
extern uintptr_t __preinit_array_end[];
14+
extern uintptr_t __init_array_start[];
15+
extern uintptr_t __init_array_end[];
16+
17+
void __libc_init_array(void);
18+
} // extern "C"

0 commit comments

Comments
 (0)