...
Run Format

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  		*mode = BuildModeExe
    39  	case "pie":
    40  		switch objabi.GOOS {
    41  		case "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 "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":
    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  	switch objabi.GOOS {
   179  	case "android":
   180  		return true, "android"
   181  	case "darwin":
   182  		if ctxt.Arch.InFamily(sys.ARM, sys.ARM64) {
   183  			return true, "iOS"
   184  		}
   185  	}
   186  
   187  	if *flagMsan {
   188  		return true, "msan"
   189  	}
   190  
   191  	// Internally linking cgo is incomplete on some architectures.
   192  	// https://golang.org/issue/10373
   193  	// https://golang.org/issue/14449
   194  	// https://golang.org/issue/21961
   195  	if iscgo && ctxt.Arch.InFamily(sys.ARM64, sys.MIPS64, sys.MIPS, sys.PPC64) {
   196  		return true, objabi.GOARCH + " does not support internal cgo"
   197  	}
   198  
   199  	// When the race flag is set, the LLVM tsan relocatable file is linked
   200  	// into the final binary, which means external linking is required because
   201  	// internal linking does not support it.
   202  	if *flagRace && ctxt.Arch.InFamily(sys.PPC64) {
   203  		return true, "race on ppc64le"
   204  	}
   205  
   206  	// Some build modes require work the internal linker cannot do (yet).
   207  	switch ctxt.BuildMode {
   208  	case BuildModeCArchive:
   209  		return true, "buildmode=c-archive"
   210  	case BuildModeCShared:
   211  		return true, "buildmode=c-shared"
   212  	case BuildModePIE:
   213  		switch objabi.GOOS + "/" + objabi.GOARCH {
   214  		case "linux/amd64":
   215  		default:
   216  			// Internal linking does not support TLS_IE.
   217  			return true, "buildmode=pie"
   218  		}
   219  	case BuildModePlugin:
   220  		return true, "buildmode=plugin"
   221  	case BuildModeShared:
   222  		return true, "buildmode=shared"
   223  	}
   224  	if ctxt.linkShared {
   225  		return true, "dynamically linking with a shared library"
   226  	}
   227  
   228  	return false, ""
   229  }
   230  
   231  // determineLinkMode sets ctxt.LinkMode.
   232  //
   233  // It is called after flags are processed and inputs are processed,
   234  // so the ctxt.LinkMode variable has an initial value from the -linkmode
   235  // flag and the iscgo externalobj variables are set.
   236  func determineLinkMode(ctxt *Link) {
   237  	switch ctxt.LinkMode {
   238  	case LinkAuto:
   239  		// The environment variable GO_EXTLINK_ENABLED controls the
   240  		// default value of -linkmode. If it is not set when the
   241  		// linker is called we take the value it was set to when
   242  		// cmd/link was compiled. (See make.bash.)
   243  		switch objabi.Getgoextlinkenabled() {
   244  		case "0":
   245  			if needed, reason := mustLinkExternal(ctxt); needed {
   246  				Exitf("internal linking requested via GO_EXTLINK_ENABLED, but external linking required: %s", reason)
   247  			}
   248  			ctxt.LinkMode = LinkInternal
   249  		case "1":
   250  			if objabi.GOARCH == "ppc64" {
   251  				Exitf("external linking requested via GO_EXTLINK_ENABLED but not supported for linux/ppc64")
   252  			}
   253  			ctxt.LinkMode = LinkExternal
   254  		default:
   255  			if needed, _ := mustLinkExternal(ctxt); needed {
   256  				ctxt.LinkMode = LinkExternal
   257  			} else if iscgo && externalobj {
   258  				ctxt.LinkMode = LinkExternal
   259  			} else if ctxt.BuildMode == BuildModePIE {
   260  				ctxt.LinkMode = LinkExternal // https://golang.org/issue/18968
   261  			} else {
   262  				ctxt.LinkMode = LinkInternal
   263  			}
   264  			if objabi.GOARCH == "ppc64" && ctxt.LinkMode == LinkExternal {
   265  				Exitf("external linking is not supported for linux/ppc64")
   266  			}
   267  		}
   268  	case LinkInternal:
   269  		if needed, reason := mustLinkExternal(ctxt); needed {
   270  			Exitf("internal linking requested but external linking required: %s", reason)
   271  		}
   272  	case LinkExternal:
   273  		if objabi.GOARCH == "ppc64" {
   274  			Exitf("external linking not supported for linux/ppc64")
   275  		}
   276  	}
   277  }
   278  

View as plain text