aboutsummaryrefslogtreecommitdiff
path: root/libc/startup/linux/CMakeLists.txt
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()