Golang中为MIPS架构进行交叉编译时遇到的运行时错误

Golang中为MIPS架构进行交叉编译时遇到的运行时错误 代码:

package main

import "fmt"
import "os/exec"

func main() {
    out, _ := exec.Command("date").Output()
    fmt.Println(string(out))
}

Go 版本: go version go1.14.6 windows/amd64

Go 环境: set GO111MODULE= set GOARCH=mipsle set GOBIN= set GOCACHE=C:\Users\wakoy\AppData\Local\go-build set GOENV=C:\Users\wakoy\AppData\Roaming\go\env set GOEXE= set GOFLAGS= set GOHOSTARCH=amd64 set GOHOSTOS=windows set GOINSECURE= set GONOPROXY= set GONOSUMDB= set GOOS=linux set GOPATH=C:\Users\wakoy\go set GOPRIVATE= set GOPROXY=https://proxy.golang.org,direct set GOROOT=c:\go set GOSUMDB=sum.golang.org set GOTMPDIR= set GOTOOLDIR=c:\go\pkg\tool\windows_amd64 set GCCGO=gccgo set GOMIPS=hardfloat set AR=ar set CC=gcc set CXX=g++ set CGO_ENABLED=0 set GOMOD= set CGO_CFLAGS=-g -O2 set CGO_CPPFLAGS= set CGO_CXXFLAGS=-g -O2 set CGO_FFLAGS=-g -O2 set CGO_LDFLAGS=-g -O2 set PKG_CONFIG=pkg-config set GOGCCFLAGS=-fPIC -mabi=32 -march=mips32 -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fdebug-prefix-map=C:\Users\wakoy\AppData\Local\Temp\go-build932383906=/tmp/go-build -gno-record-gcc-switches

MIPS 系统信息: Linux **** 2.6.36+ #36 Wed Jul 15 16:06:23 KST 2020 mips unknown

错误信息: ./stdout runtime: epollcreate failed with 89 fatal error: runtime: netpollinit failed

goroutine 1 [running]: runtime.throw(0x10c690, 0x1b) c:/go/src/runtime/panic.go:1116 +0x60 fp=0x41c56c sp=0x41c558 pc=0x47d60 runtime.netpollinit() c:/go/src/runtime/netpoll_epoll.go:33 +0x27c fp=0x41c5a4 sp=0x41c56c pc=0x43cf0 runtime.netpollGenericInit() c:/go/src/runtime/netpoll.go:112 +0xa0 fp=0x41c5ac sp=0x41c5a4 pc=0x42c4c internal/poll.runtime_pollServerInit() c:/go/src/runtime/netpoll.go:105 +0x34 fp=0x41c5b0 sp=0x41c5ac pc=0x42b9c sync.(*Once).doSlow(0x1c2f00, 0x1104ac) c:/go/src/sync/once.go:66 +0x168 fp=0x41c5dc sp=0x41c5b0 pc=0x8f518 sync.(*Once).Do(…) c:/go/src/sync/once.go:57 internal/poll.(*pollDesc).init(0x40e194, 0x40e180, 0x410001, 0x40e180) c:/go/src/internal/poll/fd_poll_runtime.go:38 +0x190 fp=0x41c5f4 sp=0x41c5dc pc=0xb9a20 internal/poll.(*FD).Init(0x40e180, 0x108464, 0x4, 0x1, 0x0, 0x0) c:/go/src/internal/poll/fd_unix.go:63 +0xb0 fp=0x41c608 sp=0x41c5f4 pc=0xb9e68 os.newFile(0x4, 0x108cc3, 0x9, 0x1, 0x0) c:/go/src/os/file_unix.go:155 +0x110 fp=0x41c630 sp=0x41c608 pc=0xbc598 os.openFileNolog(0x108cc3, 0x9, 0x0, 0x0, 0x410000, 0xc, 0xc) c:/go/src/os/file_unix.go:226 +0x1ac fp=0x41c65c sp=0x41c630 pc=0xbc860 os.OpenFile(0x108cc3, 0x9, 0x0, 0x0, 0x0, 0x0, 0x5f0eaac5) c:/go/src/os/file.go:307 +0x6c fp=0x41c67c sp=0x41c65c pc=0xbc388 os.Open(…) c:/go/src/os/file.go:287 os/exec.(*Cmd).stdin(0x458000, 0x0, 0x3, 0x40a030) c:/go/src/os/exec/exec.go:246 +0x418 fp=0x41c6bc sp=0x41c67c pc=0xce0f4 os/exec.(*Cmd).Start(0x458000, 0x108401, 0x43c030) c:/go/src/os/exec/exec.go:407 +0x120 fp=0x41c75c sp=0x41c6bc pc=0xceb7c os/exec.(*Cmd).Run(0x458000, 0x43c030, 0x0) c:/go/src/os/exec/exec.go:338 +0x3c fp=0x41c76c sp=0x41c75c pc=0xcea04 os/exec.(*Cmd).Output(0x458000, 0x4, 0x0, 0x0, 0x0, 0x458000) c:/go/src/os/exec/exec.go:546 +0x98 fp=0x41c794 sp=0x41c76c pc=0xcf770 main.main() c:/go/skt/stdout.go:7 +0x64 fp=0x41c7c0 sp=0x41c794 pc=0xd1368 runtime.main() c:/go/src/runtime/proc.go:203 +0x24c fp=0x41c7ec sp=0x41c7c0 pc=0x4af7c runtime.goexit() c:/go/src/runtime/asm_mipsx.s:651 +0x4 fp=0x41c7ec sp=0x41c7ec pc=0x7edb4


更多关于Golang中为MIPS架构进行交叉编译时遇到的运行时错误的实战教程也可以访问 https://www.itying.com/category-94-b0.html

2 回复

如果让我猜测的话,我会说内核版本太旧了。你能尝试使用更新的内核吗?

如果你搜索类似的错误,会找到像这样的问题:https://github.com/golang/go/issues/24980,其中就提到了内核版本过旧。

更多关于Golang中为MIPS架构进行交叉编译时遇到的运行时错误的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


这个错误是因为Go运行时在MIPS架构上尝试使用epoll系统调用失败。错误代码89对应ENOSYS,表示内核不支持epoll。你的MIPS系统运行的是较老的Linux内核(2.6.36),可能不支持epoll。

解决方案是禁用netpoll或使用兼容的编译选项。以下是修改后的代码示例:

package main

import (
    "fmt"
    "os/exec"
    "runtime"
    "time"
)

func main() {
    // 设置GOMAXPROCS为1避免netpoll初始化
    runtime.GOMAXPROCS(1)
    
    // 或者使用环境变量方式(编译时设置)
    // GODEBUG=asyncpreemptoff=1
    
    cmd := exec.Command("date")
    out, err := cmd.Output()
    if err != nil {
        fmt.Printf("执行错误: %v\n", err)
        return
    }
    fmt.Println(string(out))
}

编译时添加-ldflags参数禁用异步抢占:

GOOS=linux GOARCH=mipsle GOMIPS=hardfloat CGO_ENABLED=0 \
go build -ldflags="-extldflags=-static" -a -o stdout_mips

或者创建自定义的编译脚本:

// build_mips.sh
#!/bin/bash
export GOOS=linux
export GOARCH=mipsle
export GOMIPS=hardfloat
export CGO_ENABLED=0
export GODEBUG=asyncpreemptoff=1

go build -ldflags="-extldflags=-static" -a -o output_mips main.go

如果问题仍然存在,可以尝试使用静态链接并禁用更多运行时特性:

// 在代码开头添加build tag
//go:build linux && mipsle
// +build linux,mipsle

package main

import (
    "fmt"
    "os/exec"
    "syscall"
)

func main() {
    cmd := exec.Command("date")
    cmd.SysProcAttr = &syscall.SysProcAttr{
        Setsid: true,
    }
    
    out, err := cmd.Output()
    if err != nil {
        fmt.Printf("错误: %v\n", err)
        return
    }
    fmt.Print(string(out))
}

对于MIPS架构的交叉编译,还需要确保使用正确的工具链。可以尝试使用musl libc进行静态链接:

# 使用musl-cross-make工具链
CC=mips-linux-musl-gcc GOOS=linux GOARCH=mipsle GOMIPS=hardfloat \
CGO_ENABLED=1 go build -o stdout_mips main.go

如果目标系统内核确实不支持epoll,最终的解决方案可能是升级内核到2.6.32以上版本(完全支持epoll),或者使用更保守的编译选项。

回到顶部