Black Lives Matter. Support the Equal Justice Initiative.

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

Documentation: cmd/link/internal/ld

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

View as plain text