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

View as plain text