blob: 7b553b9a4dff574608442df2463911df2eb1471c [file] [log] [blame]
# Copyright 2023 The Fuchsia Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import("//build/cpp/library_headers.gni")
import("//build/cpp/verify_public_symbols.gni")
import("//build/toolchain/ifs_extract.gni")
import("//build/toolchain/ifs_shared_library.gni")
import("//build/toolchain/toolchain_environment.gni")
import("//build/toolchain/zircon/user_basic_redirect.gni")
# This provides access to additional <lib/ld/...> headers for support code in
# the `ld` namespace, which isn't itself part of of the passive ABI.
library_headers("headers") {
headers = [
"lib/ld/decoded-module-in-memory.h",
"lib/ld/decoded-module.h",
"lib/ld/diagnostics.h",
"lib/ld/load-module.h",
"lib/ld/load.h",
"lib/ld/memory.h",
"lib/ld/tlsdesc.h",
]
public_deps = [
":abi-headers",
"//sdk/lib/fit",
"//src/lib/symbolizer-markup",
"//zircon/kernel/lib/arch:headers",
]
if (is_fuchsia) {
headers += [
"lib/ld/remote-abi-heap.h",
"lib/ld/remote-abi-stub.h",
"lib/ld/remote-abi-transcriber.h",
"lib/ld/remote-abi.h",
"lib/ld/remote-decoded-module.h",
"lib/ld/remote-dynamic-linker.h",
"lib/ld/remote-load-module.h",
]
public_deps += [
# <lib/ld/remote-decoded-module.h> has `#include <fbl/ref_ptr.h>`.
"//zircon/system/ulib/fbl",
]
# Make sure that there's no transitive deps on libzircon, so header-only
# use of the library doesn't affect dynamic linking dependencies.
if (zircon_toolchain == false) {
_headers = ""
} else {
_headers = ":headers"
}
public_deps += [
"//src/zircon/lib/zircon:headers",
"//zircon/system/ulib/zx$_headers",
]
}
}
# This is the linkable target for using the passive ABI.
# It gives access to the passive ABI dynamic linkage symbols
# and to the header files declaring the `ld::abi` namespace.
ifs_shared_library("ld") {
abi = "ld.ifs"
public_deps = [ ":abi-headers" ]
}
# This provides access to the <lib/ld/...> headers that specify the passive ABI
# defined in the `ld::abi` C++ namespace.
library_headers("abi-headers") {
headers = [
"lib/ld/abi.h",
"lib/ld/module.h",
"lib/ld/tls.h",
]
public_deps = [
"//sdk/lib/stdcompat",
"//src/lib/elfldltl:headers",
]
}
# This is the SONAME reflecting the passive ABI defined here.
# It has to match what's in ld.ifs and in ld::abi::kSoname (<lib/ld/abi.h>).
abi_soname = "ld.so.1"
config("abi-soname") {
ldflags = [ "-Wl,-soname=$abi_soname" ]
}
config("abi-interp") {
ldflags = [ "-Wl,-dynamic-linker=${toolchain_variant.libprefix}$abi_soname" ]
}
# This provides the __tls_get_addr ABI symbol used by TLS GD accesses when
# TLSDESC is not in use. This implementation uses the passive ABI to resolve
# references in the initial exec set's static TLS layout. A different
# implementation would be required to also support post-startup modules.
source_set("static-tls-get-addr") {
sources = [ "static-tls-get-addr.cc" ]
deps = [ "." ]
}
# `verify_ld_abi(ld) {}` defines "$ld.verify-abi" to check that the
# shared_library(ld) or loadable_module(ld) matches the passive ABI.
template("verify_ld_abi") {
ld_target = target_name
verify_target = "$ld_target.verify-abi"
extract_target = "$ld_target.ifs"
ifs_file = "$target_out_dir/$extract_target"
if (defined(invoker.variant_target)) {
# Do variant selection as if for the ld_target, approximately.
variant_selection_target = verify_target
verify_target += ".variant"
variant_target("group") {
visibility = [ "./*" ]
variant_selector_target_type = invoker.variant_target
target_name = variant_selection_target
variant_shared_redirection = true
data_deps = [ ":$verify_target" ]
}
}
ifs_extract(extract_target) {
visibility = [ ":*" ]
forward_variables_from(invoker, [ "testonly" ])
outputs = [ ifs_file ]
deps = [ ":$ld_target" ]
}
verify_public_symbols(verify_target) {
visibility = [ "./*" ]
forward_variables_from(invoker, [ "testonly" ])
deps = [ ":$extract_target" ]
current = ifs_file
reference = "ld.ifs"
library_name = get_label_info(":$ld_target", "label_with_toolchain")
}
}
# There's no real difference between a shared library and a loadable module
# with a SONAME, but loadable_module() does its own variant selection. Since
# the stub ld.so is really just a data ABI image, there's no meaningful sense
# in which it could be in the same variant as its users.
loadable_module("ld-stub") {
configs += [
"//build/config/fuchsia:no_cpp_standard_library",
"//build/config/zircon:nolibc",
":abi-soname",
]
deps = [
":abi",
":tlsdesc.no-gc",
]
# Since it has no C++ code (only a data definition), it doesn't really matter
# for this to use the user.basic build environment as the startup dynamic
# linker must. But we don't want it to have any instrumentation hair that
# might be generated even with no C++ functions.
exclude_toolchain_tags = [ "instrumented" ]
}
# This redirects to the user.basic toolchain where ld-stub.so should be built.
# It only serves to get it built and reached via data_deps so it will be
# included in a package.
user_basic_redirect("ld-stub.basic") {
public_deps = [ ":ld-stub.verify-abi" ]
}
verify_ld_abi("ld-stub") {
variant_target = "loadable_module"
}
source_set("abi") {
visibility = [ ":*" ]
public = [ "mutable-abi.h" ]
sources = [ "mutable-abi.cc" ]
deps = [ ":headers" ]
}
source_set("bootstrap") {
visibility = [ ":*" ]
public = [ "bootstrap.h" ]
public_deps = [
":headers",
"//src/lib/elfldltl",
# TODO(https://fxbug.dev/42080826): This gets users of bootstrap.h the config that
# plumbs the HAVE_LLVM_PROFDATA predefine used there.
"//src/lib/llvm-profdata",
]
}
# This is a proper archive library of the bits from libc and the stubs that can
# be used in the standalone implementation. Having the source_set() targets as
# direct or transitive deps not via a `complete_static_lib=true` archive would
# eagerly link unused code into the standalone binary and rely on linker GC to
# remove it, which is suboptimal.
static_library("standalone") {
visibility = [ "./*" ]
complete_static_lib = true
sources = [ "standalone-assert.cc" ]
deps = [
"//zircon/system/public",
"//zircon/system/ulib/c/stdlib:hermetic",
"//zircon/system/ulib/c/string:hermetic",
]
if (is_linux) {
deps += [ ":linux-syscalls" ]
}
public_configs = [ ":standalone.config" ]
}
config("standalone.config") {
visibility = [ "./*" ]
ldflags = []
if (toolchain_environment != "user.basic") {
# The user.basic environment doesn't have implicit dependencies or libc.
# Other environments like host need the compiler driver's defaults disabled
# to build something that doesn't use the system libc.
ldflags += [
"-nostartfiles",
"-nolibc",
]
}
if (!is_gcc) {
# The standard profiling runtime can't be used in the minimal standalone
# context of ld.so.
#
# TODO(https://fxbug.dev/42080826): The instrumentation works fine to collect data,
# but the data needs to be plumbed out somewhere using a custom
# runtime. For now, the data is just ignored.
ldflags += [ "-noprofilelib" ]
}
}
source_set("posix-header") {
public = [ "posix.h" ]
public_deps = [
":startup-load",
"//src/lib/elfldltl",
]
}
source_set("zircon") {
public = [ "zircon.h" ]
public_deps = [
":startup-diagnostics",
":startup-load",
"//sdk/lib/stdcompat",
"//src/lib/elfldltl",
]
sources = [
"ldsvc.cc",
"procargs.cc",
]
deps = [
"//zircon/system/ulib/ldmsg",
"//zircon/system/ulib/processargs",
"//zircon/system/ulib/zircon-internal",
]
# TODO(https://fxbug.dev/42085293): delete the below and fix compiler warnings
configs += [ "//build/config:Wno-vla-cxx-extension" ]
}
source_set("startup-load") {
public = [ "startup-load.h" ]
public_deps = [
":abi",
":allocator",
":bootstrap",
":headers",
":startup-diagnostics",
"//src/lib/elfldltl",
"//zircon/system/ulib/fbl",
]
}
shared_library("ld-startup") {
configs += [ ":abi-soname" ]
sources = []
deps = [
":standalone",
":startup-load",
":tlsdesc",
]
if (is_fuchsia) {
sources += [
"zircon-startup.S",
"zircon-startup.cc",
]
deps += [
":zircon",
":zircon-diagnostics",
"//sdk/lib/stdcompat",
"//src/lib/llvm-profdata",
"//src/zircon/lib/zircon",
"//zircon/kernel/lib/arch",
"//zircon/system/ulib/zx",
]
} else {
sources += [
"posix-startup.S",
"posix-startup.cc",
]
deps += [
":posix-diagnostics",
":posix-header",
"//zircon/kernel/lib/arch:headers",
]
# There is no way to get the data out anyway.
configs += [ "//build/config:no_profile" ]
}
output_path = "$root_out_dir/lib$target_name.so"
metadata = {
distribution_entries = [
{
destination = "lib/${toolchain_variant.libprefix}$abi_soname"
source = rebase_path(output_path, root_build_dir)
label = get_label_info(target_name, "label_with_toolchain")
},
]
# This is collected by test:ld-test-switches.rsp. The user_basic_redirect
# may wind up in a different variant than the one requested, if the test's
# variant isn't available in user.basic, so we don't know statically which
# libprefix the test should load from.
ld_test_switches =
[ "'-DLD_TEST_LIBPREFIX=\"${toolchain_variant.libprefix}\"'" ]
}
}
source_set("startup-diagnostics") {
visibility = [ ":*" ]
public = [ "startup-diagnostics.h" ]
public_deps = [
":headers",
"//src/lib/elfldltl",
]
sources = [ "startup-diagnostics.cc" ]
}
source_set("posix-diagnostics") {
visibility = [ ":*" ]
sources = [ "posix-diagnostics.cc" ]
deps = [
":posix-header",
":startup-diagnostics",
"//zircon/system/ulib/c/stdio:snprintf",
"//zircon/system/ulib/c/stdio/printf_core:wrapper",
]
}
source_set("zircon-diagnostics") {
visibility = [ ":*" ]
sources = [ "zircon-diagnostics.cc" ]
deps = [
":startup-diagnostics",
":zircon",
"//src/lib/symbolizer-markup",
"//zircon/system/ulib/c/stdio/printf_core:wrapper",
"//zircon/system/ulib/zx",
]
}
source_set("allocator") {
visibility = [ ":*" ]
public = [ "allocator.h" ]
public_deps = [
":startup-diagnostics",
"//src/lib/trivial-allocator",
]
deps = [ "//src/lib/trivial-allocator:stub-delete" ]
}
source_set("linux-syscalls") {
visibility = [ ":*" ]
sources = [ "linux-syscalls.cc" ]
include_dirs = [ "//third_party/linux-syscall-support/src" ]
}
# The TLSDESC runtime assembly code is provided in library form as needed for
# use by an in-process dynamic linker (ld-startup and libdl). The stub dynamic
# linker includes this code but with neither references nor exported symbols,
# so it needs a mandatory-linked version of the code that's immune to GC.
template("_tlsdesc_runtime") {
target(invoker.target_type, target_name) {
public_deps = [
":headers",
"//zircon/kernel/lib/arch",
]
sources = [
"tlsdesc-runtime-static.S",
"tlsdesc-runtime-undefined-weak.S",
]
defines = [ "TLSDESC_RETAIN=${invoker.retain}" ]
}
}
_tlsdesc_runtime("tlsdesc") {
target_type = "static_library"
retain = ""
}
_tlsdesc_runtime("tlsdesc.no-gc") {
target_type = "source_set"
retain = "R"
}
user_basic_redirect("ld-startup.basic") {
public_deps = [ ":ld-startup" ]
}
# This is reached from test:ld-startup.test-data, where it will be instantiated
# in each environment and variant for which any tests are built.
verify_ld_abi("ld-startup") {
}
group("tests") {
testonly = true
deps = [
":ld-stub.basic", # This just gets it built and its ABI verified.
"test:tests",
]
}