golang / go

The Go programming language
https://go.dev
BSD 3-Clause "New" or "Revised" License
124.11k stars 17.68k forks source link

cmd/go: package main fails to compile with gccgo in module mode due to //go:linkname restriction #30344

Closed bcmills closed 5 years ago

bcmills commented 5 years ago

Noticed in the course of updating misc/cgo/testshared.

    shared_test.go:680: executing go install -installsuffix=3916589616287113937 -compiler=gccgo -linkshared ./exe2 failed exit status 2:
        # testshared/exe2
        /tmp/go-build891467494/b001/_gomod_.go:3:3: error: __debug_modinfo__ is not a function; //go:linkname is only supported for functions
         //go:linkname __debug_modinfo__ runtime/debug.modinfo
           ^
~/bin$ $(go env GCCGO) --version
gccgo (Debian 8-20180218-1) 8.0.1 20180218 (experimental) [trunk revision 257787]

I believe that this restriction will cause all gccgo builds to fail in module mode.

(CC @ianlancetaylor @thanm @jayconrod)

ianlancetaylor commented 5 years ago

Yeah, the gccgo version of this code looks like this:

func ModInfoProg(info string) []byte {
    return []byte(fmt.Sprintf(`package main
import _ "unsafe"
//go:linkname __set_debug_modinfo__ runtime..z2fdebug.setmodinfo
func __set_debug_modinfo__(string)
func init() { __set_debug_modinfo__(%q) }
    `, string(infoStart)+info+string(infoEnd)))
}

We'll need to change cmd/go to switch based on the compiler in use. The gccgo variant is not as good because it assumes that the package does not redefine string. But the concept of using go:linkname with a variable can not be implemented by gccgo. The problem is that we don't know whether go:linkname is being used with a variable definition or a variable reference. The Go linker finesses this issue by marking variables that use go:linkname as "dupok", and then treating the variable as a definition. Since gccgo does not have its own linker, that avenue is not available.

gopherbot commented 5 years ago

Change https://golang.org/cl/171768 mentions this issue: cmd/go: use alternate debug_modinfo recipe for gccgo

cherrymui commented 5 years ago

For linkname on variables, would it work if we always treat it as definition, but generate a weak symbol if it is not explicitly initialized, and generate a strong symbol if it is? Then the linker will choose the strong symbol if there is one, otherwise use the weak symbol, and allow duplication. It doesn't work if more than one have initialization values, but I think this is fine -- it cannot work anyway.

thanm commented 5 years ago

Also worth noting that with gccgo we support shared linkage (runtime + std packages in libgo.so), so we can't assume that when a program is linked the linker will see the runtime package object file.

ianlancetaylor commented 5 years ago

Defining a weak symbol, intended to be a reference, means that the strong definition will not be brought in from an archive, so in the general case that approach doesn't work. I think the compiler needs to know whether the variable is intended to be a definition or a reference, but go:linkname supports both use cases. To distinguish them, we would need to use different comments.

gopherbot commented 5 years ago

Change https://golang.org/cl/196237 mentions this issue: cmd/go: fix buglet in alternate gccgo debug_modinfo recipe