github.com/bir3/gocompiler@v0.3.205/src/cmd/link/internal/ld/config.go (about)

     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  	"github.com/bir3/gocompiler/src/cmd/internal/sys"
     9  	"fmt"
    10  	"github.com/bir3/gocompiler/src/internal/buildcfg"
    11  	"github.com/bir3/gocompiler/src/internal/platform"
    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, buildcfg.GOOS, buildcfg.GOARCH)
    33  	}
    34  	switch s {
    35  	default:
    36  		return fmt.Errorf("invalid buildmode: %q", s)
    37  	case "exe":
    38  		switch buildcfg.GOOS + "/" + buildcfg.GOARCH {
    39  		case "darwin/arm64", "windows/arm", "windows/arm64": // On these platforms, everything is PIE
    40  			*mode = BuildModePIE
    41  		default:
    42  			*mode = BuildModeExe
    43  		}
    44  	case "pie":
    45  		switch buildcfg.GOOS {
    46  		case "aix", "android", "linux", "windows", "darwin", "ios":
    47  		case "freebsd":
    48  			switch buildcfg.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 buildcfg.GOOS {
    59  		case "aix", "darwin", "ios", "linux":
    60  		case "freebsd":
    61  			switch buildcfg.GOARCH {
    62  			case "amd64":
    63  			default:
    64  				return badmode()
    65  			}
    66  		case "windows":
    67  			switch buildcfg.GOARCH {
    68  			case "amd64", "386", "arm", "arm64":
    69  			default:
    70  				return badmode()
    71  			}
    72  		default:
    73  			return badmode()
    74  		}
    75  		*mode = BuildModeCArchive
    76  	case "c-shared":
    77  		switch buildcfg.GOARCH {
    78  		case "386", "amd64", "arm", "arm64", "ppc64le", "riscv64", "s390x":
    79  		default:
    80  			return badmode()
    81  		}
    82  		*mode = BuildModeCShared
    83  	case "shared":
    84  		switch buildcfg.GOOS {
    85  		case "linux":
    86  			switch buildcfg.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 buildcfg.GOOS {
    97  		case "linux":
    98  			switch buildcfg.GOARCH {
    99  			case "386", "amd64", "arm", "arm64", "s390x", "ppc64le":
   100  			default:
   101  				return badmode()
   102  			}
   103  		case "darwin":
   104  			switch buildcfg.GOARCH {
   105  			case "amd64", "arm64":
   106  			default:
   107  				return badmode()
   108  			}
   109  		case "freebsd":
   110  			switch buildcfg.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  				ctxt.Logf("external linking is forced by: %s\n", reason)
   185  			}
   186  		}()
   187  	}
   188  
   189  	if platform.MustLinkExternal(buildcfg.GOOS, buildcfg.GOARCH) {
   190  		return true, fmt.Sprintf("%s/%s requires external linking", buildcfg.GOOS, buildcfg.GOARCH)
   191  	}
   192  
   193  	if *flagMsan {
   194  		return true, "msan"
   195  	}
   196  
   197  	if *flagAsan {
   198  		return true, "asan"
   199  	}
   200  
   201  	// Internally linking cgo is incomplete on some architectures.
   202  	// https://golang.org/issue/14449
   203  	if iscgo && ctxt.Arch.InFamily(sys.Loong64, sys.MIPS64, sys.MIPS, sys.RISCV64) {
   204  		return true, buildcfg.GOARCH + " does not support internal cgo"
   205  	}
   206  	if iscgo && (buildcfg.GOOS == "android" || buildcfg.GOOS == "dragonfly") {
   207  		// It seems that on Dragonfly thread local storage is
   208  		// set up by the dynamic linker, so internal cgo linking
   209  		// doesn't work. Test case is "go test runtime/cgo".
   210  		return true, buildcfg.GOOS + " does not support internal cgo"
   211  	}
   212  	if iscgo && buildcfg.GOOS == "windows" && buildcfg.GOARCH == "arm64" {
   213  		// windows/arm64 internal linking is not implemented.
   214  		return true, buildcfg.GOOS + "/" + buildcfg.GOARCH + " does not support internal cgo"
   215  	}
   216  	if iscgo && ctxt.Arch == sys.ArchPPC64 {
   217  		// Big Endian PPC64 cgo internal linking is not implemented for aix or linux.
   218  		return true, buildcfg.GOOS + " does not support internal cgo"
   219  	}
   220  
   221  	// Some build modes require work the internal linker cannot do (yet).
   222  	switch ctxt.BuildMode {
   223  	case BuildModeCArchive:
   224  		return true, "buildmode=c-archive"
   225  	case BuildModeCShared:
   226  		return true, "buildmode=c-shared"
   227  	case BuildModePIE:
   228  		switch buildcfg.GOOS + "/" + buildcfg.GOARCH {
   229  		case "android/arm64":
   230  		case "linux/amd64", "linux/arm64", "linux/ppc64le":
   231  		case "windows/386", "windows/amd64", "windows/arm", "windows/arm64":
   232  		case "darwin/amd64", "darwin/arm64":
   233  		default:
   234  			// Internal linking does not support TLS_IE.
   235  			return true, "buildmode=pie"
   236  		}
   237  	case BuildModePlugin:
   238  		return true, "buildmode=plugin"
   239  	case BuildModeShared:
   240  		return true, "buildmode=shared"
   241  	}
   242  	if ctxt.linkShared {
   243  		return true, "dynamically linking with a shared library"
   244  	}
   245  
   246  	if unknownObjFormat {
   247  		return true, "some input objects have an unrecognized file format"
   248  	}
   249  
   250  	if len(dynimportfail) > 0 {
   251  		// This error means that we were unable to generate
   252  		// the _cgo_import.go file for some packages.
   253  		// This typically means that there are some dependencies
   254  		// that the cgo tool could not figure out.
   255  		// See issue #52863.
   256  		return true, fmt.Sprintf("some packages could not be built to support internal linking (%v)", dynimportfail)
   257  	}
   258  
   259  	return false, ""
   260  }
   261  
   262  // determineLinkMode sets ctxt.LinkMode.
   263  //
   264  // It is called after flags are processed and inputs are processed,
   265  // so the ctxt.LinkMode variable has an initial value from the -linkmode
   266  // flag and the iscgo, externalobj, and unknownObjFormat variables are set.
   267  func determineLinkMode(ctxt *Link) {
   268  	extNeeded, extReason := mustLinkExternal(ctxt)
   269  	via := ""
   270  
   271  	if ctxt.LinkMode == LinkAuto {
   272  		// The environment variable GO_EXTLINK_ENABLED controls the
   273  		// default value of -linkmode. If it is not set when the
   274  		// linker is called we take the value it was set to when
   275  		// cmd/link was compiled. (See make.bash.)
   276  		switch buildcfg.Getgoextlinkenabled() {
   277  		case "0":
   278  			ctxt.LinkMode = LinkInternal
   279  			via = "via GO_EXTLINK_ENABLED "
   280  		case "1":
   281  			ctxt.LinkMode = LinkExternal
   282  			via = "via GO_EXTLINK_ENABLED "
   283  		default:
   284  			preferExternal := len(preferlinkext) != 0
   285  			if preferExternal && ctxt.Debugvlog > 0 {
   286  				ctxt.Logf("external linking prefer list is %v\n", preferlinkext)
   287  			}
   288  			if extNeeded || (iscgo && (externalobj || preferExternal)) {
   289  				ctxt.LinkMode = LinkExternal
   290  			} else {
   291  				ctxt.LinkMode = LinkInternal
   292  			}
   293  		}
   294  	}
   295  
   296  	switch ctxt.LinkMode {
   297  	case LinkInternal:
   298  		if extNeeded {
   299  			Exitf("internal linking requested %sbut external linking required: %s", via, extReason)
   300  		}
   301  	case LinkExternal:
   302  		switch {
   303  		case buildcfg.GOARCH == "ppc64" && buildcfg.GOOS != "aix":
   304  			Exitf("external linking not supported for %s/ppc64", buildcfg.GOOS)
   305  		}
   306  	}
   307  }