英文:
static linking a no-op binary with `net` and cgo turned off fails
问题
我尝试提交了一个错误报告(https://github.com/golang/go/issues/48081),但被发送到了这里。
我正在尝试静态链接一个二进制文件,即使是一个空操作的二进制文件,也会遇到陷阱问题。
我使用的是docker golang:1.17-buster
镜像,但在1.16版本中也可以重现这个问题。
我尝试静态编译一个简单的主文件:
$ cat go.mod
module naphatkrit/go-bug-repro
go 1.17
$ cat main.go
package main
func main() {
}
然后我使用需要静态链接二进制文件的标志运行go build,结果出现了一个关于找不到cgo的警告。
$ go build -a -v -o /tmp/my-binary -ldflags "-linkmode external -extldflags -static" -trimpath .
runtime/internal/sys
internal/goexperiment
internal/cpu
internal/abi
runtime/internal/atomic
runtime/internal/math
internal/bytealg
runtime
naphatkrit/go-bug-repro
# naphatkrit/go-bug-repro
loadinternal: cannot find runtime/cgo
执行二进制文件会导致陷阱错误。
$ /tmp/my-binary
Trace/breakpoint trap
此外,以下是strace的输出:
root@3f441e3ed41c:/code# strace /tmp/my-binary
execve("/tmp/my-binary", ["/tmp/my-binary"], 0x7fff5db80d00 /* 10 vars */) = 0
brk(NULL) = 0xf03000
brk(0xf041c0) = 0xf041c0
arch_prctl(ARCH_SET_FS, 0xf03880) = 0
uname({sysname="Linux", nodename="3f441e3ed41c", ...}) = 0
readlink("/proc/self/exe", "/tmp/my-binary", 4096) = 14
brk(0xf251c0) = 0xf251c0
brk(0xf26000) = 0xf26000
arch_prctl(ARCH_SET_FS, 0x55fd90) = 0
--- SIGTRAP {si_signo=SIGTRAP, si_code=SI_KERNEL} ---
+++ killed by SIGTRAP +++
Trace/breakpoint trap
如果我强制包含runtime/cgo,构建警告就会消失,编译后的二进制文件可以正常运行。
$ cat main.go
package main
import _ "runtime/cgo"
func main() {
}
$ go build -a -v -o /tmp/my-binary -ldflags "-linkmode external -extldflags -static" -trimpath .
internal/race
runtime/internal/sys
internal/abi
internal/cpu
internal/goexperiment
runtime/internal/atomic
sync/atomic
runtime/internal/math
internal/bytealg
runtime
sync
runtime/cgo
naphatkrit/go-bug-repro
$ /tmp/my-binary
$
我是不是静态链接的方法有问题?
我已经在https://github.com/naphatkrit/go-bug-repro 上放置了我的复现代码,以方便查看。
编辑:我意识到我简化了我的复现代码,这使得问题变得不明显。我想要做的是静态链接一个使用net
包并关闭其cgo使用的二进制文件。
特别是,考虑以下代码,看看它与上面的问题相同:
package main
import _ "net"
func main() {
}
$ go build -a -v -o /tmp/gobuild -ldflags "-linkmode external -extldflags -static" -trimpath -tags 'netgo' .
...
loadinternal: cannot find runtime/cgo
$ /tmp/gobuild
Trace/breakpoint trap
英文:
I tried to file a bug report (https://github.com/golang/go/issues/48081) but was sent here instead.
I am trying to statically link a binary, and am running into trap issues even with a no op binary.
$ go version
go version go1.17 linux/amd64
Note I was using the docker golang:1.17-buster
image, but this repros with 1.16 too.
$ go env
GO111MODULE=""
GOARCH="amd64"
GOBIN=""
GOCACHE="/root/.cache/go-build"
GOENV="/root/.config/go/env"
GOEXE=""
GOEXPERIMENT=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GOINSECURE=""
GOMODCACHE="/go/pkg/mod"
GONOPROXY=""
GONOSUMDB=""
GOOS="linux"
GOPATH="/go"
GOPRIVATE=""
GOPROXY="https://proxy.golang.org,direct"
GOROOT="/usr/local/go"
GOSUMDB="sum.golang.org"
GOTMPDIR=""
GOTOOLDIR="/usr/local/go/pkg/tool/linux_amd64"
GOVCS=""
GOVERSION="go1.17"
GCCGO="gccgo"
AR="ar"
CC="gcc"
CXX="g++"
CGO_ENABLED="1"
GOMOD="/dev/null"
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -m64 -pthread -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build838287027=/tmp/go-build -gno-record-gcc-switches"
I tried to statically compile a simple main file:
$ cat go.mod
module naphatkrit/go-bug-repro
go 1.17
$ cat main.go
package main
func main() {
}
I then ran go build with the flags needed to statically link my binary, this results in a warning about not being able to find cgo.
$ go build -a -v -o /tmp/my-binary -ldflags "-linkmode external -extldflags -static" -trimpath .
runtime/internal/sys
internal/goexperiment
internal/cpu
internal/abi
runtime/internal/atomic
runtime/internal/math
internal/bytealg
runtime
naphatkrit/go-bug-repro
# naphatkrit/go-bug-repro
loadinternal: cannot find runtime/cgo
Executing the binary results in a trap error
$ /tmp/my-binary
Trace/breakpoint trap
Additionally, here is what strace shows:
root@3f441e3ed41c:/code# strace /tmp/my-binary
execve("/tmp/my-binary", ["/tmp/my-binary"], 0x7fff5db80d00 /* 10 vars */) = 0
brk(NULL) = 0xf03000
brk(0xf041c0) = 0xf041c0
arch_prctl(ARCH_SET_FS, 0xf03880) = 0
uname({sysname="Linux", nodename="3f441e3ed41c", ...}) = 0
readlink("/proc/self/exe", "/tmp/my-binary", 4096) = 14
brk(0xf251c0) = 0xf251c0
brk(0xf26000) = 0xf26000
arch_prctl(ARCH_SET_FS, 0x55fd90) = 0
--- SIGTRAP {si_signo=SIGTRAP, si_code=SI_KERNEL} ---
+++ killed by SIGTRAP +++
Trace/breakpoint trap
If I forcibly include runtime/cgo, the build warning goes away and the compiled binary runs fine.
$ cat main.go
package main
import _ "runtime/cgo"
func main() {
}
$ go build -a -v -o /tmp/my-binary -ldflags "-linkmode external -extldflags -static" -trimpath .
internal/race
runtime/internal/sys
internal/abi
internal/cpu
internal/goexperiment
runtime/internal/atomic
sync/atomic
runtime/internal/math
internal/bytealg
runtime
sync
runtime/cgo
naphatkrit/go-bug-repro
$ /tmp/my-binary
$
Am I doing static linking wrong?
I have put up my repro at https://github.com/naphatkrit/go-bug-repro for convenience
Edit: I realized that I simplified my repro too far and it detracted from the issue I was facing. What I am trying to do is statically link a binary that uses net
and turn off its cgo usage.
In particular, consider this instead and see how it has the same issue as above:
package main
import _ "net"
func main() {
}
$ go build -a -v -o /tmp/gobuild -ldflags "-linkmode external -extldflags -static" -trimpath -tags 'netgo' .
...
loadinternal: cannot find runtime/cgo
$ /tmp/gobuild
Trace/breakpoint trap
答案1
得分: 1
Go默认情况下构建静态二进制文件(除非你实际上使用cgo导入C代码)。标准库中有两个例外。net
和os/user
包默认使用本地代码。
编辑:
要在不使用本地代码的情况下使用net
包,可以执行以下操作:
CGO_ENABLED=0 go build ...
或者
go build -tags netgo ...
但是你的方法也应该可以正常工作,尽管我会省略-a
标志。
英文:
Go builds static binaries by default (unless you are actually using cgo to import C code). There are two exceptions with the std library. The net
and os/user
packages do use native code by default.
EDIT:
To use the net
package without native code, you can do
CGO_ENABLED=0 go build ...
or
go build -tags netgo ...
But what you have should also work as well, although I'd omit the -a
flag.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论