[llvm-branch-commits] [libc] [llvm] [libc][bazel] Add targets for startup objects on linux (PR #218995)
Jackson Stogel via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Thu Aug 27 09:46:07 PDT 2026
https://github.com/jtstogel updated https://github.com/llvm/llvm-project/pull/218995
>From dfedd86473f30ea975a5adb42c68281cbbc852cf Mon Sep 17 00:00:00 2001
From: jtstogel <jtstogel at gmail.com>
Date: Thu, 16 Jul 2026 14:11:45 -0700
Subject: [PATCH] [libc][bazel] Add targets for startup objects
[libc][bazel] more startup object rules
[libc][bazel] Refactor internal_copts for libc_support_library
---
libc/startup/linux/x86_64/tls.cpp | 2 +-
.../llvm-project-overlay/libc/BUILD.bazel | 1 +
.../libc/libc_build_rules.bzl | 43 ++++-
.../libc/startup/BUILD.bazel | 3 +
.../libc/startup/linux/BUILD.bazel | 103 ++++++++++
.../libc/startup/linux/x86_64/BUILD.bazel | 46 +++++
.../libc/startup/startup_rules.bzl | 176 ++++++++++++++++++
7 files changed, 371 insertions(+), 3 deletions(-)
create mode 100644 utils/bazel/llvm-project-overlay/libc/startup/BUILD.bazel
create mode 100644 utils/bazel/llvm-project-overlay/libc/startup/linux/BUILD.bazel
create mode 100644 utils/bazel/llvm-project-overlay/libc/startup/linux/x86_64/BUILD.bazel
create mode 100644 utils/bazel/llvm-project-overlay/libc/startup/startup_rules.bzl
diff --git a/libc/startup/linux/x86_64/tls.cpp b/libc/startup/linux/x86_64/tls.cpp
index 98c5fbeb9d84b..13f6491295fe8 100644
--- a/libc/startup/linux/x86_64/tls.cpp
+++ b/libc/startup/linux/x86_64/tls.cpp
@@ -6,13 +6,13 @@
//
//===----------------------------------------------------------------------===//
+#include "config/app.h"
#include "hdr/sys_mman_macros.h"
#include "src/__support/OSUtil/linux/syscall_wrappers/getrandom.h"
#include "src/__support/OSUtil/linux/syscall_wrappers/mmap.h"
#include "src/__support/OSUtil/linux/syscall_wrappers/munmap.h"
#include "src/__support/macros/config.h"
#include "src/string/memory_utils/inline_memcpy.h"
-#include "startup/linux/do_start.h"
#include <asm/prctl.h>
#include <sys/syscall.h>
diff --git a/utils/bazel/llvm-project-overlay/libc/BUILD.bazel b/utils/bazel/llvm-project-overlay/libc/BUILD.bazel
index c545d6bbde68d..1119735ad0243 100644
--- a/utils/bazel/llvm-project-overlay/libc/BUILD.bazel
+++ b/utils/bazel/llvm-project-overlay/libc/BUILD.bazel
@@ -4300,6 +4300,7 @@ libc_support_library(
],
"//conditions:default": [],
}),
+ copt_sets = ["threading"],
deps = [
":__support_common",
":__support_cpp_array",
diff --git a/utils/bazel/llvm-project-overlay/libc/libc_build_rules.bzl b/utils/bazel/llvm-project-overlay/libc/libc_build_rules.bzl
index a8021776c1bc6..8ae46c8b9adca 100644
--- a/utils/bazel/llvm-project-overlay/libc/libc_build_rules.bzl
+++ b/utils/bazel/llvm-project-overlay/libc/libc_build_rules.bzl
@@ -75,21 +75,46 @@ def libc_release_copts():
})
return copts + platform_copts
-def _libc_library(name, deps = [], **kwargs):
+# Adding copts here is discouraged, as it complicates the build.
+# The only use cases for per-TU copts are currently startup objects and threads.
+_LIBC_LIBRARY_COPT_SETS = {
+ "startup_object": [
+ "-ffreestanding",
+ "-fno-builtin",
+ "-fno-omit-frame-pointer",
+ "-fno-stack-protector",
+ ],
+ "threading": [
+ "-fno-omit-frame-pointer",
+ "-Wno-frame-address",
+ ],
+}
+
+def _libc_library(
+ name,
+ deps = [],
+ copt_sets = [],
+ **kwargs):
"""Internal macro to serve as a base for all other libc library rules.
Args:
name: Target name.
deps: cc_library deps.
+ copt_sets: Which sets of allow-listed copts to include.
**kwargs: All other attributes relevant for the cc_library rule.
"""
for attr in ["copts", "local_defines"]:
if attr in kwargs:
fail("disallowed attribute: '{}' in rule: '{}'".format(attr, name))
+
+ copts = []
+ for feature in copt_sets:
+ copts.extend(_LIBC_LIBRARY_COPT_SETS[feature])
+
cc_library(
name = name,
- copts = libc_common_copts(),
+ copts = libc_common_copts() + copts,
local_defines = LIBC_CONFIGURE_OPTIONS,
deps = deps + libc_common_deps(),
linkstatic = 1,
@@ -102,6 +127,20 @@ def _libc_library(name, deps = [], **kwargs):
def libc_support_library(name, **kwargs):
_libc_library(name = name, **kwargs)
+def libc_startup_library(name, **kwargs):
+ """Add target for a libc startup library.
+
+ Args:
+ name: Target name.
+ **kwargs: Other attributes relevant for a cc_library.
+ """
+
+ _libc_library(
+ name = name,
+ copt_sets = ["startup_object"],
+ **kwargs
+ )
+
def libc_function(name, **kwargs):
"""Add target for a libc function.
diff --git a/utils/bazel/llvm-project-overlay/libc/startup/BUILD.bazel b/utils/bazel/llvm-project-overlay/libc/startup/BUILD.bazel
new file mode 100644
index 0000000000000..3b65f08ee74a1
--- /dev/null
+++ b/utils/bazel/llvm-project-overlay/libc/startup/BUILD.bazel
@@ -0,0 +1,3 @@
+# This file is licensed 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
diff --git a/utils/bazel/llvm-project-overlay/libc/startup/linux/BUILD.bazel b/utils/bazel/llvm-project-overlay/libc/startup/linux/BUILD.bazel
new file mode 100644
index 0000000000000..a141dd8452dcf
--- /dev/null
+++ b/utils/bazel/llvm-project-overlay/libc/startup/linux/BUILD.bazel
@@ -0,0 +1,103 @@
+# This file is licensed 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
+
+load("//libc:libc_build_rules.bzl", "libc_startup_library", "libc_support_library")
+load("//libc:platforms.bzl", "PLATFORM_CPU_X86_64")
+load("//libc/startup:startup_rules.bzl", "libc_startup_object", "merge_relocatable_object")
+
+package(
+ default_visibility = ["//visibility:public"],
+)
+
+libc_support_library(
+ name = "gnu_property_section",
+ srcs = ["gnu_property_section.cpp"],
+ hdrs = ["gnu_property_section.h"],
+ deps = [
+ "//libc:__support_cpp_string_view",
+ "//libc:__support_macros_attributes",
+ "//libc:__support_macros_config",
+ "//libc:hdr_elf_proxy",
+ "//libc:hdr_link_macros",
+ "//libc:string_memory_utils",
+ ],
+)
+
+libc_support_library(
+ name = "irelative_hdr",
+ hdrs = ["irelative.h"],
+ deps = [
+ "//libc:__support_macros_config",
+ "//libc:hdr_link_macros",
+ "//libc:hdr_stdint_proxy",
+ ],
+)
+
+libc_startup_library(
+ name = "do_start",
+ srcs = ["do_start.cpp"],
+ hdrs = [
+ "do_start.h",
+ ],
+ target_compatible_with = select({
+ "@platforms//os:linux": [],
+ "//conditions:default": ["@platforms//:incompatible"],
+ }),
+ deps = [
+ ":gnu_property_section",
+ ":irelative_hdr",
+ "//libc:__support_macros_config",
+ "//libc:__support_osutil_linux_auxv",
+ "//libc:__support_osutil_syscall",
+ "//libc:__support_threads_thread",
+ "//libc:__support_threads_thread_headers",
+ "//libc:_r_debug",
+ "//libc:atexit",
+ "//libc:config_app_h",
+ "//libc:config_linux_app_h",
+ "//libc:environ",
+ "//libc:exit",
+ "//libc:hdr_elf_proxy",
+ "//libc:hdr_link_macros",
+ "//libc:hdr_pthread_macros",
+ "//libc:hdr_stdint_proxy",
+ "//libc:hdr_sys_auxv_macros",
+ "//libc:hdr_sys_mman_macros",
+ "//libc:hdr_types_struct_link_map",
+ "//libc:hdr_types_struct_r_debug",
+ "//libc:program_invocation_name",
+ "//libc:program_invocation_short_name",
+ ] + select({
+ PLATFORM_CPU_X86_64: [
+ "//libc/startup/linux/x86_64:irelative",
+ "//libc/startup/linux/x86_64:tls",
+ ],
+ "//conditions:default": [],
+ }),
+)
+
+merge_relocatable_object(
+ name = "crt1",
+ deps = [
+ ":do_start",
+ ":gnu_property_section",
+ ] + select({
+ PLATFORM_CPU_X86_64: [
+ "//libc/startup/linux/x86_64:irelative",
+ "//libc/startup/linux/x86_64:start",
+ "//libc/startup/linux/x86_64:tls",
+ ],
+ "//conditions:default": [],
+ }),
+)
+
+libc_startup_object(
+ name = "crti",
+ src = "crti.cpp",
+)
+
+libc_startup_object(
+ name = "crtn",
+ src = "crtn.cpp",
+)
diff --git a/utils/bazel/llvm-project-overlay/libc/startup/linux/x86_64/BUILD.bazel b/utils/bazel/llvm-project-overlay/libc/startup/linux/x86_64/BUILD.bazel
new file mode 100644
index 0000000000000..b9936609522b9
--- /dev/null
+++ b/utils/bazel/llvm-project-overlay/libc/startup/linux/x86_64/BUILD.bazel
@@ -0,0 +1,46 @@
+# This file is licensed 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
+
+load("//libc:libc_build_rules.bzl", "libc_startup_library")
+
+package(
+ default_visibility = ["//visibility:public"],
+)
+
+libc_startup_library(
+ name = "tls",
+ srcs = ["tls.cpp"],
+ deps = [
+ "//libc:__support_macros_config",
+ "//libc:__support_osutil_linux_syscall_wrappers_getrandom",
+ "//libc:__support_osutil_linux_syscall_wrappers_mmap",
+ "//libc:__support_osutil_linux_syscall_wrappers_munmap",
+ "//libc:config_app_h",
+ "//libc:hdr_sys_mman_macros",
+ "//libc:string_memory_utils",
+ ],
+)
+
+libc_startup_library(
+ name = "start",
+ srcs = ["start.cpp"],
+ deps = [
+ "//libc:__support_macros_attributes",
+ "//libc:config_app_h",
+ "//libc/startup/linux:do_start",
+ ],
+)
+
+libc_startup_library(
+ name = "irelative",
+ srcs = ["irelative.cpp"],
+ deps = [
+ "//libc:__support_macros_config",
+ "//libc:hdr_elf_macros",
+ "//libc:hdr_elf_proxy",
+ "//libc:hdr_link_macros",
+ "//libc:hdr_stdint_proxy",
+ "//libc/startup/linux:irelative_hdr",
+ ],
+)
diff --git a/utils/bazel/llvm-project-overlay/libc/startup/startup_rules.bzl b/utils/bazel/llvm-project-overlay/libc/startup/startup_rules.bzl
new file mode 100644
index 0000000000000..db518e1ffddb7
--- /dev/null
+++ b/utils/bazel/llvm-project-overlay/libc/startup/startup_rules.bzl
@@ -0,0 +1,176 @@
+# This file is licensed 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
+
+"""LLVM libc starlark rules for building startup objects."""
+
+load("@bazel_skylib//lib:paths.bzl", "paths")
+load("@rules_cc//cc:action_names.bzl", "ACTION_NAMES")
+load("@rules_cc//cc:find_cc_toolchain.bzl", "find_cc_toolchain", "use_cc_toolchain")
+load("@rules_cc//cc/common:cc_common.bzl", "cc_common")
+load("@rules_cc//cc/common:cc_info.bzl", "CcInfo")
+load("//libc:libc_build_rules.bzl", "libc_startup_library")
+
+def _get_compilation_outputs(deps):
+ outputs = []
+ for dep in deps:
+ if OutputGroupInfo in dep and "compilation_outputs" in dep[OutputGroupInfo]:
+ outputs.extend(dep[OutputGroupInfo].compilation_outputs.to_list())
+ return outputs
+
+def _extract_object_file_impl(ctx):
+ output = ctx.actions.declare_file(ctx.label.name + ".o")
+ input_objs = _get_compilation_outputs([ctx.attr.dep])
+ if len(input_objs) != 1:
+ fail("Expected exactly one input object, got: {}".format(input_objs))
+
+ input_obj = input_objs[0]
+
+ ctx.actions.symlink(
+ output = output,
+ target_file = input_obj,
+ )
+
+ return [DefaultInfo(files = depset([output]))]
+
+_extract_object_file = rule(
+ implementation = _extract_object_file_impl,
+ attrs = {
+ "dep": attr.label(
+ mandatory = True,
+ providers = [CcInfo],
+ ),
+ },
+)
+
+def libc_startup_object(name, src, visibility = None, **kwargs):
+ """Compiles a C++ source file into a startup object file.
+
+ Args:
+ name: The name of the target.
+ src: The C++ source file to compile.
+ visibility: Visibility of targets created by this macro.
+ **kwargs: Other arguments to
+ """
+ library_name = name + "_lib"
+ libc_startup_library(
+ name = library_name,
+ srcs = [src],
+ visibility = visibility,
+ **kwargs
+ )
+ _extract_object_file(
+ name = name,
+ dep = ":" + library_name,
+ visibility = visibility,
+ )
+
+def _filter_flags(
+ flags,
+ separate_flag_names,
+ joined_flag_prefixes):
+ """Filters flags to those in joined_flag_prefixes or separate_flag_names.
+
+ Args:
+ flags: The flags to filter.
+ separate_flag_names: Names of flags whose value is specified separately
+ from the flag (for example "--target value").
+ joined_flag_prefixes: Prefixes of flags whose value is joined to the
+ flag name (for example, --target=value).
+ """
+ filtered_flags = []
+ skip_next = False
+ for i, flag in enumerate(flags):
+ if skip_next:
+ skip_next = False
+ continue
+
+ if flag in separate_flag_names:
+ if i + 1 < len(flags):
+ filtered_flags.append(flag)
+ filtered_flags.append(flags[i + 1])
+ skip_next = True
+ continue
+
+ for prefix in joined_flag_prefixes:
+ if flag.startswith(prefix):
+ filtered_flags.append(flag)
+ continue
+
+ return filtered_flags
+
+def _merge_relocatable_object_impl(ctx):
+ cc_toolchain = find_cc_toolchain(ctx)
+ output = ctx.actions.declare_file(ctx.label.name + ".o")
+
+ input_objs = _get_compilation_outputs(ctx.attr.deps)
+
+ feature_configuration = cc_common.configure_features(
+ ctx = ctx,
+ cc_toolchain = cc_toolchain,
+ requested_features = ctx.features,
+ unsupported_features = ctx.disabled_features,
+ )
+ link_variables = cc_common.create_link_variables(
+ cc_toolchain = cc_toolchain,
+ feature_configuration = feature_configuration,
+ is_linking_dynamic_library = False,
+ )
+ link_flags = cc_common.get_memory_inefficient_command_line(
+ feature_configuration = feature_configuration,
+ action_name = ACTION_NAMES.cpp_link_executable,
+ variables = link_variables,
+ )
+ linker = cc_common.get_tool_for_action(
+ feature_configuration = feature_configuration,
+ action_name = ACTION_NAMES.cpp_link_executable,
+ )
+ relocatable_link_flags = _filter_flags(
+ link_flags,
+ ("-target", "--target", "--sysroot", "-isysroot"),
+ ("-fuse-ld=", "-m", "--target=", "--sysroot="),
+ )
+
+ args = ctx.actions.args()
+ args.add_all(relocatable_link_flags)
+
+ bindir = paths.dirname(linker)
+ if bindir:
+ args.add("-B" + bindir)
+
+ args.add("-r")
+ args.add("-nostdlib")
+ args.add("-o", output)
+ args.add_all(input_objs)
+
+ ctx.actions.run(
+ outputs = [output],
+ inputs = depset(
+ input_objs,
+ transitive = [cc_toolchain.all_files],
+ ),
+ executable = linker,
+ arguments = [args],
+ mnemonic = "MergeRelocatableObject",
+ use_default_shell_env = True,
+ )
+
+ return [DefaultInfo(files = depset([output]))]
+
+merge_relocatable_object = rule(
+ implementation = _merge_relocatable_object_impl,
+ doc = """Merges multiple object files into a single relocatable object file.
+
+ This rule mimics CMake's `merge_relocatable_object`,
+ running the toolchain's linker driver `-r -nostdlib` on all direct deps.
+ """,
+ attrs = {
+ "deps": attr.label_list(
+ mandatory = True,
+ providers = [CcInfo],
+ doc = "The list of cc targets whose object files should be merged.",
+ ),
+ },
+ toolchains = use_cc_toolchain(),
+ fragments = ["cpp"],
+)
More information about the llvm-branch-commits
mailing list