[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