blob: a287bc4d633d45fb470e37edb1143df6adaa4382 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
|
# This function merges multiple objects into a single relocatable object
# cc -r obj1.o obj2.o -o obj.o
# A relocatable object is an object file that is not fully linked into an
# executable or a shared library. It is an intermediate file format that can
# be passed into the linker.
# A crt object has arch-specific code and arch-agnostic code. To reduce code
# duplication, the implementation is split into multiple units. As a result,
# we need to merge them into a single relocatable object.
# See also: https://maskray.me/blog/2022-11-21-relocatable-linking
function(merge_relocatable_object name)
set(obj_list "")
set(fq_link_libraries "")
get_fq_deps_list(fq_dep_list ${ARGN})
foreach(target IN LISTS fq_dep_list)
list(APPEND obj_list "$<TARGET_OBJECTS:${target}>")
get_target_property(libs ${target} DEPS)
list(APPEND fq_link_libraries "${libs}")
endforeach()
list(REMOVE_DUPLICATES obj_list)
list(REMOVE_DUPLICATES fq_link_libraries)
get_fq_target_name(${name} fq_name)
set(relocatable_target "${fq_name}.__relocatable__")
add_executable(
${relocatable_target}
${obj_list}
)
# Pass -r to the driver is much cleaner than passing -Wl,-r: the compiler knows it is
# a relocatable linking and will not pass other irrelevant flags to the linker.
target_link_options(${relocatable_target} PRIVATE -r -nostdlib)
set_target_properties(
${relocatable_target}
PROPERTIES
RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
OUTPUT_NAME ${name}.o
)
add_library(${fq_name} OBJECT IMPORTED GLOBAL)
add_dependencies(${fq_name} ${relocatable_target})
target_link_libraries(${fq_name} INTERFACE ${fq_link_libraries})
set_target_properties(
${fq_name}
PROPERTIES
LINKER_LANGUAGE CXX
IMPORTED_OBJECTS ${CMAKE_CURRENT_BINARY_DIR}/${name}.o
TARGET_TYPE ${OBJECT_LIBRARY_TARGET_TYPE}
DEPS "${fq_link_libraries}"
)
endfunction()
function(add_startup_object name)
cmake_parse_arguments(
"ADD_STARTUP_OBJECT"
"" # Option argument
"SRC" # Single value arguments
"DEPENDS;COMPILE_OPTIONS" # Multi value arguments
${ARGN}
)
get_fq_target_name(${name} fq_target_name)
add_object_library(
${name}
SRCS ${ADD_STARTUP_OBJECT_SRC}
DEPENDS ${ADD_STARTUP_OBJECT_DEPENDS}
COMPILE_OPTIONS ${ADD_STARTUP_OBJECT_COMPILE_OPTIONS}
)
set_target_properties(
${fq_target_name}
PROPERTIES
OUTPUT_NAME ${name}.o
)
endfunction()
check_cxx_compiler_flag("-r" LIBC_LINKER_SUPPORTS_RELOCATABLE)
if(NOT LIBC_LINKER_SUPPORTS_RELOCATABLE)
message(STATUS "Skipping startup for target architecture ${LIBC_TARGET_ARCHITECTURE}: linker does not support -r")
return()
endif()
if(NOT (EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${LIBC_TARGET_ARCHITECTURE}))
message(STATUS "Skipping startup for target architecture ${LIBC_TARGET_ARCHITECTURE}")
return()
endif()
add_subdirectory(${LIBC_TARGET_ARCHITECTURE})
add_object_library(
do_start
SRCS
do_start.cpp
HDRS
do_start.h
DEPENDS
libc.config.linux.app_h
libc.include.sys_mman
libc.include.sys_syscall
libc.src.__support.threads.thread
libc.src.__support.OSUtil.osutil
libc.src.stdlib.exit
libc.src.stdlib.atexit
libc.src.unistd.environ
COMPILE_OPTIONS
-ffreestanding # To avoid compiler warnings about calling the main function.
-fno-builtin # avoid emit unexpected calls
-fno-stack-protector # stack protect canary is not available yet.
)
# TODO: factor out crt1 into multiple objects
merge_relocatable_object(
crt1
.${LIBC_TARGET_ARCHITECTURE}.start
.${LIBC_TARGET_ARCHITECTURE}.tls
.do_start
)
add_startup_object(
crti
SRC
crti.cpp
)
add_startup_object(
crtn
SRC
crtn.cpp
)
add_custom_target(libc-startup)
set(startup_components crt1 crti crtn)
foreach(target IN LISTS startup_components)
set(fq_target_name libc.startup.linux.${target})
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>
EXCLUDE_FROM_ALL
COMPONENT libc)
endforeach()
|