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

3 回复

大胆猜测,可能是因为内存分配器的变化?

图片

Go 1.22 发布说明 - Go 编程语言

尝试使用 GOEXPERIMENT=noallocheaders 进行构建,以恢复旧的行为。

更多关于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环境下工作。

回到顶部