github.com/gagliardetto/golang-go@v0.0.0-20201020153340-53909ea70814/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/gagliardetto/golang-go/cmd/internal/objabi"
     9  	"github.com/gagliardetto/golang-go/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", "freebsd":
    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  	extNeeded, extReason := mustLinkExternal(ctxt)
   232  	via := ""
   233  
   234  	if ctxt.LinkMode == LinkAuto {
   235  		// The environment variable GO_EXTLINK_ENABLED controls the
   236  		// default value of -linkmode. If it is not set when the
   237  		// linker is called we take the value it was set to when
   238  		// cmd/link was compiled. (See make.bash.)
   239  		switch objabi.Getgoextlinkenabled() {
   240  		case "0":
   241  			ctxt.LinkMode = LinkInternal
   242  			via = "via GO_EXTLINK_ENABLED "
   243  		case "1":
   244  			ctxt.LinkMode = LinkExternal
   245  			via = "via GO_EXTLINK_ENABLED "
   246  		default:
   247  			if extNeeded || (iscgo && externalobj) || ctxt.BuildMode == BuildModePIE {
   248  				ctxt.LinkMode = LinkExternal
   249  			} else {
   250  				ctxt.LinkMode = LinkInternal
   251  			}
   252  		}
   253  	}
   254  
   255  	switch ctxt.LinkMode {
   256  	case LinkInternal:
   257  		if extNeeded {
   258  			Exitf("internal linking requested %sbut external linking required: %s", via, extReason)
   259  		}
   260  	case LinkExternal:
   261  		switch {
   262  		case objabi.GOARCH == "riscv64":
   263  			Exitf("external linking not supported for %s/riscv64", objabi.GOOS)
   264  		case objabi.GOARCH == "ppc64" && objabi.GOOS != "aix":
   265  			Exitf("external linking not supported for %s/ppc64", objabi.GOOS)
   266  		}
   267  	}
   268  }