Skip to content

Commit 6984982

Browse files
committed
bazel/toolchains_llvm: Add compiler rt support
Signed-off-by: Ryan Northey <ryan@synca.io>
1 parent 5e0c573 commit 6984982

7 files changed

Lines changed: 252 additions & 3 deletions

File tree

.github/workflows/_bazel.yml

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -131,16 +131,24 @@ jobs:
131131
run: |
132132
exec bazel test ${{ inputs.bazel-args }} \
133133
--platforms=@toolchains_llvm//platforms:linux-aarch64 \
134+
//compile/test:cross_compile_aarch64_compiler_rt_test \
134135
//compile/test:cross_compile_aarch64_test \
135136
//compile/test:cross_compile_aarch64_unwind_test
136137
working-directory: ${{ inputs.bazel-path }}
137-
- name: Cross-compile test (x86_64 -> aarch64/${{ inputs.bazel-mode }})
138+
- name: Cross-compile test libunwind (x86_64 -> aarch64/${{ inputs.bazel-mode }})
138139
run: |
139140
exec bazel test ${{ inputs.bazel-args }} \
140141
--platforms=@toolchains_llvm//platforms:linux-aarch64 \
141142
--@toolchains_llvm//toolchain/config:libunwind=False \
142143
//compile/test:cross_compile_aarch64_no_unwind_test
143144
working-directory: ${{ inputs.bazel-path }}
145+
- name: Cross-compile test compiler-rt (x86_64 -> aarch64/${{ inputs.bazel-mode }})
146+
run: |
147+
exec bazel test ${{ inputs.bazel-args }} \
148+
--platforms=@toolchains_llvm//platforms:linux-aarch64 \
149+
--@toolchains_llvm//toolchain/config:compiler-rt=False \
150+
//compile/test:cross_compile_aarch64_no_compiler_rt_test
151+
working-directory: ${{ inputs.bazel-path }}
144152

145153
xcompile-arm-to-x86:
146154
if: inputs.action == 'test'
@@ -164,13 +172,21 @@ jobs:
164172
run: |
165173
exec bazel test ${{ inputs.bazel-args }} \
166174
--platforms=@toolchains_llvm//platforms:linux-x86_64 \
175+
//compile/test:cross_compile_x86_64_compiler_rt_test \
167176
//compile/test:cross_compile_x86_64_test \
168177
//compile/test:cross_compile_x86_64_unwind_test
169178
working-directory: ${{ inputs.bazel-path }}
170-
- name: Cross-compile test (x86_64 -> x86_64/${{ inputs.bazel-mode }})
179+
- name: Cross-compile test libunwind (aarch64 -> x86_64/${{ inputs.bazel-mode }})
171180
run: |
172181
exec bazel test ${{ inputs.bazel-args }} \
173182
--platforms=@toolchains_llvm//platforms:linux-x86_64 \
174183
--@toolchains_llvm//toolchain/config:libunwind=False \
175184
//compile/test:cross_compile_x86_64_no_unwind_test
176185
working-directory: ${{ inputs.bazel-path }}
186+
- name: Cross-compile test compiler-rt (aarch64 -> x86_64/${{ inputs.bazel-mode }})
187+
run: |
188+
exec bazel test ${{ inputs.bazel-args }} \
189+
--platforms=@toolchains_llvm//platforms:linux-x86_64 \
190+
--@toolchains_llvm//toolchain/config:compiler-rt=False \
191+
//compile/test:cross_compile_x86_64_no_compiler_rt_test
192+
working-directory: ${{ inputs.bazel-path }}

bazel/compile/README.md

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,3 +201,36 @@ bazel test //compile/test:cross_compile_x86_64_no_unwind_test \
201201
--platforms=@toolchains_llvm//platforms:linux-x86_64 \
202202
--@toolchains_llvm//toolchain/config:libunwind=False
203203
```
204+
205+
### Compiler-rt tests
206+
207+
The compiler-rt tests verify that `libclang_rt.builtins.a` (compiler-rt) is **statically
208+
linked** into the `test_compiler_rt` binary. They use `llvm-nm` to check for a defined
209+
`__divti3` symbol (a 128-bit integer division function that is provided by compiler-rt
210+
builtins and referenced by `__int128` division) and `llvm-readelf` to confirm there is no
211+
`libgcc_s` dynamic dependency.
212+
213+
```bash
214+
# Test aarch64 cross-compilation with compiler-rt statically linked
215+
bazel test //compile/test:cross_compile_aarch64_compiler_rt_test \
216+
--platforms=@toolchains_llvm//platforms:linux-aarch64
217+
218+
# Test x86_64 cross-compilation with compiler-rt statically linked
219+
bazel test //compile/test:cross_compile_x86_64_compiler_rt_test \
220+
--platforms=@toolchains_llvm//platforms:linux-x86_64
221+
```
222+
223+
**Negative compiler-rt tests** verify that compiler-rt builtins are *not* statically
224+
linked when `--@toolchains_llvm//toolchain/config:compiler-rt=False` is passed:
225+
226+
```bash
227+
# Verify compiler-rt is NOT linked for aarch64 when disabled
228+
bazel test //compile/test:cross_compile_aarch64_no_compiler_rt_test \
229+
--platforms=@toolchains_llvm//platforms:linux-aarch64 \
230+
--@toolchains_llvm//toolchain/config:compiler-rt=False
231+
232+
# Verify compiler-rt is NOT linked for x86_64 when disabled
233+
bazel test //compile/test:cross_compile_x86_64_no_compiler_rt_test \
234+
--platforms=@toolchains_llvm//platforms:linux-x86_64 \
235+
--@toolchains_llvm//toolchain/config:compiler-rt=False
236+
```

bazel/compile/test/BUILD.bazel

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,3 +157,111 @@ sh_test(
157157
},
158158
tags = ["manual"],
159159
)
160+
161+
# C++ compiler-rt builtins binary — exercises __int128 division to reference
162+
# the __divti3 symbol provided by libclang_rt.builtins.a (compiler-rt).
163+
# Build for aarch64:
164+
# bazel build //compile/test:test_compiler_rt --platforms=@toolchains_llvm//platforms:linux-aarch64
165+
# Build for x86_64:
166+
# bazel build //compile/test:test_compiler_rt --platforms=@toolchains_llvm//platforms:linux-x86_64
167+
cc_binary(
168+
name = "test_compiler_rt",
169+
srcs = ["test_compiler_rt.cc"],
170+
copts = ["-Werror"],
171+
)
172+
173+
# Cross-compilation compiler-rt tests.
174+
# These tests verify that the test_compiler_rt binary has libclang_rt.builtins.a
175+
# statically linked by checking for the defined __divti3 symbol (via llvm-nm)
176+
# and the absence of libgcc_s in dynamic NEEDED entries (via llvm-readelf).
177+
#
178+
# Run with:
179+
# bazel test //compile/test:cross_compile_aarch64_compiler_rt_test \
180+
# --platforms=@toolchains_llvm//platforms:linux-aarch64
181+
sh_test(
182+
name = "cross_compile_aarch64_compiler_rt_test",
183+
size = "small",
184+
srcs = ["check_compiler_rt.sh"],
185+
data = [
186+
":test_compiler_rt",
187+
"@llvm_toolchain_llvm//:nm",
188+
"@llvm_toolchain_llvm//:readelf",
189+
],
190+
env = {
191+
"BINARY": "$(rootpath :test_compiler_rt)",
192+
"EXPECT_COMPILER_RT": "true",
193+
"EXPECTED_ARCH": "AArch64",
194+
"LLVM_NM": "$(rootpath @llvm_toolchain_llvm//:nm)",
195+
"LLVM_READELF": "$(rootpath @llvm_toolchain_llvm//:readelf)",
196+
},
197+
tags = ["manual"],
198+
)
199+
200+
# Run with:
201+
# bazel test //compile/test:cross_compile_x86_64_compiler_rt_test \
202+
# --platforms=@toolchains_llvm//platforms:linux-x86_64
203+
sh_test(
204+
name = "cross_compile_x86_64_compiler_rt_test",
205+
size = "small",
206+
srcs = ["check_compiler_rt.sh"],
207+
data = [
208+
":test_compiler_rt",
209+
"@llvm_toolchain_llvm//:nm",
210+
"@llvm_toolchain_llvm//:readelf",
211+
],
212+
env = {
213+
"BINARY": "$(rootpath :test_compiler_rt)",
214+
"EXPECT_COMPILER_RT": "true",
215+
"EXPECTED_ARCH": "X86-64",
216+
"LLVM_NM": "$(rootpath @llvm_toolchain_llvm//:nm)",
217+
"LLVM_READELF": "$(rootpath @llvm_toolchain_llvm//:readelf)",
218+
},
219+
tags = ["manual"],
220+
)
221+
222+
# Negative compiler-rt tests — verify that compiler-rt builtins are NOT
223+
# statically linked when the flag is disabled. Run with:
224+
# bazel test //compile/test:cross_compile_aarch64_no_compiler_rt_test \
225+
# --platforms=@toolchains_llvm//platforms:linux-aarch64 \
226+
# --@toolchains_llvm//toolchain/config:compiler-rt=False
227+
sh_test(
228+
name = "cross_compile_aarch64_no_compiler_rt_test",
229+
size = "small",
230+
srcs = ["check_compiler_rt.sh"],
231+
data = [
232+
":test_compiler_rt",
233+
"@llvm_toolchain_llvm//:nm",
234+
"@llvm_toolchain_llvm//:readelf",
235+
],
236+
env = {
237+
"BINARY": "$(rootpath :test_compiler_rt)",
238+
"EXPECT_COMPILER_RT": "false",
239+
"EXPECTED_ARCH": "AArch64",
240+
"LLVM_NM": "$(rootpath @llvm_toolchain_llvm//:nm)",
241+
"LLVM_READELF": "$(rootpath @llvm_toolchain_llvm//:readelf)",
242+
},
243+
tags = ["manual"],
244+
)
245+
246+
# Run with:
247+
# bazel test //compile/test:cross_compile_x86_64_no_compiler_rt_test \
248+
# --platforms=@toolchains_llvm//platforms:linux-x86_64 \
249+
# --@toolchains_llvm//toolchain/config:compiler-rt=False
250+
sh_test(
251+
name = "cross_compile_x86_64_no_compiler_rt_test",
252+
size = "small",
253+
srcs = ["check_compiler_rt.sh"],
254+
data = [
255+
":test_compiler_rt",
256+
"@llvm_toolchain_llvm//:nm",
257+
"@llvm_toolchain_llvm//:readelf",
258+
],
259+
env = {
260+
"BINARY": "$(rootpath :test_compiler_rt)",
261+
"EXPECT_COMPILER_RT": "false",
262+
"EXPECTED_ARCH": "X86-64",
263+
"LLVM_NM": "$(rootpath @llvm_toolchain_llvm//:nm)",
264+
"LLVM_READELF": "$(rootpath @llvm_toolchain_llvm//:readelf)",
265+
},
266+
tags = ["manual"],
267+
)
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
#!/bin/bash
2+
# Checks that a cross-compiled binary has (or does not have) compiler-rt builtins statically linked.
3+
#
4+
# Required environment variables:
5+
# BINARY - path to the compiled binary
6+
# EXPECTED_ARCH - expected ELF architecture (e.g. AArch64, X86-64)
7+
# EXPECT_COMPILER_RT - "true" if libclang_rt.builtins.a should be statically linked, "false" otherwise
8+
# LLVM_NM - path to llvm-nm binary
9+
# LLVM_READELF - path to llvm-readelf binary
10+
set -euo pipefail
11+
12+
: "${BINARY:?BINARY must be set to the path of the compiled binary}"
13+
: "${EXPECTED_ARCH:?EXPECTED_ARCH must be set to the expected architecture (e.g. AArch64, X86-64)}"
14+
: "${EXPECT_COMPILER_RT:?EXPECT_COMPILER_RT must be set to 'true' or 'false'}"
15+
: "${LLVM_NM:?LLVM_NM must be set to the path of llvm-nm}"
16+
: "${LLVM_READELF:?LLVM_READELF must be set to the path of llvm-readelf}"
17+
18+
# Check architecture using llvm-readelf -h
19+
READELF_OUTPUT="$("${LLVM_READELF}" -h "${BINARY}")"
20+
echo "llvm-readelf -h output:"
21+
echo "${READELF_OUTPUT}"
22+
23+
if echo "${READELF_OUTPUT}" | grep -q "${EXPECTED_ARCH}"; then
24+
echo "PASS: binary is ${EXPECTED_ARCH}"
25+
else
26+
echo "FAIL: expected ${EXPECTED_ARCH} in readelf output"
27+
exit 1
28+
fi
29+
30+
# Check for __divti3 defined (T/t) symbol via llvm-nm.
31+
# __divti3 is the 128-bit signed integer division function provided by
32+
# compiler-rt builtins (libclang_rt.builtins.a). Its presence as a defined
33+
# symbol proves that compiler-rt was statically linked.
34+
NM_OUTPUT="$("${LLVM_NM}" "${BINARY}")"
35+
echo "llvm-nm output (filtered):"
36+
echo "${NM_OUTPUT}" | grep -i "__divti3" || echo "(no __divti3 symbols found)"
37+
38+
COMPILER_RT_DEFINED="false"
39+
if grep -qE '[Tt] __divti3' <<< "${NM_OUTPUT}"; then
40+
COMPILER_RT_DEFINED="true"
41+
fi
42+
43+
# Check for libgcc_s in dynamic NEEDED entries via llvm-readelf -d
44+
DYNAMIC_OUTPUT="$("${LLVM_READELF}" -d "${BINARY}")"
45+
echo "llvm-readelf -d output:"
46+
echo "${DYNAMIC_OUTPUT}"
47+
48+
HAS_LIBGCC_S="false"
49+
if echo "${DYNAMIC_OUTPUT}" | grep -q "libgcc_s"; then
50+
HAS_LIBGCC_S="true"
51+
fi
52+
53+
if [[ "${EXPECT_COMPILER_RT}" = "true" ]]; then
54+
if [ "${COMPILER_RT_DEFINED}" = "true" ]; then
55+
echo "PASS: __divti3 is defined (statically linked from libclang_rt.builtins.a)"
56+
else
57+
echo "FAIL: expected __divti3 to be a defined (T/t) symbol, but it was not found"
58+
exit 1
59+
fi
60+
if [[ "${HAS_LIBGCC_S}" = "false" ]]; then
61+
echo "PASS: no libgcc_s in dynamic NEEDED entries"
62+
else
63+
echo "FAIL: found libgcc_s in dynamic NEEDED entries (binary is using libgcc fallback)"
64+
exit 1
65+
fi
66+
else
67+
if [[ "${COMPILER_RT_DEFINED}" = "false" ]]; then
68+
echo "PASS: __divti3 is not a defined (T/t) symbol (compiler-rt not statically linked)"
69+
else
70+
echo "FAIL: expected __divti3 to NOT be a defined (T/t) symbol, but it was found"
71+
exit 1
72+
fi
73+
fi
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
#include <iostream>
2+
3+
// Exercise compiler-rt builtins by performing 128-bit integer division.
4+
// The __divti3 symbol (128-bit signed division) is provided by
5+
// libclang_rt.builtins.a (compiler-rt) or libgcc on platforms that do not
6+
// have a native 128-bit division instruction (e.g. aarch64, x86_64).
7+
int main() {
8+
volatile __int128 a = static_cast<__int128>(1000000000) * 1000000000;
9+
volatile __int128 b = 7;
10+
volatile __int128 result = a / b;
11+
std::cout << "result: " << static_cast<long long>(result) << std::endl;
12+
return 0;
13+
}

bazel/patches/toolchains_llvm.patch

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,7 @@ index 4ab592b..979e21f 100644
212212
diff --git a/toolchain/cc_toolchain_config.bzl b/toolchain/cc_toolchain_config.bzl
213213
--- a/toolchain/cc_toolchain_config.bzl
214214
+++ b/toolchain/cc_toolchain_config.bzl
215-
@@ -340,5 +340,11 @@
215+
@@ -340,5 +340,14 @@
216216
elif stdlib == "libc":
217217
cxx_flags = [
218218
"-std=" + cxx_standard,
@@ -222,5 +222,8 @@ diff --git a/toolchain/cc_toolchain_config.bzl b/toolchain/cc_toolchain_config.b
222222
+ # To support libunwind.
223223
+ "-lpthread",
224224
+ "-ldl",
225+
+ ]
226+
+ compiler_rt_link_flags = [
227+
+ "-rtlib=compiler-rt",
225228
+ ]
226229
elif stdlib == "none":

bazel/toolchains_llvm.bzl

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@ def setup_llvm_toolchain(llvm_version = None):
66
compatibility_proxy_repo()
77
llvm_toolchain(
88
name = "llvm_toolchain",
9+
libclang_rt = {
10+
"@libcxx_libs_aarch64//:lib/libclang_rt.builtins.a": "linux/libclang_rt.builtins-aarch64.a",
11+
},
912
llvm_version = llvm_version or VERSIONS["llvm"],
1013
cxx_cross_lib = {
1114
"linux-aarch64": "@libcxx_libs_aarch64",

0 commit comments

Comments
 (0)