From 6b70ee73503a273a087f09d16116ad7af1428351 Mon Sep 17 00:00:00 2001 From: Sunrisepeak Date: Thu, 5 Nov 2026 07:05:17 +0900 Subject: [PATCH] fix: retain emulated TLS during image LTO code generation --- .github/workflows/ci.yml | 17 +++++++++++++++++ README.md | 5 +++++ checks/lto/mcpp.toml | 16 ++++++++++++++++ checks/lto/src/main.cpp | 17 +++++++++++++++++ mcpp.toml | 5 +++-- 5 files changed, 58 insertions(+), 2 deletions(-) create mode 100644 checks/lto/mcpp.toml create mode 100644 checks/lto/src/main.cpp diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6d1007f..a3a46a3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -155,6 +155,23 @@ jobs: OKRUN_PLACE=0 "$okrun" "$image" one two | tee anywhere.log grep -q "image ok: 3 args" anywhere.log || { echo "::error::the image placed anywhere"; exit 1; } + - name: ThinLTO keeps thread-local storage emulated + working-directory: checks/lto + run: | + t='${{ matrix.arch }}-openkal' + other=x86_64; [ '${{ matrix.arch }}' = x86_64 ] && other=aarch64 + mcpp run --release --target "$t" | tee lto.log + grep -q 'LTO TLS ok' lto.log || { echo "::error::LTO TLS isolation failed"; exit 1; } + mcpp build --release --target "$other-openkal" + py=python3; command -v python3 > /dev/null 2>&1 && python3 -c '' 2>/dev/null || py=python + "$py" - <<'PY' + from pathlib import Path + for arch in ('x86_64', 'aarch64'): + objects = list(Path('target', arch + '-openkal').rglob('main.o')) + if not any(p.read_bytes()[:4] == b'BC\xc0\xde' for p in objects): + raise SystemExit('no ThinLTO bitcode object for ' + arch) + PY + - name: A snapshot of a C++ program's initialisers (0.23.0) working-directory: checks/snapshot run: | diff --git a/README.md b/README.md index be370e3..f5ad4b1 100644 --- a/README.md +++ b/README.md @@ -41,6 +41,11 @@ mcpp pack --target x86_64-openkal --pkg-format okb # one file okrun runs | hosted | the toolchain and the layers for the host triples, over the system's openkal implementation | | versions | the release group of the openkal family | +Platform 0.23.6 also sets emulated TLS for the linker's LTO code generation. +Compiling bitcode with `-femulated-tls` alone does not retain that choice at the +final link. Both ordinary object files and ThinLTO builds use the platform's +emulated thread-local storage. + A project overrides any group under `[target.]`, for example `[target.'cfg(platform = "openkal")'.layers] "c++-abi" = false`, and selects another platform, or none, with `platform = "..."` or `--platform`. diff --git a/checks/lto/mcpp.toml b/checks/lto/mcpp.toml new file mode 100644 index 0000000..704e8a2 --- /dev/null +++ b/checks/lto/mcpp.toml @@ -0,0 +1,16 @@ +[package] +name = "image-lto" +version = "0.1.0" + +[language] +standard = "c++23" + +[build] +cxxflags = ["-flto=thin"] + +[target.'cfg(os = "openkal")'] +platform = { path = "../.." } + +[targets.image-lto] +kind = "bin" +main = "src/main.cpp" diff --git a/checks/lto/src/main.cpp b/checks/lto/src/main.cpp new file mode 100644 index 0000000..fdc464e --- /dev/null +++ b/checks/lto/src/main.cpp @@ -0,0 +1,17 @@ +#include +#include + +// Volatile accesses keep the TLS operations present under LTO, including the +// main thread's read after a worker changes its own instance. +thread_local volatile int tls_value = 7; + +int main() { + int worker_value = 0; + std::thread worker([&] { + tls_value = 9; + worker_value = tls_value; + }); + worker.join(); + if (worker_value != 9 || tls_value != 7) return 1; + std::puts("LTO TLS ok"); +} diff --git a/mcpp.toml b/mcpp.toml index 9a5b4e0..348148a 100644 --- a/mcpp.toml +++ b/mcpp.toml @@ -12,7 +12,7 @@ [package] namespace = "mcpplibs" name = "openkal-platform" -version = "0.23.5" +version = "0.23.6" description = "The platform of ok images (-openkal): their toolchain, C library and C++ run-time, tools, compile and link conventions, seal, runner and carrier, as one versioned statement mcpp reads." license = "Apache-2.0" authors = ["mcpplibs"] @@ -137,7 +137,8 @@ asmflags = ["-ffixed-x18", "-mno-outline-atomics", "-mbranch-protection=pac-ret+ driver = "lld" start = "ok_main" flags = ["-shared", "-z", "max-page-size=65536", "-z", "pack-relative-relocs", "-z", "now", "-z", "noexecstack", - "--hash-style=both", "--gc-sections", "--icf=safe", "--eh-frame-hdr", "--build-id=sha1"] + "--hash-style=both", "--gc-sections", "--icf=safe", "--eh-frame-hdr", "--build-id=sha1", + "-mllvm", "-emulated-tls"] inputs = [{ from = ["okld", "note-source"], as = "ok-notes.S" }] exe = "{name}.oke" shared = "lib{name}.okso"