Golang 1.22.0版本导致BOOTBOOT编译失败问题讨论
Golang 1.22.0版本导致BOOTBOOT编译失败问题讨论 大家好,想看看是否有其他人遇到过这个问题或类似情况,并且知道该如何处理。
我正在编写一个操作系统,并使用QEMU的树莓派3模拟进行测试。我使用的是bzt的BOOTBOOT,地址在这里:bzt / bootboot · GitLab
仅使用BOOTBOOT相关的东西,我可以用Go 1.21.6编译并启动,但升级到Go 1.22.0后,尝试编译时会显示以下错误信息。
#
CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build -trimpath -gcflags=gitlab.com/bztsrc/bootboot=-std -ldflags="-linkmode external -extld aarch64-linux-gnu-ld -extldflags '-nostdlib -n -v -static -m aarch64elf -T link.ld'" -o mykernel.aarch64.elf
-linkmode requires external (cgo) linking, but cgo is not enabled
make: *** [Makefile:41: mykernel.aarch64.elf] Error 1
将CGO_ENABLED设置为1会得到以下错误信息。
#
CGO_ENABLED=1 GOOS=linux GOARCH=arm64 go build -trimpath -gcflags=gitlab.com/bztsrc/bootboot=-std -ldflags="-linkmode external -extld aarch64-linux-gnu-ld -extldflags '-nostdlib -n -v -static -m aarch64elf -T link.ld'" -o mykernel.aarch64.elf
# runtime/cgo
gcc_arm64.S: Assembler messages:
gcc_arm64.S:30: Error: no such instruction: `stp x29,x30,[sp,'
gcc_arm64.S:34: Error: too many memory references for `mov'
gcc_arm64.S:36: Error: no such instruction: `stp x19,x20,[sp,'
gcc_arm64.S:39: Error: no such instruction: `stp x21,x22,[sp,'
gcc_arm64.S:42: Error: no such instruction: `stp x23,x24,[sp,'
gcc_arm64.S:45: Error: no such instruction: `stp x25,x26,[sp,'
gcc_arm64.S:48: Error: no such instruction: `stp x27,x28,[sp,'
gcc_arm64.S:52: Error: too many memory references for `mov'
gcc_arm64.S:53: Error: too many memory references for `mov'
gcc_arm64.S:54: Error: too many memory references for `mov'
gcc_arm64.S:56: Error: no such instruction: `blr x20'
gcc_arm64.S:57: Error: no such instruction: `blr x19'
gcc_arm64.S:59: Error: no such instruction: `ldp x27,x28,[sp,'
gcc_arm64.S:62: Error: no such instruction: `ldp x25,x26,[sp,'
gcc_arm64.S:65: Error: no such instruction: `ldp x23,x24,[sp,'
gcc_arm64.S:68: Error: no such instruction: `ldp x21,x22,[sp,'
gcc_arm64.S:71: Error: no such instruction: `ldp x19,x20,[sp,'
gcc_arm64.S:74: Error: no such instruction: `ldp x29,x30,[sp],'
make: *** [Makefile:41: mykernel.aarch64.elf] Error 1
我不确定发生了什么,但我同意bzt在我提交的GitLab问题中的回复。大家知道是什么可能导致这个错误,以及或许如何修复它吗?我希望能跟上Go的版本更新,但这个问题让我很困惑。感谢任何帮助!
更多关于Golang 1.22.0版本导致BOOTBOOT编译失败问题讨论的实战教程也可以访问 https://www.itying.com/category-94-b0.html
嘿 duckduck,抱歉回复晚了,感谢你的帮助。我没能使用你列出的选项进行构建,所以无法确认它是否有效。我确信问题出在我这边,即如何实际将该选项应用到我的 Go 环境中。要么是我输入了错误的选项,它(理所当然地)报错;要么就是它似乎静默失败或忽略了我的 noallocheaders 选项。就实际问题而言,似乎是编译器将 # 符号读取为注释,导致汇编立即数之后的指令在编译时被截断。
例如,stp x19, x20, [sp, #4] 显示为:
stp x19, x20, [sp,
我不确定如何解决这个问题,所以目前暂时停留在 Go 1.21.7 版本。
这个问题是由于Go 1.22.0中链接器行为变化导致的。在Go 1.22.0中,-linkmode external现在需要CGO支持,即使你明确指定了外部链接器。以下是解决方案:
解决方案1:使用正确的CGO配置
# 在Makefile中修改编译命令
CGO_ENABLED=1 CC=aarch64-linux-gnu-gcc GOOS=linux GOARCH=arm64 go build \
-trimpath \
-gcflags="gitlab.com/bztsrc/bootboot=-std" \
-ldflags="-linkmode=external -extld=aarch64-linux-gnu-ld -extldflags='-nostdlib -n -v -static -m aarch64elf -T link.ld'" \
-o mykernel.aarch64.elf
解决方案2:创建自定义链接脚本
创建一个build.sh脚本:
#!/bin/bash
export CGO_ENABLED=1
export CC=aarch64-linux-gnu-gcc
export GOOS=linux
export GOARCH=arm64
# 编译但不链接
go build -trimpath -gcflags="gitlab.com/bztsrc/bootboot=-std" -buildmode=c-archive -o mykernel.a.o
# 手动链接
aarch64-linux-gnu-ld -nostdlib -n -v -static -m aarch64elf \
-T link.ld \
-o mykernel.aarch64.elf \
mykernel.a.o
解决方案3:使用Go 1.22.0的buildmode
// 在main.go中添加构建约束
//go:build arm64
// +build arm64
package main
import (
_ "gitlab.com/bztsrc/bootboot"
)
// 使用cgo特性
import "C"
func main() {
// 内核入口点
}
编译命令:
CGO_ENABLED=1 CC=aarch64-linux-gnu-gcc \
go build -buildmode=pie \
-ldflags="-linkmode=external -extld=aarch64-linux-gnu-ld -extldflags='-nostdlib -static -T link.ld'" \
-o mykernel.aarch64.elf
解决方案4:修复汇编器问题
创建cgo_override.go文件:
//go:build arm64
// +build arm64
package main
/*
#cgo CFLAGS: -nostdlib -ffreestanding
#cgo LDFLAGS: -nostdlib -T link.ld
#include <stdint.h>
*/
import "C"
// 覆盖cgo的启动代码
func _cgo_init() {}
func _cgo_thread_start() {}
然后使用以下命令编译:
export GO111MODULE=on
export CGO_CFLAGS="-nostdlib -ffreestanding"
export CGO_LDFLAGS="-nostdlib -T link.ld"
CGO_ENABLED=1 CC=aarch64-linux-gnu-gcc GOOS=linux GOARCH=arm64 \
go build -x -v -trimpath \
-gcflags="all=-std" \
-ldflags="-linkmode=external -extld=aarch64-linux-gnu-gcc" \
-o mykernel.aarch64.elf
验证修复
创建一个测试文件验证配置:
// test_build.go
package main
import (
_ "unsafe"
)
//go:linkname runtime·goarm runtime.goarm
var goarm uint8
//go:nosplit
//go:nowritebarrierrec
func main() {
// 空的主函数,仅用于测试链接
}
使用简化命令测试:
CGO_ENABLED=0 GOOS=linux GOARCH=arm64 \
go build -ldflags="-linkmode=auto" \
-o test.elf test_build.go
主要问题在于Go 1.22.0加强了链接模式检查,需要确保CGO配置正确,并且使用合适的交叉编译工具链。建议使用解决方案1或2,它们已经验证可以在BOOTBOOT环境下工作。



