Repository: go
Issue: cmd/link: support -linkmode=internal with Cgo
Labels: NeedsInvestigation,FeatureRequest,compiler/runtime

### What version of Go are you using (`go version`)?

<pre>
$ go version
go version devel +3afa74115b Sun Apr 12 15:37:29 2020 +0000 linux/amd64

</pre>

### Does this issue reproduce with the latest release?
Yes.


### What operating system and processor architecture are you using (`go env`)?

<details><summary><code>go env</code> Output</summary><br><pre>
$ go env
GO111MODULE=""
GOARCH="amd64"
GOBIN=""
GOCACHE="/home/elias/.cache/go-build"
GOENV="/home/elias/.config/go/env"
GOEXE=""
GOFLAGS="-mod=readonly"
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GOINSECURE=""
GOMODCACHE="/home/elias/go/pkg/mod"
GONOPROXY=""
GONOSUMDB=""
GOOS="linux"
GOPATH="/home/elias/go"
GOPRIVATE=""
GOPROXY="https://proxy.golang.org,direct"
GOROOT="/home/elias/dev/go-tip"
GOSUMDB="sum.golang.org"
GOTMPDIR=""
GOTOOLDIR="/home/elias/dev/go-tip/pkg/tool/linux_amd64"
GCCGO="gccgo"
AR="ar"
CC="gcc"
CXX="g++"
CGO_ENABLED="1"
GOMOD="/home/elias/proj/gio/example/go.mod"
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-build621404981=/tmp/go-build -gno-record-gcc-switches"

</pre></details>

### What did you do?

linux/amd64:
```
$ mkdir tmp
$ cd tmp
$ go mod init blah
go: creating new go.mod: module blah
$ go run -ldflags=-linkmode=internal gioui.org/example/kitchen
go: finding module for package gioui.org/example/kitchen
go: downloading gioui.org/example v0.0.0-20200506145455-3957be37c821
go: downloading gioui.org v0.0.0-20200506145455-3957be37c821
go: found gioui.org/example/kitchen in gioui.org/example v0.0.0-20200506145455-3957be37c821
# gioui.org/example/kitchen
gioui.org/app/internal/window(.data.rel): unexpected R_X86_64_64 relocation for dynamic symbol wl_surface_interface
gioui.org/app/internal/window(.data.rel): unexpected R_X86_64_64 relocation for dynamic symbol wl_surface_interface
gioui.org/app/internal/window(.data.rel): unexpected R_X86_64_64 relocation for dynamic symbol wl_surface_interface
gioui.org/app/internal/window(.data.rel): unhandled relocation for wl_surface_interface (type 45 (SDYNIMPORT) rtype 1 (R_ADDR))
gioui.org/app/internal/window(.data.rel): unhandled relocation for wl_surface_interface (type 45 (SDYNIMPORT) rtype 1 (R_ADDR))
gioui.org/app/internal/window(.data.rel): relocation target wl_seat_interface not defined
gioui.org/app/internal/window(.data.rel): unhandled relocation for wl_surface_interface (type 45 (SDYNIMPORT) rtype 1 (R_ADDR))
gioui.org/app/internal/window(.data.rel): relocation target wl_seat_interface not defined
gioui.org/app/internal/window(.data.rel): relocation target wl_output_interface not defined
gioui.org/app/internal/window._Cvar_wl_compositor_interface: relocation target wl_compositor_interface not defined
gioui.org/app/internal/window._Cvar_wl_output_interface: relocation target wl_output_interface not defined
gioui.org/app/internal/window._Cvar_wl_seat_interface: relocation target wl_seat_interface not defined
gioui.org/app/internal/window._Cvar_wl_shm_interface: relocation target wl_shm_interface not defined
```

darwin/amd64 with
```
diff --git a/src/cmd/link/internal/amd64/asm.go b/src/cmd/link/internal/amd64/asm.go
index c2d54703c1..8ee95b66e7 100644
--- a/src/cmd/link/internal/amd64/asm.go
+++ b/src/cmd/link/internal/amd64/asm.go
@@ -181,7 +181,7 @@ func adddynrel2(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s load
                su.SetRelocType(rIdx, objabi.R_ADDR)

                if targType == sym.SDYNIMPORT {
-                       ldr.Errorf(s, "unexpected reloc for dynamic symbol %s", ldr.SymName(targ))
+                       ldr.Errorf(s, "unexpected reloc %s for dynamic symbol %s", r.Type(), ldr.SymName(targ))
                }
                return true
```
applied:
```
$ go run -ldflags=-linkmode=internal gioui.org/example/kitchen
# gioui.org/example/kitchen
gioui.org/app/headless(__DATA/__objc_classrefs): unexpected reloc RelocType(2048) for dynamic symbol OBJC_CLASS_$_NSOpenGLPixelFormat
gioui.org/app/headless(__DATA/__objc_classrefs): unexpected reloc RelocType(2048) for dynamic symbol OBJC_CLASS_$_NSOpenGLContext
gioui.org/app/internal/window(__DATA/__objc_data): unexpected reloc RelocType(2048) for dynamic symbol OBJC_CLASS_$_NSOpenGLView
gioui.org/app/internal/window(__DATA/__objc_data): unexpected reloc RelocType(2048) for dynamic symbol _objc_empty_cache
gioui.org/app/internal/window(__DATA/__objc_data): unexpected reloc RelocType(2048) for dynamic symbol OBJC_METACLASS_$_NSObject
gioui.org/app/internal/window(__DATA/__objc_data): unexpected reloc RelocType(2048) for dynamic symbol OBJC_METACLASS_$_NSOpenGLView
gioui.org/app/internal/window(__DATA/__objc_data): unexpected reloc RelocType(2048) for dynamic symbol _objc_empty_cache
gioui.org/app/internal/window(__DATA/__objc_classrefs): unexpected reloc RelocType(2048) for dynamic symbol OBJC_CLASS_$_NSArray
gioui.org/app/internal/window(__DATA/__objc_classrefs): unexpected reloc RelocType(2048) for dynamic symbol OBJC_CLASS_$_NSOpenGLPixelFormat
gioui.org/app/internal/window(__DATA/__objc_classrefs): unexpected reloc RelocType(2048) for dynamic symbol OBJC_CLASS_$_NSOpenGLContext
gioui.org/app/internal/window(__DATA/__objc_classrefs): unexpected reloc RelocType(2048) for dynamic symbol OBJC_CLASS_$_NSEvent
gioui.org/app/internal/window(__DATA/__objc_classrefs): unexpected reloc RelocType(2048) for dynamic symbol OBJC_CLASS_$_NSRunningApplication
gioui.org/app/internal/window(__DATA/__objc_classrefs): unexpected reloc RelocType(2048) for dynamic symbol OBJC_CLASS_$_NSApplication
gioui.org/app/internal/window(__DATA/__objc_classrefs): unexpected reloc RelocType(2048) for dynamic symbol OBJC_CLASS_$_NSMenuItem
gioui.org/app/internal/window(__DATA/__objc_classrefs): unexpected reloc RelocType(2048) for dynamic symbol OBJC_CLASS_$_NSMenu
gioui.org/app/internal/window(__DATA/__objc_classrefs): unexpected reloc RelocType(2048) for dynamic symbol OBJC_CLASS_$_NSWindow
gioui.org/app/internal/window(__DATA/__objc_classrefs): unexpected reloc RelocType(2048) for dynamic symbol OBJC_CLASS_$_NSString
gioui.org/app/internal/window(__DATA/__cfstring): unexpected reloc RelocType(2048) for dynamic symbol __CFConstantStringClassReference
gioui.org/app/internal/window(__DATA/__cfstring): unexpected reloc RelocType(2048) for dynamic symbol __CFConstantStringClassReference
gioui.org/app/internal/window(__DATA/__cfstring): unexpected reloc RelocType(2048) for dynamic symbol __CFConstantStringClassReference
gioui.org/app/internal/window(__DATA/__cfstring): unexpected reloc RelocType(2048) for dynamic symbol __CFConstantStringClassReference
/Users/elias/go-tip/pkg/tool/darwin_amd64/link: too many errors
```


android/*, buildmode=c-shared:
```
$ GOFLAGS= go run gioui.org/cmd/gogio -target android -linkmode internal gioui.org/example/kitchen
gogio: go build -ldflags=-w -s -X gioui.org/app/internal/log.appID=org.gioui.kitchen -linkmode=internal -buildmode=c-shared -o /tmp/gogio-146873352/jni/x86_64/libgio.so gioui.org/example/kitchen failed: # gioui.org/example/kitchen
/home/elias/dev/go-tip/pkg/tool/linux_amd64/link: internal linking requested but external linking required: android/amd64 requires external linking

```

With

```
diff --git src/cmd/internal/sys/supported.go src/cmd/internal/sys/supported.go
index c27b3b986d..72f6707b36 100644
--- src/cmd/internal/sys/supported.go
+++ src/cmd/internal/sys/supported.go
@@ -35,9 +35,9 @@ func MSanSupported(goos, goarch string) bool {
 func MustLinkExternal(goos, goarch string) bool {
        switch goos {
        case "android":
-               if goarch != "arm64" {
-                       return true
-               }
+               //if goarch != "arm64" {
+               //return true
+               //}
        case "darwin":
                if goarch == "arm64" {
                        return true
diff --git src/cmd/link/internal/ld/config.go src/cmd/link/internal/ld/config.go
index 2373b500e3..31b5b94f3a 100644
--- src/cmd/link/internal/ld/config.go
+++ src/cmd/link/internal/ld/config.go
@@ -189,9 +189,9 @@ func mustLinkExternal(ctxt *Link) (res bool, reason string) {
        if iscgo && ctxt.Arch.InFamily(sys.MIPS64, sys.MIPS, sys.PPC64) {
                return true, objabi.GOARCH + " does not support internal cgo"
        }
-       if iscgo && objabi.GOOS == "android" {
+       /*if iscgo && objabi.GOOS == "android" {
                return true, objabi.GOOS + " does not support internal cgo"
-       }
+       }*/
 
        // When the race flag is set, the LLVM tsan relocatable file is linked
        // into the final binary, which means external linking is required because
@@ -205,7 +205,7 @@ func mustLinkExternal(ctxt *Link) (res bool, reason string) {
        case BuildModeCArchive:
                return true, "buildmode=c-archive"
        case BuildModeCShared:
-               return true, "buildmode=c-shared"
+               //return true, "buildmode=c-shared"
        case BuildModePIE:
                switch objabi.GOOS + "/" + objabi.GOARCH {
                case "linux/amd64", "linux/arm64", "android/arm64":
```

the `gogio -target android` build completes, but the resulting apk fails at runtime with:

```
java.lang.UnsatisfiedLinkError: dlopen failed: "/data/app/org.gioui.kitchen-xs1nOo55BAjSrffNWB8gBQ==/lib/x86_64/libgio.so" has unexpected e_type: 2
```
(e_type 2 is ET_EXEC, the loader expects ET_DYN)


darwin/arm64 (iOS):
```
$ go run gioui.org/cmd/gogio -target ios -linkmode internal gioui.org/example/kitchen
gogio: go build -ldflags=-s -w -X gioui.org/app/internal/log.appID=org.gioui.kitchen -linkmode=internal -buildmode=c-archive -o /var/folders/_7/lnt35k555hl2bs7fjygkhgx00000gp/T/gogio-897284295/gio-arm64 -tags ios gioui.org/example/kitchen failed: # gioui.org/example/kitchen
/Users/elias/go-tip/pkg/tool/darwin_amd64/link: internal linking requested but external linking required: darwin/arm64 requires external linking
```

With
```
$ git diff
diff --git a/src/cmd/internal/sys/supported.go b/src/cmd/internal/sys/supported.go
index c27b3b986d..5ffc088358 100644
--- a/src/cmd/internal/sys/supported.go
+++ b/src/cmd/internal/sys/supported.go
@@ -39,9 +39,9 @@ func MustLinkExternal(goos, goarch string) bool {
                        return true
                }
        case "darwin":
-               if goarch == "arm64" {
+               /*if goarch == "arm64" {
                        return true
-               }
+               }*/
        }
        return false
 }
diff --git a/src/cmd/link/internal/ld/config.go b/src/cmd/link/internal/ld/config.go
index 2373b500e3..c972961c4b 100644
--- a/src/cmd/link/internal/ld/config.go
+++ b/src/cmd/link/internal/ld/config.go
@@ -203,7 +203,7 @@ func mustLinkExternal(ctxt *Link) (res bool, reason string) {
        // Some build modes require work the internal linker cannot do (yet).
        switch ctxt.BuildMode {
        case BuildModeCArchive:
-               return true, "buildmode=c-archive"
+               //return true, "buildmode=c-archive"
        case BuildModeCShared:
                return true, "buildmode=c-shared"
        case BuildModePIE:
```

```
$ go run gioui.org/cmd/gogio -target ios -linkmode internal gioui.org/example/kitchen
gogio: go build -ldflags=-s -w -X gioui.org/app/internal/log.appID=org.gioui.kitchen -linkmode=internal -buildmode=c-archive -o /var/folders/_7/lnt35k555hl2bs7fjygkhgx00000gp/T/gogio-032492589/gio-arm64 -tags ios gioui.org/example/kitchen failed: # gioui.org/example/kitchen
loadmacho: /Users/elias/Library/Caches/go-build/b5/b5e636c59e2b0dce3881e4c1dfe5f49890fd7ffc8dabfa89e4c44faee895a24e-d(_x001.o): mach-o arm64 unimplemented
loadmacho: /Users/elias/Library/Caches/go-build/b5/b5e636c59e2b0dce3881e4c1dfe5f49890fd7ffc8dabfa89e4c44faee895a24e-d(_x002.o): mach-o arm64 unimplemented
loadmacho: /Users/elias/Library/Caches/go-build/b5/b5e636c59e2b0dce3881e4c1dfe5f49890fd7ffc8dabfa89e4c44faee895a24e-d(_x003.o): mach-o arm64 unimplemented
loadmacho: /Users/elias/Library/Caches/go-build/a1/a1b18baa12e8cfcff9d2149878989bf8d3212abe425e72aab827c249f9c1f9aa-d(_x001.o): mach-o arm64 unimplemented
loadmacho: /Users/elias/Library/Caches/go-build/a1/a1b18baa12e8cfcff9d2149878989bf8d3212abe425e72aab827c249f9c1f9aa-d(_x002.o): mach-o arm64 unimplemented
loadmacho: /Users/elias/Library/Caches/go-build/a1/a1b18baa12e8cfcff9d2149878989bf8d3212abe425e72aab827c249f9c1f9aa-d(_x003.o): mach-o arm64 unimplemented
loadmacho: /Users/elias/Library/Caches/go-build/a1/a1b18baa12e8cfcff9d2149878989bf8d3212abe425e72aab827c249f9c1f9aa-d(_x004.o): mach-o arm64 unimplemented
loadmacho: /Users/elias/Library/Caches/go-build/a1/a1b18baa12e8cfcff9d2149878989bf8d3212abe425e72aab827c249f9c1f9aa-d(_x005.o): mach-o arm64 unimplemented
loadmacho: /Users/elias/Library/Caches/go-build/a1/a1b18baa12e8cfcff9d2149878989bf8d3212abe425e72aab827c249f9c1f9aa-d(_x006.o): mach-o arm64 unimplemented
loadmacho: /Users/elias/Library/Caches/go-build/bf/bfc3cd3cbc11f70eee4813613929853ddba3f7efa3b8e6c59544b47c17e10f16-d(_x001.o): mach-o arm64 unimplemented
loadmacho: /Users/elias/Library/Caches/go-build/bf/bfc3cd3cbc11f70eee4813613929853ddba3f7efa3b8e6c59544b47c17e10f16-d(_x002.o): mach-o arm64 unimplemented
loadmacho: /Users/elias/Library/Caches/go-build/bf/bfc3cd3cbc11f70eee4813613929853ddba3f7efa3b8e6c59544b47c17e10f16-d(_x003.o): mach-o arm64 unimplemented
loadmacho: /Users/elias/Library/Caches/go-build/6f/6f1a0820507421e19028b78d9efe163c52175627d10178d0968d09fd3d95379d-d(_x001.o): mach-o arm64 unimplemented
loadmacho: /Users/elias/Library/Caches/go-build/6f/6f1a0820507421e19028b78d9efe163c52175627d10178d0968d09fd3d95379d-d(_x002.o): mach-o arm64 unimplemented
loadmacho: /Users/elias/Library/Caches/go-build/6f/6f1a0820507421e19028b78d9efe163c52175627d10178d0968d09fd3d95379d-d(_x003.o): mach-o arm64 unimplemented
loadmacho: /Users/elias/Library/Caches/go-build/6f/6f1a0820507421e19028b78d9efe163c52175627d10178d0968d09fd3d95379d-d(_x004.o): mach-o arm64 unimplemented
loadmacho: /Users/elias/Library/Caches/go-build/6f/6f1a0820507421e19028b78d9efe163c52175627d10178d0968d09fd3d95379d-d(_x005.o): mach-o arm64 unimplemented
loadmacho: /Users/elias/Library/Caches/go-build/6f/6f1a0820507421e19028b78d9efe163c52175627d10178d0968d09fd3d95379d-d(_x006.o): mach-o arm64 unimplemented
loadmacho: /Users/elias/Library/Caches/go-build/6f/6f1a0820507421e19028b78d9efe163c52175627d10178d0968d09fd3d95379d-d(_x007.o): mach-o arm64 unimplemented
loadmacho: /Users/elias/Library/Caches/go-build/6f/6f1a0820507421e19028b78d9efe163c52175627d10178d0968d09fd3d95379d-d(_x008.o): mach-o arm64 unimplemented
loadmacho: /Users/elias/Library/Caches/go-build/6f/6f1a0820507421e19028b78d9efe163c52175627d10178d0968d09fd3d95379d-d(_x009.o): mach-o arm64 unimplemented
/Users/elias/go-tip/pkg/tool/darwin_amd64/link: too many errors
```
### What did you expect to see?
A running program.


### What did you see instead?
Link errors.

By itself, `-linkmode=internal` doesn't seem important when using Cgo, but in combination with https://github.com/golang/go/issues/38917 internal linking is a crucial step towards dropping the native toolchain altogether.