feat(build, kernel): 内核链接直接产出带符号 kernel.elf,再由 objcopy 二次产出 kernel.bin
按方案调整: - VKernel/project.vpj:linker 去掉 --oformat binary / --strip-all,output 改为 kernel.elf。 - build.py:用 objcopy -O binary --set-section-flags .bss=alloc,load,contents 由 kernel.elf 二次产出 kernel.bin,再拷到 disk/。同源产出 ⇒ 两者布局逐字节一致,日志里的 rip 可直接用 objdump / nm / readelf 落到函数名;原来那段依赖 phase2cmd.bat 的改写字样已整体删除。 - --set-section-flags .bss=...contents 把 .bss 一并写进裸镜像(ELF 里 .bss 默认 NOBITS), 于是 bootloader 按“文件大小”预留即可覆盖 .bss(boot.c 里另有 256KB 余量,双保险)。 - linker.ld:移除此前对 lld 无效的 LONG(0) 写法,.bss 恢复为干净定义。 注意:需完整重编(不能只 --onlyrun)才会生成新的 kernel.elf / kernel.bin。
This commit is contained in:
1 parent
1ebb744418
commit
8b0d24e0d5
3 files changed
+14
-53
No files matched your search
@@ -26,13 +26,6 @@ SECTIONS {
|
||||
*(.bss)
|
||||
*(.bss.*)
|
||||
*(COMMON)
|
||||
/* 强制本输出段为 PROGBITS 并占用文件空间:.bss 默认是 NOBITS(不占文件),
|
||||
于是 kernel.bin 的 FileSize 不包含 .bss。bootloader 只按文件大小预留物理页
|
||||
(PagesNeeded = KernelSize/4096),.bss 尾部(ticks/_perf_* 等全局量)便留在
|
||||
未预留的 EfiConventionalMemory 里,被 mm 的堆 arena 覆盖 → 破坏内核全局量、
|
||||
并反过来破坏堆元数据。加一条数据语句(LONG)即让整段 .bss 写入 kernel.bin。 */
|
||||
. = ALIGN(16);
|
||||
LONG(0);
|
||||
__bss_end = .;
|
||||
}
|
||||
|
||||
|
||||
+2
-5
@@ -18,12 +18,9 @@
|
||||
"-m",
|
||||
"elf_x86_64",
|
||||
"-T",
|
||||
"linker.ld",
|
||||
"--oformat",
|
||||
"binary",
|
||||
"--strip-all"
|
||||
"linker.ld"
|
||||
],
|
||||
"output": "kernel.bin"
|
||||
"output": "kernel.elf"
|
||||
},
|
||||
"includes": [
|
||||
"../../../includes"
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import shutil
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
import subprocess
|
||||
|
||||
@@ -16,52 +15,24 @@ only_run = '--onlyrun' in sys.argv
|
||||
|
||||
|
||||
def BuildKernel():
|
||||
"""编译内核 + 产出带符号 kernel.elf(仅供分析)"""
|
||||
"""编译内核:链接器一次产出带符号 kernel.elf,再由 objcopy 二次处理成裸镜像 kernel.bin"""
|
||||
cmd = r'..\..\ViperC\output\viperc.exe --project ./VKernel/project.vpj --clear-cache --rebuild-includes'
|
||||
if clean:
|
||||
cmd += ' --clean'
|
||||
os.system(cmd)
|
||||
|
||||
shutil.copy("VKernel/__vpcbuild__/output/kernel.bin", "./disk/sys/kernel/x86_64/kernel.bin")
|
||||
|
||||
# 额外产出带符号的 kernel.elf(仅供分析:objdump / nm / readelf 定位崩溃 rip)。
|
||||
# kernel.bin 是 --oformat binary --strip-all 的裸镜像、无符号表,不便把日志里的
|
||||
# rip 映射回函数。要点:**对象顺序决定段内布局**,自行 glob 一组 .obj 去链会得到
|
||||
# 与 kernel.bin 不同的地址(实测前 247KB 里 230KB 不同),没法对上日志。
|
||||
# 因此用 viperc 自己的 --phase2command:它把 llc/链接命令按“精确顺序”写进 .bat,
|
||||
# 我们只把该链接行里的 --oformat binary/--strip-all 去掉、输出改为 kernel.elf 再执行。
|
||||
# project.vpj 的 linker 已改为直接产出 ELF(保留符号表,去掉 --oformat binary/--strip-all),
|
||||
# kernel.bin 由同一份 ELF 二次处理得到 —— 两者布局逐字节一致,日志里的 rip 可直接用
|
||||
# objdump / nm / readelf 落到函数名,不必再猜地址(此前自行 glob .obj 去链会得到不同布局)。
|
||||
# --set-section-flags .bss=alloc,load,contents:把 .bss 一并写进裸镜像(ELF 里 .bss 默认
|
||||
# NOBITS、不占文件空间),这样 bootloader 按“文件大小”预留就能覆盖 .bss。
|
||||
kernel_elf = "VKernel/__vpcbuild__/output/kernel.elf"
|
||||
p2c_bat = "VKernel/__vpcbuild__/phase2cmd.bat"
|
||||
os.system(r'..\..\ViperC\output\viperc.exe --project ./VKernel/project.vpj --phase2command ' + p2c_bat)
|
||||
link_line = None
|
||||
if os.path.exists(p2c_bat):
|
||||
with open(p2c_bat, "r", encoding="utf-8", errors="replace") as f:
|
||||
for line in f:
|
||||
low = line.lower()
|
||||
if "ld.lld" in low and (".bin" in low or "output" in low):
|
||||
link_line = line.rstrip("\r\n")
|
||||
if link_line is not None:
|
||||
# 稳健改写:--oformat 可能是 "--oformat binary" 或 "--oformat=binary";输出可能是
|
||||
# "-o <path>" 或 "--output=<path>"。任一没匹配上就放弃(绝不去执行原样命令,否则会把
|
||||
# kernel.bin 覆盖成非预期产物)。
|
||||
elf_line = re.sub(r"--oformat[ =]binary", "", link_line)
|
||||
elf_line = re.sub(r"--strip-all", "", elf_line)
|
||||
elf_line = re.sub(r"(-o\s+)\S+", r"\1" + kernel_elf, elf_line)
|
||||
elf_line = re.sub(r"(--output=)\S+", r"\1" + kernel_elf, elf_line)
|
||||
if elf_line == link_line or kernel_elf not in elf_line:
|
||||
print("[build] 警告: 未能改写链接命令,跳过 kernel.elf(避免误覆盖 kernel.bin)")
|
||||
else:
|
||||
# .bat 里的对象路径可能已过期(例如 --rebuild-includes 之后 includes.binary_mlir
|
||||
# 下的目标文件名变化),逐个校验;缺任何一个就跳过,避免刷一屏 ld.lld 报错。
|
||||
missing = [t for t in elf_line.split() if t.endswith(".obj") and not os.path.exists(t)]
|
||||
if missing:
|
||||
print(f"[build] 跳过 kernel.elf:{len(missing)} 个对象缺失(.bat 路径已过期),例:{missing[0]}")
|
||||
else:
|
||||
print("[build] linking kernel.elf for analysis ...")
|
||||
if os.system(elf_line) != 0:
|
||||
print("[build] 警告: kernel.elf 链接失败(不影响 kernel.bin)")
|
||||
else:
|
||||
print("[build] 警告: 未从 phase2command 取到链接命令,跳过 kernel.elf")
|
||||
kernel_bin = "VKernel/__vpcbuild__/output/kernel.bin"
|
||||
rc = os.system(f'llvm-objcopy.exe -O binary --set-section-flags .bss=alloc,load,contents "{kernel_elf}" "{kernel_bin}"')
|
||||
if rc != 0:
|
||||
print("[build] 警告: objcopy 生成 kernel.bin 失败")
|
||||
|
||||
shutil.copy(kernel_bin, "./disk/sys/kernel/x86_64/kernel.bin")
|
||||
|
||||
|
||||
def BuildApps():
|
||||
|
||||
Reference in new issue
Block a user