diff --git a/src/cmd/go/internal/load/pkg.go b/src/cmd/go/internal/load/pkg.go index db2434260f..f73b79d089 100644 --- a/src/cmd/go/internal/load/pkg.go +++ b/src/cmd/go/internal/load/pkg.go @@ -1948,6 +1948,10 @@ func LinkerDeps(p *Package) []string { // externalLinkingForced reports whether external linking is being // forced even for programs that do not use cgo. func externalLinkingForced(p *Package) bool { + if !cfg.BuildContext.CgoEnabled { + return false + } + // Some targets must use external linking even inside GOROOT. switch cfg.BuildContext.GOOS { case "android": @@ -1960,9 +1964,6 @@ func externalLinkingForced(p *Package) bool { } } - if !cfg.BuildContext.CgoEnabled { - return false - } // Currently build modes c-shared, pie (on systems that do not // support PIE with internal linking mode (currently all // systems: issue #18968)), plugin, and -linkshared force diff --git a/src/cmd/internal/sys/supported.go b/src/cmd/internal/sys/supported.go index 07be998035..c433a872be 100644 --- a/src/cmd/internal/sys/supported.go +++ b/src/cmd/internal/sys/supported.go @@ -118,7 +118,7 @@ func BuildModeSupported(compiler, buildmode, goos, goarch string) bool { func InternalLinkPIESupported(goos, goarch string) bool { switch goos + "/" + goarch { - case "darwin/amd64", + case "darwin/amd64", "darwin/arm64", "linux/amd64", "linux/arm64", "android/arm64", "windows-amd64", "windows-386", "windows-arm": diff --git a/src/cmd/link/internal/arm64/asm.go b/src/cmd/link/internal/arm64/asm.go index 1d2aa591d7..7bf41c93a6 100644 --- a/src/cmd/link/internal/arm64/asm.go +++ b/src/cmd/link/internal/arm64/asm.go @@ -219,6 +219,15 @@ func adddynrel(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s loade // External linker will do this relocation. return true } + if target.IsDarwin() { // XXX why we don't need this for ELF? + // Internal linking. + // Build a PLT entry and change the relocation target to that entry. + addpltsym(target, ldr, syms, targ) + su := ldr.MakeSymbolUpdater(s) + su.SetRelocSym(rIdx, syms.PLT) + su.SetRelocAdd(rIdx, int64(ldr.SymPlt(targ))) + return true + } case objabi.R_ADDR: if ldr.SymType(s) == sym.STEXT && target.IsElf() { @@ -313,6 +322,18 @@ func adddynrel(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s loade // (e.g. go version). return true } + + if target.IsDarwin() { + // Mach-O relocations are a royal pain to lay out. + // They use a compact stateful bytecode representation. + // Here we record what are needed and encode them later. + ld.MachoAddRebase(s, int64(r.Off())) + // Not mark r done here. So we still apply it statically, + // so in the file content we'll also have the right offset + // to the relocation target. So it can be examined statically + // (e.g. go version). + return true + } } return false } @@ -812,6 +833,34 @@ func addpltsym(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s loade rela.AddUint64(target.Arch, 0) ldr.SetPlt(s, int32(plt.Size()-16)) + } else if target.IsDarwin() { + ld.AddGotSym(target, ldr, syms, s, 0) + + sDynid := ldr.SymDynid(s) + lep := ldr.MakeSymbolUpdater(syms.LinkEditPLT) + lep.AddUint32(target.Arch, uint32(sDynid)) + + plt := ldr.MakeSymbolUpdater(syms.PLT) + ldr.SetPlt(s, int32(plt.Size())) + + // adrp x16, GOT + plt.AddUint32(target.Arch, 0x90000010) + r, _ := plt.AddRel(objabi.R_ARM64_GOT) + r.SetOff(int32(plt.Size() - 4)) + r.SetSiz(4) + r.SetSym(syms.GOT) + r.SetAdd(int64(ldr.SymGot(s))) + + // ldr x17, [x16, ] + plt.AddUint32(target.Arch, 0xf9400211) + r, _ = plt.AddRel(objabi.R_ARM64_GOT) + r.SetOff(int32(plt.Size() - 4)) + r.SetSiz(4) + r.SetSym(syms.GOT) + r.SetAdd(int64(ldr.SymGot(s))) + + // br x17 + plt.AddUint32(target.Arch, 0xd61f0220) } else { ldr.Errorf(s, "addpltsym: unsupported binary format") } diff --git a/src/cmd/link/internal/arm64/obj.go b/src/cmd/link/internal/arm64/obj.go index a980cfee52..ab3dfd99f7 100644 --- a/src/cmd/link/internal/arm64/obj.go +++ b/src/cmd/link/internal/arm64/obj.go @@ -102,7 +102,7 @@ func archinit(ctxt *ld.Link) { case objabi.Hdarwin: /* apple MACH */ ld.HEADR = ld.INITIAL_MACHO_HEADR if *ld.FlagTextAddr == -1 { - *ld.FlagTextAddr = 4096 + int64(ld.HEADR) + *ld.FlagTextAddr = 1<<32 + int64(ld.HEADR) } if *ld.FlagRound == -1 { *ld.FlagRound = 16384 // 16K page alignment diff --git a/src/cmd/link/internal/ld/config.go b/src/cmd/link/internal/ld/config.go index c680d11c1d..f55e4fc027 100644 --- a/src/cmd/link/internal/ld/config.go +++ b/src/cmd/link/internal/ld/config.go @@ -35,6 +35,10 @@ func (mode *BuildMode) Set(s string) error { default: return fmt.Errorf("invalid buildmode: %q", s) case "exe": + if objabi.GOOS == "darwin" && objabi.GOARCH == "arm64" { + *mode = BuildModePIE // On darwin/arm64 everything is PIE. + break + } *mode = BuildModeExe case "pie": switch objabi.GOOS { @@ -187,7 +191,7 @@ func mustLinkExternal(ctxt *Link) (res bool, reason string) { }() } - if sys.MustLinkExternal(objabi.GOOS, objabi.GOARCH) { + if sys.MustLinkExternal(objabi.GOOS, objabi.GOARCH) && !(objabi.GOOS == "darwin" && objabi.GOARCH == "arm64") { // XXX allow internal linking for darwin/arm64 but not change the default return true, fmt.Sprintf("%s/%s requires external linking", objabi.GOOS, objabi.GOARCH) } @@ -204,6 +208,9 @@ func mustLinkExternal(ctxt *Link) (res bool, reason string) { if iscgo && objabi.GOOS == "android" { return true, objabi.GOOS + " does not support internal cgo" } + if iscgo && objabi.GOOS == "darwin" && objabi.GOARCH == "arm64" { + return true, objabi.GOOS + "/" + objabi.GOARCH + " 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 @@ -222,7 +229,7 @@ func mustLinkExternal(ctxt *Link) (res bool, reason string) { switch objabi.GOOS + "/" + objabi.GOARCH { case "linux/amd64", "linux/arm64", "android/arm64": case "windows/386", "windows/amd64", "windows/arm": - case "darwin/amd64": + case "darwin/amd64", "darwin/arm64": default: // Internal linking does not support TLS_IE. return true, "buildmode=pie" @@ -263,6 +270,8 @@ func determineLinkMode(ctxt *Link) { default: if extNeeded || (iscgo && externalobj) { ctxt.LinkMode = LinkExternal + } else if ctxt.IsDarwin() && ctxt.IsARM64() { + ctxt.LinkMode = LinkExternal // default to external linking for now } else { ctxt.LinkMode = LinkInternal } diff --git a/src/cmd/link/internal/ld/macho.go b/src/cmd/link/internal/ld/macho.go index a19a4afd9a..155769c48f 100644 --- a/src/cmd/link/internal/ld/macho.go +++ b/src/cmd/link/internal/ld/macho.go @@ -751,11 +751,9 @@ func asmbMacho(ctxt *Link) { ml.data[2+32+1] = uint32(Entryvalue(ctxt) >> 32) case sys.ARM64: - ml := newMachoLoad(ctxt.Arch, LC_UNIXTHREAD, 68+2) - ml.data[0] = 6 /* thread type */ - ml.data[1] = 68 /* word count */ - ml.data[2+64] = uint32(Entryvalue(ctxt)) /* start pc */ - ml.data[2+64+1] = uint32(Entryvalue(ctxt) >> 32) + ml := newMachoLoad(ctxt.Arch, LC_MAIN, 4) + ml.data[0] = uint32(uint64(Entryvalue(ctxt)) - (Segtext.Vaddr - uint64(HEADR))) + ml.data[1] = uint32((uint64(Entryvalue(ctxt)) - (Segtext.Vaddr - uint64(HEADR))) >> 32) } } diff --git a/src/cmd/link/internal/ld/main.go b/src/cmd/link/internal/ld/main.go index 50c643748c..3f7370b636 100644 --- a/src/cmd/link/internal/ld/main.go +++ b/src/cmd/link/internal/ld/main.go @@ -169,7 +169,7 @@ func Main(arch *sys.Arch, theArch Arch) { startProfile() if ctxt.BuildMode == BuildModeUnset { - ctxt.BuildMode = BuildModeExe + ctxt.BuildMode.Set("exe") } if ctxt.BuildMode != BuildModeShared && flag.NArg() != 1 { diff --git a/src/runtime/rt0_darwin_arm64.s b/src/runtime/rt0_darwin_arm64.s index e3972f4924..0040361215 100644 --- a/src/runtime/rt0_darwin_arm64.s +++ b/src/runtime/rt0_darwin_arm64.s @@ -4,11 +4,14 @@ #include "textflag.h" -// No need for _rt0_arm64_darwin as darwin/arm64 only -// supports external linking. TEXT _rt0_arm64_darwin(SB),NOSPLIT|NOFRAME,$0 - MOVD $42, R0 - BL libc_exit(SB) + MOVD $runtime·rt0_go(SB), R2 + BL (R2) +exit: + MOVD $0, R0 + MOVD $1, R16 // sys_exit + SVC $0x80 + B exit // When linking with -buildmode=c-archive or -buildmode=c-shared, // this symbol is called from a global initialization function. @@ -86,11 +89,6 @@ GLOBL _rt0_arm64_darwin_lib_argc<>(SB),NOPTR, $8 DATA _rt0_arm64_darwin_lib_argv<>(SB)/8, $0 GLOBL _rt0_arm64_darwin_lib_argv<>(SB),NOPTR, $8 +// external linking entry point. TEXT main(SB),NOSPLIT|NOFRAME,$0 - MOVD $runtime·rt0_go(SB), R2 - BL (R2) -exit: - MOVD $0, R0 - MOVD $1, R16 // sys_exit - SVC $0x80 - B exit + JMP _rt0_arm64_darwin(SB)