2015-02-27 22:57:28 -05:00
// Inferno utils/8l/asm.c
2016-08-28 17:04:46 -07:00
// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/8l/asm.c
2015-02-27 22:57:28 -05:00
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
// Portions Copyright © 1997-1999 Vita Nuova Limited
// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
// Portions Copyright © 2004,2006 Bruce Ellis
// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
2016-04-10 14:32:26 -07:00
// Portions Copyright © 2009 The Go Authors. All rights reserved.
2015-02-27 22:57:28 -05:00
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
package ld
import (
2015-04-29 10:59:22 -04:00
"bufio"
2015-02-27 22:57:28 -05:00
"bytes"
2016-04-06 21:45:29 -07:00
"cmd/internal/bio"
2019-07-30 17:28:29 -04:00
"cmd/internal/obj"
2017-04-18 12:53:25 -07:00
"cmd/internal/objabi"
2016-04-06 12:01:40 -07:00
"cmd/internal/sys"
2017-10-06 16:01:02 -04:00
"cmd/link/internal/loadelf"
2019-10-14 10:06:37 -04:00
"cmd/link/internal/loader"
2017-10-06 11:53:52 -04:00
"cmd/link/internal/loadmacho"
2017-10-12 13:38:45 -04:00
"cmd/link/internal/loadpe"
2018-09-28 17:02:16 +02:00
"cmd/link/internal/loadxcoff"
2017-09-30 17:28:05 +00:00
"cmd/link/internal/objfile"
2017-10-04 17:54:04 -04:00
"cmd/link/internal/sym"
2015-04-11 12:05:21 +08:00
"crypto/sha1"
2015-04-01 14:57:34 +13:00
"debug/elf"
2019-03-20 20:10:38 +01:00
"debug/macho"
2017-09-30 12:36:34 +00:00
"encoding/base64"
2015-05-25 13:59:08 +12:00
"encoding/binary"
2016-12-05 23:20:20 -05:00
"encoding/hex"
2015-02-27 22:57:28 -05:00
"fmt"
2015-04-08 16:49:43 -04:00
"io"
2015-02-27 22:57:28 -05:00
"io/ioutil"
"log"
"os"
"os/exec"
2015-04-01 14:57:34 +13:00
"path/filepath"
2015-07-15 09:05:33 -07:00
"runtime"
2015-02-27 22:57:28 -05:00
"strings"
2015-10-28 14:41:58 -04:00
"sync"
2015-02-27 22:57:28 -05:00
)
// Data layout and relocation.
// Derived from Inferno utils/6l/l.h
2016-08-28 17:04:46 -07:00
// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/6l/l.h
2015-02-27 22:57:28 -05:00
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
// Portions Copyright © 1997-1999 Vita Nuova Limited
// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
// Portions Copyright © 2004,2006 Bruce Ellis
// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
2016-04-10 14:32:26 -07:00
// Portions Copyright © 2009 The Go Authors. All rights reserved.
2015-02-27 22:57:28 -05:00
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
type Arch struct {
2018-07-06 12:45:03 -04:00
Funcalign int
Maxalign int
Minalign int
Dwarfregsp int
Dwarfreglr int
Linuxdynld string
Freebsddynld string
Netbsddynld string
Openbsddynld string
Dragonflydynld string
Solarisdynld string
Adddynrel func ( * Link , * sym . Symbol , * sym . Reloc ) bool
Archinit func ( * Link )
// Archreloc is an arch-specific hook that assists in
// relocation processing (invoked by 'relocsym'); it handles
// target-specific relocation tasks. Here "rel" is the current
// relocation being examined, "sym" is the symbol containing the
// chunk of data to which the relocation applies, and "off" is the
// contents of the to-be-relocated data item (from sym.P). Return
// value is the appropriately relocated value (to be written back
// to the same spot in sym.P) and a boolean indicating
// success/failure (a failing value indicates a fatal error).
Archreloc func ( link * Link , rel * sym . Reloc , sym * sym . Symbol ,
offset int64 ) ( relocatedOffset int64 , success bool )
// Archrelocvariant is a second arch-specific hook used for
// relocation processing; it handles relocations where r.Type is
// insufficient to describe the relocation (r.Variant !=
// sym.RV_NONE). Here "rel" is the relocation being applied, "sym"
// is the symbol containing the chunk of data to which the
// relocation applies, and "off" is the contents of the
// to-be-relocated data item (from sym.P). Return is an updated
// offset value.
Archrelocvariant func ( link * Link , rel * sym . Reloc , sym * sym . Symbol ,
offset int64 ) ( relocatedOffset int64 )
2019-04-03 22:41:48 -04:00
Trampoline func ( * Link , * sym . Reloc , * sym . Symbol )
// Asmb and Asmb2 are arch-specific routines that write the output
// file. Typically, Asmb writes most of the content (sections and
// segments), for which we have computed the size and offset. Asmb2
// writes the rest.
Asmb func ( * Link )
Asmb2 func ( * Link )
2018-07-06 12:45:03 -04:00
Elfreloc1 func ( * Link , * sym . Reloc , int64 ) bool
Elfsetupplt func ( * Link )
Gentext func ( * Link )
Machoreloc1 func ( * sys . Arch , * OutBuf , * sym . Symbol , * sym . Reloc , int64 ) bool
PEreloc1 func ( * sys . Arch , * OutBuf , * sym . Symbol , * sym . Reloc , int64 ) bool
2019-02-20 16:16:38 +01:00
Xcoffreloc1 func ( * sys . Arch , * OutBuf , * sym . Symbol , * sym . Reloc , int64 ) bool
2016-09-06 07:46:59 -04:00
// TLSIEtoLE converts a TLS Initial Executable relocation to
// a TLS Local Executable relocation.
//
// This is possible when a TLS IE relocation refers to a local
// symbol in an executable, which is typical when internally
// linking PIE binaries.
2017-10-04 17:54:04 -04:00
TLSIEtoLE func ( s * sym . Symbol , off , size int )
2018-03-04 12:59:15 +01:00
// optional override for assignAddress
AssignAddress func ( ctxt * Link , sect * sym . Section , n int , s * sym . Symbol , va uint64 , isTramp bool ) ( * sym . Section , int , uint64 )
2015-02-27 22:57:28 -05:00
}
2015-03-07 16:28:07 +13:00
var (
2018-04-01 00:58:48 +03:00
thearch Arch
2015-03-07 16:28:07 +13:00
Lcsize int32
2015-04-12 02:31:28 +02:00
rpath Rpath
2015-03-07 16:28:07 +13:00
Spsize int32
Symsize int32
)
2015-02-27 22:57:28 -05:00
const (
2015-03-05 13:57:36 -05:00
MINFUNC = 16 // minimum size for a function
2015-02-27 22:57:28 -05:00
)
2018-11-22 11:46:44 +01:00
// DynlinkingGo reports whether we are producing Go code that can live
2015-03-30 02:59:10 +00:00
// in separate shared libraries linked together at runtime.
2016-08-25 21:06:10 -04:00
func ( ctxt * Link ) DynlinkingGo ( ) bool {
2016-08-25 21:58:45 -04:00
if ! ctxt . Loaded {
panic ( "DynlinkingGo called before all symbols loaded" )
}
2019-09-04 11:25:06 -04:00
return ctxt . BuildMode == BuildModeShared || ctxt . linkShared || ctxt . BuildMode == BuildModePlugin || ctxt . canUsePlugins
2017-08-15 14:34:53 -04:00
}
2018-11-22 11:46:44 +01:00
// CanUsePlugins reports whether a plugins can be used
2017-08-15 14:34:53 -04:00
func ( ctxt * Link ) CanUsePlugins ( ) bool {
2019-09-04 11:25:06 -04:00
if ! ctxt . Loaded {
panic ( "CanUsePlugins called before all symbols loaded" )
}
return ctxt . canUsePlugins
2015-03-30 02:59:10 +00:00
}
2018-11-22 11:46:44 +01:00
// UseRelro reports whether to make use of "read only relocations" aka
2015-05-21 13:07:19 +12:00
// relro.
2017-10-05 10:20:17 -04:00
func ( ctxt * Link ) UseRelro ( ) bool {
switch ctxt . BuildMode {
case BuildModeCArchive , BuildModeCShared , BuildModeShared , BuildModePIE , BuildModePlugin :
2019-03-22 12:54:37 +01:00
return ctxt . IsELF || ctxt . HeadType == objabi . Haix
2015-10-19 12:53:36 -04:00
default :
2019-02-20 16:16:38 +01:00
return ctxt . linkShared || ( ctxt . HeadType == objabi . Haix && ctxt . LinkMode == LinkExternal )
2015-10-19 12:53:36 -04:00
}
2015-05-21 13:07:19 +12:00
}
2015-03-07 16:28:07 +13:00
var (
2017-10-04 17:54:04 -04:00
dynexp [ ] * sym . Symbol
2016-08-21 18:34:24 -04:00
dynlib [ ] string
ldflag [ ] string
havedynamic int
Funcalign int
iscgo bool
elfglobalsymndx int
2016-08-22 22:29:24 -07:00
interpreter string
2016-08-21 18:34:24 -04:00
2017-10-07 13:49:44 -04:00
debug_s bool // backup old value of debug['s']
HEADR int32
2016-08-21 18:34:24 -04:00
nerrors int
liveness int64
2019-03-26 12:02:36 -04:00
// See -strictdups command line flag.
checkStrictDups int // 0=off 1=warning 2=error
strictDupMsgCount int
2015-03-07 16:28:07 +13:00
)
2015-02-27 22:57:28 -05:00
2015-03-07 16:28:07 +13:00
var (
2017-10-04 17:54:04 -04:00
Segtext sym . Segment
Segrodata sym . Segment
Segrelrodata sym . Segment
Segdata sym . Segment
Segdwarf sym . Segment
2015-03-07 16:28:07 +13:00
)
2015-02-27 22:57:28 -05:00
2017-08-28 15:10:25 +09:00
const pkgdef = "__.PKGDEF"
2015-02-27 22:57:28 -05:00
2015-03-07 16:28:07 +13:00
var (
// Set if we see an object compiled by the host compiler that is not
// from a package that is known to support internal linking mode.
externalobj = false
theline string
)
2015-02-27 22:57:28 -05:00
2016-08-19 22:40:38 -04:00
func Lflag ( ctxt * Link , arg string ) {
ctxt . Libdir = append ( ctxt . Libdir , arg )
2015-02-27 22:57:28 -05:00
}
/ *
* Unix doesn ' t like it when we write to a running ( or , sometimes ,
* recently run ) binary , so remove the output file before writing it .
* On Windows 7 , remove ( ) can force a subsequent create ( ) to fail .
* S_ISREG ( ) does not exist on Plan 9.
* /
func mayberemoveoutfile ( ) {
2016-08-21 18:34:24 -04:00
if fi , err := os . Lstat ( * flagOutfile ) ; err == nil && ! fi . Mode ( ) . IsRegular ( ) {
2015-02-27 22:57:28 -05:00
return
}
2016-08-21 18:34:24 -04:00
os . Remove ( * flagOutfile )
2015-02-27 22:57:28 -05:00
}
2016-08-19 22:40:38 -04:00
func libinit ( ctxt * Link ) {
2018-04-01 00:58:48 +03:00
Funcalign = thearch . Funcalign
2015-02-27 22:57:28 -05:00
// add goroot to the end of the libdir list.
2015-03-02 12:35:15 -05:00
suffix := ""
2015-02-27 22:57:28 -05:00
2015-03-02 12:35:15 -05:00
suffixsep := ""
2016-08-21 18:34:24 -04:00
if * flagInstallSuffix != "" {
2015-02-27 22:57:28 -05:00
suffixsep = "_"
2016-08-21 18:34:24 -04:00
suffix = * flagInstallSuffix
} else if * flagRace {
2015-02-27 22:57:28 -05:00
suffixsep = "_"
suffix = "race"
2016-08-21 18:34:24 -04:00
} else if * flagMsan {
2015-10-21 07:11:01 -07:00
suffixsep = "_"
suffix = "msan"
2015-02-27 22:57:28 -05:00
}
2017-04-18 12:53:25 -07:00
Lflag ( ctxt , filepath . Join ( objabi . GOROOT , "pkg" , fmt . Sprintf ( "%s_%s%s%s" , objabi . GOOS , objabi . GOARCH , suffixsep , suffix ) ) )
2015-02-27 22:57:28 -05:00
mayberemoveoutfile ( )
2019-04-03 22:41:48 -04:00
f , err := os . OpenFile ( * flagOutfile , os . O_RDWR | os . O_CREATE | os . O_TRUNC , 0775 )
2015-02-27 22:57:28 -05:00
if err != nil {
2016-08-21 18:34:24 -04:00
Exitf ( "cannot create %s: %v" , * flagOutfile , err )
2015-02-27 22:57:28 -05:00
}
2017-10-01 02:37:20 +00:00
ctxt . Out . w = bufio . NewWriter ( f )
ctxt . Out . f = f
2015-02-27 22:57:28 -05:00
2016-08-21 18:34:24 -04:00
if * flagEntrySymbol == "" {
2017-10-05 10:20:17 -04:00
switch ctxt . BuildMode {
case BuildModeCShared , BuildModeCArchive :
2017-04-18 12:53:25 -07:00
* flagEntrySymbol = fmt . Sprintf ( "_rt0_%s_%s_lib" , objabi . GOARCH , objabi . GOOS )
2017-10-05 10:20:17 -04:00
case BuildModeExe , BuildModePIE :
2017-04-18 12:53:25 -07:00
* flagEntrySymbol = fmt . Sprintf ( "_rt0_%s_%s" , objabi . GOARCH , objabi . GOOS )
2017-10-05 10:20:17 -04:00
case BuildModeShared , BuildModePlugin :
2016-08-25 21:58:45 -04:00
// No *flagEntrySymbol for -buildmode=shared and plugin
2015-03-27 02:48:27 +00:00
default :
2017-10-05 10:20:17 -04:00
Errorf ( nil , "unknown *flagEntrySymbol for buildmode %v" , ctxt . BuildMode )
2015-02-27 22:57:28 -05:00
}
}
}
2015-04-09 07:37:17 -04:00
func errorexit ( ) {
2015-02-27 22:57:28 -05:00
if nerrors != 0 {
Exit ( 2 )
}
2019-03-26 12:02:36 -04:00
if checkStrictDups > 1 && strictDupMsgCount > 0 {
Exit ( 2 )
}
2015-02-27 22:57:28 -05:00
Exit ( 0 )
}
2017-10-04 18:13:35 -04:00
func loadinternal ( ctxt * Link , name string ) * sym . Library {
2017-10-07 13:28:51 -04:00
if ctxt . linkShared && ctxt . PackageShlib != nil {
2017-06-09 11:15:53 -04:00
if shlib := ctxt . PackageShlib [ name ] ; shlib != "" {
return addlibpath ( ctxt , "internal" , "internal" , "" , name , shlib )
2017-05-31 11:35:29 -04:00
}
}
if ctxt . PackageFile != nil {
if pname := ctxt . PackageFile [ name ] ; pname != "" {
return addlibpath ( ctxt , "internal" , "internal" , pname , name , "" )
}
ctxt . Logf ( "loadinternal: cannot find %s\n" , name )
return nil
}
2018-04-06 21:41:06 +01:00
for _ , libdir := range ctxt . Libdir {
2017-10-07 13:28:51 -04:00
if ctxt . linkShared {
2018-04-06 21:41:06 +01:00
shlibname := filepath . Join ( libdir , name + ".shlibname" )
2016-08-21 18:25:28 -04:00
if ctxt . Debugvlog != 0 {
2016-08-25 12:32:42 +10:00
ctxt . Logf ( "searching for %s.a in %s\n" , name , shlibname )
2015-04-01 14:57:34 +13:00
}
2015-09-07 15:00:52 +12:00
if _ , err := os . Stat ( shlibname ) ; err == nil {
2016-09-14 14:47:12 -04:00
return addlibpath ( ctxt , "internal" , "internal" , "" , name , shlibname )
2015-04-01 14:57:34 +13:00
}
}
2018-04-06 21:41:06 +01:00
pname := filepath . Join ( libdir , name + ".a" )
2016-08-21 18:25:28 -04:00
if ctxt . Debugvlog != 0 {
2016-08-25 12:32:42 +10:00
ctxt . Logf ( "searching for %s.a in %s\n" , name , pname )
2015-02-27 22:57:28 -05:00
}
2015-09-07 15:00:52 +12:00
if _ , err := os . Stat ( pname ) ; err == nil {
2016-09-14 14:47:12 -04:00
return addlibpath ( ctxt , "internal" , "internal" , pname , name , "" )
2015-02-27 22:57:28 -05:00
}
}
2016-09-14 14:47:12 -04:00
ctxt . Logf ( "warning: unable to find %s.a\n" , name )
return nil
2015-02-27 22:57:28 -05:00
}
2019-02-20 16:39:09 +01:00
// extld returns the current external linker.
func ( ctxt * Link ) extld ( ) string {
2016-08-10 11:06:46 +10:00
if * flagExtld == "" {
* flagExtld = "gcc"
}
2019-02-20 16:39:09 +01:00
return * flagExtld
}
// findLibPathCmd uses cmd command to find gcc library libname.
// It returns library full path if found, or "none" if not found.
func ( ctxt * Link ) findLibPathCmd ( cmd , libname string ) string {
extld := ctxt . extld ( )
2017-09-30 21:10:49 +00:00
args := hostlinkArchArgs ( ctxt . Arch )
2016-08-10 11:06:46 +10:00
args = append ( args , cmd )
if ctxt . Debugvlog != 0 {
2019-02-20 16:39:09 +01:00
ctxt . Logf ( "%s %v\n" , extld , args )
2016-08-10 11:06:46 +10:00
}
2019-02-20 16:39:09 +01:00
out , err := exec . Command ( extld , args ... ) . Output ( )
2016-08-10 11:06:46 +10:00
if err != nil {
if ctxt . Debugvlog != 0 {
ctxt . Logf ( "not using a %s file because compiler failed\n%v\n%s\n" , libname , err , out )
}
return "none"
}
return strings . TrimSpace ( string ( out ) )
}
// findLibPath searches for library libname.
// It returns library full path if found, or "none" if not found.
func ( ctxt * Link ) findLibPath ( libname string ) string {
return ctxt . findLibPathCmd ( "--print-file-name=" + libname , libname )
}
2016-08-19 22:40:38 -04:00
func ( ctxt * Link ) loadlib ( ) {
2019-09-17 16:14:37 -04:00
if * flagNewobj {
2019-10-14 10:06:37 -04:00
ctxt . loader = loader . NewLoader ( )
2015-02-27 22:57:28 -05:00
}
2019-10-04 22:05:41 -04:00
ctxt . cgo_export_static = make ( map [ string ] bool )
ctxt . cgo_export_dynamic = make ( map [ string ] bool )
2016-08-19 22:40:38 -04:00
loadinternal ( ctxt , "runtime" )
2017-09-30 21:10:49 +00:00
if ctxt . Arch . Family == sys . ARM {
2016-08-19 22:40:38 -04:00
loadinternal ( ctxt , "math" )
2015-02-27 22:57:28 -05:00
}
2016-08-21 18:34:24 -04:00
if * flagRace {
2016-08-19 22:40:38 -04:00
loadinternal ( ctxt , "runtime/race" )
2015-02-27 22:57:28 -05:00
}
2016-08-21 18:34:24 -04:00
if * flagMsan {
2016-08-19 22:40:38 -04:00
loadinternal ( ctxt , "runtime/msan" )
2015-10-21 07:11:01 -07:00
}
2015-02-27 22:57:28 -05:00
2017-06-09 11:15:53 -04:00
// ctxt.Library grows during the loop, so not a range loop.
for i := 0 ; i < len ( ctxt . Library ) ; i ++ {
lib := ctxt . Library [ i ]
if lib . Shlib == "" {
2016-08-21 18:25:28 -04:00
if ctxt . Debugvlog > 1 {
2017-06-09 11:15:53 -04:00
ctxt . Logf ( "%5.2f autolib: %s (from %s)\n" , Cputime ( ) , lib . File , lib . Objref )
2016-01-20 15:31:26 +13:00
}
2017-09-30 17:28:05 +00:00
loadobjfile ( ctxt , lib )
2016-01-20 15:31:26 +13:00
}
}
2019-09-17 16:14:37 -04:00
if * flagNewobj {
2019-10-04 22:05:41 -04:00
iscgo = ctxt . loader . Lookup ( "x_cgo_init" , 0 ) != 0
ctxt . canUsePlugins = ctxt . loader . Lookup ( "plugin.Open" , sym . SymVerABIInternal ) != 0
} else {
iscgo = ctxt . Syms . ROLookup ( "x_cgo_init" , 0 ) != nil
ctxt . canUsePlugins = ctxt . Syms . ROLookup ( "plugin.Open" , sym . SymVerABIInternal ) != nil
2015-02-27 22:57:28 -05:00
}
2016-09-09 17:34:07 -04:00
// We now have enough information to determine the link mode.
determineLinkMode ( ctxt )
2015-02-27 22:57:28 -05:00
2019-09-24 17:31:12 -04:00
if ctxt . LinkMode == LinkExternal && ! iscgo && ctxt . LibraryByPkg [ "runtime/cgo" ] == nil && ! ( objabi . GOOS == "darwin" && ( ctxt . Arch . Family == sys . AMD64 || ctxt . Arch . Family == sys . I386 ) ) {
// This indicates a user requested -linkmode=external.
// The startup code uses an import of runtime/cgo to decide
// whether to initialize the TLS. So give it one. This could
// be handled differently but it's an unusual case.
if lib := loadinternal ( ctxt , "runtime/cgo" ) ; lib != nil {
if lib . Shlib != "" {
ldshlibsyms ( ctxt , lib . Shlib )
} else {
if ctxt . BuildMode == BuildModeShared || ctxt . linkShared {
Exitf ( "cannot implicitly include runtime/cgo in a shared library" )
}
loadobjfile ( ctxt , lib )
}
}
}
2019-10-04 22:05:41 -04:00
if * flagNewobj {
// Add references of externally defined symbols.
2019-10-14 10:06:37 -04:00
ctxt . loader . LoadRefs ( ctxt . Arch , ctxt . Syms )
2019-10-04 22:05:41 -04:00
}
// Now that we know the link mode, set the dynexp list.
if ! * flagNewobj { // set this later in newobj mode
setupdynexp ( ctxt )
}
for _ , lib := range ctxt . Library {
if lib . Shlib != "" {
if ctxt . Debugvlog > 1 {
ctxt . Logf ( "%5.2f autolib: %s (from %s)\n" , Cputime ( ) , lib . Shlib , lib . Objref )
}
ldshlibsyms ( ctxt , lib . Shlib )
}
}
2019-09-23 22:44:02 -04:00
// In internal link mode, read the host object files.
2019-09-24 17:31:12 -04:00
if ctxt . LinkMode == LinkInternal && len ( hostobj ) != 0 {
2015-02-27 22:57:28 -05:00
// Drop all the cgo_import_static declarations.
// Turns out we won't be needing them.
2016-09-20 14:59:39 +12:00
for _ , s := range ctxt . Syms . Allsym {
2017-10-04 17:54:04 -04:00
if s . Type == sym . SHOSTOBJ {
2015-02-27 22:57:28 -05:00
// If a symbol was marked both
// cgo_import_static and cgo_import_dynamic,
// then we want to make it cgo_import_dynamic
// now.
2018-07-17 11:02:57 -04:00
if s . Extname ( ) != "" && s . Dynimplib ( ) != "" && ! s . Attr . CgoExport ( ) {
2017-10-04 17:54:04 -04:00
s . Type = sym . SDYNIMPORT
2015-02-27 22:57:28 -05:00
} else {
s . Type = 0
}
}
}
2016-08-19 22:40:38 -04:00
hostobjs ( ctxt )
2015-11-04 11:14:19 -08:00
// If we have any undefined symbols in external
2015-11-16 18:11:35 -08:00
// objects, try to read them from the libgcc file.
2015-11-04 11:14:19 -08:00
any := false
2016-09-20 14:59:39 +12:00
for _ , s := range ctxt . Syms . Allsym {
2018-05-17 19:47:52 +03:00
for i := range s . R {
2018-08-27 11:49:38 -04:00
r := & s . R [ i ] // Copying sym.Reloc has measurable impact on performance
2017-04-28 13:01:03 +12:00
if r . Sym != nil && r . Sym . Type == sym . SXREF && r . Sym . Name != ".got" {
2015-11-04 11:14:19 -08:00
any = true
break
}
}
}
if any {
2016-08-21 18:34:24 -04:00
if * flagLibGCC == "" {
2016-08-10 11:06:46 +10:00
* flagLibGCC = ctxt . findLibPathCmd ( "--print-libgcc-file-name" , "libgcc" )
2015-11-16 18:11:35 -08:00
}
2018-12-17 01:18:51 +11:00
if runtime . GOOS == "openbsd" && * flagLibGCC == "libgcc.a" {
// On OpenBSD `clang --print-libgcc-file-name` returns "libgcc.a".
// In this case we fail to load libgcc.a and can encounter link
// errors - see if we can find libcompiler_rt.a instead.
* flagLibGCC = ctxt . findLibPathCmd ( "--print-file-name=libcompiler_rt.a" , "libcompiler_rt" )
}
2016-08-21 18:34:24 -04:00
if * flagLibGCC != "none" {
hostArchive ( ctxt , * flagLibGCC )
2015-11-16 18:11:35 -08:00
}
2017-10-07 13:49:44 -04:00
if ctxt . HeadType == objabi . Hwindows {
2016-08-10 11:06:46 +10:00
if p := ctxt . findLibPath ( "libmingwex.a" ) ; p != "none" {
hostArchive ( ctxt , p )
}
if p := ctxt . findLibPath ( "libmingw32.a" ) ; p != "none" {
hostArchive ( ctxt , p )
}
// TODO: maybe do something similar to peimporteddlls to collect all lib names
// and try link them all to final exe just like libmingwex.a and libmingw32.a:
/ *
for :
# cgo windows LDFLAGS : - lmsvcrt - lm
import :
libmsvcrt . a libm . a
* /
}
2015-11-04 11:14:19 -08:00
}
2019-09-24 17:31:12 -04:00
} else if ctxt . LinkMode == LinkExternal {
2017-10-01 02:37:20 +00:00
hostlinksetup ( ctxt )
2015-02-27 22:57:28 -05:00
}
// We've loaded all the code now.
2016-08-25 21:58:45 -04:00
ctxt . Loaded = true
2019-09-24 17:31:12 -04:00
importcycles ( )
2019-09-23 22:44:02 -04:00
}
2018-11-01 12:30:23 -04:00
2019-10-04 22:05:41 -04:00
// Set up dynexp list.
func setupdynexp ( ctxt * Link ) {
dynexpMap := ctxt . cgo_export_dynamic
if ctxt . LinkMode == LinkExternal {
dynexpMap = ctxt . cgo_export_static
}
dynexp = make ( [ ] * sym . Symbol , 0 , len ( dynexpMap ) )
for exp := range dynexpMap {
s := ctxt . Syms . Lookup ( exp , 0 )
dynexp = append ( dynexp , s )
}
// Resolve ABI aliases in the list of cgo-exported functions.
// This is necessary because we load the ABI0 symbol for all
// cgo exports.
for i , s := range dynexp {
if s . Type != sym . SABIALIAS {
continue
}
t := resolveABIAlias ( s )
t . Attr |= s . Attr
t . SetExtname ( s . Extname ( ) )
dynexp [ i ] = t
}
ctxt . cgo_export_static = nil
ctxt . cgo_export_dynamic = nil
}
2019-09-23 22:44:02 -04:00
// Set up flags and special symbols depending on the platform build mode.
func ( ctxt * Link ) linksetup ( ) {
switch ctxt . BuildMode {
case BuildModeCShared , BuildModePlugin :
s := ctxt . Syms . Lookup ( "runtime.islibrary" , 0 )
s . Type = sym . SNOPTRDATA
s . Attr |= sym . AttrDuplicateOK
s . AddUint8 ( 1 )
case BuildModeCArchive :
s := ctxt . Syms . Lookup ( "runtime.isarchive" , 0 )
s . Type = sym . SNOPTRDATA
s . Attr |= sym . AttrDuplicateOK
s . AddUint8 ( 1 )
}
// Recalculate pe parameters now that we have ctxt.LinkMode set.
if ctxt . HeadType == objabi . Hwindows {
Peinit ( ctxt )
}
if ctxt . HeadType == objabi . Hdarwin && ctxt . LinkMode == LinkExternal {
* FlagTextAddr = 0
}
// If there are no dynamic libraries needed, gcc disables dynamic linking.
// Because of this, glibc's dynamic ELF loader occasionally (like in version 2.13)
// assumes that a dynamic binary always refers to at least one dynamic library.
// Rather than be a source of test cases for glibc, disable dynamic linking
// the same way that gcc would.
//
// Exception: on OS X, programs such as Shark only work with dynamic
// binaries, so leave it enabled on OS X (Mach-O) binaries.
// Also leave it enabled on Solaris which doesn't support
// statically linked binaries.
if ctxt . BuildMode == BuildModeExe {
if havedynamic == 0 && ctxt . HeadType != objabi . Hdarwin && ctxt . HeadType != objabi . Hsolaris {
* FlagD = true
}
}
if ctxt . LinkMode == LinkExternal && ctxt . Arch . Family == sys . PPC64 && objabi . GOOS != "aix" {
toc := ctxt . Syms . Lookup ( ".TOC." , 0 )
toc . Type = sym . SDYNIMPORT
}
// The Android Q linker started to complain about underalignment of the our TLS
// section. We don't actually use the section on android, so dont't
// generate it.
if objabi . GOOS != "android" {
tlsg := ctxt . Syms . Lookup ( "runtime.tlsg" , 0 )
// runtime.tlsg is used for external linking on platforms that do not define
// a variable to hold g in assembly (currently only intel).
if tlsg . Type == 0 {
tlsg . Type = sym . STLSBSS
tlsg . Size = int64 ( ctxt . Arch . PtrSize )
} else if tlsg . Type != sym . SDYNIMPORT {
Errorf ( nil , "runtime declared tlsg variable %v" , tlsg . Type )
}
tlsg . Attr |= sym . AttrReachable
ctxt . Tlsg = tlsg
}
var moduledata * sym . Symbol
if ctxt . BuildMode == BuildModePlugin {
moduledata = ctxt . Syms . Lookup ( "local.pluginmoduledata" , 0 )
moduledata . Attr |= sym . AttrLocal
} else {
moduledata = ctxt . Syms . Lookup ( "runtime.firstmoduledata" , 0 )
}
if moduledata . Type != 0 && moduledata . Type != sym . SDYNIMPORT {
// If the module (toolchain-speak for "executable or shared
// library") we are linking contains the runtime package, it
// will define the runtime.firstmoduledata symbol and we
// truncate it back to 0 bytes so we can define its entire
// contents in symtab.go:symtab().
moduledata . Size = 0
// In addition, on ARM, the runtime depends on the linker
// recording the value of GOARM.
if ctxt . Arch . Family == sys . ARM {
s := ctxt . Syms . Lookup ( "runtime.goarm" , 0 )
s . Type = sym . SDATA
s . Size = 0
s . AddUint8 ( uint8 ( objabi . GOARM ) )
}
if objabi . Framepointer_enabled ( objabi . GOOS , objabi . GOARCH ) {
s := ctxt . Syms . Lookup ( "runtime.framepointer_enabled" , 0 )
s . Type = sym . SDATA
s . Size = 0
s . AddUint8 ( 1 )
}
} else {
// If OTOH the module does not contain the runtime package,
// create a local symbol for the moduledata.
moduledata = ctxt . Syms . Lookup ( "local.moduledata" , 0 )
moduledata . Attr |= sym . AttrLocal
}
// In all cases way we mark the moduledata as noptrdata to hide it from
// the GC.
moduledata . Type = sym . SNOPTRDATA
moduledata . Attr |= sym . AttrReachable
ctxt . Moduledata = moduledata
// If package versioning is required, generate a hash of the
// packages used in the link.
if ctxt . BuildMode == BuildModeShared || ctxt . BuildMode == BuildModePlugin || ctxt . CanUsePlugins ( ) {
for _ , lib := range ctxt . Library {
if lib . Shlib == "" {
genhash ( ctxt , lib )
}
}
}
if ctxt . Arch == sys . Arch386 && ctxt . HeadType != objabi . Hwindows {
if ( ctxt . BuildMode == BuildModeCArchive && ctxt . IsELF ) || ctxt . BuildMode == BuildModeCShared || ctxt . BuildMode == BuildModePIE || ctxt . DynlinkingGo ( ) {
got := ctxt . Syms . Lookup ( "_GLOBAL_OFFSET_TABLE_" , 0 )
got . Type = sym . SDYNIMPORT
got . Attr |= sym . AttrReachable
2018-11-01 12:30:23 -04:00
}
}
2015-02-27 22:57:28 -05:00
}
2018-08-23 14:01:59 +02:00
// mangleTypeSym shortens the names of symbols that represent Go types
// if they are visible in the symbol table.
2017-09-30 12:36:34 +00:00
//
// As the names of these symbols are derived from the string of
// the type, they can run to many kilobytes long. So we shorten
// them using a SHA-1 when the name appears in the final binary.
2018-08-23 14:01:59 +02:00
// This also removes characters that upset external linkers.
2017-09-30 12:36:34 +00:00
//
// These are the symbols that begin with the prefix 'type.' and
// contain run-time type information used by the runtime and reflect
2018-10-08 01:19:51 +00:00
// packages. All Go binaries contain these symbols, but only
2017-09-30 12:36:34 +00:00
// those programs loaded dynamically in multiple parts need these
// symbols to have entries in the symbol table.
2018-08-23 14:01:59 +02:00
func ( ctxt * Link ) mangleTypeSym ( ) {
2018-11-01 12:30:23 -04:00
if ctxt . BuildMode != BuildModeShared && ! ctxt . linkShared && ctxt . BuildMode != BuildModePlugin && ! ctxt . CanUsePlugins ( ) {
2018-08-23 14:01:59 +02:00
return
}
for _ , s := range ctxt . Syms . Allsym {
newName := typeSymbolMangle ( s . Name )
if newName != s . Name {
ctxt . Syms . Rename ( s . Name , newName , int ( s . Version ) , ctxt . Reachparent )
}
}
2017-09-30 12:36:34 +00:00
}
// typeSymbolMangle mangles the given symbol name into something shorter.
2018-08-23 14:01:59 +02:00
//
// Keep the type.. prefix, which parts of the linker (like the
// DWARF generator) know means the symbol is not decodable.
// Leave type.runtime. symbols alone, because other parts of
// the linker manipulates them.
2017-10-09 10:11:00 +01:00
func typeSymbolMangle ( name string ) string {
2017-09-30 12:36:34 +00:00
if ! strings . HasPrefix ( name , "type." ) {
return name
}
if strings . HasPrefix ( name , "type.runtime." ) {
return name
}
if len ( name ) <= 14 && ! strings . Contains ( name , "@" ) { // Issue 19529
return name
}
hash := sha1 . Sum ( [ ] byte ( name ) )
prefix := "type."
if name [ 5 ] == '.' {
prefix = "type.."
}
return prefix + base64 . StdEncoding . EncodeToString ( hash [ : 6 ] )
}
2015-02-27 22:57:28 -05:00
/ *
* look for the next file in an archive .
* adapted from libmach .
* /
2016-04-08 19:14:03 +10:00
func nextar ( bp * bio . Reader , off int64 , a * ArHdr ) int64 {
2015-02-27 22:57:28 -05:00
if off & 1 != 0 {
off ++
}
2019-05-08 18:46:04 -04:00
bp . MustSeek ( off , 0 )
2016-04-08 18:19:10 +02:00
var buf [ SAR_HDR ] byte
if n , err := io . ReadFull ( bp , buf [ : ] ) ; err != nil {
if n == 0 && err != io . EOF {
return - 1
2015-02-27 22:57:28 -05:00
}
2016-04-08 18:19:10 +02:00
return 0
2015-02-27 22:57:28 -05:00
}
a . name = artrim ( buf [ 0 : 16 ] )
a . date = artrim ( buf [ 16 : 28 ] )
a . uid = artrim ( buf [ 28 : 34 ] )
a . gid = artrim ( buf [ 34 : 40 ] )
a . mode = artrim ( buf [ 40 : 48 ] )
a . size = artrim ( buf [ 48 : 58 ] )
a . fmag = artrim ( buf [ 58 : 60 ] )
arsize := atolwhex ( a . size )
if arsize & 1 != 0 {
arsize ++
}
2016-04-14 19:04:45 -07:00
return arsize + SAR_HDR
2015-02-27 22:57:28 -05:00
}
2017-10-04 18:13:35 -04:00
func genhash ( ctxt * Link , lib * sym . Library ) {
2016-12-05 23:20:20 -05:00
f , err := bio . Open ( lib . File )
if err != nil {
Errorf ( nil , "cannot open file %s for hash generation: %v" , lib . File , err )
return
}
defer f . Close ( )
2017-07-25 11:34:30 +09:00
var magbuf [ len ( ARMAG ) ] byte
if _ , err := io . ReadFull ( f , magbuf [ : ] ) ; err != nil {
Exitf ( "file %s too short" , lib . File )
}
if string ( magbuf [ : ] ) != ARMAG {
Exitf ( "%s is not an archive file" , lib . File )
}
2016-12-05 23:20:20 -05:00
var arhdr ArHdr
2017-07-25 11:34:30 +09:00
l := nextar ( f , f . Offset ( ) , & arhdr )
2016-12-05 23:20:20 -05:00
if l <= 0 {
Errorf ( nil , "%s: short read on archive file symbol header" , lib . File )
return
}
2018-03-23 13:12:07 -07:00
if arhdr . name != pkgdef {
Errorf ( nil , "%s: missing package data entry" , lib . File )
return
}
2016-12-05 23:20:20 -05:00
h := sha1 . New ( )
2017-04-12 16:08:46 +12:00
// To compute the hash of a package, we hash the first line of
// __.PKGDEF (which contains the toolchain version and any
// GOEXPERIMENT flags) and the export data (which is between
2017-08-22 15:41:50 +05:30
// the first two occurrences of "\n$$").
2017-04-12 16:08:46 +12:00
pkgDefBytes := make ( [ ] byte , atolwhex ( arhdr . size ) )
_ , err = io . ReadFull ( f , pkgDefBytes )
if err != nil {
Errorf ( nil , "%s: error reading package data: %v" , lib . File , err )
return
}
2017-09-21 19:23:51 +02:00
firstEOL := bytes . IndexByte ( pkgDefBytes , '\n' )
2017-04-12 16:08:46 +12:00
if firstEOL < 0 {
Errorf ( nil , "cannot parse package data of %s for hash generation, no newline found" , lib . File )
return
}
firstDoubleDollar := bytes . Index ( pkgDefBytes , [ ] byte ( "\n$$" ) )
if firstDoubleDollar < 0 {
Errorf ( nil , "cannot parse package data of %s for hash generation, no \\n$$ found" , lib . File )
return
}
secondDoubleDollar := bytes . Index ( pkgDefBytes [ firstDoubleDollar + 1 : ] , [ ] byte ( "\n$$" ) )
if secondDoubleDollar < 0 {
Errorf ( nil , "cannot parse package data of %s for hash generation, only one \\n$$ found" , lib . File )
2016-12-05 23:20:20 -05:00
return
}
2017-04-12 16:08:46 +12:00
h . Write ( pkgDefBytes [ 0 : firstEOL ] )
2019-10-09 10:22:20 -04:00
//h.Write(pkgDefBytes[firstDoubleDollar : firstDoubleDollar+secondDoubleDollar]) // TODO: newobj: -dynlink may change symbol numbering? which will make the export data differ
2017-10-04 18:13:35 -04:00
lib . Hash = hex . EncodeToString ( h . Sum ( nil ) )
2016-12-05 23:20:20 -05:00
}
2017-09-30 17:28:05 +00:00
func loadobjfile ( ctxt * Link , lib * sym . Library ) {
2017-04-17 18:46:09 -05:00
pkg := objabi . PathToPrefix ( lib . Pkg )
2015-02-27 22:57:28 -05:00
2016-08-21 18:25:28 -04:00
if ctxt . Debugvlog > 1 {
2017-04-18 12:53:25 -07:00
ctxt . Logf ( "%5.2f ldobj: %s (%s)\n" , Cputime ( ) , lib . File , pkg )
2015-02-27 22:57:28 -05:00
}
2016-04-06 21:45:29 -07:00
f , err := bio . Open ( lib . File )
2015-02-27 22:57:28 -05:00
if err != nil {
2015-04-11 12:05:21 +08:00
Exitf ( "cannot open file %s: %v" , lib . File , err )
2015-02-27 22:57:28 -05:00
}
2019-09-27 14:49:44 -04:00
defer f . Close ( )
2018-03-23 10:28:39 -07:00
defer func ( ) {
if pkg == "main" && ! lib . Main {
Exitf ( "%s: not package main" , lib . File )
}
// Ideally, we'd check that *all* object files within
// the archive were marked safe, but here we settle
// for *any*.
//
// Historically, cmd/link only checked the __.PKGDEF
// file, which in turn came from the first object
// file, typically produced by cmd/compile. The
// remaining object files are normally produced by
// cmd/asm, which doesn't support marking files as
// safe anyway. So at least in practice, this matches
// how safe mode has always worked.
if * flagU && ! lib . Safe {
Exitf ( "%s: load of unsafe package %s" , lib . File , pkg )
}
} ( )
2015-02-27 22:57:28 -05:00
2016-04-08 18:19:10 +02:00
for i := 0 ; i < len ( ARMAG ) ; i ++ {
if c , err := f . ReadByte ( ) ; err == nil && c == ARMAG [ i ] {
continue
}
2015-02-27 22:57:28 -05:00
/* load it as a regular file */
2019-05-08 18:46:04 -04:00
l := f . MustSeek ( 0 , 2 )
f . MustSeek ( 0 , 0 )
2018-03-23 10:28:39 -07:00
ldobj ( ctxt , f , lib , l , lib . File , lib . File )
2015-02-27 22:57:28 -05:00
return
}
/ *
* load all the object files from the archive now .
* this gives us sequential file access and keeps us
* from needing to come back later to pick up more
* objects . it breaks the usual C archive model , but
* this is Go , not C . the common case in Go is that
* we need to load all the objects , and then we throw away
* the individual symbols that are unused .
*
* loading every object will also make it possible to
2016-02-25 14:58:03 -08:00
* load foreign objects not referenced by __ . PKGDEF .
2015-02-27 22:57:28 -05:00
* /
2018-03-23 10:28:39 -07:00
var arhdr ArHdr
off := f . Offset ( )
2015-02-27 22:57:28 -05:00
for {
2018-03-23 10:28:39 -07:00
l := nextar ( f , off , & arhdr )
2015-02-27 22:57:28 -05:00
if l == 0 {
break
}
if l < 0 {
2015-04-11 12:05:21 +08:00
Exitf ( "%s: malformed archive" , lib . File )
2015-02-27 22:57:28 -05:00
}
off += l
2018-03-23 10:28:39 -07:00
// __.PKGDEF isn't a real Go object file, and it's
// absent in -linkobj builds anyway. Skipping it
// ensures consistency between -linkobj and normal
// build modes.
if arhdr . name == pkgdef {
continue
}
2018-10-31 13:18:17 -04:00
// Skip other special (non-object-file) sections that
// build tools may have added. Such sections must have
// short names so that the suffix is not truncated.
2018-12-13 23:55:22 -05:00
if len ( arhdr . name ) < 16 {
if ext := filepath . Ext ( arhdr . name ) ; ext != ".o" && ext != ".syso" {
continue
}
2018-10-31 13:18:17 -04:00
}
2018-03-23 10:28:39 -07:00
pname := fmt . Sprintf ( "%s(%s)" , lib . File , arhdr . name )
2015-02-27 22:57:28 -05:00
l = atolwhex ( arhdr . size )
2018-03-23 10:28:39 -07:00
ldobj ( ctxt , f , lib , l , pname , lib . File )
2015-02-27 22:57:28 -05:00
}
}
type Hostobj struct {
2016-08-19 22:40:38 -04:00
ld func ( * Link , * bio . Reader , string , int64 , string )
2015-02-27 22:57:28 -05:00
pkg string
pn string
file string
off int64
length int64
}
var hostobj [ ] Hostobj
// These packages can use internal linking mode.
// Others trigger external mode.
var internalpkg = [ ] string {
"crypto/x509" ,
"net" ,
"os/user" ,
"runtime/cgo" ,
"runtime/race" ,
2015-10-21 07:11:01 -07:00
"runtime/msan" ,
2015-02-27 22:57:28 -05:00
}
2017-10-07 13:49:44 -04:00
func ldhostobj ( ld func ( * Link , * bio . Reader , string , int64 , string ) , headType objabi . HeadType , f * bio . Reader , pkg string , length int64 , pn string , file string ) * Hostobj {
2015-03-02 11:31:29 -08:00
isinternal := false
2018-04-06 21:41:06 +01:00
for _ , intpkg := range internalpkg {
if pkg == intpkg {
2015-03-02 11:31:29 -08:00
isinternal = true
2015-02-27 22:57:28 -05:00
break
}
}
// DragonFly declares errno with __thread, which results in a symbol
// type of R_386_TLS_GD or R_X86_64_TLSGD. The Go linker does not
// currently know how to handle TLS relocations, hence we have to
// force external linking for any libraries that link in code that
// uses errno. This can be removed if the Go linker ever supports
// these relocation types.
2017-10-07 13:49:44 -04:00
if headType == objabi . Hdragonfly {
2015-02-27 22:57:28 -05:00
if pkg == "net" || pkg == "os/user" {
2015-03-02 11:31:29 -08:00
isinternal = false
2015-02-27 22:57:28 -05:00
}
}
2015-03-02 11:31:29 -08:00
if ! isinternal {
externalobj = true
2015-02-27 22:57:28 -05:00
}
hostobj = append ( hostobj , Hostobj { } )
2015-03-02 12:35:15 -05:00
h := & hostobj [ len ( hostobj ) - 1 ]
2015-02-27 22:57:28 -05:00
h . ld = ld
h . pkg = pkg
h . pn = pn
h . file = file
2016-04-08 19:14:03 +10:00
h . off = f . Offset ( )
2015-02-27 22:57:28 -05:00
h . length = length
2015-11-04 11:14:19 -08:00
return h
2015-02-27 22:57:28 -05:00
}
2016-08-19 22:40:38 -04:00
func hostobjs ( ctxt * Link ) {
2015-02-27 22:57:28 -05:00
var h * Hostobj
2015-03-02 12:35:15 -05:00
for i := 0 ; i < len ( hostobj ) ; i ++ {
2015-02-27 22:57:28 -05:00
h = & hostobj [ i ]
2016-04-08 19:14:03 +10:00
f , err := bio . Open ( h . file )
if err != nil {
2015-04-09 07:37:17 -04:00
Exitf ( "cannot reopen %s: %v" , h . pn , err )
2015-02-27 22:57:28 -05:00
}
2019-05-08 18:46:04 -04:00
f . MustSeek ( h . off , 0 )
2016-08-19 22:40:38 -04:00
h . ld ( ctxt , f , h . pkg , h . length , h . pn )
2016-04-06 21:45:29 -07:00
f . Close ( )
2015-02-27 22:57:28 -05:00
}
}
2017-10-01 02:37:20 +00:00
func hostlinksetup ( ctxt * Link ) {
2017-10-05 10:20:17 -04:00
if ctxt . LinkMode != LinkExternal {
2015-02-27 22:57:28 -05:00
return
}
2015-06-29 13:12:10 -04:00
// For external link, record that we need to tell the external linker -s,
// and turn off -s internally: the external linker needs the symbol
// information for its final link.
2016-08-21 18:34:24 -04:00
debug_s = * FlagS
* FlagS = false
2015-06-29 13:12:10 -04:00
2015-02-27 22:57:28 -05:00
// create temporary directory and arrange cleanup
2016-08-21 18:34:24 -04:00
if * flagTmpdir == "" {
2015-02-27 22:57:28 -05:00
dir , err := ioutil . TempDir ( "" , "go-link-" )
if err != nil {
log . Fatal ( err )
}
2016-08-21 18:34:24 -04:00
* flagTmpdir = dir
2018-05-20 14:53:00 +10:00
AtExit ( func ( ) {
ctxt . Out . f . Close ( )
os . RemoveAll ( * flagTmpdir )
} )
2015-02-27 22:57:28 -05:00
}
// change our output to temporary object file
2017-10-01 02:37:20 +00:00
ctxt . Out . f . Close ( )
2015-07-15 09:05:33 -07:00
mayberemoveoutfile ( )
2015-02-27 22:57:28 -05:00
2016-08-21 18:34:24 -04:00
p := filepath . Join ( * flagTmpdir , "go.o" )
2015-02-27 22:57:28 -05:00
var err error
2019-04-03 22:41:48 -04:00
f , err := os . OpenFile ( p , os . O_RDWR | os . O_CREATE | os . O_TRUNC , 0775 )
2015-02-27 22:57:28 -05:00
if err != nil {
2015-04-09 07:37:17 -04:00
Exitf ( "cannot create %s: %v" , p , err )
2015-02-27 22:57:28 -05:00
}
2017-10-01 02:37:20 +00:00
ctxt . Out . w = bufio . NewWriter ( f )
ctxt . Out . f = f
ctxt . Out . off = 0
2015-02-27 22:57:28 -05:00
}
2015-04-09 10:44:05 -04:00
// hostobjCopy creates a copy of the object files in hostobj in a
// temporary directory.
func hostobjCopy ( ) ( paths [ ] string ) {
2015-10-28 14:41:58 -04:00
var wg sync . WaitGroup
sema := make ( chan struct { } , runtime . NumCPU ( ) ) // limit open file descriptors
2015-04-09 10:44:05 -04:00
for i , h := range hostobj {
2015-10-28 14:41:58 -04:00
h := h
2016-08-21 18:34:24 -04:00
dst := filepath . Join ( * flagTmpdir , fmt . Sprintf ( "%06d.o" , i ) )
2015-10-28 14:41:58 -04:00
paths = append ( paths , dst )
wg . Add ( 1 )
go func ( ) {
sema <- struct { } { }
defer func ( ) {
<- sema
wg . Done ( )
} ( )
f , err := os . Open ( h . file )
if err != nil {
Exitf ( "cannot reopen %s: %v" , h . pn , err )
}
2018-12-05 09:52:19 -08:00
defer f . Close ( )
2015-10-28 14:41:58 -04:00
if _ , err := f . Seek ( h . off , 0 ) ; err != nil {
Exitf ( "cannot seek %s: %v" , h . pn , err )
}
2015-04-09 10:44:05 -04:00
2015-10-28 14:41:58 -04:00
w , err := os . Create ( dst )
if err != nil {
Exitf ( "cannot create %s: %v" , dst , err )
}
if _ , err := io . CopyN ( w , f , h . length ) ; err != nil {
Exitf ( "cannot write %s: %v" , dst , err )
}
if err := w . Close ( ) ; err != nil {
Exitf ( "cannot close %s: %v" , dst , err )
}
} ( )
2015-04-09 10:44:05 -04:00
}
2015-10-28 14:41:58 -04:00
wg . Wait ( )
2015-04-09 10:44:05 -04:00
return paths
}
2017-05-11 11:55:59 +10:00
// writeGDBLinkerScript creates gcc linker script file in temp
// directory. writeGDBLinkerScript returns created file path.
// The script is used to work around gcc bug
// (see https://golang.org/issue/20183 for details).
func writeGDBLinkerScript ( ) string {
name := "fix_debug_gdb_scripts.ld"
path := filepath . Join ( * flagTmpdir , name )
src := ` SECTIONS
{
. debug_gdb_scripts BLOCK ( __section_alignment__ ) ( NOLOAD ) :
{
* ( . debug_gdb_scripts )
}
}
INSERT AFTER . debug_types ;
`
err := ioutil . WriteFile ( path , [ ] byte ( src ) , 0666 )
if err != nil {
Errorf ( nil , "WriteFile %s failed: %v" , name , err )
}
return path
}
2015-04-09 10:44:05 -04:00
// archive builds a .a archive from the hostobj object files.
2016-08-21 13:52:23 -04:00
func ( ctxt * Link ) archive ( ) {
2017-10-05 10:20:17 -04:00
if ctxt . BuildMode != BuildModeCArchive {
2015-04-09 10:44:05 -04:00
return
}
2016-08-21 18:34:24 -04:00
if * flagExtar == "" {
* flagExtar = "ar"
2016-01-25 11:44:02 -08:00
}
2015-07-15 09:05:33 -07:00
mayberemoveoutfile ( )
2015-12-13 08:02:29 -05:00
// Force the buffer to flush here so that external
// tools will see a complete file.
2017-10-01 02:37:20 +00:00
ctxt . Out . Flush ( )
if err := ctxt . Out . f . Close ( ) ; err != nil {
2015-12-13 08:02:29 -05:00
Exitf ( "close: %v" , err )
}
2017-10-01 02:37:20 +00:00
ctxt . Out . f = nil
2015-12-13 08:02:29 -05:00
2019-03-25 10:33:49 +01:00
argv := [ ] string { * flagExtar , "-q" , "-c" , "-s" }
if ctxt . HeadType == objabi . Haix {
argv = append ( argv , "-X64" )
}
argv = append ( argv , * flagOutfile )
2016-08-21 18:34:24 -04:00
argv = append ( argv , filepath . Join ( * flagTmpdir , "go.o" ) )
2015-11-16 15:45:12 -05:00
argv = append ( argv , hostobjCopy ( ) ... )
2015-04-09 10:44:05 -04:00
2016-08-21 18:25:28 -04:00
if ctxt . Debugvlog != 0 {
2016-08-25 12:32:42 +10:00
ctxt . Logf ( "archive: %s\n" , strings . Join ( argv , " " ) )
2015-04-09 10:44:05 -04:00
}
if out , err := exec . Command ( argv [ 0 ] , argv [ 1 : ] ... ) . CombinedOutput ( ) ; err != nil {
2015-04-09 07:37:17 -04:00
Exitf ( "running %s failed: %v\n%s" , argv [ 0 ] , err , out )
2015-04-09 10:44:05 -04:00
}
}
2017-10-05 10:20:17 -04:00
func ( ctxt * Link ) hostlink ( ) {
if ctxt . LinkMode != LinkExternal || nerrors > 0 {
2015-02-27 22:57:28 -05:00
return
}
2017-10-05 10:20:17 -04:00
if ctxt . BuildMode == BuildModeCArchive {
2015-04-09 10:44:05 -04:00
return
}
2015-02-27 22:57:28 -05:00
2015-03-02 12:35:15 -05:00
var argv [ ] string
2019-02-20 16:39:09 +01:00
argv = append ( argv , ctxt . extld ( ) )
2017-10-05 10:20:17 -04:00
argv = append ( argv , hostlinkArchArgs ( ctxt . Arch ) ... )
2015-02-27 22:57:28 -05:00
2017-10-26 10:15:29 -04:00
if * FlagS || debug_s {
if ctxt . HeadType == objabi . Hdarwin {
// Recent versions of macOS print
// ld: warning: option -s is obsolete and being ignored
// so do not pass any arguments.
} else {
argv = append ( argv , "-s" )
}
2015-02-27 22:57:28 -05:00
}
2017-10-07 13:49:44 -04:00
switch ctxt . HeadType {
2017-04-18 12:53:25 -07:00
case objabi . Hdarwin :
2016-09-19 14:13:07 -04:00
argv = append ( argv , "-Wl,-headerpad,1144" )
2018-11-27 16:07:14 +01:00
if ctxt . DynlinkingGo ( ) && ! ctxt . Arch . InFamily ( sys . ARM , sys . ARM64 ) {
2016-09-19 14:13:07 -04:00
argv = append ( argv , "-Wl,-flat_namespace" )
2017-08-27 19:09:18 +09:00
}
2017-10-05 10:20:17 -04:00
if ctxt . BuildMode == BuildModeExe && ! ctxt . Arch . InFamily ( sys . ARM64 ) {
2016-09-19 14:13:07 -04:00
argv = append ( argv , "-Wl,-no_pie" )
}
2017-04-18 12:53:25 -07:00
case objabi . Hopenbsd :
2015-02-27 22:57:28 -05:00
argv = append ( argv , "-Wl,-nopie" )
2017-04-18 12:53:25 -07:00
case objabi . Hwindows :
2017-03-27 15:58:14 +11:00
if windowsgui {
argv = append ( argv , "-mwindows" )
} else {
argv = append ( argv , "-mconsole" )
}
2019-08-26 07:08:51 -06:00
// Mark as having awareness of terminal services, to avoid
// ancient compatibility hacks.
argv = append ( argv , "-Wl,--tsaware" )
2019-08-26 07:21:36 -06:00
argv = append ( argv , fmt . Sprintf ( "-Wl,--major-os-version=%d" , PeMinimumTargetMajorVersion ) )
argv = append ( argv , fmt . Sprintf ( "-Wl,--minor-os-version=%d" , PeMinimumTargetMinorVersion ) )
argv = append ( argv , fmt . Sprintf ( "-Wl,--major-subsystem-version=%d" , PeMinimumTargetMajorVersion ) )
argv = append ( argv , fmt . Sprintf ( "-Wl,--minor-subsystem-version=%d" , PeMinimumTargetMinorVersion ) )
2019-02-20 16:16:38 +01:00
case objabi . Haix :
argv = append ( argv , "-pthread" )
// prevent ld to reorder .text functions to keep the same
// first/last functions for moduledata.
argv = append ( argv , "-Wl,-bnoobjreorder" )
2019-02-20 16:42:11 +01:00
// mcmodel=large is needed for every gcc generated files, but
// ld still need -bbigtoc in order to allow larger TOC.
argv = append ( argv , "-mcmodel=large" )
argv = append ( argv , "-Wl,-bbigtoc" )
2015-03-09 03:05:40 -04:00
}
2015-02-27 22:57:28 -05:00
2017-10-05 10:20:17 -04:00
switch ctxt . BuildMode {
case BuildModeExe :
2017-10-07 13:49:44 -04:00
if ctxt . HeadType == objabi . Hdarwin {
2017-10-24 21:14:39 -04:00
if ctxt . Arch . Family == sys . ARM64 {
// __PAGEZERO segment size determined empirically.
// XCode 9.0.1 successfully uploads an iOS app with this value.
argv = append ( argv , "-Wl,-pagezero_size,100000000" )
} else {
argv = append ( argv , "-Wl,-pagezero_size,4000000" )
}
2015-06-16 10:07:45 -07:00
}
2017-10-05 10:20:17 -04:00
case BuildModePIE :
2017-08-05 18:25:26 +09:00
// ELF.
2019-03-22 12:54:37 +01:00
if ctxt . HeadType != objabi . Hdarwin && ctxt . HeadType != objabi . Haix {
2017-10-05 10:20:17 -04:00
if ctxt . UseRelro ( ) {
2017-08-05 18:25:26 +09:00
argv = append ( argv , "-Wl,-z,relro" )
}
argv = append ( argv , "-pie" )
2016-05-02 13:58:48 +12:00
}
2017-10-05 10:20:17 -04:00
case BuildModeCShared :
2017-10-07 13:49:44 -04:00
if ctxt . HeadType == objabi . Hdarwin {
2017-05-04 17:36:20 -04:00
argv = append ( argv , "-dynamiclib" )
2017-10-05 10:20:17 -04:00
if ctxt . Arch . Family != sys . AMD64 {
2017-05-04 17:36:20 -04:00
argv = append ( argv , "-Wl,-read_only_relocs,suppress" )
}
2015-06-16 10:07:45 -07:00
} else {
2015-10-08 10:22:50 -07:00
// ELF.
2015-06-16 10:07:45 -07:00
argv = append ( argv , "-Wl,-Bsymbolic" )
2017-10-05 10:20:17 -04:00
if ctxt . UseRelro ( ) {
2015-05-21 13:07:19 +12:00
argv = append ( argv , "-Wl,-z,relro" )
}
2017-10-05 17:36:13 +11:00
argv = append ( argv , "-shared" )
2017-10-07 13:49:44 -04:00
if ctxt . HeadType != objabi . Hwindows {
2017-10-05 17:36:13 +11:00
// Pass -z nodelete to mark the shared library as
// non-closeable: a dlclose will do nothing.
argv = append ( argv , "-Wl,-z,nodelete" )
}
2015-06-16 10:07:45 -07:00
}
2017-10-05 10:20:17 -04:00
case BuildModeShared :
if ctxt . UseRelro ( ) {
2015-09-16 22:06:16 +12:00
argv = append ( argv , "-Wl,-z,relro" )
2015-05-21 13:07:19 +12:00
}
2015-09-16 22:06:16 +12:00
argv = append ( argv , "-shared" )
2017-10-05 10:20:17 -04:00
case BuildModePlugin :
2017-10-07 13:49:44 -04:00
if ctxt . HeadType == objabi . Hdarwin {
2016-09-19 14:13:07 -04:00
argv = append ( argv , "-dynamiclib" )
} else {
2017-10-05 10:20:17 -04:00
if ctxt . UseRelro ( ) {
2016-09-19 14:13:07 -04:00
argv = append ( argv , "-Wl,-z,relro" )
}
argv = append ( argv , "-shared" )
}
2015-02-27 22:57:28 -05:00
}
2017-10-07 13:43:38 -04:00
if ctxt . IsELF && ctxt . DynlinkingGo ( ) {
2015-04-01 14:57:34 +13:00
// We force all symbol resolution to be done at program startup
// because lazy PLT resolution can use large amounts of stack at
// times we cannot allow it to do so.
2015-04-30 11:57:34 +10:00
argv = append ( argv , "-Wl,-znow" )
2016-04-16 11:08:41 -04:00
// Do not let the host linker generate COPY relocations. These
// can move symbols out of sections that rely on stable offsets
2017-10-04 17:54:04 -04:00
// from the beginning of the section (like sym.STYPE).
2016-04-16 11:08:41 -04:00
argv = append ( argv , "-Wl,-znocopyreloc" )
2019-09-05 08:50:11 +03:00
if ctxt . Arch . InFamily ( sys . ARM , sys . ARM64 ) && ( objabi . GOOS == "linux" || objabi . GOOS == "android" ) {
2016-04-18 07:24:48 -04:00
// On ARM, the GNU linker will generate COPY relocations
// even with -znocopyreloc set.
2016-04-16 11:08:41 -04:00
// https://sourceware.org/bugzilla/show_bug.cgi?id=19962
2016-04-18 07:24:48 -04:00
//
// On ARM64, the GNU linker will fail instead of
// generating COPY relocations.
//
// In both cases, switch to gold.
2016-04-16 11:08:41 -04:00
argv = append ( argv , "-fuse-ld=gold" )
2016-05-24 13:40:02 -04:00
// If gold is not installed, gcc will silently switch
// back to ld.bfd. So we parse the version information
// and provide a useful error if gold is missing.
2016-08-21 18:34:24 -04:00
cmd := exec . Command ( * flagExtld , "-fuse-ld=gold" , "-Wl,--version" )
2016-05-25 13:24:36 +02:00
if out , err := cmd . CombinedOutput ( ) ; err == nil {
2016-05-24 13:40:02 -04:00
if ! bytes . Contains ( out , [ ] byte ( "GNU gold" ) ) {
log . Fatalf ( "ARM external linker must be gold (issue #15696), but is not: %s" , out )
}
}
2016-04-16 11:08:41 -04:00
}
2015-04-01 14:57:34 +13:00
}
2017-10-07 13:43:38 -04:00
if ctxt . IsELF && len ( buildinfo ) > 0 {
2015-07-15 00:18:51 -07:00
argv = append ( argv , fmt . Sprintf ( "-Wl,--build-id=0x%x" , buildinfo ) )
}
2015-07-15 09:05:33 -07:00
// On Windows, given -o foo, GCC will append ".exe" to produce
// "foo.exe". We have decided that we want to honor the -o
2016-03-01 23:21:55 +00:00
// option. To make this work, we append a '.' so that GCC
// will decide that the file already has an extension. We
2015-07-15 09:05:33 -07:00
// only want to do this when producing a Windows output file
// on a Windows host.
2016-08-21 18:34:24 -04:00
outopt := * flagOutfile
2017-04-18 12:53:25 -07:00
if objabi . GOOS == "windows" && runtime . GOOS == "windows" && filepath . Ext ( outopt ) == "" {
2015-07-15 09:05:33 -07:00
outopt += "."
}
2015-02-27 22:57:28 -05:00
argv = append ( argv , "-o" )
2015-07-15 09:05:33 -07:00
argv = append ( argv , outopt )
2015-02-27 22:57:28 -05:00
2015-04-12 02:31:28 +02:00
if rpath . val != "" {
argv = append ( argv , fmt . Sprintf ( "-Wl,-rpath,%s" , rpath . val ) )
2015-02-27 22:57:28 -05:00
}
// Force global symbols to be exported for dlopen, etc.
2017-10-07 13:43:38 -04:00
if ctxt . IsELF {
2015-02-27 22:57:28 -05:00
argv = append ( argv , "-rdynamic" )
}
2019-02-20 16:26:54 +01:00
if ctxt . HeadType == objabi . Haix {
fileName := xcoffCreateExportFile ( ctxt )
argv = append ( argv , "-Wl,-bE:" + fileName )
}
2015-02-27 22:57:28 -05:00
if strings . Contains ( argv [ 0 ] , "clang" ) {
argv = append ( argv , "-Qunused-arguments" )
}
2018-05-07 13:44:22 -04:00
const compressDWARF = "-Wl,--compress-debug-sections=zlib-gnu"
2018-06-20 16:45:25 -04:00
if ctxt . compressDWARF && linkerFlagSupported ( argv [ 0 ] , compressDWARF ) {
2018-05-07 13:44:22 -04:00
argv = append ( argv , compressDWARF )
}
2016-08-21 18:34:24 -04:00
argv = append ( argv , filepath . Join ( * flagTmpdir , "go.o" ) )
2015-11-16 15:45:12 -05:00
argv = append ( argv , hostobjCopy ( ) ... )
2019-02-20 16:52:35 +01:00
if ctxt . HeadType == objabi . Haix {
// We want to have C files after Go files to remove
// trampolines csects made by ld.
argv = append ( argv , "-nostartfiles" )
argv = append ( argv , "/lib/crt0_64.o" )
extld := ctxt . extld ( )
// Get starting files.
getPathFile := func ( file string ) string {
args := [ ] string { "-maix64" , "--print-file-name=" + file }
out , err := exec . Command ( extld , args ... ) . CombinedOutput ( )
if err != nil {
log . Fatalf ( "running %s failed: %v\n%s" , extld , err , out )
}
return strings . Trim ( string ( out ) , "\n" )
}
argv = append ( argv , getPathFile ( "crtcxa.o" ) )
argv = append ( argv , getPathFile ( "crtdbase.o" ) )
}
2015-04-01 14:57:34 +13:00
2017-10-07 13:28:51 -04:00
if ctxt . linkShared {
2015-05-25 14:51:02 +12:00
seenDirs := make ( map [ string ] bool )
seenLibs := make ( map [ string ] bool )
addshlib := func ( path string ) {
dir , base := filepath . Split ( path )
if ! seenDirs [ dir ] {
argv = append ( argv , "-L" + dir )
if ! rpath . set {
argv = append ( argv , "-Wl,-rpath=" + dir )
}
seenDirs [ dir ] = true
2015-04-12 02:31:28 +02:00
}
2015-04-01 14:57:34 +13:00
base = strings . TrimSuffix ( base , ".so" )
base = strings . TrimPrefix ( base , "lib" )
2015-05-25 14:51:02 +12:00
if ! seenLibs [ base ] {
argv = append ( argv , "-l" + base )
seenLibs [ base ] = true
}
}
2017-10-05 10:20:17 -04:00
for _ , shlib := range ctxt . Shlibs {
2015-05-25 14:51:02 +12:00
addshlib ( shlib . Path )
for _ , dep := range shlib . Deps {
if dep == "" {
continue
}
2017-10-05 10:20:17 -04:00
libpath := findshlib ( ctxt , dep )
2015-05-25 14:51:02 +12:00
if libpath != "" {
addshlib ( libpath )
}
}
2015-04-01 14:57:34 +13:00
}
}
2018-07-03 10:16:03 -07:00
// clang, unlike GCC, passes -rdynamic to the linker
// even when linking with -static, causing a linker
// error when using GNU ld. So take out -rdynamic if
// we added it. We do it in this order, rather than
// only adding -rdynamic later, so that -*extldflags
// can override -rdynamic without using -static.
checkStatic := func ( arg string ) {
if ctxt . IsELF && arg == "-static" {
for i := range argv {
if argv [ i ] == "-rdynamic" {
argv [ i ] = "-static"
}
}
}
}
for _ , p := range ldflag {
argv = append ( argv , p )
checkStatic ( p )
}
2015-02-27 22:57:28 -05:00
2016-11-10 22:08:51 -08:00
// When building a program with the default -buildmode=exe the
// gc compiler generates code requires DT_TEXTREL in a
// position independent executable (PIE). On systems where the
// toolchain creates PIEs by default, and where DT_TEXTREL
// does not work, the resulting programs will not run. See
// issue #17847. To avoid this problem pass -no-pie to the
// toolchain if it is supported.
2018-04-05 10:07:41 +12:00
if ctxt . BuildMode == BuildModeExe && ! ctxt . linkShared {
2017-07-18 13:15:05 -07:00
// GCC uses -no-pie, clang uses -nopie.
for _ , nopie := range [ ] string { "-no-pie" , "-nopie" } {
2018-05-07 13:44:22 -04:00
if linkerFlagSupported ( argv [ 0 ] , nopie ) {
2017-07-18 13:15:05 -07:00
argv = append ( argv , nopie )
break
}
2016-04-26 21:37:49 +12:00
}
}
2016-08-21 18:34:24 -04:00
for _ , p := range strings . Fields ( * flagExtldflags ) {
2015-02-27 22:57:28 -05:00
argv = append ( argv , p )
2018-07-03 10:16:03 -07:00
checkStatic ( p )
2015-02-27 22:57:28 -05:00
}
2017-10-07 13:49:44 -04:00
if ctxt . HeadType == objabi . Hwindows {
2017-05-11 11:55:59 +10:00
// use gcc linker script to work around gcc bug
// (see https://golang.org/issue/20183 for details).
p := writeGDBLinkerScript ( )
argv = append ( argv , "-Wl,-T," + p )
2016-08-10 11:06:46 +10:00
// libmingw32 and libmingwex have some inter-dependencies,
// so must use linker groups.
argv = append ( argv , "-Wl,--start-group" , "-lmingwex" , "-lmingw32" , "-Wl,--end-group" )
2015-03-09 03:05:40 -04:00
argv = append ( argv , peimporteddlls ( ) ... )
}
2015-02-27 22:57:28 -05:00
2017-10-05 10:20:17 -04:00
if ctxt . Debugvlog != 0 {
ctxt . Logf ( "%5.2f host link:" , Cputime ( ) )
2015-04-08 16:49:43 -04:00
for _ , v := range argv {
2017-10-05 10:20:17 -04:00
ctxt . Logf ( " %q" , v )
2015-02-27 22:57:28 -05:00
}
2017-10-05 10:20:17 -04:00
ctxt . Logf ( "\n" )
2015-02-27 22:57:28 -05:00
}
2018-10-24 12:01:13 -04:00
out , err := exec . Command ( argv [ 0 ] , argv [ 1 : ] ... ) . CombinedOutput ( )
if err != nil {
2015-04-09 07:37:17 -04:00
Exitf ( "running %s failed: %v\n%s" , argv [ 0 ] , err , out )
2018-10-24 12:01:13 -04:00
}
// Filter out useless linker warnings caused by bugs outside Go.
// See also cmd/go/internal/work/exec.go's gccld method.
var save [ ] [ ] byte
2019-02-20 16:42:11 +01:00
var skipLines int
2018-10-24 12:01:13 -04:00
for _ , line := range bytes . SplitAfter ( out , [ ] byte ( "\n" ) ) {
// golang.org/issue/26073 - Apple Xcode bug
if bytes . Contains ( line , [ ] byte ( "ld: warning: text-based stub file" ) ) {
continue
}
2019-02-20 16:42:11 +01:00
if skipLines > 0 {
skipLines --
continue
}
// Remove TOC overflow warning on AIX.
if bytes . Contains ( line , [ ] byte ( "ld: 0711-783" ) ) {
skipLines = 2
continue
}
2018-10-24 12:01:13 -04:00
save = append ( save , line )
}
out = bytes . Join ( save , nil )
if len ( out ) > 0 {
2016-11-16 01:05:34 -05:00
// always print external output even if the command is successful, so that we don't
// swallow linker warnings (see https://golang.org/issue/17935).
2017-10-05 10:20:17 -04:00
ctxt . Logf ( "%s" , out )
2015-02-27 22:57:28 -05:00
}
2015-04-08 12:55:34 -07:00
2017-10-07 13:49:44 -04:00
if ! * FlagS && ! * FlagW && ! debug_s && ctxt . HeadType == objabi . Hdarwin {
2018-04-19 15:09:34 -04:00
dsym := filepath . Join ( * flagTmpdir , "go.dwarf" )
if out , err := exec . Command ( "dsymutil" , "-f" , * flagOutfile , "-o" , dsym ) . CombinedOutput ( ) ; err != nil {
Exitf ( "%s: running dsymutil failed: %v\n%s" , os . Args [ 0 ] , err , out )
}
// Skip combining if `dsymutil` didn't generate a file. See #11994.
if _ , err := os . Stat ( dsym ) ; os . IsNotExist ( err ) {
return
}
// For os.Rename to work reliably, must be in same directory as outfile.
combinedOutput := * flagOutfile + "~"
2019-03-20 20:10:38 +01:00
exef , err := os . Open ( * flagOutfile )
2018-05-03 15:38:37 +02:00
if err != nil {
2018-04-19 15:09:34 -04:00
Exitf ( "%s: combining dwarf failed: %v" , os . Args [ 0 ] , err )
}
2019-03-20 20:10:38 +01:00
defer exef . Close ( )
exem , err := macho . NewFile ( exef )
if err != nil {
Exitf ( "%s: parsing Mach-O header failed: %v" , os . Args [ 0 ] , err )
}
// Only macOS supports unmapped segments such as our __DWARF segment.
2019-04-27 11:28:49 +02:00
if machoPlatform == PLATFORM_MACOS {
2019-03-20 20:10:38 +01:00
if err := machoCombineDwarf ( ctxt , exef , exem , dsym , combinedOutput ) ; err != nil {
Exitf ( "%s: combining dwarf failed: %v" , os . Args [ 0 ] , err )
}
2018-05-03 15:38:37 +02:00
os . Remove ( * flagOutfile )
if err := os . Rename ( combinedOutput , * flagOutfile ) ; err != nil {
Exitf ( "%s: %v" , os . Args [ 0 ] , err )
}
2015-04-08 12:55:34 -07:00
}
}
2015-02-27 22:57:28 -05:00
}
2018-05-07 13:44:22 -04:00
var createTrivialCOnce sync . Once
func linkerFlagSupported ( linker , flag string ) bool {
createTrivialCOnce . Do ( func ( ) {
src := filepath . Join ( * flagTmpdir , "trivial.c" )
if err := ioutil . WriteFile ( src , [ ] byte ( "int main() { return 0; }" ) , 0666 ) ; err != nil {
Errorf ( nil , "WriteFile trivial.c failed: %v" , err )
}
} )
2018-09-07 12:53:52 -07:00
flagsWithNextArgSkip := [ ] string {
"-F" ,
"-l" ,
"-L" ,
"-framework" ,
"-Wl,-framework" ,
"-Wl,-rpath" ,
"-Wl,-undefined" ,
}
flagsWithNextArgKeep := [ ] string {
"-arch" ,
"-isysroot" ,
"--sysroot" ,
"-target" ,
}
prefixesToKeep := [ ] string {
"-f" ,
"-m" ,
"-p" ,
"-Wl," ,
"-arch" ,
"-isysroot" ,
"--sysroot" ,
"-target" ,
}
2018-08-20 18:42:02 -07:00
var flags [ ] string
2018-09-07 12:53:52 -07:00
keep := false
skip := false
extldflags := strings . Fields ( * flagExtldflags )
for _ , f := range append ( extldflags , ldflag ... ) {
if keep {
flags = append ( flags , f )
keep = false
} else if skip {
skip = false
} else if f == "" || f [ 0 ] != '-' {
} else if contains ( flagsWithNextArgSkip , f ) {
skip = true
} else if contains ( flagsWithNextArgKeep , f ) {
flags = append ( flags , f )
keep = true
} else {
for _ , p := range prefixesToKeep {
if strings . HasPrefix ( f , p ) {
flags = append ( flags , f )
break
}
}
}
}
2018-08-20 18:42:02 -07:00
flags = append ( flags , flag , "trivial.c" )
cmd := exec . Command ( linker , flags ... )
2018-05-07 13:44:22 -04:00
cmd . Dir = * flagTmpdir
cmd . Env = append ( [ ] string { "LC_ALL=C" } , os . Environ ( ) ... )
out , err := cmd . CombinedOutput ( )
// GCC says "unrecognized command line option ‘ -no-pie’ "
// clang says "unknown argument: '-no-pie'"
return err == nil && ! bytes . Contains ( out , [ ] byte ( "unrecognized" ) ) && ! bytes . Contains ( out , [ ] byte ( "unknown" ) )
}
2015-11-16 18:11:35 -08:00
// hostlinkArchArgs returns arguments to pass to the external linker
// based on the architecture.
2017-09-30 21:10:49 +00:00
func hostlinkArchArgs ( arch * sys . Arch ) [ ] string {
switch arch . Family {
2016-04-06 12:01:40 -07:00
case sys . I386 :
2015-11-16 18:11:35 -08:00
return [ ] string { "-m32" }
2019-02-20 16:16:38 +01:00
case sys . AMD64 , sys . S390X :
2015-11-16 18:11:35 -08:00
return [ ] string { "-m64" }
2016-04-06 12:01:40 -07:00
case sys . ARM :
2015-11-16 18:11:35 -08:00
return [ ] string { "-marm" }
2016-04-06 12:01:40 -07:00
case sys . ARM64 :
2015-11-16 18:11:35 -08:00
// nothing needed
2016-05-04 21:38:45 -07:00
case sys . MIPS64 :
2016-04-27 22:18:09 -04:00
return [ ] string { "-mabi=64" }
2016-12-13 21:23:39 +01:00
case sys . MIPS :
return [ ] string { "-mabi=32" }
2019-02-20 16:16:38 +01:00
case sys . PPC64 :
if objabi . GOOS == "aix" {
return [ ] string { "-maix64" }
} else {
return [ ] string { "-m64" }
}
2015-11-16 18:11:35 -08:00
}
return nil
}
2016-03-01 23:21:55 +00:00
// ldobj loads an input object. If it is a host object (an object
// compiled by a non-Go compiler) it returns the Hostobj pointer. If
2015-11-04 11:14:19 -08:00
// it is a Go object, it returns nil.
2018-03-23 10:28:39 -07:00
func ldobj ( ctxt * Link , f * bio . Reader , lib * sym . Library , length int64 , pn string , file string ) * Hostobj {
2017-04-17 18:46:09 -05:00
pkg := objabi . PathToPrefix ( lib . Pkg )
2015-02-27 22:57:28 -05:00
2016-09-14 14:47:12 -04:00
eof := f . Offset ( ) + length
2016-04-08 19:14:03 +10:00
start := f . Offset ( )
2016-04-08 20:44:56 +10:00
c1 := bgetc ( f )
c2 := bgetc ( f )
c3 := bgetc ( f )
c4 := bgetc ( f )
2019-05-08 18:46:04 -04:00
f . MustSeek ( start , 0 )
2015-02-27 22:57:28 -05:00
2019-08-09 11:36:03 -04:00
unit := & sym . CompilationUnit { Lib : lib }
lib . Units = append ( lib . Units , unit )
2015-03-02 12:35:15 -05:00
magic := uint32 ( c1 ) << 24 | uint32 ( c2 ) << 16 | uint32 ( c3 ) << 8 | uint32 ( c4 )
2015-02-27 22:57:28 -05:00
if magic == 0x7f454c46 { // \x7F E L F
2017-10-06 16:01:02 -04:00
ldelf := func ( ctxt * Link , f * bio . Reader , pkg string , length int64 , pn string ) {
textp , flags , err := loadelf . Load ( ctxt . Arch , ctxt . Syms , f , pkg , length , pn , ehdr . flags )
if err != nil {
Errorf ( nil , "%v" , err )
return
}
ehdr . flags = flags
ctxt . Textp = append ( ctxt . Textp , textp ... )
}
2017-10-07 13:49:44 -04:00
return ldhostobj ( ldelf , ctxt . HeadType , f , pkg , length , pn , file )
2015-02-27 22:57:28 -05:00
}
if magic &^ 1 == 0xfeedface || magic &^ 0x01000000 == 0xcefaedfe {
2019-10-11 13:58:43 -04:00
if * flagNewobj {
ldmacho := func ( ctxt * Link , f * bio . Reader , pkg string , length int64 , pn string ) {
err := loadmacho . Load ( ctxt . loader , ctxt . Arch , ctxt . Syms , f , pkg , length , pn )
if err != nil {
Errorf ( nil , "%v" , err )
return
}
2017-10-06 11:53:52 -04:00
}
2019-10-11 13:58:43 -04:00
return ldhostobj ( ldmacho , ctxt . HeadType , f , pkg , length , pn , file )
} else {
ldmacho := func ( ctxt * Link , f * bio . Reader , pkg string , length int64 , pn string ) {
textp , err := loadmacho . LoadOld ( ctxt . Arch , ctxt . Syms , f , pkg , length , pn )
if err != nil {
Errorf ( nil , "%v" , err )
return
}
ctxt . Textp = append ( ctxt . Textp , textp ... )
}
return ldhostobj ( ldmacho , ctxt . HeadType , f , pkg , length , pn , file )
2017-10-06 11:53:52 -04:00
}
2015-02-27 22:57:28 -05:00
}
if c1 == 0x4c && c2 == 0x01 || c1 == 0x64 && c2 == 0x86 {
2017-10-12 13:38:45 -04:00
ldpe := func ( ctxt * Link , f * bio . Reader , pkg string , length int64 , pn string ) {
textp , rsrc , err := loadpe . Load ( ctxt . Arch , ctxt . Syms , f , pkg , length , pn )
if err != nil {
Errorf ( nil , "%v" , err )
return
}
if rsrc != nil {
setpersrc ( ctxt , rsrc )
}
ctxt . Textp = append ( ctxt . Textp , textp ... )
}
2017-10-07 13:49:44 -04:00
return ldhostobj ( ldpe , ctxt . HeadType , f , pkg , length , pn , file )
2015-02-27 22:57:28 -05:00
}
2018-09-28 17:02:16 +02:00
if c1 == 0x01 && ( c2 == 0xD7 || c2 == 0xF7 ) {
ldxcoff := func ( ctxt * Link , f * bio . Reader , pkg string , length int64 , pn string ) {
textp , err := loadxcoff . Load ( ctxt . Arch , ctxt . Syms , f , pkg , length , pn )
if err != nil {
Errorf ( nil , "%v" , err )
return
}
ctxt . Textp = append ( ctxt . Textp , textp ... )
}
return ldhostobj ( ldxcoff , ctxt . HeadType , f , pkg , length , pn , file )
}
2015-02-27 22:57:28 -05:00
/* check the header */
2016-04-08 20:44:56 +10:00
line , err := f . ReadString ( '\n' )
if err != nil {
2016-09-17 09:39:33 -04:00
Errorf ( nil , "truncated object file: %s: %v" , pn , err )
2015-11-04 11:14:19 -08:00
return nil
2015-02-27 22:57:28 -05:00
}
if ! strings . HasPrefix ( line , "go object " ) {
if strings . HasSuffix ( pn , ".go" ) {
2016-04-06 18:54:17 -07:00
Exitf ( "%s: uncompiled .go source file" , pn )
return nil
2015-02-27 22:57:28 -05:00
}
2017-09-30 21:10:49 +00:00
if line == ctxt . Arch . Name {
2015-02-27 22:57:28 -05:00
// old header format: just $GOOS
2016-09-17 09:39:33 -04:00
Errorf ( nil , "%s: stale object file" , pn )
2015-11-04 11:14:19 -08:00
return nil
2015-02-27 22:57:28 -05:00
}
2016-09-17 09:39:33 -04:00
Errorf ( nil , "%s: not an object file" , pn )
2015-11-04 11:14:19 -08:00
return nil
2015-02-27 22:57:28 -05:00
}
2016-09-09 08:13:16 -04:00
// First, check that the basic GOOS, GOARCH, and Version match.
2017-04-18 12:53:25 -07:00
t := fmt . Sprintf ( "%s %s %s " , objabi . GOOS , objabi . GOARCH , objabi . Version )
2015-02-27 22:57:28 -05:00
line = strings . TrimRight ( line , "\n" )
2016-08-21 18:34:24 -04:00
if ! strings . HasPrefix ( line [ 10 : ] + " " , t ) && ! * flagF {
2016-09-17 09:39:33 -04:00
Errorf ( nil , "%s: object is [%s] expected [%s]" , pn , line [ 10 : ] , t )
2015-11-04 11:14:19 -08:00
return nil
2015-02-27 22:57:28 -05:00
}
// Second, check that longer lines match each other exactly,
// so that the Go compiler and write additional information
// that must be the same from run to run.
if len ( line ) >= len ( t ) + 10 {
if theline == "" {
theline = line [ 10 : ]
} else if theline != line [ 10 : ] {
2016-09-17 09:39:33 -04:00
Errorf ( nil , "%s: object is [%s] expected [%s]" , pn , line [ 10 : ] , theline )
2015-11-04 11:14:19 -08:00
return nil
2015-02-27 22:57:28 -05:00
}
}
2017-11-21 11:27:20 -08:00
// Skip over exports and other info -- ends with \n!\n.
//
// Note: It's possible for "\n!\n" to appear within the binary
// package export data format. To avoid truncating the package
2018-10-06 06:10:25 +00:00
// definition prematurely (issue 21703), we keep track of
2017-11-21 11:27:20 -08:00
// how many "$$" delimiters we've seen.
2016-04-08 19:14:03 +10:00
import0 := f . Offset ( )
2015-02-27 22:57:28 -05:00
c1 = '\n' // the last line ended in \n
2016-04-08 20:44:56 +10:00
c2 = bgetc ( f )
c3 = bgetc ( f )
2017-11-21 11:27:20 -08:00
markers := 0
for {
if c1 == '\n' {
if markers % 2 == 0 && c2 == '!' && c3 == '\n' {
break
}
if c2 == '$' && c3 == '$' {
markers ++
}
}
2015-02-27 22:57:28 -05:00
c1 = c2
c2 = c3
2016-04-08 20:44:56 +10:00
c3 = bgetc ( f )
if c3 == - 1 {
2016-09-17 09:39:33 -04:00
Errorf ( nil , "truncated object file: %s" , pn )
2015-11-04 11:14:19 -08:00
return nil
2015-02-27 22:57:28 -05:00
}
}
2016-04-08 19:14:03 +10:00
import1 := f . Offset ( )
2015-02-27 22:57:28 -05:00
2019-05-08 18:46:04 -04:00
f . MustSeek ( import0 , 0 )
2018-03-23 10:28:39 -07:00
ldpkg ( ctxt , f , lib , import1 - import0 - 2 , pn ) // -2 for !\n
2019-05-08 18:46:04 -04:00
f . MustSeek ( import1 , 0 )
2015-02-27 22:57:28 -05:00
cmd/link: add optional sanity checking for duplicate symbols
Introduce a new linker command line option "-strictdups", which
enables sanity checking of "ok to duplicate" symbols, especially
DWARF info symbols. Acceptable values are 0 (no checking) 1 (issue
warnings) and 2 (issue a fatal error checks fail).
Currently if we read a DWARF symbol (such as "go.info.PKG.FUNCTION")
from one object file, and then encounter the same symbol later on
while reading another object file, we simply discard the second one
and move on with the link, since the two should in theory be
identical.
If as a result of a compiler bug we wind up with symbols that are not
identical, this tends to (silently) result in incorrect DWARF
generation, which may or may not be discovered depending on who is
consuming the DWARF and what's being done with it.
When this option is turned on, at the point where a duplicate
symbol is detected in the object file reader, we check to make sure
that the length/contents of the symbol are the same as the previously
read symbol, and print a descriptive warning (or error) if not.
For the time being this can be used for one-off testing to find
problems; at some point it would be nice if we can enable it by
default.
Updates #30908.
Change-Id: I64c4e07c326b4572db674ff17c93307e2eec607c
Reviewed-on: https://go-review.googlesource.com/c/go/+/168410
Run-TryBot: Than McIntosh <thanm@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Keith Randall <khr@golang.org>
2019-03-21 09:20:11 -04:00
flags := 0
switch * FlagStrictDups {
case 0 :
break
case 1 :
flags = objfile . StrictDupsWarnFlag
case 2 :
flags = objfile . StrictDupsErrFlag
default :
log . Fatalf ( "invalid -strictdups flag value %d" , * FlagStrictDups )
}
2019-09-17 16:14:37 -04:00
var c int
if * flagNewobj {
2019-10-14 10:06:37 -04:00
ctxt . loader . Preload ( ctxt . Arch , ctxt . Syms , f , lib , unit , eof - f . Offset ( ) , pn , flags )
2019-09-17 16:14:37 -04:00
} else {
c = objfile . Load ( ctxt . Arch , ctxt . Syms , f , lib , unit , eof - f . Offset ( ) , pn , flags )
}
2019-03-26 12:02:36 -04:00
strictDupMsgCount += c
2017-10-04 18:13:35 -04:00
addImports ( ctxt , lib , pn )
2015-11-04 11:14:19 -08:00
return nil
2015-02-27 22:57:28 -05:00
}
2016-08-19 22:40:38 -04:00
func readelfsymboldata ( ctxt * Link , f * elf . File , sym * elf . Symbol ) [ ] byte {
2015-04-11 12:05:21 +08:00
data := make ( [ ] byte , sym . Size )
sect := f . Sections [ sym . Section ]
2015-05-25 13:59:08 +12:00
if sect . Type != elf . SHT_PROGBITS && sect . Type != elf . SHT_NOTE {
2016-09-17 09:39:33 -04:00
Errorf ( nil , "reading %s from non-data section" , sym . Name )
2015-04-11 12:05:21 +08:00
}
2015-05-25 16:13:50 +12:00
n , err := sect . ReadAt ( data , int64 ( sym . Value - sect . Addr ) )
2015-04-11 12:05:21 +08:00
if uint64 ( n ) != sym . Size {
2016-09-17 09:39:33 -04:00
Errorf ( nil , "reading contents of %s: %v" , sym . Name , err )
2015-04-11 12:05:21 +08:00
}
return data
}
2015-05-25 13:59:08 +12:00
func readwithpad ( r io . Reader , sz int32 ) ( [ ] byte , error ) {
data := make ( [ ] byte , Rnd ( int64 ( sz ) , 4 ) )
_ , err := io . ReadFull ( r , data )
if err != nil {
return nil , err
}
data = data [ : sz ]
return data , nil
}
func readnote ( f * elf . File , name [ ] byte , typ int32 ) ( [ ] byte , error ) {
for _ , sect := range f . Sections {
if sect . Type != elf . SHT_NOTE {
continue
}
r := sect . Open ( )
for {
var namesize , descsize , noteType int32
err := binary . Read ( r , f . ByteOrder , & namesize )
if err != nil {
if err == io . EOF {
break
}
2015-10-30 16:25:29 +01:00
return nil , fmt . Errorf ( "read namesize failed: %v" , err )
2015-05-25 13:59:08 +12:00
}
err = binary . Read ( r , f . ByteOrder , & descsize )
if err != nil {
2015-10-30 16:25:29 +01:00
return nil , fmt . Errorf ( "read descsize failed: %v" , err )
2015-05-25 13:59:08 +12:00
}
err = binary . Read ( r , f . ByteOrder , & noteType )
if err != nil {
2015-10-30 16:25:29 +01:00
return nil , fmt . Errorf ( "read type failed: %v" , err )
2015-05-25 13:59:08 +12:00
}
noteName , err := readwithpad ( r , namesize )
if err != nil {
2015-10-30 16:25:29 +01:00
return nil , fmt . Errorf ( "read name failed: %v" , err )
2015-05-25 13:59:08 +12:00
}
desc , err := readwithpad ( r , descsize )
if err != nil {
2015-10-30 16:25:29 +01:00
return nil , fmt . Errorf ( "read desc failed: %v" , err )
2015-05-25 13:59:08 +12:00
}
if string ( name ) == string ( noteName ) && typ == noteType {
return desc , nil
}
}
}
return nil , nil
}
2016-08-19 22:40:38 -04:00
func findshlib ( ctxt * Link , shlib string ) string {
2017-06-09 11:15:53 -04:00
if filepath . IsAbs ( shlib ) {
return shlib
}
2016-08-19 22:40:38 -04:00
for _ , libdir := range ctxt . Libdir {
2015-05-25 14:51:02 +12:00
libpath := filepath . Join ( libdir , shlib )
2015-04-01 14:57:34 +13:00
if _ , err := os . Stat ( libpath ) ; err == nil {
2015-05-25 14:51:02 +12:00
return libpath
2015-04-01 14:57:34 +13:00
}
}
2016-09-17 09:39:33 -04:00
Errorf ( nil , "cannot find shared library: %s" , shlib )
2015-05-25 14:51:02 +12:00
return ""
}
2016-08-19 22:40:38 -04:00
func ldshlibsyms ( ctxt * Link , shlib string ) {
2017-06-09 11:15:53 -04:00
var libpath string
if filepath . IsAbs ( shlib ) {
libpath = shlib
shlib = filepath . Base ( shlib )
} else {
libpath = findshlib ( ctxt , shlib )
if libpath == "" {
return
}
2015-04-01 14:57:34 +13:00
}
2016-08-19 22:40:38 -04:00
for _ , processedlib := range ctxt . Shlibs {
2015-04-11 12:05:21 +08:00
if processedlib . Path == libpath {
2015-04-01 14:57:34 +13:00
return
}
}
2016-08-25 12:32:42 +10:00
if ctxt . Debugvlog > 1 {
2017-04-18 12:53:25 -07:00
ctxt . Logf ( "%5.2f ldshlibsyms: found library with name %s at %s\n" , Cputime ( ) , shlib , libpath )
2015-04-01 14:57:34 +13:00
}
f , err := elf . Open ( libpath )
if err != nil {
2016-09-17 09:39:33 -04:00
Errorf ( nil , "cannot open shared library: %s" , libpath )
2015-04-01 14:57:34 +13:00
return
}
2017-08-22 19:50:43 +09:00
defer f . Close ( )
2015-05-25 13:59:08 +12:00
hash , err := readnote ( f , ELF_NOTE_GO_NAME , ELF_NOTE_GOABIHASH_TAG )
if err != nil {
2016-09-17 09:39:33 -04:00
Errorf ( nil , "cannot read ABI hash from shared library %s: %v" , libpath , err )
2015-05-25 13:59:08 +12:00
return
}
2015-05-25 14:51:02 +12:00
depsbytes , err := readnote ( f , ELF_NOTE_GO_NAME , ELF_NOTE_GODEPS_TAG )
if err != nil {
2016-09-17 09:39:33 -04:00
Errorf ( nil , "cannot read dep list from shared library %s: %v" , libpath , err )
2015-05-25 14:51:02 +12:00
return
}
2017-06-09 11:15:53 -04:00
var deps [ ] string
for _ , dep := range strings . Split ( string ( depsbytes ) , "\n" ) {
if dep == "" {
continue
}
if ! filepath . IsAbs ( dep ) {
// If the dep can be interpreted as a path relative to the shlib
// in which it was found, do that. Otherwise, we will leave it
// to be resolved by libdir lookup.
abs := filepath . Join ( filepath . Dir ( libpath ) , dep )
if _ , err := os . Stat ( abs ) ; err == nil {
dep = abs
}
}
deps = append ( deps , dep )
}
2015-05-25 14:51:02 +12:00
2015-05-25 16:13:50 +12:00
syms , err := f . DynamicSymbols ( )
2015-04-01 14:57:34 +13:00
if err != nil {
2016-09-17 09:39:33 -04:00
Errorf ( nil , "cannot read symbols from shared library: %s" , libpath )
2015-04-01 14:57:34 +13:00
return
}
2017-10-04 17:54:04 -04:00
gcdataLocations := make ( map [ uint64 ] * sym . Symbol )
2015-06-16 13:41:11 +12:00
for _ , elfsym := range syms {
if elf . ST_TYPE ( elfsym . Info ) == elf . STT_NOTYPE || elf . ST_TYPE ( elfsym . Info ) == elf . STT_SECTION {
2015-04-01 14:57:34 +13:00
continue
}
2019-07-13 12:20:43 -07:00
// Symbols whose names start with "type." are compiler
// generated, so make functions with that prefix internal.
ver := 0
if elf . ST_TYPE ( elfsym . Info ) == elf . STT_FUNC && strings . HasPrefix ( elfsym . Name , "type." ) {
ver = sym . SymVerABIInternal
}
2019-10-04 22:05:41 -04:00
lsym := ctxt . Syms . Lookup ( elfsym . Name , ver )
2016-01-20 15:31:26 +13:00
// Because loadlib above loads all .a files before loading any shared
2016-05-04 11:23:24 +12:00
// libraries, any non-dynimport symbols we find that duplicate symbols
// already loaded should be ignored (the symbols from the .a files
// "win").
2017-10-04 17:54:04 -04:00
if lsym . Type != 0 && lsym . Type != sym . SDYNIMPORT {
2016-01-20 15:31:26 +13:00
continue
2015-04-01 14:57:34 +13:00
}
2017-10-04 17:54:04 -04:00
lsym . Type = sym . SDYNIMPORT
2018-07-18 10:19:35 -04:00
lsym . SetElfType ( elf . ST_TYPE ( elfsym . Info ) )
2015-06-16 13:41:11 +12:00
lsym . Size = int64 ( elfsym . Size )
if elfsym . Section != elf . SHN_UNDEF {
2015-05-25 16:13:50 +12:00
// Set .File for the library that actually defines the symbol.
lsym . File = libpath
// The decodetype_* functions in decodetype.go need access to
// the type data.
if strings . HasPrefix ( lsym . Name , "type." ) && ! strings . HasPrefix ( lsym . Name , "type.." ) {
2016-08-19 22:40:38 -04:00
lsym . P = readelfsymboldata ( ctxt , f , & elfsym )
2017-09-30 21:10:49 +00:00
gcdataLocations [ elfsym . Value + 2 * uint64 ( ctxt . Arch . PtrSize ) + 8 + 1 * uint64 ( ctxt . Arch . PtrSize ) ] = lsym
2015-07-02 11:37:51 +12:00
}
}
2018-11-01 12:30:23 -04:00
// For function symbols, we don't know what ABI is
// available, so alias it under both ABIs.
//
// TODO(austin): This is almost certainly wrong once
// the ABIs are actually different. We might have to
// mangle Go function names in the .so to include the
// ABI.
2019-07-13 12:20:43 -07:00
if elf . ST_TYPE ( elfsym . Info ) == elf . STT_FUNC && ver == 0 {
2018-11-01 12:30:23 -04:00
alias := ctxt . Syms . Lookup ( elfsym . Name , sym . SymVerABIInternal )
if alias . Type != 0 {
continue
}
alias . Type = sym . SABIALIAS
alias . R = [ ] sym . Reloc { { Sym : lsym } }
}
2015-07-02 11:37:51 +12:00
}
2017-10-04 17:54:04 -04:00
gcdataAddresses := make ( map [ * sym . Symbol ] uint64 )
2017-09-30 21:10:49 +00:00
if ctxt . Arch . Family == sys . ARM64 {
2015-07-02 11:37:51 +12:00
for _ , sect := range f . Sections {
if sect . Type == elf . SHT_RELA {
var rela elf . Rela64
rdr := sect . Open ( )
for {
err := binary . Read ( rdr , f . ByteOrder , & rela )
if err == io . EOF {
break
} else if err != nil {
2016-09-17 09:39:33 -04:00
Errorf ( nil , "reading relocation failed %v" , err )
2015-07-02 11:37:51 +12:00
return
}
t := elf . R_AARCH64 ( rela . Info & 0xffff )
if t != elf . R_AARCH64_RELATIVE {
continue
}
2016-08-22 10:33:13 -04:00
if lsym , ok := gcdataLocations [ rela . Off ] ; ok {
gcdataAddresses [ lsym ] = uint64 ( rela . Addend )
2015-07-02 11:37:51 +12:00
}
}
2015-04-01 16:20:44 +13:00
}
}
2015-04-01 14:57:34 +13:00
}
2016-08-22 10:33:13 -04:00
ctxt . Shlibs = append ( ctxt . Shlibs , Shlib { Path : libpath , Hash : hash , Deps : deps , File : f , gcdataAddresses : gcdataAddresses } )
2015-04-01 14:57:34 +13:00
}
2017-10-04 17:54:04 -04:00
func addsection ( arch * sys . Arch , seg * sym . Segment , name string , rwx int ) * sym . Section {
sect := new ( sym . Section )
2015-02-27 22:57:28 -05:00
sect . Rwx = uint8 ( rwx )
sect . Name = name
sect . Seg = seg
2017-09-30 21:10:49 +00:00
sect . Align = int32 ( arch . PtrSize ) // everything is at least pointer-aligned
2017-04-18 21:52:06 +12:00
seg . Sections = append ( seg . Sections , sect )
2015-02-27 22:57:28 -05:00
return sect
}
2016-08-22 10:33:13 -04:00
type chain struct {
2017-10-04 17:54:04 -04:00
sym * sym . Symbol
2016-08-22 10:33:13 -04:00
up * chain
2015-03-05 13:57:36 -05:00
limit int // limit on entry to sym
2015-02-27 22:57:28 -05:00
}
2017-10-04 17:54:04 -04:00
var morestack * sym . Symbol
2015-02-27 22:57:28 -05:00
// TODO: Record enough information in new object files to
// allow stack checks here.
2016-08-19 22:40:38 -04:00
func haslinkregister ( ctxt * Link ) bool {
return ctxt . FixedFrameSize ( ) != 0
2015-02-27 22:57:28 -05:00
}
2016-08-19 22:40:38 -04:00
func callsize ( ctxt * Link ) int {
if haslinkregister ( ctxt ) {
2015-02-27 22:57:28 -05:00
return 0
}
2017-09-30 21:10:49 +00:00
return ctxt . Arch . RegSize
2015-02-27 22:57:28 -05:00
}
2016-08-19 22:40:38 -04:00
func ( ctxt * Link ) dostkcheck ( ) {
2016-08-22 10:33:13 -04:00
var ch chain
2015-02-27 22:57:28 -05:00
cmd/link: use ctxt.{Lookup,ROLookup} in favour of function versions of same
Done with two eg templates:
package p
import (
"cmd/link/internal/ld"
)
func before(ctxt *ld.Link, name string, v int) *ld.Symbol {
return ld.Linklookup(ctxt, name, v)
}
func after(ctxt *ld.Link, name string, v int) *ld.Symbol {
return ctxt.Syms.Lookup(name, v)
}
package p
import (
"cmd/link/internal/ld"
)
func before(ctxt *ld.Link, name string, v int) *ld.Symbol {
return ld.Linkrlookup(ctxt, name, v)
}
func after(ctxt *ld.Link, name string, v int) *ld.Symbol {
return ctxt.Syms.ROLookup(name, v)
}
Change-Id: I00647dbf62294557bd24c29ad1f108fc786335f1
Reviewed-on: https://go-review.googlesource.com/29343
Run-TryBot: Michael Hudson-Doyle <michael.hudson@canonical.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
2016-09-20 15:06:08 +12:00
morestack = ctxt . Syms . Lookup ( "runtime.morestack" , 0 )
2015-02-27 22:57:28 -05:00
// Every splitting function ensures that there are at least StackLimit
// bytes available below SP when the splitting prologue finishes.
// If the splitting function calls F, then F begins execution with
// at least StackLimit - callsize() bytes available.
// Check that every function behaves correctly with this amount
// of stack, following direct calls in order to piece together chains
// of non-splitting functions.
ch . up = nil
2017-04-18 12:53:25 -07:00
ch . limit = objabi . StackLimit - callsize ( ctxt )
2018-08-29 14:55:03 +08:00
if objabi . GOARCH == "arm64" {
// need extra 8 bytes below SP to save FP
ch . limit -= 8
}
2015-02-27 22:57:28 -05:00
// Check every function, but do the nosplit functions in a first pass,
// to make the printed failure chains as short as possible.
2016-08-19 22:40:38 -04:00
for _ , s := range ctxt . Textp {
2015-02-27 22:57:28 -05:00
// runtime.racesymbolizethunk is called from gcc-compiled C
// code running on the operating system thread stack.
// It uses more than the usual amount of stack but that's okay.
if s . Name == "runtime.racesymbolizethunk" {
continue
}
2016-03-02 07:59:49 -05:00
if s . Attr . NoSplit ( ) {
2015-02-27 22:57:28 -05:00
ch . sym = s
2016-08-19 22:40:38 -04:00
stkcheck ( ctxt , & ch , 0 )
2015-02-27 22:57:28 -05:00
}
}
2016-08-19 22:40:38 -04:00
for _ , s := range ctxt . Textp {
2016-03-02 07:59:49 -05:00
if ! s . Attr . NoSplit ( ) {
2015-02-27 22:57:28 -05:00
ch . sym = s
2016-08-19 22:40:38 -04:00
stkcheck ( ctxt , & ch , 0 )
2015-02-27 22:57:28 -05:00
}
}
}
2016-08-22 10:33:13 -04:00
func stkcheck ( ctxt * Link , up * chain , depth int ) int {
2015-03-02 12:35:15 -05:00
limit := up . limit
s := up . sym
2015-02-27 22:57:28 -05:00
// Don't duplicate work: only need to consider each
// function at top of safe zone once.
2017-04-18 12:53:25 -07:00
top := limit == objabi . StackLimit - callsize ( ctxt )
2015-07-29 15:07:35 -04:00
if top {
2016-03-02 07:59:49 -05:00
if s . Attr . StackCheck ( ) {
2015-02-27 22:57:28 -05:00
return 0
}
2017-10-04 17:54:04 -04:00
s . Attr |= sym . AttrStackCheck
2015-02-27 22:57:28 -05:00
}
2019-08-09 10:54:43 -07:00
if depth > 500 {
2016-09-17 09:39:33 -04:00
Errorf ( s , "nosplit stack check too deep" )
2016-08-19 22:40:38 -04:00
stkbroke ( ctxt , up , 0 )
2015-02-27 22:57:28 -05:00
return - 1
}
2016-04-12 23:18:47 +03:00
if s . Attr . External ( ) || s . FuncInfo == nil {
2015-02-27 22:57:28 -05:00
// external function.
// should never be called directly.
2016-08-19 22:40:38 -04:00
// onlyctxt.Diagnose the direct caller.
2015-03-30 02:59:10 +00:00
// TODO(mwhudson): actually think about this.
2018-04-23 07:30:32 -07:00
// TODO(khr): disabled for now. Calls to external functions can only happen on the g0 stack.
// See the trampolines in src/runtime/sys_darwin_$ARCH.go.
2017-10-04 17:54:04 -04:00
if depth == 1 && s . Type != sym . SXREF && ! ctxt . DynlinkingGo ( ) &&
2017-10-05 10:20:17 -04:00
ctxt . BuildMode != BuildModeCArchive && ctxt . BuildMode != BuildModePIE && ctxt . BuildMode != BuildModeCShared && ctxt . BuildMode != BuildModePlugin {
2018-04-23 07:30:32 -07:00
//Errorf(s, "call to external function")
2015-02-27 22:57:28 -05:00
}
return - 1
}
if limit < 0 {
2016-08-19 22:40:38 -04:00
stkbroke ( ctxt , up , limit )
2015-02-27 22:57:28 -05:00
return - 1
}
// morestack looks like it calls functions,
// but it switches the stack pointer first.
if s == morestack {
return 0
}
2016-08-22 10:33:13 -04:00
var ch chain
2015-02-27 22:57:28 -05:00
ch . up = up
2016-03-02 07:59:49 -05:00
if ! s . Attr . NoSplit ( ) {
2015-05-28 17:23:58 -07:00
// Ensure we have enough stack to call morestack.
2016-08-19 22:40:38 -04:00
ch . limit = limit - callsize ( ctxt )
2015-07-29 15:07:35 -04:00
ch . sym = morestack
2016-08-19 22:40:38 -04:00
if stkcheck ( ctxt , & ch , depth + 1 ) < 0 {
2015-05-28 17:23:58 -07:00
return - 1
}
2015-07-29 15:07:35 -04:00
if ! top {
return 0
}
// Raise limit to allow frame.
2016-04-11 22:19:34 +03:00
locals := int32 ( 0 )
2016-04-12 23:18:47 +03:00
if s . FuncInfo != nil {
locals = s . FuncInfo . Locals
2016-04-11 22:19:34 +03:00
}
2019-01-09 14:05:17 +01:00
limit = objabi . StackLimit + int ( locals ) + int ( ctxt . FixedFrameSize ( ) )
2015-05-28 17:23:58 -07:00
}
2015-02-27 22:57:28 -05:00
// Walk through sp adjustments in function, consuming relocs.
2015-03-02 12:35:15 -05:00
ri := 0
2015-02-27 22:57:28 -05:00
2015-03-02 12:35:15 -05:00
endr := len ( s . R )
2016-08-22 10:33:13 -04:00
var ch1 chain
2019-07-30 17:28:29 -04:00
pcsp := obj . NewPCIter ( uint32 ( ctxt . Arch . MinLC ) )
2017-10-04 17:54:04 -04:00
var r * sym . Reloc
2019-07-30 17:28:29 -04:00
for pcsp . Init ( s . FuncInfo . Pcsp . P ) ; ! pcsp . Done ; pcsp . Next ( ) {
2015-02-27 22:57:28 -05:00
// pcsp.value is in effect for [pcsp.pc, pcsp.nextpc).
// Check stack size in effect for this span.
2019-07-30 17:28:29 -04:00
if int32 ( limit ) - pcsp . Value < 0 {
stkbroke ( ctxt , up , int ( int32 ( limit ) - pcsp . Value ) )
2015-02-27 22:57:28 -05:00
return - 1
}
// Process calls in this span.
2019-07-30 17:28:29 -04:00
for ; ri < endr && uint32 ( s . R [ ri ] . Off ) < pcsp . NextPC ; ri ++ {
2015-02-27 22:57:28 -05:00
r = & s . R [ ri ]
switch r . Type {
// Direct call.
2017-04-18 12:53:25 -07:00
case objabi . R_CALL , objabi . R_CALLARM , objabi . R_CALLARM64 , objabi . R_CALLPOWER , objabi . R_CALLMIPS :
2019-07-30 17:28:29 -04:00
ch . limit = int ( int32 ( limit ) - pcsp . Value - int32 ( callsize ( ctxt ) ) )
2015-02-27 22:57:28 -05:00
ch . sym = r . Sym
2016-08-19 22:40:38 -04:00
if stkcheck ( ctxt , & ch , depth + 1 ) < 0 {
2015-02-27 22:57:28 -05:00
return - 1
}
2016-03-01 23:21:55 +00:00
// Indirect call. Assume it is a call to a splitting function,
2015-02-27 22:57:28 -05:00
// so we have to make sure it can call morestack.
// Arrange the data structures to report both calls, so that
// if there is an error, stkprint shows all the steps involved.
2017-04-18 12:53:25 -07:00
case objabi . R_CALLIND :
2019-07-30 17:28:29 -04:00
ch . limit = int ( int32 ( limit ) - pcsp . Value - int32 ( callsize ( ctxt ) ) )
2015-02-27 22:57:28 -05:00
ch . sym = nil
2016-08-19 22:40:38 -04:00
ch1 . limit = ch . limit - callsize ( ctxt ) // for morestack in called prologue
2015-02-27 22:57:28 -05:00
ch1 . up = & ch
ch1 . sym = morestack
2016-08-19 22:40:38 -04:00
if stkcheck ( ctxt , & ch1 , depth + 2 ) < 0 {
2015-02-27 22:57:28 -05:00
return - 1
}
}
}
}
return 0
}
2016-08-22 10:33:13 -04:00
func stkbroke ( ctxt * Link , ch * chain , limit int ) {
2016-09-17 09:39:33 -04:00
Errorf ( ch . sym , "nosplit stack overflow" )
2016-08-19 22:40:38 -04:00
stkprint ( ctxt , ch , limit )
2015-02-27 22:57:28 -05:00
}
2016-08-22 10:33:13 -04:00
func stkprint ( ctxt * Link , ch * chain , limit int ) {
2015-02-27 22:57:28 -05:00
var name string
if ch . sym != nil {
name = ch . sym . Name
2016-03-02 07:59:49 -05:00
if ch . sym . Attr . NoSplit ( ) {
2015-07-29 15:07:35 -04:00
name += " (nosplit)"
}
2015-02-27 22:57:28 -05:00
} else {
name = "function pointer"
}
if ch . up == nil {
// top of chain. ch->sym != nil.
2016-03-02 07:59:49 -05:00
if ch . sym . Attr . NoSplit ( ) {
2015-02-27 22:57:28 -05:00
fmt . Printf ( "\t%d\tassumed on entry to %s\n" , ch . limit , name )
} else {
fmt . Printf ( "\t%d\tguaranteed after split check in %s\n" , ch . limit , name )
}
} else {
2016-08-19 22:40:38 -04:00
stkprint ( ctxt , ch . up , ch . limit + callsize ( ctxt ) )
if ! haslinkregister ( ctxt ) {
2015-02-27 22:57:28 -05:00
fmt . Printf ( "\t%d\ton entry to %s\n" , ch . limit , name )
}
}
if ch . limit != limit {
fmt . Printf ( "\t%d\tafter %s uses %d\n" , limit , name , ch . limit - limit )
}
}
func usage ( ) {
2015-05-21 13:28:17 -04:00
fmt . Fprintf ( os . Stderr , "usage: link [options] main.o\n" )
2017-12-24 16:50:28 +00:00
objabi . Flagprint ( os . Stderr )
2015-02-27 22:57:28 -05:00
Exit ( 2 )
}
2016-09-16 16:22:08 +12:00
type SymbolType int8
const (
2018-06-01 17:29:59 -03:00
// see also https://9p.io/magic/man2html/1/nm
2016-09-16 16:22:08 +12:00
TextSym SymbolType = 'T'
2018-04-06 21:41:06 +01:00
DataSym SymbolType = 'D'
BSSSym SymbolType = 'B'
UndefinedSym SymbolType = 'U'
TLSSym SymbolType = 't'
FrameSym SymbolType = 'm'
ParamSym SymbolType = 'p'
AutoSym SymbolType = 'a'
2017-12-01 15:23:30 -05:00
// Deleted auto (not a real sym, just placeholder for type)
DeletedAutoSym = 'x'
2016-09-16 16:22:08 +12:00
)
2017-10-04 17:54:04 -04:00
func genasmsym ( ctxt * Link , put func ( * Link , * sym . Symbol , string , SymbolType , int64 , * sym . Symbol ) ) {
2015-02-27 22:57:28 -05:00
// These symbols won't show up in the first loop below because we
2017-10-04 17:54:04 -04:00
// skip sym.STEXT symbols. Normal sym.STEXT symbols are emitted by walking textp.
cmd/link: use ctxt.{Lookup,ROLookup} in favour of function versions of same
Done with two eg templates:
package p
import (
"cmd/link/internal/ld"
)
func before(ctxt *ld.Link, name string, v int) *ld.Symbol {
return ld.Linklookup(ctxt, name, v)
}
func after(ctxt *ld.Link, name string, v int) *ld.Symbol {
return ctxt.Syms.Lookup(name, v)
}
package p
import (
"cmd/link/internal/ld"
)
func before(ctxt *ld.Link, name string, v int) *ld.Symbol {
return ld.Linkrlookup(ctxt, name, v)
}
func after(ctxt *ld.Link, name string, v int) *ld.Symbol {
return ctxt.Syms.ROLookup(name, v)
}
Change-Id: I00647dbf62294557bd24c29ad1f108fc786335f1
Reviewed-on: https://go-review.googlesource.com/29343
Run-TryBot: Michael Hudson-Doyle <michael.hudson@canonical.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
2016-09-20 15:06:08 +12:00
s := ctxt . Syms . Lookup ( "runtime.text" , 0 )
2017-10-04 17:54:04 -04:00
if s . Type == sym . STEXT {
2017-09-11 07:51:57 +09:00
// We've already included this symbol in ctxt.Textp
2019-02-20 16:20:56 +01:00
// if ctxt.DynlinkingGo() && ctxt.HeadType == objabi.Hdarwin or
// on AIX with external linker.
2017-09-11 07:51:57 +09:00
// See data.go:/textaddress
2019-02-20 16:20:56 +01:00
if ! ( ctxt . DynlinkingGo ( ) && ctxt . HeadType == objabi . Hdarwin ) && ! ( ctxt . HeadType == objabi . Haix && ctxt . LinkMode == LinkExternal ) {
2017-09-11 07:51:57 +09:00
put ( ctxt , s , s . Name , TextSym , s . Value , nil )
}
2015-02-27 22:57:28 -05:00
}
2016-08-25 11:07:33 -05:00
n := 0
// Generate base addresses for all text sections if there are multiple
2017-04-18 21:52:06 +12:00
for _ , sect := range Segtext . Sections {
2016-08-25 11:07:33 -05:00
if n == 0 {
n ++
continue
}
2019-02-20 16:48:43 +01:00
if sect . Name != ".text" || ( ctxt . HeadType == objabi . Haix && ctxt . LinkMode == LinkExternal ) {
// On AIX, runtime.text.X are symbols already in the symtab.
2016-08-25 11:07:33 -05:00
break
}
s = ctxt . Syms . ROLookup ( fmt . Sprintf ( "runtime.text.%d" , n ) , 0 )
if s == nil {
break
}
2017-10-04 17:54:04 -04:00
if s . Type == sym . STEXT {
2016-08-25 11:07:33 -05:00
put ( ctxt , s , s . Name , TextSym , s . Value , nil )
}
n ++
}
cmd/link: use ctxt.{Lookup,ROLookup} in favour of function versions of same
Done with two eg templates:
package p
import (
"cmd/link/internal/ld"
)
func before(ctxt *ld.Link, name string, v int) *ld.Symbol {
return ld.Linklookup(ctxt, name, v)
}
func after(ctxt *ld.Link, name string, v int) *ld.Symbol {
return ctxt.Syms.Lookup(name, v)
}
package p
import (
"cmd/link/internal/ld"
)
func before(ctxt *ld.Link, name string, v int) *ld.Symbol {
return ld.Linkrlookup(ctxt, name, v)
}
func after(ctxt *ld.Link, name string, v int) *ld.Symbol {
return ctxt.Syms.ROLookup(name, v)
}
Change-Id: I00647dbf62294557bd24c29ad1f108fc786335f1
Reviewed-on: https://go-review.googlesource.com/29343
Run-TryBot: Michael Hudson-Doyle <michael.hudson@canonical.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
2016-09-20 15:06:08 +12:00
s = ctxt . Syms . Lookup ( "runtime.etext" , 0 )
2017-10-04 17:54:04 -04:00
if s . Type == sym . STEXT {
2017-09-11 07:51:57 +09:00
// We've already included this symbol in ctxt.Textp
2019-02-20 16:20:56 +01:00
// if ctxt.DynlinkingGo() && ctxt.HeadType == objabi.Hdarwin or
// on AIX with external linker.
2017-09-11 07:51:57 +09:00
// See data.go:/textaddress
2019-02-20 16:20:56 +01:00
if ! ( ctxt . DynlinkingGo ( ) && ctxt . HeadType == objabi . Hdarwin ) && ! ( ctxt . HeadType == objabi . Haix && ctxt . LinkMode == LinkExternal ) {
2017-09-11 07:51:57 +09:00
put ( ctxt , s , s . Name , TextSym , s . Value , nil )
}
2015-02-27 22:57:28 -05:00
}
2019-04-29 16:34:34 +02:00
shouldBeInSymbolTable := func ( s * sym . Symbol ) bool {
2017-04-28 12:22:50 +12:00
if s . Attr . NotInSymbolTable ( ) {
2019-04-29 16:34:34 +02:00
return false
}
if ctxt . HeadType == objabi . Haix && s . Name == ".go.buildinfo" {
// On AIX, .go.buildinfo must be in the symbol table as
// it has relocations.
return true
2016-03-02 07:59:49 -05:00
}
2018-10-19 17:42:11 -04:00
if ( s . Name == "" || s . Name [ 0 ] == '.' ) && ! s . IsFileLocal ( ) && s . Name != ".rathole" && s . Name != ".TOC." {
2019-04-29 16:34:34 +02:00
return false
}
return true
}
for _ , s := range ctxt . Syms . Allsym {
if ! shouldBeInSymbolTable ( s ) {
2015-02-27 22:57:28 -05:00
continue
}
2017-04-28 13:01:03 +12:00
switch s . Type {
2017-10-04 17:54:04 -04:00
case sym . SCONST ,
sym . SRODATA ,
sym . SSYMTAB ,
sym . SPCLNTAB ,
sym . SINITARR ,
sym . SDATA ,
sym . SNOPTRDATA ,
sym . SELFROSECT ,
sym . SMACHOGOT ,
sym . STYPE ,
sym . SSTRING ,
sym . SGOSTRING ,
sym . SGOFUNC ,
sym . SGCBITS ,
sym . STYPERELRO ,
sym . SSTRINGRELRO ,
sym . SGOSTRINGRELRO ,
sym . SGOFUNCRELRO ,
sym . SGCBITSRELRO ,
sym . SRODATARELRO ,
sym . STYPELINK ,
sym . SITABLINK ,
sym . SWINDOWS :
2016-03-02 07:59:49 -05:00
if ! s . Attr . Reachable ( ) {
2015-02-27 22:57:28 -05:00
continue
}
2016-09-17 09:39:33 -04:00
put ( ctxt , s , s . Name , DataSym , Symaddr ( s ) , s . Gotype )
2015-02-27 22:57:28 -05:00
2017-10-04 17:54:04 -04:00
case sym . SBSS , sym . SNOPTRBSS :
2016-03-02 07:59:49 -05:00
if ! s . Attr . Reachable ( ) {
2015-02-27 22:57:28 -05:00
continue
}
if len ( s . P ) > 0 {
cmd/internal/obj: fix LSym.Type during compilation, not linking
Prior to this CL, the compiler and assembler
were sloppy about the LSym.Type for LSyms
containing static data.
The linker then fixed this up, converting
Sxxx and SBSS to SDATA, and SNOPTRBSS to SNOPTRDATA
if it noticed that the symbol had associated data.
It is preferable to just get this right in cmd/compile
and cmd/asm, because it removes an unnecessary traversal
of the symbol table from the linker (see #14624).
Do this by touching up the LSym.Type fixes in
LSym.prepwrite and Link.Globl.
I have confirmed by instrumenting the linker
that the now-eliminated code paths were unreached.
And an additional check in the object file writing code
will help preserve that invariant.
There was a case in the Windows linker,
with internal linking and cgo,
where we were generating SNOPTRBSS symbols with data.
For now, convert those at the site at which they occur
into SNOPTRDATA, just like they were.
Does not pass toolstash-check,
but does generate identical linked binaries.
No compiler performance changes.
Change-Id: I77b071ab103685ff8e042cee9abb864385488872
Reviewed-on: https://go-review.googlesource.com/40864
Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Alex Brainman <alex.brainman@gmail.com>
Reviewed-by: Michael Hudson-Doyle <michael.hudson@canonical.com>
2017-04-16 08:22:44 -07:00
Errorf ( s , "should not be bss (size=%d type=%v special=%v)" , len ( s . P ) , s . Type , s . Attr . Special ( ) )
2015-02-27 22:57:28 -05:00
}
2016-09-17 09:39:33 -04:00
put ( ctxt , s , s . Name , BSSSym , Symaddr ( s ) , s . Gotype )
2015-02-27 22:57:28 -05:00
2017-10-04 17:54:04 -04:00
case sym . SHOSTOBJ :
2017-10-07 13:49:44 -04:00
if ctxt . HeadType == objabi . Hwindows || ctxt . IsELF {
2016-09-16 16:47:28 +12:00
put ( ctxt , s , s . Name , UndefinedSym , s . Value , nil )
2015-03-09 03:05:40 -04:00
}
2017-10-04 17:54:04 -04:00
case sym . SDYNIMPORT :
2016-03-02 07:59:49 -05:00
if ! s . Attr . Reachable ( ) {
2015-03-29 21:03:05 +00:00
continue
}
2018-07-17 11:02:57 -04:00
put ( ctxt , s , s . Extname ( ) , UndefinedSym , 0 , nil )
2015-03-29 21:03:05 +00:00
2017-10-04 17:54:04 -04:00
case sym . STLSBSS :
2017-10-05 10:20:17 -04:00
if ctxt . LinkMode == LinkExternal {
2016-09-17 09:39:33 -04:00
put ( ctxt , s , s . Name , TLSSym , Symaddr ( s ) , s . Gotype )
2015-03-29 21:03:05 +00:00
}
2015-02-27 22:57:28 -05:00
}
}
2016-08-19 22:40:38 -04:00
for _ , s := range ctxt . Textp {
2016-09-16 16:47:28 +12:00
put ( ctxt , s , s . Name , TextSym , s . Value , s . Gotype )
2015-02-27 22:57:28 -05:00
2016-04-11 22:19:34 +03:00
locals := int32 ( 0 )
2016-04-12 23:18:47 +03:00
if s . FuncInfo != nil {
locals = s . FuncInfo . Locals
2016-04-11 22:19:34 +03:00
}
2015-02-27 22:57:28 -05:00
// NOTE(ality): acid can't produce a stack trace without .frame symbols
2017-09-30 21:10:49 +00:00
put ( ctxt , nil , ".frame" , FrameSym , int64 ( locals ) + int64 ( ctxt . Arch . PtrSize ) , nil )
2015-02-27 22:57:28 -05:00
2016-04-12 23:18:47 +03:00
if s . FuncInfo == nil {
2016-04-11 22:19:34 +03:00
continue
}
2015-02-27 22:57:28 -05:00
}
2016-08-21 18:34:24 -04:00
if ctxt . Debugvlog != 0 || * flagN {
2017-04-18 12:53:25 -07:00
ctxt . Logf ( "%5.2f symsize = %d\n" , Cputime ( ) , uint32 ( Symsize ) )
2015-02-27 22:57:28 -05:00
}
}
2017-10-04 17:54:04 -04:00
func Symaddr ( s * sym . Symbol ) int64 {
2016-03-02 07:59:49 -05:00
if ! s . Attr . Reachable ( ) {
2016-09-17 09:39:33 -04:00
Errorf ( s , "unreachable symbol in symaddr" )
2015-02-27 22:57:28 -05:00
}
return s . Value
}
2017-10-04 17:54:04 -04:00
func ( ctxt * Link ) xdefine ( p string , t sym . SymKind , v int64 ) {
cmd/link: use ctxt.{Lookup,ROLookup} in favour of function versions of same
Done with two eg templates:
package p
import (
"cmd/link/internal/ld"
)
func before(ctxt *ld.Link, name string, v int) *ld.Symbol {
return ld.Linklookup(ctxt, name, v)
}
func after(ctxt *ld.Link, name string, v int) *ld.Symbol {
return ctxt.Syms.Lookup(name, v)
}
package p
import (
"cmd/link/internal/ld"
)
func before(ctxt *ld.Link, name string, v int) *ld.Symbol {
return ld.Linkrlookup(ctxt, name, v)
}
func after(ctxt *ld.Link, name string, v int) *ld.Symbol {
return ctxt.Syms.ROLookup(name, v)
}
Change-Id: I00647dbf62294557bd24c29ad1f108fc786335f1
Reviewed-on: https://go-review.googlesource.com/29343
Run-TryBot: Michael Hudson-Doyle <michael.hudson@canonical.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
2016-09-20 15:06:08 +12:00
s := ctxt . Syms . Lookup ( p , 0 )
2016-09-07 14:45:27 -04:00
s . Type = t
2015-02-27 22:57:28 -05:00
s . Value = v
2017-10-04 17:54:04 -04:00
s . Attr |= sym . AttrReachable
s . Attr |= sym . AttrSpecial
s . Attr |= sym . AttrLocal
2015-02-27 22:57:28 -05:00
}
2017-10-04 17:54:04 -04:00
func datoff ( s * sym . Symbol , addr int64 ) int64 {
2015-02-27 22:57:28 -05:00
if uint64 ( addr ) >= Segdata . Vaddr {
return int64 ( uint64 ( addr ) - Segdata . Vaddr + Segdata . Fileoff )
}
if uint64 ( addr ) >= Segtext . Vaddr {
return int64 ( uint64 ( addr ) - Segtext . Vaddr + Segtext . Fileoff )
}
2016-09-17 09:39:33 -04:00
Errorf ( s , "invalid datoff %#x" , addr )
2015-02-27 22:57:28 -05:00
return 0
}
2016-08-19 22:40:38 -04:00
func Entryvalue ( ctxt * Link ) int64 {
2016-08-21 18:34:24 -04:00
a := * flagEntrySymbol
2015-02-27 22:57:28 -05:00
if a [ 0 ] >= '0' && a [ 0 ] <= '9' {
return atolwhex ( a )
}
cmd/link: use ctxt.{Lookup,ROLookup} in favour of function versions of same
Done with two eg templates:
package p
import (
"cmd/link/internal/ld"
)
func before(ctxt *ld.Link, name string, v int) *ld.Symbol {
return ld.Linklookup(ctxt, name, v)
}
func after(ctxt *ld.Link, name string, v int) *ld.Symbol {
return ctxt.Syms.Lookup(name, v)
}
package p
import (
"cmd/link/internal/ld"
)
func before(ctxt *ld.Link, name string, v int) *ld.Symbol {
return ld.Linkrlookup(ctxt, name, v)
}
func after(ctxt *ld.Link, name string, v int) *ld.Symbol {
return ctxt.Syms.ROLookup(name, v)
}
Change-Id: I00647dbf62294557bd24c29ad1f108fc786335f1
Reviewed-on: https://go-review.googlesource.com/29343
Run-TryBot: Michael Hudson-Doyle <michael.hudson@canonical.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
2016-09-20 15:06:08 +12:00
s := ctxt . Syms . Lookup ( a , 0 )
2015-02-27 22:57:28 -05:00
if s . Type == 0 {
2016-08-21 18:34:24 -04:00
return * FlagTextAddr
2015-02-27 22:57:28 -05:00
}
2018-09-28 17:02:16 +02:00
if ctxt . HeadType != objabi . Haix && s . Type != sym . STEXT {
2016-09-17 09:39:33 -04:00
Errorf ( s , "entry not text" )
2015-02-27 22:57:28 -05:00
}
return s . Value
}
2017-10-04 17:54:04 -04:00
func undefsym ( ctxt * Link , s * sym . Symbol ) {
var r * sym . Reloc
2015-02-27 22:57:28 -05:00
2015-03-02 12:35:15 -05:00
for i := 0 ; i < len ( s . R ) ; i ++ {
2015-02-27 22:57:28 -05:00
r = & s . R [ i ]
if r . Sym == nil { // happens for some external ARM relocs
continue
}
2017-04-28 12:43:06 +12:00
// TODO(mwhudson): the test of VisibilityHidden here probably doesn't make
// sense and should be removed when someone has thought about it properly.
if ( r . Sym . Type == sym . Sxxx || r . Sym . Type == sym . SXREF ) && ! r . Sym . Attr . VisibilityHidden ( ) {
2016-09-17 09:39:33 -04:00
Errorf ( s , "undefined: %q" , r . Sym . Name )
2015-02-27 22:57:28 -05:00
}
2017-04-18 12:53:25 -07:00
if ! r . Sym . Attr . Reachable ( ) && r . Type != objabi . R_WEAKADDROFF {
2016-09-17 09:39:33 -04:00
Errorf ( s , "relocation target %q" , r . Sym . Name )
2015-02-27 22:57:28 -05:00
}
}
}
2016-08-19 22:40:38 -04:00
func ( ctxt * Link ) undef ( ) {
2018-05-21 21:00:01 +03:00
// undefsym performs checks (almost) identical to checks
// that report undefined relocations in relocsym.
// Both undefsym and relocsym can report same symbol as undefined,
// which results in error message duplication (see #10978).
//
// The undef is run after Arch.Asmb and could detect some
// programming errors there, but if object being linked is already
// failed with errors, it is better to avoid duplicated errors.
if nerrors > 0 {
return
}
2016-08-19 22:40:38 -04:00
for _ , s := range ctxt . Textp {
undefsym ( ctxt , s )
2015-02-27 22:57:28 -05:00
}
2016-04-18 14:50:14 -04:00
for _ , s := range datap {
2016-08-19 22:40:38 -04:00
undefsym ( ctxt , s )
2015-02-27 22:57:28 -05:00
}
if nerrors > 0 {
2015-04-09 07:37:17 -04:00
errorexit ( )
2015-02-27 22:57:28 -05:00
}
}
2016-08-19 22:40:38 -04:00
func ( ctxt * Link ) callgraph ( ) {
2016-08-21 18:34:24 -04:00
if ! * FlagC {
2015-02-27 22:57:28 -05:00
return
}
2015-03-02 12:35:15 -05:00
var i int
2017-10-04 17:54:04 -04:00
var r * sym . Reloc
2016-08-19 22:40:38 -04:00
for _ , s := range ctxt . Textp {
2015-02-27 22:57:28 -05:00
for i = 0 ; i < len ( s . R ) ; i ++ {
r = & s . R [ i ]
if r . Sym == nil {
continue
}
2018-09-26 10:12:18 +00:00
if ( r . Type == objabi . R_CALL || r . Type == objabi . R_CALLARM || r . Type == objabi . R_CALLARM64 || r . Type == objabi . R_CALLPOWER || r . Type == objabi . R_CALLMIPS ) && r . Sym . Type == sym . STEXT {
2016-08-25 12:32:42 +10:00
ctxt . Logf ( "%s calls %s\n" , s . Name , r . Sym . Name )
2015-02-27 22:57:28 -05:00
}
}
}
}
func Rnd ( v int64 , r int64 ) int64 {
if r <= 0 {
return v
}
v += r - 1
2015-03-02 12:35:15 -05:00
c := v % r
2015-02-27 22:57:28 -05:00
if c < 0 {
c += r
}
v -= c
return v
}
2016-04-08 20:44:56 +10:00
func bgetc ( r * bio . Reader ) int {
c , err := r . ReadByte ( )
if err != nil {
if err != io . EOF {
log . Fatalf ( "reading input: %v" , err )
}
return - 1
}
return int ( c )
}
2016-09-14 14:47:12 -04:00
type markKind uint8 // for postorder traversal
const (
2018-04-06 21:41:06 +01:00
_ markKind = iota
2016-09-14 14:47:12 -04:00
visiting
visited
)
2017-10-04 18:13:35 -04:00
func postorder ( libs [ ] * sym . Library ) [ ] * sym . Library {
order := make ( [ ] * sym . Library , 0 , len ( libs ) ) // hold the result
mark := make ( map [ * sym . Library ] markKind , len ( libs ) )
2016-09-14 14:47:12 -04:00
for _ , lib := range libs {
dfs ( lib , mark , & order )
}
return order
}
2017-10-04 18:13:35 -04:00
func dfs ( lib * sym . Library , mark map [ * sym . Library ] markKind , order * [ ] * sym . Library ) {
2016-09-14 14:47:12 -04:00
if mark [ lib ] == visited {
return
}
if mark [ lib ] == visiting {
panic ( "found import cycle while visiting " + lib . Pkg )
}
mark [ lib ] = visiting
2017-10-04 18:13:35 -04:00
for _ , i := range lib . Imports {
2016-09-14 14:47:12 -04:00
dfs ( i , mark , order )
}
mark [ lib ] = visited
* order = append ( * order , lib )
}
2019-09-17 16:14:37 -04:00
func ( ctxt * Link ) loadlibfull ( ) {
// Load full symbol contents, resolve indexed references.
2019-10-14 10:06:37 -04:00
ctxt . loader . LoadFull ( ctxt . Arch , ctxt . Syms )
2019-09-17 16:14:37 -04:00
// For now, add all symbols to ctxt.Syms.
for _ , s := range ctxt . loader . Syms {
if s != nil && s . Name != "" {
ctxt . Syms . Add ( s )
}
}
2019-09-30 11:43:41 -04:00
2019-10-04 22:05:41 -04:00
// Load cgo directives.
for _ , d := range ctxt . cgodata {
setCgoAttr ( ctxt , d . file , d . pkg , d . directives )
}
setupdynexp ( ctxt )
2019-09-30 11:43:41 -04:00
// Drop the reference.
ctxt . loader = nil
2019-10-04 22:05:41 -04:00
ctxt . cgodata = nil
2019-09-28 22:42:35 -04:00
addToTextp ( ctxt )
2019-09-17 16:14:37 -04:00
}
func ( ctxt * Link ) dumpsyms ( ) {
for _ , s := range ctxt . Syms . Allsym {
fmt . Printf ( "%s %s %p\n" , s , s . Type , s )
for i := range s . R {
fmt . Println ( "\t" , s . R [ i ] . Type , s . R [ i ] . Sym )
}
}
}