Skip to content

feat: getrandom through the interface layer, and getentropy where a consumer looks for it - #6

Closed
Sunrisepeak wants to merge 2 commits into
mainfrom
feat/getrandom-through-openkal
Closed

feat: getrandom through the interface layer, and getentropy where a consumer looks for it#6
Sunrisepeak wants to merge 2 commits into
mainfrom
feat/getrandom-through-openkal

Conversation

@Sunrisepeak

Copy link
Copy Markdown
Member

musl 的 src/linux/getrandom.c 直接发 SYS_getrandom——在 Linux 内核底下对,在这里错:这个 port 的理由就是让每次请求经 openkal 到达环境。

dispatch 加一个 case 转给 kal_random_fill,与已在那里的 69 个系统调用同路。

⚠️ 并且 getentropy 的声明位置,glibc 与 musl 不同

glibc   <sys/random.h> 声明 getrandom 与 getentropy
musl    <sys/random.h> 只声明 getrandom;getentropy 在 <unistd.h>

而 libc++ 的 GETENTROPY 分支只 include 前者:error: use of undeclared identifier 'getentropy'

⭐ 这正是 port/include/ overlay 的问题类型——消费者问「这是哪个操作系统」并假定那个系统的 C 库,而这里的 C 库是 musl。用 #include_next 取回 musl 那份再补一行声明。⚠️ 只加声明,定义仍是 musl 的、未改。

实测:整条链全程走接口层,两次调用字节不同。依赖 mcpplibs/openkal#8

…onsumer looks for it

musl 自己的 `src/linux/getrandom.c` 直接发 `SYS_getrandom`。在 Linux 内核
底下时这是对的,在这里是错的:**这个 port 存在的理由就是让每一次请求
经 openkal 到达环境。**

dispatch 里加一个 case,转给 `kal_random_fill` —— 与已经在那里的 69 个
系统调用同一条路。

⚠️ flags 被忽略:`GRND_NONBLOCK` 要的是短读,而 `kal_random_fill` 没有
部分成功可报。一个会阻塞的环境在 `kal_random_props` 里说这件事。

── ⚠️ 并且 `getentropy` 的声明位置,glibc 与 musl 不同 ────────

    glibc   <sys/random.h> 声明 getrandom 与 getentropy
    musl    <sys/random.h> 只声明 getrandom;getentropy 在 <unistd.h>

而 libc++ 的 GETENTROPY 分支只 include 前者:

    random.cpp:52:14: error: use of undeclared identifier 'getentropy'

⭐ 这正是 `port/include/` overlay 存在的问题类型 —— 消费者问的是
「这是哪个操作系统」并假定那个系统的 C 库,而这里的 C 库是 musl。
`port/include/sys/random.h` 用 `#include_next` 取回 musl 那份,
再补上那一行声明。

⚠️ **只加声明,别的什么都不加。** 定义仍是 musl 的 `src/misc/getentropy.c`,
未经修改;本文件纠正的是消费者去哪里找这个名字。两处都声明正是 glibc 的做法,
也是消费者所针对的。

实测:`getentropy` 返回 0,两次调用字节不同 —— 整条链
`std::random_device → getentropy → getrandom → kal_random_fill → 后端`
全程走接口层。
Sunrisepeak added a commit to mcpplibs/openkal-llvm-runtime that referenced this pull request Aug 24, 2026
使用者报 `_LIBCPP_HAS_RANDOM_DEVICE 0` 让 5 个 TU 编不过,本地改成 1 即修好。
⚠️ 那个 0 不是保守设置,是当时事实的准确记录 —— 改成 1 只让编译期通过,
链接会缺符号。现在 openkal 有了随机源接口,这四层可以逐一拆掉。

**① 宏改为 1** —— 只在 `generic`;`freestanding` 保持 0,因为裸机后端
只有板子有源时才提供 `openkal.random`,而 6.1 条在链接期报告缺席。

**② `random.cpp` 曾被 sources 显式排除**,与那个宏配对。排除删掉。

**③ ⚠️ 默认后端在这里走不通,而它不会报错。** libc++ 对不认识的目标
落到 `_LIBCPP_USING_DEV_RANDOM`,那条要 `open("/dev/urandom")` ——
而能力型文件系统刻意不发绝对路径。必须在 `__config_site` 里**显式**选
`_LIBCPP_USING_GETENTROPY`:它不要描述符也不要路径。

**④ 声明找不到** —— musl 把 `getentropy` 放在 `<unistd.h>`,glibc 放在
`<sys/random.h>`,而 libc++ 只 include 后者。修在 openkal-musl 的 overlay
(见 mcpplibs/openkal-musl#6)。

⭐ 第三层最要紧:**那条默认路径在 openkal 上走不通,而它不报错,
只会在运行期打不开设备。**

实测,完整链路全程走接口层:

    std::random_device → getentropy → getrandom → kal_random_fill → 后端

    x86_64-linux    random_device: 3415089597 356442272   differ = true
    x86_64-windows  random_device: 1945321362 2880234856  differ = true (wine)

`entropy() = 0` 是 libc++ GETENTROPY 后端的既定行为,不是缺陷。
规范新增 `openkal.random`,版本升到 0.7.0。CI 的版本同步门要求实现与规范
同步声明 —— 它的诊断说得很准:「Nothing is wrong with either; they are not
in step.」
@Sunrisepeak
Sunrisepeak deleted the feat/getrandom-through-openkal branch August 24, 2026 21:15
Sunrisepeak added a commit to mcpplibs/openkal-llvm-runtime that referenced this pull request Aug 25, 2026
…system one (#5)

* fix: the x87 routines are an architecture property, not an operating-system one

`--target aarch64-linux-musl` 编不过:

    truncxfhf2.c:13:36: error: unknown type name 'xf_float';
                               did you mean 'tf_float'?

`*xf*.c` 与 `*xc3.c` 是 x87 80 位 `long double` 的例程。本清单里排除它们的
条件有两处,`cfg(os = "macos")` 与 `cfg(os = "none")` —— **都按操作系统分,
而这是架构的性质**。于是 aarch64-linux 落进 `os = "linux"` 那一支,
去编一个只有 x86 才有的类型。

⭐ **两处此前都是对的,只是排错了轴。** `os = "macos"` 与 `os = "none"`
今天恰好都蕴含「非 x87 架构」,所以那条排除看起来像 OS 属性。它不是。

⚠️ 并且 linux 段**不排除**它们也是对的,注释里记着理由:x86 上
`long double` 真是 x87 80 位,`-lgcc` 从链接行拿掉之后

    ld.lld: error: undefined symbol: __mulxc3

—— libc++ `<complex>` 里的复数乘法真的会调它。所以这不是「多编了没用的
文件」,两个方向都会坏。

新增一段按架构分:

    [target.'cfg(all(os = "linux", not(arch = "x86_64")))'.build]
    sources = ["!…/*xf*.c", "!…/*xc3.c"]

按事实真正所在的那条轴来分,是让第二个架构可用而不必再抄一份列表的做法。

实测:该错误消失,构建推进到下一处(BMI 目标特性不匹配,另案)。
报告 mcpp-community/mcpp#492 (comment)。

* feat(aarch64): supply the 125 outline-atomics helpers, because this package is that compiler-rt

`--target aarch64-linux-musl` 链接失败:

    ld.lld: error: undefined symbol: __aarch64_swp4_acq
    ld.lld: error: undefined symbol: __aarch64_cas8_acq_rel

⭐ **`--rtlib=compiler-rt` 让 clang 在 aarch64 上开启 `+outline-atomics`,
而它是对的** —— 那些 `__aarch64_*` 辅助函数本来就住在 compiler-rt 里,
只是本包没产出它们。特性被开启而无人实现,于是缺符号。

⚠️ 引用来自 `openkal-linux/src/memory.o` 与 `openkal-musl/port/src/okm_fd.o`
—— 两个对这件事一无所知、只是用了原子操作的包。**缺的是这份运行时该有的
东西**,所以修在这里,而不是让引擎去关掉那个特性。

── ⭐ 把宏从命令行移进文件,而不是复制 125 份实现 ────────

upstream 用 CMake 把 `aarch64/lse.S` 编 125 遍,每遍给不同的
`-DL_<pat> -DSIZE=<n> -DMODEL=<m>`(6 模式 × 5 尺寸 × 5 模型,
非 cas 的 16 字节档不存在)。`sources` 是 glob,传不了 per-file 定义。

于是每个组合成为一个**只声明宏、再 include 共享正文**的小文件:

    #define L_cas
    #define SIZE 1
    #define MODEL 1
    #include "../../llvm/compiler-rt/lib/builtins/assembly.h"
    #include "../../llvm/compiler-rt/lib/builtins/aarch64/lse.S"

正文是 upstream 的、未经修改、留在原处 —— `git diff` 对着一份新 checkout
仍然为空。

── ⚠️ 途中两处「以为做完了其实没有」 ──────────────────

**① `#include "assembly.h"` 解析不到。** upstream 靠
`INCLUDE_DIRECTORIES "${CMAKE_CURRENT_SOURCE_DIR}"` 供给;生成的文件在
别的目录,汇编器于是把 `HIDDEN(...)` 读成指令:

    error: unrecognized instruction mnemonic

解法是让生成文件**自己按相对自身的路径 include 那个头** —— 不需要任何
flag,而 flag 正是「任何再包含这个目录的人都得重复一遍」的那种东西。

**② `__aarch64_have_lse_atomics` 未定义。** 125 个辅助函数每个都读它 ——
运行时决定走 LSE 指令还是 load/store-exclusive 循环。它在
`cpu_model/aarch64.c`,而 `[build]` 段的 glob 是 `builtins/*.c`,
**不含子目录**,所以这个文件从未被编过。

── 实测 ────────────────────────────────────────────

    已定义的 __aarch64_* 符号  10        未定义  0
    产物中的 LSE 指令          8 处      ← 特性真的在工作
    file                       ELF 64-bit LSB executable, ARM aarch64,
                               statically linked

⭐ 这是**真正支持**,不是关掉特性绕过去。mcpp 引擎零改动。
来源:mcpp-community/mcpp#492 (comment)。

* fix(aarch64): disable FMV — half that file cannot compile on a macOS host

`cpu_model/aarch64.c` 的后半是函数多版本(FMV),按宿主分支 include
一个 `.inc`。Apple 那支拉系统头:

    aarch64/fmv/apple.inc:1:10: fatal error: 'TargetConditionals.h' file not found

而本包的 `include_dirs` 刻意不含任何来自机器的路径(见该段的
⭐⭐ NOTHING FROM THE MACHINE)。⚠️ 本机 Linux 编得过,CI 的 macOS 那格才炸 ——
典型的「一台宿主看不见」的形状。

⭐ 本包**不需要** FMV:要的只是 `__aarch64_have_lse_atomics`,它定义在
`#if !defined(DISABLE_AARCH64_FMV)` **之外**。upstream 自己带这个开关
(`COMPILER_RT_DISABLE_AARCH64_FMV`),所以这是走它给的门,不是绕过。

实测关掉后 aarch64 仍产出 ARM aarch64 静态 ELF,10 个 __aarch64_* 符号
已定义、0 个未定义。

* feat: std::random_device works, and it took four layers to make it so

使用者报 `_LIBCPP_HAS_RANDOM_DEVICE 0` 让 5 个 TU 编不过,本地改成 1 即修好。
⚠️ 那个 0 不是保守设置,是当时事实的准确记录 —— 改成 1 只让编译期通过,
链接会缺符号。现在 openkal 有了随机源接口,这四层可以逐一拆掉。

**① 宏改为 1** —— 只在 `generic`;`freestanding` 保持 0,因为裸机后端
只有板子有源时才提供 `openkal.random`,而 6.1 条在链接期报告缺席。

**② `random.cpp` 曾被 sources 显式排除**,与那个宏配对。排除删掉。

**③ ⚠️ 默认后端在这里走不通,而它不会报错。** libc++ 对不认识的目标
落到 `_LIBCPP_USING_DEV_RANDOM`,那条要 `open("/dev/urandom")` ——
而能力型文件系统刻意不发绝对路径。必须在 `__config_site` 里**显式**选
`_LIBCPP_USING_GETENTROPY`:它不要描述符也不要路径。

**④ 声明找不到** —— musl 把 `getentropy` 放在 `<unistd.h>`,glibc 放在
`<sys/random.h>`,而 libc++ 只 include 后者。修在 openkal-musl 的 overlay
(见 mcpplibs/openkal-musl#6)。

⭐ 第三层最要紧:**那条默认路径在 openkal 上走不通,而它不报错,
只会在运行期打不开设备。**

实测,完整链路全程走接口层:

    std::random_device → getentropy → getrandom → kal_random_fill → 后端

    x86_64-linux    random_device: 3415089597 356442272   differ = true
    x86_64-windows  random_device: 1945321362 2880234856  differ = true (wine)

`entropy() = 0` 是 libc++ GETENTROPY 后端的既定行为,不是缺陷。

* release: 0.1.3, on openkal-musl 0.3.4

`std::random_device` needs `getentropy` declared where libc++ looks for
it, which is `<sys/random.h>` — glibc's layout, and the one libc++ is
written against. musl declares it in `<unistd.h>`, and openkal-musl
0.3.4 adds an overlay header that declares it in both places, as glibc
does. Below that, `SYS_getrandom` is forwarded to `kal_random_fill`
rather than issued as a system call, so the entropy comes through the
interface layer on every system openkal has an implementation for.

    std::random_device → getentropy → getrandom → syscall_cp(SYS_getrandom)
                       → port dispatch → kal_random_fill → backend

0.1.2 is the version in the index and the version this branch carried,
and the content behind that number has changed: this branch also
supplies the 125 outline-atomics helpers for aarch64 and stops
excluding the x87 routines by operating system.

* docs: the generated files said 130 while their own arithmetic said 125

Every one of the 125 files opened with "One of the 130 instantiations",
and the same comment then described a rule that yields 125. Upstream's
CMake is the arbiter and agrees with the arithmetic, not the number:

    foreach(pat cas swp ldadd ldclr ldeor ldset)
      foreach(size 1 2 4 8 16)
        foreach(model 1 2 3 4 5)
          if(pat STREQUAL "cas" OR NOT size STREQUAL "16")

`cas` at five sizes and five further patterns at four sizes, times five
orderings: 25 + 100. The directory holds 125 files, which is what a
reader would have counted if the sentence had not told them otherwise.

* fix(freestanding): random.cpp must not be compiled where the switch is off

Removing the `!llvm/libcxx/src/random.cpp` exclusion was right for the
hosted configuration, which turned `_LIBCPP_HAS_RANDOM_DEVICE` on. The
freestanding configuration keeps it at 0 — a bare-metal backend provides
`openkal.random` only if its board has a source, and clause 6.1 reports
that absence at link time rather than at compile time — and the same
removal reached it.

With the switch off, `<random>` does not declare the class while
`src/random.cpp` defines its members unconditionally; that file carries
no guard of its own, unlike the filesystem sources beside it:

    llvm/libcxx/src/random.cpp:68:1:
        error: use of undeclared identifier 'random_device'

⚠️ One exclusion, two decisions. The hosted block and the freestanding
block disagree about the switch, so they cannot share the removal — and
the comment in the hosted block already stated the freestanding position
without acting on it.

* deps: openkal-musl 0.3.5

0.3.4's syscall dispatcher referenced `kal_random_fill` strongly, which
made an optional interface mandatory: this package's freestanding target
links a program over openkal-opensbi, which does not provide
`openkal.random`, and the link failed on a symbol nothing in the program
asked for.

    ld.lld: error: undefined symbol: kal_random_fill

* docs: the freestanding switch refuses at compile time, not at link time

The note said clause 6.1 would report the absence at link time. It does
not: with `_LIBCPP_HAS_RANDOM_DEVICE` at 0, `<random>` does not declare
the class, so a bare-metal program naming `std::random_device` is
refused where it is written.

    __random/random_device.h:24:  #if _LIBCPP_HAS_RANDOM_DEVICE
    __random/random_device.h:26:  class random_device {

That is the better of the two diagnoses and it is the one that happens;
what was wrong was the account of it. The reason mattered because the
same sentence was the argument for keeping the switch off, and an
argument resting on a mechanism that does not apply is one nobody can
check.

Also records what the switch cannot express: a board with a hardware
source could have a backend that provides `openkal.random`, and this
answer would still be 0. The configuration is generated once, before any
graph is resolved.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant