Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 18 additions & 2 deletions .github/workflows/_bazel.yml
Original file line number Diff line number Diff line change
Expand Up @@ -131,16 +131,24 @@ jobs:
run: |
exec bazel test ${{ inputs.bazel-args }} \
--platforms=@toolchains_llvm//platforms:linux-aarch64 \
//compile/test:cross_compile_aarch64_compiler_rt_test \
//compile/test:cross_compile_aarch64_test \
//compile/test:cross_compile_aarch64_unwind_test
working-directory: ${{ inputs.bazel-path }}
- name: Cross-compile test (x86_64 -> aarch64/${{ inputs.bazel-mode }})
- name: Cross-compile test libunwind (x86_64 -> aarch64/${{ inputs.bazel-mode }})
run: |
exec bazel test ${{ inputs.bazel-args }} \
--platforms=@toolchains_llvm//platforms:linux-aarch64 \
--@toolchains_llvm//toolchain/config:libunwind=False \
//compile/test:cross_compile_aarch64_no_unwind_test
working-directory: ${{ inputs.bazel-path }}
- name: Cross-compile test compiler-rt (x86_64 -> aarch64/${{ inputs.bazel-mode }})
run: |
exec bazel test ${{ inputs.bazel-args }} \
--platforms=@toolchains_llvm//platforms:linux-aarch64 \
--@toolchains_llvm//toolchain/config:compiler-rt=False \
//compile/test:cross_compile_aarch64_no_compiler_rt_test
working-directory: ${{ inputs.bazel-path }}

xcompile-arm-to-x86:
if: inputs.action == 'test'
Expand All @@ -164,13 +172,21 @@ jobs:
run: |
exec bazel test ${{ inputs.bazel-args }} \
--platforms=@toolchains_llvm//platforms:linux-x86_64 \
//compile/test:cross_compile_x86_64_compiler_rt_test \
//compile/test:cross_compile_x86_64_test \
//compile/test:cross_compile_x86_64_unwind_test
working-directory: ${{ inputs.bazel-path }}
- name: Cross-compile test (x86_64 -> x86_64/${{ inputs.bazel-mode }})
- name: Cross-compile test libunwind (aarch64 -> x86_64/${{ inputs.bazel-mode }})
run: |
exec bazel test ${{ inputs.bazel-args }} \
--platforms=@toolchains_llvm//platforms:linux-x86_64 \
--@toolchains_llvm//toolchain/config:libunwind=False \
//compile/test:cross_compile_x86_64_no_unwind_test
working-directory: ${{ inputs.bazel-path }}
- name: Cross-compile test compiler-rt (aarch64 -> x86_64/${{ inputs.bazel-mode }})
run: |
exec bazel test ${{ inputs.bazel-args }} \
--platforms=@toolchains_llvm//platforms:linux-x86_64 \
--@toolchains_llvm//toolchain/config:compiler-rt=False \
//compile/test:cross_compile_x86_64_no_compiler_rt_test
working-directory: ${{ inputs.bazel-path }}
33 changes: 33 additions & 0 deletions bazel/compile/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -201,3 +201,36 @@ bazel test //compile/test:cross_compile_x86_64_no_unwind_test \
--platforms=@toolchains_llvm//platforms:linux-x86_64 \
--@toolchains_llvm//toolchain/config:libunwind=False
```

### Compiler-rt tests

The compiler-rt tests verify that `libclang_rt.builtins.a` (compiler-rt) is **statically
linked** into the `test_compiler_rt` binary. They use `llvm-nm` to check for a defined
`__divti3` symbol (a 128-bit integer division function that is provided by compiler-rt
builtins and referenced by `__int128` division) and `llvm-readelf` to confirm there is no
`libgcc_s` dynamic dependency.

```bash
# Test aarch64 cross-compilation with compiler-rt statically linked
bazel test //compile/test:cross_compile_aarch64_compiler_rt_test \
--platforms=@toolchains_llvm//platforms:linux-aarch64

# Test x86_64 cross-compilation with compiler-rt statically linked
bazel test //compile/test:cross_compile_x86_64_compiler_rt_test \
--platforms=@toolchains_llvm//platforms:linux-x86_64
```

**Negative compiler-rt tests** verify that compiler-rt builtins are *not* statically
linked when `--@toolchains_llvm//toolchain/config:compiler-rt=False` is passed:

```bash
# Verify compiler-rt is NOT linked for aarch64 when disabled
bazel test //compile/test:cross_compile_aarch64_no_compiler_rt_test \
--platforms=@toolchains_llvm//platforms:linux-aarch64 \
--@toolchains_llvm//toolchain/config:compiler-rt=False

# Verify compiler-rt is NOT linked for x86_64 when disabled
bazel test //compile/test:cross_compile_x86_64_no_compiler_rt_test \
--platforms=@toolchains_llvm//platforms:linux-x86_64 \
--@toolchains_llvm//toolchain/config:compiler-rt=False
```
108 changes: 108 additions & 0 deletions bazel/compile/test/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -157,3 +157,111 @@ sh_test(
},
tags = ["manual"],
)

# C++ compiler-rt builtins binary — exercises __int128 division to reference
# the __divti3 symbol provided by libclang_rt.builtins.a (compiler-rt).
# Build for aarch64:
# bazel build //compile/test:test_compiler_rt --platforms=@toolchains_llvm//platforms:linux-aarch64
# Build for x86_64:
# bazel build //compile/test:test_compiler_rt --platforms=@toolchains_llvm//platforms:linux-x86_64
cc_binary(
name = "test_compiler_rt",
srcs = ["test_compiler_rt.cc"],
copts = ["-Werror"],
)

# Cross-compilation compiler-rt tests.
# These tests verify that the test_compiler_rt binary has libclang_rt.builtins.a
# statically linked by checking for the defined __divti3 symbol (via llvm-nm)
# and the absence of libgcc_s in dynamic NEEDED entries (via llvm-readelf).
#
# Run with:
# bazel test //compile/test:cross_compile_aarch64_compiler_rt_test \
# --platforms=@toolchains_llvm//platforms:linux-aarch64
sh_test(
name = "cross_compile_aarch64_compiler_rt_test",
size = "small",
srcs = ["check_compiler_rt.sh"],
data = [
":test_compiler_rt",
"@llvm_toolchain_llvm//:nm",
"@llvm_toolchain_llvm//:readelf",
],
env = {
"BINARY": "$(rootpath :test_compiler_rt)",
"EXPECT_COMPILER_RT": "true",
"EXPECTED_ARCH": "AArch64",
"LLVM_NM": "$(rootpath @llvm_toolchain_llvm//:nm)",
"LLVM_READELF": "$(rootpath @llvm_toolchain_llvm//:readelf)",
},
tags = ["manual"],
)

# Run with:
# bazel test //compile/test:cross_compile_x86_64_compiler_rt_test \
# --platforms=@toolchains_llvm//platforms:linux-x86_64
sh_test(
name = "cross_compile_x86_64_compiler_rt_test",
size = "small",
srcs = ["check_compiler_rt.sh"],
data = [
":test_compiler_rt",
"@llvm_toolchain_llvm//:nm",
"@llvm_toolchain_llvm//:readelf",
],
env = {
"BINARY": "$(rootpath :test_compiler_rt)",
"EXPECT_COMPILER_RT": "true",
"EXPECTED_ARCH": "X86-64",
"LLVM_NM": "$(rootpath @llvm_toolchain_llvm//:nm)",
"LLVM_READELF": "$(rootpath @llvm_toolchain_llvm//:readelf)",
},
tags = ["manual"],
)

# Negative compiler-rt tests — verify that compiler-rt builtins are NOT
# statically linked when the flag is disabled. Run with:
# bazel test //compile/test:cross_compile_aarch64_no_compiler_rt_test \
# --platforms=@toolchains_llvm//platforms:linux-aarch64 \
# --@toolchains_llvm//toolchain/config:compiler-rt=False
sh_test(
name = "cross_compile_aarch64_no_compiler_rt_test",
size = "small",
srcs = ["check_compiler_rt.sh"],
data = [
":test_compiler_rt",
"@llvm_toolchain_llvm//:nm",
"@llvm_toolchain_llvm//:readelf",
],
env = {
"BINARY": "$(rootpath :test_compiler_rt)",
"EXPECT_COMPILER_RT": "false",
"EXPECTED_ARCH": "AArch64",
"LLVM_NM": "$(rootpath @llvm_toolchain_llvm//:nm)",
"LLVM_READELF": "$(rootpath @llvm_toolchain_llvm//:readelf)",
},
tags = ["manual"],
)

# Run with:
# bazel test //compile/test:cross_compile_x86_64_no_compiler_rt_test \
# --platforms=@toolchains_llvm//platforms:linux-x86_64 \
# --@toolchains_llvm//toolchain/config:compiler-rt=False
sh_test(
name = "cross_compile_x86_64_no_compiler_rt_test",
size = "small",
srcs = ["check_compiler_rt.sh"],
data = [
":test_compiler_rt",
"@llvm_toolchain_llvm//:nm",
"@llvm_toolchain_llvm//:readelf",
],
env = {
"BINARY": "$(rootpath :test_compiler_rt)",
"EXPECT_COMPILER_RT": "false",
"EXPECTED_ARCH": "X86-64",
"LLVM_NM": "$(rootpath @llvm_toolchain_llvm//:nm)",
"LLVM_READELF": "$(rootpath @llvm_toolchain_llvm//:readelf)",
},
tags = ["manual"],
)
73 changes: 73 additions & 0 deletions bazel/compile/test/check_compiler_rt.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
#!/bin/bash
# Checks that a cross-compiled binary has (or does not have) compiler-rt builtins statically linked.
#
# Required environment variables:
# BINARY - path to the compiled binary
# EXPECTED_ARCH - expected ELF architecture (e.g. AArch64, X86-64)
# EXPECT_COMPILER_RT - "true" if libclang_rt.builtins.a should be statically linked, "false" otherwise
# LLVM_NM - path to llvm-nm binary
# LLVM_READELF - path to llvm-readelf binary
set -euo pipefail

: "${BINARY:?BINARY must be set to the path of the compiled binary}"
: "${EXPECTED_ARCH:?EXPECTED_ARCH must be set to the expected architecture (e.g. AArch64, X86-64)}"
: "${EXPECT_COMPILER_RT:?EXPECT_COMPILER_RT must be set to 'true' or 'false'}"
: "${LLVM_NM:?LLVM_NM must be set to the path of llvm-nm}"
: "${LLVM_READELF:?LLVM_READELF must be set to the path of llvm-readelf}"

# Check architecture using llvm-readelf -h
READELF_OUTPUT="$("${LLVM_READELF}" -h "${BINARY}")"
echo "llvm-readelf -h output:"
echo "${READELF_OUTPUT}"

if echo "${READELF_OUTPUT}" | grep -q "${EXPECTED_ARCH}"; then
echo "PASS: binary is ${EXPECTED_ARCH}"
else
echo "FAIL: expected ${EXPECTED_ARCH} in readelf output"
exit 1
fi

# Check for __divti3 defined (T/t) symbol via llvm-nm.
# __divti3 is the 128-bit signed integer division function provided by
# compiler-rt builtins (libclang_rt.builtins.a). Its presence as a defined
# symbol proves that compiler-rt was statically linked.
NM_OUTPUT="$("${LLVM_NM}" "${BINARY}")"
echo "llvm-nm output (filtered):"
echo "${NM_OUTPUT}" | grep -i "__divti3" || echo "(no __divti3 symbols found)"

COMPILER_RT_DEFINED="false"
if grep -qE '[Tt]\s+__divti3' <<< "${NM_OUTPUT}"; then
COMPILER_RT_DEFINED="true"
fi

# Check for libgcc_s in dynamic NEEDED entries via llvm-readelf -d
DYNAMIC_OUTPUT="$("${LLVM_READELF}" -d "${BINARY}")"
echo "llvm-readelf -d output:"
echo "${DYNAMIC_OUTPUT}"

HAS_LIBGCC_S="false"
if echo "${DYNAMIC_OUTPUT}" | grep -q "libgcc_s"; then
HAS_LIBGCC_S="true"
fi

if [[ "${EXPECT_COMPILER_RT}" = "true" ]]; then
if [ "${COMPILER_RT_DEFINED}" = "true" ]; then
echo "PASS: __divti3 is defined (statically linked from libclang_rt.builtins.a)"
else
echo "FAIL: expected __divti3 to be a defined (T/t) symbol, but it was not found"
exit 1
fi
if [[ "${HAS_LIBGCC_S}" = "false" ]]; then
echo "PASS: no libgcc_s in dynamic NEEDED entries"
else
echo "FAIL: found libgcc_s in dynamic NEEDED entries (binary is using libgcc fallback)"
exit 1
fi
else
if [[ "${COMPILER_RT_DEFINED}" = "false" ]]; then
echo "PASS: __divti3 is not a defined (T/t) symbol (compiler-rt not statically linked)"
else
echo "FAIL: expected __divti3 to NOT be a defined (T/t) symbol, but it was found"
exit 1
fi
fi
13 changes: 13 additions & 0 deletions bazel/compile/test/test_compiler_rt.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#include <iostream>

// Exercise compiler-rt builtins by performing 128-bit integer division.
// The __divti3 symbol (128-bit signed division) is provided by
// libclang_rt.builtins.a (compiler-rt) or libgcc on platforms that do not
// have a native 128-bit division instruction (e.g. aarch64, x86_64).
int main() {
volatile __int128 a = static_cast<__int128>(1000000000) * 1000000000;
volatile __int128 b = 7;
volatile __int128 result = a / b;
std::cout << "result: " << static_cast<long long>(result) << std::endl;
return 0;
}
3 changes: 3 additions & 0 deletions bazel/toolchains_llvm.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ def setup_llvm_toolchain(llvm_version = None):
compatibility_proxy_repo()
llvm_toolchain(
name = "llvm_toolchain",
libclang_rt = {
"@libcxx_libs_aarch64//:lib/libclang_rt.builtins.a": "linux/libclang_rt.builtins-aarch64.a",
},
llvm_version = llvm_version or VERSIONS["llvm"],
cxx_cross_lib = {
"linux-aarch64": "@libcxx_libs_aarch64",
Expand Down
Loading