...

Source file src/pkg/cmd/link/internal/ld/config.go

     1	// Copyright 2016 The Go Authors. All rights reserved.
     2	// Use of this source code is governed by a BSD-style
     3	// license that can be found in the LICENSE file.
     4	
     5	package ld
     6	
     7	import (
     8		"cmd/internal/objabi"
     9		"cmd/internal/sys"
    10		"fmt"
    11		"log"
    12	)
    13	
    14	// A BuildMode indicates the sort of object we are building.
    15	//
    16	// Possible build modes are the same as those for the -buildmode flag
    17	// in cmd/go, and are documented in 'go help buildmode'.
    18	type BuildMode uint8
    19	
    20	const (
    21		BuildModeUnset BuildMode = iota
    22		BuildModeExe
    23		BuildModePIE
    24		BuildModeCArchive
    25		BuildModeCShared
    26		BuildModeShared
    27		BuildModePlugin
    28	)
    29	
    30	func (mode *BuildMode) Set(s string) error {
    31		badmode := func() error {
    32			return fmt.Errorf("buildmode %s not supported on %s/%s", s, objabi.GOOS, objabi.GOARCH)
    33		}
    34		switch s {
    35		default:
    36			return fmt.Errorf("invalid buildmode: %q", s)
    37		case "exe":
    38			*mode = BuildModeExe
    39		case "pie":
    40			switch objabi.GOOS {
    41			case "aix", "android", "linux":
    42			case "darwin", "freebsd":
    43				switch objabi.GOARCH {
    44				case "amd64":
    45				default:
    46					return badmode()
    47				}
    48			default:
    49				return badmode()
    50			}
    51			*mode = BuildModePIE
    52		case "c-archive":
    53			switch objabi.GOOS {
    54			case "aix", "darwin", "linux":
    55			case "freebsd":
    56				switch objabi.GOARCH {
    57				case "amd64":
    58				default:
    59					return badmode()
    60				}
    61			case "windows":
    62				switch objabi.GOARCH {
    63				case "amd64", "386", "arm":
    64				default:
    65					return badmode()
    66				}
    67			default:
    68				return badmode()
    69			}
    70			*mode = BuildModeCArchive
    71		case "c-shared":
    72			switch objabi.GOARCH {
    73			case "386", "amd64", "arm", "arm64", "ppc64le", "s390x":
    74			default:
    75				return badmode()
    76			}
    77			*mode = BuildModeCShared
    78		case "shared":
    79			switch objabi.GOOS {
    80			case "linux":
    81				switch objabi.GOARCH {
    82				case "386", "amd64", "arm", "arm64", "ppc64le", "s390x":
    83				default:
    84					return badmode()
    85				}
    86			default:
    87				return badmode()
    88			}
    89			*mode = BuildModeShared
    90		case "plugin":
    91			switch objabi.GOOS {
    92			case "linux":
    93				switch objabi.GOARCH {
    94				case "386", "amd64", "arm", "arm64", "s390x", "ppc64le":
    95				default:
    96					return badmode()
    97				}
    98			case "darwin":
    99				switch objabi.GOARCH {
   100				case "amd64":
   101				default:
   102					return badmode()
   103				}
   104			default:
   105				return badmode()
   106			}
   107			*mode = BuildModePlugin
   108		}
   109		return nil
   110	}
   111	
   112	func (mode *BuildMode) String() string {
   113		switch *mode {
   114		case BuildModeUnset:
   115			return "" // avoid showing a default in usage message
   116		case BuildModeExe:
   117			return "exe"
   118		case BuildModePIE:
   119			return "pie"
   120		case BuildModeCArchive:
   121			return "c-archive"
   122		case BuildModeCShared:
   123			return "c-shared"
   124		case BuildModeShared:
   125			return "shared"
   126		case BuildModePlugin:
   127			return "plugin"
   128		}
   129		return fmt.Sprintf("BuildMode(%d)", uint8(*mode))
   130	}
   131	
   132	// LinkMode indicates whether an external linker is used for the final link.
   133	type LinkMode uint8
   134	
   135	const (
   136		LinkAuto LinkMode = iota
   137		LinkInternal
   138		LinkExternal
   139	)
   140	
   141	func (mode *LinkMode) Set(s string) error {
   142		switch s {
   143		default:
   144			return fmt.Errorf("invalid linkmode: %q", s)
   145		case "auto":
   146			*mode = LinkAuto
   147		case "internal":
   148			*mode = LinkInternal
   149		case "external":
   150			*mode = LinkExternal
   151		}
   152		return nil
   153	}
   154	
   155	func (mode *LinkMode) String() string {
   156		switch *mode {
   157		case LinkAuto:
   158			return "auto"
   159		case LinkInternal:
   160			return "internal"
   161		case LinkExternal:
   162			return "external"
   163		}
   164		return fmt.Sprintf("LinkMode(%d)", uint8(*mode))
   165	}
   166	
   167	// mustLinkExternal reports whether the program being linked requires
   168	// the external linker be used to complete the link.
   169	func mustLinkExternal(ctxt *Link) (res bool, reason string) {
   170		if ctxt.Debugvlog > 1 {
   171			defer func() {
   172				if res {
   173					log.Printf("external linking is forced by: %s\n", reason)
   174				}
   175			}()
   176		}
   177	
   178		if sys.MustLinkExternal(objabi.GOOS, objabi.GOARCH) {
   179			return true, fmt.Sprintf("%s/%s requires external linking", objabi.GOOS, objabi.GOARCH)
   180		}
   181	
   182		if *flagMsan {
   183			return true, "msan"
   184		}
   185	
   186		// Internally linking cgo is incomplete on some architectures.
   187		// https://golang.org/issue/14449
   188		// https://golang.org/issue/21961
   189		if iscgo && ctxt.Arch.InFamily(sys.MIPS64, sys.MIPS, sys.PPC64) {
   190			return true, objabi.GOARCH + " does not support internal cgo"
   191		}
   192	
   193		// When the race flag is set, the LLVM tsan relocatable file is linked
   194		// into the final binary, which means external linking is required because
   195		// internal linking does not support it.
   196		if *flagRace && ctxt.Arch.InFamily(sys.PPC64) {
   197			return true, "race on " + objabi.GOARCH
   198		}
   199	
   200		// Some build modes require work the internal linker cannot do (yet).
   201		switch ctxt.BuildMode {
   202		case BuildModeCArchive:
   203			return true, "buildmode=c-archive"
   204		case BuildModeCShared:
   205			return true, "buildmode=c-shared"
   206		case BuildModePIE:
   207			switch objabi.GOOS + "/" + objabi.GOARCH {
   208			case "linux/amd64", "linux/arm64":
   209			default:
   210				// Internal linking does not support TLS_IE.
   211				return true, "buildmode=pie"
   212			}
   213		case BuildModePlugin:
   214			return true, "buildmode=plugin"
   215		case BuildModeShared:
   216			return true, "buildmode=shared"
   217		}
   218		if ctxt.linkShared {
   219			return true, "dynamically linking with a shared library"
   220		}
   221	
   222		return false, ""
   223	}
   224	
   225	// determineLinkMode sets ctxt.LinkMode.
   226	//
   227	// It is called after flags are processed and inputs are processed,
   228	// so the ctxt.LinkMode variable has an initial value from the -linkmode
   229	// flag and the iscgo externalobj variables are set.
   230	func determineLinkMode(ctxt *Link) {
   231		switch ctxt.LinkMode {
   232		case LinkAuto:
   233			// The environment variable GO_EXTLINK_ENABLED controls the
   234			// default value of -linkmode. If it is not set when the
   235			// linker is called we take the value it was set to when
   236			// cmd/link was compiled. (See make.bash.)
   237			switch objabi.Getgoextlinkenabled() {
   238			case "0":
   239				if needed, reason := mustLinkExternal(ctxt); needed {
   240					Exitf("internal linking requested via GO_EXTLINK_ENABLED, but external linking required: %s", reason)
   241				}
   242				ctxt.LinkMode = LinkInternal
   243			case "1":
   244				if objabi.GOARCH == "ppc64" && objabi.GOOS != "aix" {
   245					Exitf("external linking requested via GO_EXTLINK_ENABLED but not supported for %s/ppc64", objabi.GOOS)
   246				}
   247				ctxt.LinkMode = LinkExternal
   248			default:
   249				if needed, _ := mustLinkExternal(ctxt); needed {
   250					ctxt.LinkMode = LinkExternal
   251				} else if iscgo && externalobj {
   252					ctxt.LinkMode = LinkExternal
   253				} else if ctxt.BuildMode == BuildModePIE {
   254					ctxt.LinkMode = LinkExternal
   255				} else {
   256					ctxt.LinkMode = LinkInternal
   257				}
   258				if objabi.GOARCH == "ppc64" && objabi.GOOS != "aix" && ctxt.LinkMode == LinkExternal {
   259					Exitf("external linking is not supported for %s/ppc64", objabi.GOOS)
   260				}
   261			}
   262		case LinkInternal:
   263			if needed, reason := mustLinkExternal(ctxt); needed {
   264				Exitf("internal linking requested but external linking required: %s", reason)
   265			}
   266		case LinkExternal:
   267			if objabi.GOARCH == "ppc64" && objabi.GOOS != "aix" {
   268				Exitf("external linking not supported for %s/ppc64", objabi.GOOS)
   269			}
   270		}
   271	}
   272	

View as plain text