blob: 17e7c3cb9d3e1fab78d85a0cb2b0bf6ea68dd8a7 [file] [log] [blame]
// Copyright 2025 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.
#ifndef LIB_C_ASM_LINKAGE_H_
#define LIB_C_ASM_LINKAGE_H_
// LIBC_ASM_LINKAGE(SymbolName) is used as the linkage name for some
// LIBC_NAMESPACE::SymbolName that needs to be referenced either directly from
// assembly code or across an hermetic partial link boundary (where the build
// logic has to include verbatim linkage symbol names). This is essentially a
// private name-mangling protocol that's trivial enough to be used in assembly
// and build code, unlike the complexity of C++ ABI name mangling.
//
// A function or variable used in assembly as LIBC_ASM_LINKAGE(SymbolName) and
// in build code as "${libc_namespace}_SymbolName" must be declared `extern` by
// some header file, inside `namespace LIBC_NAMESPACE_DECL` by adding the
// clause `LIBC_ASM_LINKAGE_DECLARE(SymbolName)` at the end of the declaration.
// The actual definition might be either in C++ code that includes that header,
// or in assembly code that uses the prefixed name via this macro.
//
// The optional second argument can be a literal prefix for the mangled name.
// This is used for the `__start_` and `__stop_` when the name isn't really a
// symbol but is instead an identifier-compatible section name.
#define LIBC_ASM_LINKAGE(name, ...) LIBC_ASM_LINKAGE_PASTE4(__VA_ARGS__, LIBC_NAMESPACE, _, name)
#define LIBC_ASM_LINKAGE_PASTE4(a, b, c, d) LIBC_ASM_LINKAGE_PASTE4_HELPER(a, b, c, d)
#define LIBC_ASM_LINKAGE_PASTE4_HELPER(a, b, c, d) a##b##c##d
#ifndef __ASSEMBLER__
#include "src/__support/common.h"
// This is used like:
// ```
// namespace LIBC_NAMESPACE_DECL {
// void SomeFunction(T1, T2) LIBC_ASM_LINKAGE_DECLARE(SomeFunction);
// extern int SomeVariable LIBC_ASM_LINKAGE_DECLARE(SomeVariable);
// } // namespace LIBC_NAMESPACE_DECL
// ```
#define LIBC_ASM_LINKAGE_DECLARE(name, ...) \
__asm__(LIBC_ASM_LINKAGE_STRING(name, __VA_ARGS__)) LIBC_ASM_LINKAGE_ATTR
#define LIBC_ASM_LINKAGE_STRING(name, ...) LIBC_MACRO_TO_STRING(LIBC_ASM_LINKAGE(name, __VA_ARGS__))
#ifdef __clang__
// When definitions or references are in assembly or user.basic code, they
// won't have tagged symbol values. This can't use [[...]] syntax when it
// follows __asm__(...).
#define LIBC_ASM_LINKAGE_ATTR __attribute__((no_sanitize("hwaddress")))
#else
#define LIBC_ASM_LINKAGE_ATTR
#endif
#else // clang-format off
// This replaces `.function` for a function defined in LIBC_NAMESPACE_DECL.
.macro .llvm_libc_function name, args:vararg
.function LIBC_ASM_LINKAGE(\name), global, \args
.endm
// This makes a namespaced alias of an `.llvm_libc_function`-defined symbol.
.macro .llvm_libc_alias name, alias, type=function
.label LIBC_ASM_LINKAGE(\alias), global, \type, LIBC_ASM_LINKAGE(\name)
.endm
// This puts an `.llvm_libc_function`-defined symbol into the public libc ABI.
// The optional \public argument can be used for a different public alias name.
.macro .llvm_libc_public name, public=, scope=export, type=function
#if defined(LIBC_COPT_PUBLIC_PACKAGING)
.ifb \public
.label \name, \scope, \type, LIBC_ASM_LINKAGE(\name)
.else
.label \public, \scope, \type, LIBC_ASM_LINKAGE(\name)
.endif
#endif
.endm
#endif // clang-format on
#endif // LIB_C_ASM_LINKAGE_H_