feat(freestanding): x86_64-none-elf,以及驱动拒绝执行的那次链接 - #472
Merged
Conversation
…uses
A target row is normally two table entries. This one needed engine code, and
the reason is a property of clang rather than of the instruction set.
clang selects a toolchain from the triple. It has a BareMetal toolchain for
arm, aarch64 and riscv, which reaches `ld.lld` directly; it has none for
x86_64, so every spelling of a bare x86_64 triple falls through to the generic
GCC toolchain, whose linker is the HOST'S `g++`:
g++: error: unrecognized command-line option
'-fuse-ld=/…/llvm/22.1.8/bin/ld.lld'
Measured for `x86_64-none-elf`, `x86_64-unknown-none-elf`,
`x86_64-unknown-none`, `x86_64-elf`, `x86_64-none-none` and
`x86_64-unknown-unknown`, and unchanged by `-fuse-ld=lld`, `--ld-path=`,
`--gcc-toolchain=` or `-B`. Only putting `linux` in the OS position changes it,
and that adds eight host `-L` paths to a bare-metal link.
Neither outcome is acceptable: a host `g++` makes the row work on one host and
nowhere else, and host search paths on a freestanding link are the hermeticity
this engine exists to keep. So the ISA-profile row carries an `lldEmulation`
column, and when it is set the engine drives the link with `ld.lld` itself.
The flag vocabulary changes with the tool — `-Map=` rather than `-Wl,-Map=`,
`-m elf_x86_64` rather than `--target=` — and the driver-only flags are dropped
rather than translated, because the first attempt left two behind:
ld.lld: error: unknown argument '-nostdlib++'
ld.lld: error: unknown argument '-Wl,--disable-new-dtags'
The column is empty for the riscv and aarch64 rows: their driver already
reaches lld, and changing a working link to make three rows look alike is how a
regression is introduced. Their link lines are byte-identical to before.
A second new column, `extra`, carries `-mno-red-zone`. That is not a preference
either. The System V ABI's 128-byte red zone is safe on a hosted system because
the kernel switches stacks for interrupts; on bare metal the processor pushes
the interrupt frame into it, and the interrupted leaf function resumes with its
locals overwritten — no fault, no diagnostic, and only when an interrupt
happens to land inside a leaf. There is no bare-metal x86_64 program for which
the red zone is safe.
Verified: `tests/e2e/137_x86_64_zero_libc_target.sh` asserts the image is
x86-64, loads where the script says, has zero undefined symbols, names no
dynamic loader, produced a link map through a linker-native flag, went through
`ld.lld`, and carries `-march=x86-64` and `-mno-red-zone`. The 92 unit tests
pass unchanged.
Also verified outside this repository: openarch's probe — one source file —
builds and runs on riscv64, aarch64 and x86_64 with byte-identical output.
That is the first evidence its interface abstracts rather than merely fits two
similar RISC machines.
⚠️ 两处本方案原先判断错了,记在文档里而不是悄悄改掉: 1. §4 断言 x86_64 目标行「不是代码,是模拟器载荷」。实测下来它需要引擎代码 —— clang 没有 x86_64 的 BareMetal 工具链,于是每一种裸 x86_64 triple 的链接都落到 宿主的 g++ 上。 2. §3 给的目录树是「根为虚拟 workspace、接口在 spec/ 成员里」。那个形状会让根上的 跨编译对所有成员扇出,把 aarch64 汇编喂给 riscv 汇编器。混合式的根修好了它。 以及一处排序错误:第 5 项(x86_64)原先排在最后,理由是它被外部依赖卡住。它却是 唯一一项改变了对已完成工作之信心的 —— 第三台机器挖出三条两台 RISC 机器合起来也 看不见的东西。「被卡住」和「价值低」在列表上看起来一样,而它们不是一回事。
Same package, same manifest, two commands, different source sets:
mcpp build --target riscv64-none-elf skips src/kal/** (correct)
mcpp test --target riscv64-none-elf compiles it, and dies on
'openkal/abort.h' file not found
The header arrives through that feature's `[feature-deps]`; with the feature
inactive it is not there, and neither are the files that include it.
⭐ TWO FAMILIES REACH THIS CODE AND THEY WANT OPPOSITE THINGS.
gtest lists `*/googletest/src/gtest_main.cc` in base `sources` AND
under `features.main`. The package provides the file
unconditionally; the feature is a gate over it, and the
dev-dependency track's per-test main detection must SEE it in
order to prune it per test.
riscv-virt-rt names `src/kal/**` under `features.openkal` and nowhere else.
Those files are not part of the package without the feature.
The engine gated the whole exclusion on "is this a test build", which is right
for the first family and wrong for the second.
⚠️ THIS IS THE FOURTH ATTEMPT, AND THE THIRD WAS ABANDONED ON A MISTAKEN
READING. It was recorded as failing because "gtest's base entry is a glob that
MATCHES the file rather than the same string". Measured against the descriptor
the index actually carries — `compat.gtest.lua` lines 71-73 and 90 — the two
entries are byte-identical. The reason had been written from memory without
opening the file.
What actually defeated that attempt was WHEN the criterion was applied: it
tested membership against `bc.sources` after `drop()` had already removed the
entry, so the test could only ever be false.
The fix snapshots the base globs BEFORE the drop and uses them only in test
mode: a glob in both places is a gate and stays visible; a glob in one place is
a provider and gets the `!` exclusion. The exclusion is the whole mechanism —
`src/kal/**` is never in `bc.sources` at all, because that package declares no
`sources` and its files are matched by the inferred `src/**`, so erasing the
string erases nothing.
Verified, all three of the plan's criteria:
1. riscv-virt-rt: `mcpp test` no longer compiles src/kal/**; both commands
exit 0.
2. mcpp's own 92 unit tests still link and pass (the gtest family).
3. tests/e2e/138_feature_sources_gate_vs_provider.sh covers both families
with two minimal packages and no ecosystem dependency.
⭐ (3) was checked the way a regression test has to be: run against the engine
before this commit it fails with exactly the symptom above; against the engine
after it, it passes. The defect survived this long because no test covered both
families at once, and each of the three earlier attempts broke the one it did
not cover.
直连链接路径定义 cxx_link / c_link / cxx_archive,不定义共享库规则 —— 没有加载器
的目标没有东西去加载它。缺这条检查时,失败长这样:
ninja: error: build.ninja:88: unknown build rule 'cxx_shared'
对一个在清单里写下 kind = "shared" 的人,这句话指的是一条内部规则。
⚠️ 补上那条规则比省掉它更糟:ld.lld -shared 会成功,产出一个那台机器上没有任何
东西能加载的对象 —— 静默的无意义,而不是响亮的拒绝。
e2e 137 加了第 7 条断言,同时检查两件事:拒绝时提到了原因,且**没有**提到内部
规则名。
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
一个目标行不止是四个字符串
目标行通常就是两张表里的两条记录。这一行需要引擎代码,而原因是 clang 的属性,不是指令集的属性。
clang 由 triple 选工具链。它为 arm / aarch64 / riscv 备有 BareMetal 工具链,直接以
ld.lld链接;它没有 x86_64 的,于是裸 x86_64 triple 的每一种写法都落到通用 GCC 工具链上 —— 而后者的链接器是宿主的g++:对六种 triple 写法逐一实测,结果一致;
-fuse-ld=lld/--ld-path=/--gcc-toolchain=/-B逐一实测,均不改变结果。唯一能改变它的是把linux放进 OS 位 —— 那会给一次裸机链接带来八条宿主-L。两种结果都不可接受:经宿主
g++会让这一行只在 Linux 宿主成立;宿主搜索路径出现在 freestanding 链接上,正是本引擎要守住的封闭性。解法:
lldEmulation列ISA 档表新增一列;置位时引擎直接用
ld.lld驱动链接。标志词汇随工具一起变 ——-Map=而非-Wl,-Map=,-m elf_x86_64而非--target=。第二列:
extra承载-mno-red-zone也不是偏好。System V 的 128 字节红区在有 OS 的机器上安全,是因为内核为中断切了栈;裸机上处理器把中断帧压进红区,被中断的叶函数恢复后局部变量已被覆盖 —— 不触发异常、没有诊断,而且只在中断恰好落在叶函数内部时发生。不存在红区安全的裸机 x86_64 程序。
验证
tests/e2e/137_x86_64_zero_libc_target.sh:镜像是 x86-64、装载在脚本指定处、零未定义符号、不指名加载器、链接图经链接器原生标志产出、确实走了ld.lld、带-march=x86-64与-mno-red-zone。