Black Lives Matter. Support the Equal Justice Initiative.

Source file src/cmd/link/internal/ld/xcoff.go

Documentation: cmd/link/internal/ld

     1  // Copyright 2018 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package ld
     6  
     7  import (
     8  	"bytes"
     9  	"cmd/internal/objabi"
    10  	"cmd/link/internal/loader"
    11  	"cmd/link/internal/sym"
    12  	"encoding/binary"
    13  	"fmt"
    14  	"io/ioutil"
    15  	"math/bits"
    16  	"path/filepath"
    17  	"sort"
    18  	"strings"
    19  	"sync"
    20  )
    21  
    22  // This file handles all algorithms related to XCOFF files generation.
    23  // Most of them are adaptations of the ones in  cmd/link/internal/pe.go
    24  // as PE and XCOFF are based on COFF files.
    25  // XCOFF files generated are 64 bits.
    26  
    27  const (
    28  	// Total amount of space to reserve at the start of the file
    29  	// for File Header, Auxiliary Header, and Section Headers.
    30  	// May waste some.
    31  	XCOFFHDRRESERVE = FILHSZ_64 + AOUTHSZ_EXEC64 + SCNHSZ_64*23
    32  
    33  	// base on dump -o, then rounded from 32B to 64B to
    34  	// match worst case elf text section alignment on ppc64.
    35  	XCOFFSECTALIGN int64 = 64
    36  
    37  	// XCOFF binaries should normally have all its sections position-independent.
    38  	// However, this is not yet possible for .text because of some R_ADDR relocations
    39  	// inside RODATA symbols.
    40  	// .data and .bss are position-independent so their address start inside a unreachable
    41  	// segment during execution to force segfault if something is wrong.
    42  	XCOFFTEXTBASE = 0x100000000 // Start of text address
    43  	XCOFFDATABASE = 0x200000000 // Start of data address
    44  )
    45  
    46  // File Header
    47  type XcoffFileHdr64 struct {
    48  	Fmagic   uint16 // Target machine
    49  	Fnscns   uint16 // Number of sections
    50  	Ftimedat int32  // Time and date of file creation
    51  	Fsymptr  uint64 // Byte offset to symbol table start
    52  	Fopthdr  uint16 // Number of bytes in optional header
    53  	Fflags   uint16 // Flags
    54  	Fnsyms   int32  // Number of entries in symbol table
    55  }
    56  
    57  const (
    58  	U64_TOCMAGIC = 0767 // AIX 64-bit XCOFF
    59  )
    60  
    61  // Flags that describe the type of the object file.
    62  const (
    63  	F_RELFLG    = 0x0001
    64  	F_EXEC      = 0x0002
    65  	F_LNNO      = 0x0004
    66  	F_FDPR_PROF = 0x0010
    67  	F_FDPR_OPTI = 0x0020
    68  	F_DSA       = 0x0040
    69  	F_VARPG     = 0x0100
    70  	F_DYNLOAD   = 0x1000
    71  	F_SHROBJ    = 0x2000
    72  	F_LOADONLY  = 0x4000
    73  )
    74  
    75  // Auxiliary Header
    76  type XcoffAoutHdr64 struct {
    77  	Omagic      int16    // Flags - Ignored If Vstamp Is 1
    78  	Ovstamp     int16    // Version
    79  	Odebugger   uint32   // Reserved For Debugger
    80  	Otextstart  uint64   // Virtual Address Of Text
    81  	Odatastart  uint64   // Virtual Address Of Data
    82  	Otoc        uint64   // Toc Address
    83  	Osnentry    int16    // Section Number For Entry Point
    84  	Osntext     int16    // Section Number For Text
    85  	Osndata     int16    // Section Number For Data
    86  	Osntoc      int16    // Section Number For Toc
    87  	Osnloader   int16    // Section Number For Loader
    88  	Osnbss      int16    // Section Number For Bss
    89  	Oalgntext   int16    // Max Text Alignment
    90  	Oalgndata   int16    // Max Data Alignment
    91  	Omodtype    [2]byte  // Module Type Field
    92  	Ocpuflag    uint8    // Bit Flags - Cputypes Of Objects
    93  	Ocputype    uint8    // Reserved for CPU type
    94  	Otextpsize  uint8    // Requested text page size
    95  	Odatapsize  uint8    // Requested data page size
    96  	Ostackpsize uint8    // Requested stack page size
    97  	Oflags      uint8    // Flags And TLS Alignment
    98  	Otsize      uint64   // Text Size In Bytes
    99  	Odsize      uint64   // Data Size In Bytes
   100  	Obsize      uint64   // Bss Size In Bytes
   101  	Oentry      uint64   // Entry Point Address
   102  	Omaxstack   uint64   // Max Stack Size Allowed
   103  	Omaxdata    uint64   // Max Data Size Allowed
   104  	Osntdata    int16    // Section Number For Tdata Section
   105  	Osntbss     int16    // Section Number For Tbss Section
   106  	Ox64flags   uint16   // Additional Flags For 64-Bit Objects
   107  	Oresv3a     int16    // Reserved
   108  	Oresv3      [2]int32 // Reserved
   109  }
   110  
   111  // Section Header
   112  type XcoffScnHdr64 struct {
   113  	Sname    [8]byte // Section Name
   114  	Spaddr   uint64  // Physical Address
   115  	Svaddr   uint64  // Virtual Address
   116  	Ssize    uint64  // Section Size
   117  	Sscnptr  uint64  // File Offset To Raw Data
   118  	Srelptr  uint64  // File Offset To Relocation
   119  	Slnnoptr uint64  // File Offset To Line Numbers
   120  	Snreloc  uint32  // Number Of Relocation Entries
   121  	Snlnno   uint32  // Number Of Line Number Entries
   122  	Sflags   uint32  // flags
   123  }
   124  
   125  // Flags defining the section type.
   126  const (
   127  	STYP_DWARF  = 0x0010
   128  	STYP_TEXT   = 0x0020
   129  	STYP_DATA   = 0x0040
   130  	STYP_BSS    = 0x0080
   131  	STYP_EXCEPT = 0x0100
   132  	STYP_INFO   = 0x0200
   133  	STYP_TDATA  = 0x0400
   134  	STYP_TBSS   = 0x0800
   135  	STYP_LOADER = 0x1000
   136  	STYP_DEBUG  = 0x2000
   137  	STYP_TYPCHK = 0x4000
   138  	STYP_OVRFLO = 0x8000
   139  )
   140  const (
   141  	SSUBTYP_DWINFO  = 0x10000 // DWARF info section
   142  	SSUBTYP_DWLINE  = 0x20000 // DWARF line-number section
   143  	SSUBTYP_DWPBNMS = 0x30000 // DWARF public names section
   144  	SSUBTYP_DWPBTYP = 0x40000 // DWARF public types section
   145  	SSUBTYP_DWARNGE = 0x50000 // DWARF aranges section
   146  	SSUBTYP_DWABREV = 0x60000 // DWARF abbreviation section
   147  	SSUBTYP_DWSTR   = 0x70000 // DWARF strings section
   148  	SSUBTYP_DWRNGES = 0x80000 // DWARF ranges section
   149  	SSUBTYP_DWLOC   = 0x90000 // DWARF location lists section
   150  	SSUBTYP_DWFRAME = 0xA0000 // DWARF frames section
   151  	SSUBTYP_DWMAC   = 0xB0000 // DWARF macros section
   152  )
   153  
   154  // Headers size
   155  const (
   156  	FILHSZ_32      = 20
   157  	FILHSZ_64      = 24
   158  	AOUTHSZ_EXEC32 = 72
   159  	AOUTHSZ_EXEC64 = 120
   160  	SCNHSZ_32      = 40
   161  	SCNHSZ_64      = 72
   162  	LDHDRSZ_32     = 32
   163  	LDHDRSZ_64     = 56
   164  	LDSYMSZ_64     = 24
   165  	RELSZ_64       = 14
   166  )
   167  
   168  // Type representing all XCOFF symbols.
   169  type xcoffSym interface {
   170  }
   171  
   172  // Symbol Table Entry
   173  type XcoffSymEnt64 struct {
   174  	Nvalue  uint64 // Symbol value
   175  	Noffset uint32 // Offset of the name in string table or .debug section
   176  	Nscnum  int16  // Section number of symbol
   177  	Ntype   uint16 // Basic and derived type specification
   178  	Nsclass uint8  // Storage class of symbol
   179  	Nnumaux int8   // Number of auxiliary entries
   180  }
   181  
   182  const SYMESZ = 18
   183  
   184  const (
   185  	// Nscnum
   186  	N_DEBUG = -2
   187  	N_ABS   = -1
   188  	N_UNDEF = 0
   189  
   190  	//Ntype
   191  	SYM_V_INTERNAL  = 0x1000
   192  	SYM_V_HIDDEN    = 0x2000
   193  	SYM_V_PROTECTED = 0x3000
   194  	SYM_V_EXPORTED  = 0x4000
   195  	SYM_TYPE_FUNC   = 0x0020 // is function
   196  )
   197  
   198  // Storage Class.
   199  const (
   200  	C_NULL    = 0   // Symbol table entry marked for deletion
   201  	C_EXT     = 2   // External symbol
   202  	C_STAT    = 3   // Static symbol
   203  	C_BLOCK   = 100 // Beginning or end of inner block
   204  	C_FCN     = 101 // Beginning or end of function
   205  	C_FILE    = 103 // Source file name and compiler information
   206  	C_HIDEXT  = 107 // Unnamed external symbol
   207  	C_BINCL   = 108 // Beginning of include file
   208  	C_EINCL   = 109 // End of include file
   209  	C_WEAKEXT = 111 // Weak external symbol
   210  	C_DWARF   = 112 // DWARF symbol
   211  	C_GSYM    = 128 // Global variable
   212  	C_LSYM    = 129 // Automatic variable allocated on stack
   213  	C_PSYM    = 130 // Argument to subroutine allocated on stack
   214  	C_RSYM    = 131 // Register variable
   215  	C_RPSYM   = 132 // Argument to function or procedure stored in register
   216  	C_STSYM   = 133 // Statically allocated symbol
   217  	C_BCOMM   = 135 // Beginning of common block
   218  	C_ECOML   = 136 // Local member of common block
   219  	C_ECOMM   = 137 // End of common block
   220  	C_DECL    = 140 // Declaration of object
   221  	C_ENTRY   = 141 // Alternate entry
   222  	C_FUN     = 142 // Function or procedure
   223  	C_BSTAT   = 143 // Beginning of static block
   224  	C_ESTAT   = 144 // End of static block
   225  	C_GTLS    = 145 // Global thread-local variable
   226  	C_STTLS   = 146 // Static thread-local variable
   227  )
   228  
   229  // File Auxiliary Entry
   230  type XcoffAuxFile64 struct {
   231  	Xzeroes  uint32 // The name is always in the string table
   232  	Xoffset  uint32 // Offset in the string table
   233  	X_pad1   [6]byte
   234  	Xftype   uint8 // Source file string type
   235  	X_pad2   [2]byte
   236  	Xauxtype uint8 // Type of auxiliary entry
   237  }
   238  
   239  // Function Auxiliary Entry
   240  type XcoffAuxFcn64 struct {
   241  	Xlnnoptr uint64 // File pointer to line number
   242  	Xfsize   uint32 // Size of function in bytes
   243  	Xendndx  uint32 // Symbol table index of next entry
   244  	Xpad     uint8  // Unused
   245  	Xauxtype uint8  // Type of auxiliary entry
   246  }
   247  
   248  // csect Auxiliary Entry.
   249  type XcoffAuxCSect64 struct {
   250  	Xscnlenlo uint32 // Lower 4 bytes of length or symbol table index
   251  	Xparmhash uint32 // Offset of parameter type-check string
   252  	Xsnhash   uint16 // .typchk section number
   253  	Xsmtyp    uint8  // Symbol alignment and type
   254  	Xsmclas   uint8  // Storage-mapping class
   255  	Xscnlenhi uint32 // Upper 4 bytes of length or symbol table index
   256  	Xpad      uint8  // Unused
   257  	Xauxtype  uint8  // Type of auxiliary entry
   258  }
   259  
   260  // DWARF Auxiliary Entry
   261  type XcoffAuxDWARF64 struct {
   262  	Xscnlen  uint64 // Length of this symbol section
   263  	X_pad    [9]byte
   264  	Xauxtype uint8 // Type of auxiliary entry
   265  }
   266  
   267  // Auxiliary type
   268  const (
   269  	_AUX_EXCEPT = 255
   270  	_AUX_FCN    = 254
   271  	_AUX_SYM    = 253
   272  	_AUX_FILE   = 252
   273  	_AUX_CSECT  = 251
   274  	_AUX_SECT   = 250
   275  )
   276  
   277  // Xftype field
   278  const (
   279  	XFT_FN = 0   // Source File Name
   280  	XFT_CT = 1   // Compile Time Stamp
   281  	XFT_CV = 2   // Compiler Version Number
   282  	XFT_CD = 128 // Compiler Defined Information/
   283  
   284  )
   285  
   286  // Symbol type field.
   287  const (
   288  	XTY_ER  = 0    // External reference
   289  	XTY_SD  = 1    // Section definition
   290  	XTY_LD  = 2    // Label definition
   291  	XTY_CM  = 3    // Common csect definition
   292  	XTY_WK  = 0x8  // Weak symbol
   293  	XTY_EXP = 0x10 // Exported symbol
   294  	XTY_ENT = 0x20 // Entry point symbol
   295  	XTY_IMP = 0x40 // Imported symbol
   296  )
   297  
   298  // Storage-mapping class.
   299  const (
   300  	XMC_PR     = 0  // Program code
   301  	XMC_RO     = 1  // Read-only constant
   302  	XMC_DB     = 2  // Debug dictionary table
   303  	XMC_TC     = 3  // TOC entry
   304  	XMC_UA     = 4  // Unclassified
   305  	XMC_RW     = 5  // Read/Write data
   306  	XMC_GL     = 6  // Global linkage
   307  	XMC_XO     = 7  // Extended operation
   308  	XMC_SV     = 8  // 32-bit supervisor call descriptor
   309  	XMC_BS     = 9  // BSS class
   310  	XMC_DS     = 10 // Function descriptor
   311  	XMC_UC     = 11 // Unnamed FORTRAN common
   312  	XMC_TC0    = 15 // TOC anchor
   313  	XMC_TD     = 16 // Scalar data entry in the TOC
   314  	XMC_SV64   = 17 // 64-bit supervisor call descriptor
   315  	XMC_SV3264 = 18 // Supervisor call descriptor for both 32-bit and 64-bit
   316  	XMC_TL     = 20 // Read/Write thread-local data
   317  	XMC_UL     = 21 // Read/Write thread-local data (.tbss)
   318  	XMC_TE     = 22 // TOC entry
   319  )
   320  
   321  // Loader Header
   322  type XcoffLdHdr64 struct {
   323  	Lversion int32  // Loader section version number
   324  	Lnsyms   int32  // Number of symbol table entries
   325  	Lnreloc  int32  // Number of relocation table entries
   326  	Listlen  uint32 // Length of import file ID string table
   327  	Lnimpid  int32  // Number of import file IDs
   328  	Lstlen   uint32 // Length of string table
   329  	Limpoff  uint64 // Offset to start of import file IDs
   330  	Lstoff   uint64 // Offset to start of string table
   331  	Lsymoff  uint64 // Offset to start of symbol table
   332  	Lrldoff  uint64 // Offset to start of relocation entries
   333  }
   334  
   335  // Loader Symbol
   336  type XcoffLdSym64 struct {
   337  	Lvalue  uint64 // Address field
   338  	Loffset uint32 // Byte offset into string table of symbol name
   339  	Lscnum  int16  // Section number containing symbol
   340  	Lsmtype int8   // Symbol type, export, import flags
   341  	Lsmclas int8   // Symbol storage class
   342  	Lifile  int32  // Import file ID; ordinal of import file IDs
   343  	Lparm   uint32 // Parameter type-check field
   344  }
   345  
   346  type xcoffLoaderSymbol struct {
   347  	sym    loader.Sym
   348  	smtype int8
   349  	smclas int8
   350  }
   351  
   352  type XcoffLdImportFile64 struct {
   353  	Limpidpath string
   354  	Limpidbase string
   355  	Limpidmem  string
   356  }
   357  
   358  type XcoffLdRel64 struct {
   359  	Lvaddr  uint64 // Address Field
   360  	Lrtype  uint16 // Relocation Size and Type
   361  	Lrsecnm int16  // Section Number being relocated
   362  	Lsymndx int32  // Loader-Section symbol table index
   363  }
   364  
   365  // xcoffLoaderReloc holds information about a relocation made by the loader.
   366  type xcoffLoaderReloc struct {
   367  	sym    loader.Sym
   368  	roff   int32
   369  	rtype  uint16
   370  	symndx int32
   371  }
   372  
   373  const (
   374  	XCOFF_R_POS = 0x00 // A(sym) Positive Relocation
   375  	XCOFF_R_NEG = 0x01 // -A(sym) Negative Relocation
   376  	XCOFF_R_REL = 0x02 // A(sym-*) Relative to self
   377  	XCOFF_R_TOC = 0x03 // A(sym-TOC) Relative to TOC
   378  	XCOFF_R_TRL = 0x12 // A(sym-TOC) TOC Relative indirect load.
   379  
   380  	XCOFF_R_TRLA = 0x13 // A(sym-TOC) TOC Rel load address. modifiable inst
   381  	XCOFF_R_GL   = 0x05 // A(external TOC of sym) Global Linkage
   382  	XCOFF_R_TCL  = 0x06 // A(local TOC of sym) Local object TOC address
   383  	XCOFF_R_RL   = 0x0C // A(sym) Pos indirect load. modifiable instruction
   384  	XCOFF_R_RLA  = 0x0D // A(sym) Pos Load Address. modifiable instruction
   385  	XCOFF_R_REF  = 0x0F // AL0(sym) Non relocating ref. No garbage collect
   386  	XCOFF_R_BA   = 0x08 // A(sym) Branch absolute. Cannot modify instruction
   387  	XCOFF_R_RBA  = 0x18 // A(sym) Branch absolute. modifiable instruction
   388  	XCOFF_R_BR   = 0x0A // A(sym-*) Branch rel to self. non modifiable
   389  	XCOFF_R_RBR  = 0x1A // A(sym-*) Branch rel to self. modifiable instr
   390  
   391  	XCOFF_R_TLS    = 0x20 // General-dynamic reference to TLS symbol
   392  	XCOFF_R_TLS_IE = 0x21 // Initial-exec reference to TLS symbol
   393  	XCOFF_R_TLS_LD = 0x22 // Local-dynamic reference to TLS symbol
   394  	XCOFF_R_TLS_LE = 0x23 // Local-exec reference to TLS symbol
   395  	XCOFF_R_TLSM   = 0x24 // Module reference to TLS symbol
   396  	XCOFF_R_TLSML  = 0x25 // Module reference to local (own) module
   397  
   398  	XCOFF_R_TOCU = 0x30 // Relative to TOC - high order bits
   399  	XCOFF_R_TOCL = 0x31 // Relative to TOC - low order bits
   400  )
   401  
   402  type XcoffLdStr64 struct {
   403  	size uint16
   404  	name string
   405  }
   406  
   407  // xcoffFile is used to build XCOFF file.
   408  type xcoffFile struct {
   409  	xfhdr           XcoffFileHdr64
   410  	xahdr           XcoffAoutHdr64
   411  	sections        []*XcoffScnHdr64
   412  	sectText        *XcoffScnHdr64
   413  	sectData        *XcoffScnHdr64
   414  	sectBss         *XcoffScnHdr64
   415  	stringTable     xcoffStringTable
   416  	sectNameToScnum map[string]int16
   417  	loaderSize      uint64
   418  	symtabOffset    int64                // offset to the start of symbol table
   419  	symbolCount     uint32               // number of symbol table records written
   420  	symtabSym       []xcoffSym           // XCOFF symbols for the symbol table
   421  	dynLibraries    map[string]int       // Dynamic libraries in .loader section. The integer represents its import file number (- 1)
   422  	loaderSymbols   []*xcoffLoaderSymbol // symbols inside .loader symbol table
   423  	loaderReloc     []*xcoffLoaderReloc  // Reloc that must be made inside loader
   424  	sync.Mutex                           // currently protect loaderReloc
   425  }
   426  
   427  // Var used by XCOFF Generation algorithms
   428  var (
   429  	xfile xcoffFile
   430  )
   431  
   432  // xcoffStringTable is a XCOFF string table.
   433  type xcoffStringTable struct {
   434  	strings    []string
   435  	stringsLen int
   436  }
   437  
   438  // size returns size of string table t.
   439  func (t *xcoffStringTable) size() int {
   440  	// string table starts with 4-byte length at the beginning
   441  	return t.stringsLen + 4
   442  }
   443  
   444  // add adds string str to string table t.
   445  func (t *xcoffStringTable) add(str string) int {
   446  	off := t.size()
   447  	t.strings = append(t.strings, str)
   448  	t.stringsLen += len(str) + 1 // each string will have 0 appended to it
   449  	return off
   450  }
   451  
   452  // write writes string table t into the output file.
   453  func (t *xcoffStringTable) write(out *OutBuf) {
   454  	out.Write32(uint32(t.size()))
   455  	for _, s := range t.strings {
   456  		out.WriteString(s)
   457  		out.Write8(0)
   458  	}
   459  }
   460  
   461  // write writes XCOFF section sect into the output file.
   462  func (sect *XcoffScnHdr64) write(ctxt *Link) {
   463  	binary.Write(ctxt.Out, binary.BigEndian, sect)
   464  	ctxt.Out.Write32(0) // Add 4 empty bytes at the end to match alignment
   465  }
   466  
   467  // addSection adds section to the XCOFF file f.
   468  func (f *xcoffFile) addSection(name string, addr uint64, size uint64, fileoff uint64, flags uint32) *XcoffScnHdr64 {
   469  	sect := &XcoffScnHdr64{
   470  		Spaddr:  addr,
   471  		Svaddr:  addr,
   472  		Ssize:   size,
   473  		Sscnptr: fileoff,
   474  		Sflags:  flags,
   475  	}
   476  	copy(sect.Sname[:], name) // copy string to [8]byte
   477  	f.sections = append(f.sections, sect)
   478  	f.sectNameToScnum[name] = int16(len(f.sections))
   479  	return sect
   480  }
   481  
   482  // addDwarfSection adds a dwarf section to the XCOFF file f.
   483  // This function is similar to addSection, but Dwarf section names
   484  // must be modified to conventional names and they are various subtypes.
   485  func (f *xcoffFile) addDwarfSection(s *sym.Section) *XcoffScnHdr64 {
   486  	newName, subtype := xcoffGetDwarfSubtype(s.Name)
   487  	return f.addSection(newName, 0, s.Length, s.Seg.Fileoff+s.Vaddr-s.Seg.Vaddr, STYP_DWARF|subtype)
   488  }
   489  
   490  // xcoffGetDwarfSubtype returns the XCOFF name of the DWARF section str
   491  // and its subtype constant.
   492  func xcoffGetDwarfSubtype(str string) (string, uint32) {
   493  	switch str {
   494  	default:
   495  		Exitf("unknown DWARF section name for XCOFF: %s", str)
   496  	case ".debug_abbrev":
   497  		return ".dwabrev", SSUBTYP_DWABREV
   498  	case ".debug_info":
   499  		return ".dwinfo", SSUBTYP_DWINFO
   500  	case ".debug_frame":
   501  		return ".dwframe", SSUBTYP_DWFRAME
   502  	case ".debug_line":
   503  		return ".dwline", SSUBTYP_DWLINE
   504  	case ".debug_loc":
   505  		return ".dwloc", SSUBTYP_DWLOC
   506  	case ".debug_pubnames":
   507  		return ".dwpbnms", SSUBTYP_DWPBNMS
   508  	case ".debug_pubtypes":
   509  		return ".dwpbtyp", SSUBTYP_DWPBTYP
   510  	case ".debug_ranges":
   511  		return ".dwrnges", SSUBTYP_DWRNGES
   512  	}
   513  	// never used
   514  	return "", 0
   515  }
   516  
   517  // getXCOFFscnum returns the XCOFF section number of a Go section.
   518  func (f *xcoffFile) getXCOFFscnum(sect *sym.Section) int16 {
   519  	switch sect.Seg {
   520  	case &Segtext:
   521  		return f.sectNameToScnum[".text"]
   522  	case &Segdata:
   523  		if sect.Name == ".noptrbss" || sect.Name == ".bss" {
   524  			return f.sectNameToScnum[".bss"]
   525  		}
   526  		if sect.Name == ".tbss" {
   527  			return f.sectNameToScnum[".tbss"]
   528  		}
   529  		return f.sectNameToScnum[".data"]
   530  	case &Segdwarf:
   531  		name, _ := xcoffGetDwarfSubtype(sect.Name)
   532  		return f.sectNameToScnum[name]
   533  	case &Segrelrodata:
   534  		return f.sectNameToScnum[".data"]
   535  	}
   536  	Errorf(nil, "getXCOFFscnum not implemented for section %s", sect.Name)
   537  	return -1
   538  }
   539  
   540  // Xcoffinit initialised some internal value and setups
   541  // already known header information
   542  func Xcoffinit(ctxt *Link) {
   543  	xfile.dynLibraries = make(map[string]int)
   544  
   545  	HEADR = int32(Rnd(XCOFFHDRRESERVE, XCOFFSECTALIGN))
   546  	if *FlagTextAddr != -1 {
   547  		Errorf(nil, "-T not available on AIX")
   548  	}
   549  	*FlagTextAddr = XCOFFTEXTBASE + int64(HEADR)
   550  	if *FlagRound != -1 {
   551  		Errorf(nil, "-R not available on AIX")
   552  	}
   553  	*FlagRound = int(XCOFFSECTALIGN)
   554  
   555  }
   556  
   557  // SYMBOL TABLE
   558  
   559  // type records C_FILE information needed for genasmsym in XCOFF.
   560  type xcoffSymSrcFile struct {
   561  	name         string
   562  	file         *XcoffSymEnt64   // Symbol of this C_FILE
   563  	csectAux     *XcoffAuxCSect64 // Symbol for the current .csect
   564  	csectSymNb   uint64           // Symbol number for the current .csect
   565  	csectVAStart int64
   566  	csectVAEnd   int64
   567  }
   568  
   569  var (
   570  	currDwscnoff   = make(map[string]uint64) // Needed to create C_DWARF symbols
   571  	currSymSrcFile xcoffSymSrcFile
   572  	outerSymSize   = make(map[string]int64)
   573  )
   574  
   575  // xcoffUpdateOuterSize stores the size of outer symbols in order to have it
   576  // in the symbol table.
   577  func xcoffUpdateOuterSize(ctxt *Link, size int64, stype sym.SymKind) {
   578  	if size == 0 {
   579  		return
   580  	}
   581  	// TODO: use CarrierSymByType
   582  
   583  	ldr := ctxt.loader
   584  	switch stype {
   585  	default:
   586  		Errorf(nil, "unknown XCOFF outer symbol for type %s", stype.String())
   587  	case sym.SRODATA, sym.SRODATARELRO, sym.SFUNCTAB, sym.SSTRING:
   588  		// Nothing to do
   589  	case sym.STYPERELRO:
   590  		if ctxt.UseRelro() && (ctxt.BuildMode == BuildModeCArchive || ctxt.BuildMode == BuildModeCShared || ctxt.BuildMode == BuildModePIE) {
   591  			// runtime.types size must be removed, as it's a real symbol.
   592  			tsize := ldr.SymSize(ldr.Lookup("runtime.types", 0))
   593  			outerSymSize["typerel.*"] = size - tsize
   594  			return
   595  		}
   596  		fallthrough
   597  	case sym.STYPE:
   598  		if !ctxt.DynlinkingGo() {
   599  			// runtime.types size must be removed, as it's a real symbol.
   600  			tsize := ldr.SymSize(ldr.Lookup("runtime.types", 0))
   601  			outerSymSize["type.*"] = size - tsize
   602  		}
   603  	case sym.SGOSTRING:
   604  		outerSymSize["go.string.*"] = size
   605  	case sym.SGOFUNC:
   606  		if !ctxt.DynlinkingGo() {
   607  			outerSymSize["go.func.*"] = size
   608  		}
   609  	case sym.SGOFUNCRELRO:
   610  		outerSymSize["go.funcrel.*"] = size
   611  	case sym.SGCBITS:
   612  		outerSymSize["runtime.gcbits.*"] = size
   613  	case sym.SPCLNTAB:
   614  		outerSymSize["runtime.pclntab"] = size
   615  	}
   616  }
   617  
   618  // addSymbol writes a symbol or an auxiliary symbol entry on ctxt.out.
   619  func (f *xcoffFile) addSymbol(sym xcoffSym) {
   620  	f.symtabSym = append(f.symtabSym, sym)
   621  	f.symbolCount++
   622  }
   623  
   624  // xcoffAlign returns the log base 2 of the symbol's alignment.
   625  func xcoffAlign(ldr *loader.Loader, x loader.Sym, t SymbolType) uint8 {
   626  	align := ldr.SymAlign(x)
   627  	if align == 0 {
   628  		if t == TextSym {
   629  			align = int32(Funcalign)
   630  		} else {
   631  			align = symalign(ldr, x)
   632  		}
   633  	}
   634  	return logBase2(int(align))
   635  }
   636  
   637  // logBase2 returns the log in base 2 of a.
   638  func logBase2(a int) uint8 {
   639  	return uint8(bits.Len(uint(a)) - 1)
   640  }
   641  
   642  // Write symbols needed when a new file appeared:
   643  // - a C_FILE with one auxiliary entry for its name
   644  // - C_DWARF symbols to provide debug information
   645  // - a C_HIDEXT which will be a csect containing all of its functions
   646  // It needs several parameters to create .csect symbols such as its entry point and its section number.
   647  //
   648  // Currently, a new file is in fact a new package. It seems to be OK, but it might change
   649  // in the future.
   650  func (f *xcoffFile) writeSymbolNewFile(ctxt *Link, name string, firstEntry uint64, extnum int16) {
   651  	ldr := ctxt.loader
   652  	/* C_FILE */
   653  	s := &XcoffSymEnt64{
   654  		Noffset: uint32(f.stringTable.add(".file")),
   655  		Nsclass: C_FILE,
   656  		Nscnum:  N_DEBUG,
   657  		Ntype:   0, // Go isn't inside predefined language.
   658  		Nnumaux: 1,
   659  	}
   660  	f.addSymbol(s)
   661  	currSymSrcFile.file = s
   662  
   663  	// Auxiliary entry for file name.
   664  	auxf := &XcoffAuxFile64{
   665  		Xoffset:  uint32(f.stringTable.add(name)),
   666  		Xftype:   XFT_FN,
   667  		Xauxtype: _AUX_FILE,
   668  	}
   669  	f.addSymbol(auxf)
   670  
   671  	/* Dwarf */
   672  	for _, sect := range Segdwarf.Sections {
   673  		var dwsize uint64
   674  		if ctxt.LinkMode == LinkInternal {
   675  			// Find the size of this corresponding package DWARF compilation unit.
   676  			// This size is set during DWARF generation (see dwarf.go).
   677  			dwsize = getDwsectCUSize(sect.Name, name)
   678  			// .debug_abbrev is common to all packages and not found with the previous function
   679  			if sect.Name == ".debug_abbrev" {
   680  				dwsize = uint64(ldr.SymSize(loader.Sym(sect.Sym)))
   681  
   682  			}
   683  		} else {
   684  			// There is only one .FILE with external linking.
   685  			dwsize = sect.Length
   686  		}
   687  
   688  		// get XCOFF name
   689  		name, _ := xcoffGetDwarfSubtype(sect.Name)
   690  		s := &XcoffSymEnt64{
   691  			Nvalue:  currDwscnoff[sect.Name],
   692  			Noffset: uint32(f.stringTable.add(name)),
   693  			Nsclass: C_DWARF,
   694  			Nscnum:  f.getXCOFFscnum(sect),
   695  			Nnumaux: 1,
   696  		}
   697  
   698  		if currSymSrcFile.csectAux == nil {
   699  			// Dwarf relocations need the symbol number of .dw* symbols.
   700  			// It doesn't need to know it for each package, one is enough.
   701  			// currSymSrcFile.csectAux == nil means first package.
   702  			ldr.SetSymDynid(loader.Sym(sect.Sym), int32(f.symbolCount))
   703  
   704  			if sect.Name == ".debug_frame" && ctxt.LinkMode != LinkExternal {
   705  				// CIE size must be added to the first package.
   706  				dwsize += 48
   707  			}
   708  		}
   709  
   710  		f.addSymbol(s)
   711  
   712  		// update the DWARF section offset in this file
   713  		if sect.Name != ".debug_abbrev" {
   714  			currDwscnoff[sect.Name] += dwsize
   715  		}
   716  
   717  		// Auxiliary dwarf section
   718  		auxd := &XcoffAuxDWARF64{
   719  			Xscnlen:  dwsize,
   720  			Xauxtype: _AUX_SECT,
   721  		}
   722  
   723  		f.addSymbol(auxd)
   724  	}
   725  
   726  	/* .csect */
   727  	// Check if extnum is in text.
   728  	// This is temporary and only here to check if this algorithm is correct.
   729  	if extnum != 1 {
   730  		Exitf("XCOFF symtab: A new file was detected with its first symbol not in .text")
   731  	}
   732  
   733  	currSymSrcFile.csectSymNb = uint64(f.symbolCount)
   734  
   735  	// No offset because no name
   736  	s = &XcoffSymEnt64{
   737  		Nvalue:  firstEntry,
   738  		Nscnum:  extnum,
   739  		Nsclass: C_HIDEXT,
   740  		Ntype:   0, // check visibility ?
   741  		Nnumaux: 1,
   742  	}
   743  	f.addSymbol(s)
   744  
   745  	aux := &XcoffAuxCSect64{
   746  		Xsmclas:  XMC_PR,
   747  		Xsmtyp:   XTY_SD | logBase2(Funcalign)<<3,
   748  		Xauxtype: _AUX_CSECT,
   749  	}
   750  	f.addSymbol(aux)
   751  
   752  	currSymSrcFile.csectAux = aux
   753  	currSymSrcFile.csectVAStart = int64(firstEntry)
   754  	currSymSrcFile.csectVAEnd = int64(firstEntry)
   755  }
   756  
   757  // Update values for the previous package.
   758  //  - Svalue of the C_FILE symbol: if it is the last one, this Svalue must be -1
   759  //  - Xsclen of the csect symbol.
   760  func (f *xcoffFile) updatePreviousFile(ctxt *Link, last bool) {
   761  	// first file
   762  	if currSymSrcFile.file == nil {
   763  		return
   764  	}
   765  
   766  	// Update C_FILE
   767  	cfile := currSymSrcFile.file
   768  	if last {
   769  		cfile.Nvalue = 0xFFFFFFFFFFFFFFFF
   770  	} else {
   771  		cfile.Nvalue = uint64(f.symbolCount)
   772  	}
   773  
   774  	// update csect scnlen in this auxiliary entry
   775  	aux := currSymSrcFile.csectAux
   776  	csectSize := currSymSrcFile.csectVAEnd - currSymSrcFile.csectVAStart
   777  	aux.Xscnlenlo = uint32(csectSize & 0xFFFFFFFF)
   778  	aux.Xscnlenhi = uint32(csectSize >> 32)
   779  }
   780  
   781  // Write symbol representing a .text function.
   782  // The symbol table is split with C_FILE corresponding to each package
   783  // and not to each source file as it should be.
   784  func (f *xcoffFile) writeSymbolFunc(ctxt *Link, x loader.Sym) []xcoffSym {
   785  	// New XCOFF symbols which will be written.
   786  	syms := []xcoffSym{}
   787  
   788  	// Check if a new file is detected.
   789  	ldr := ctxt.loader
   790  	name := ldr.SymName(x)
   791  	if strings.Contains(name, "-tramp") || strings.HasPrefix(name, "runtime.text.") {
   792  		// Trampoline don't have a FILE so there are considered
   793  		// in the current file.
   794  		// Same goes for runtime.text.X symbols.
   795  	} else if ldr.SymPkg(x) == "" { // Undefined global symbol
   796  		// If this happens, the algorithm must be redone.
   797  		if currSymSrcFile.name != "" {
   798  			Exitf("undefined global symbol found inside another file")
   799  		}
   800  	} else {
   801  		// Current file has changed. New C_FILE, C_DWARF, etc must be generated.
   802  		if currSymSrcFile.name != ldr.SymPkg(x) {
   803  			if ctxt.LinkMode == LinkInternal {
   804  				// update previous file values
   805  				xfile.updatePreviousFile(ctxt, false)
   806  				currSymSrcFile.name = ldr.SymPkg(x)
   807  				f.writeSymbolNewFile(ctxt, ldr.SymPkg(x), uint64(ldr.SymValue(x)), xfile.getXCOFFscnum(ldr.SymSect(x)))
   808  			} else {
   809  				// With external linking, ld will crash if there is several
   810  				// .FILE and DWARF debugging enable, somewhere during
   811  				// the relocation phase.
   812  				// Therefore, all packages are merged under a fake .FILE
   813  				// "go_functions".
   814  				// TODO(aix); remove once ld has been fixed or the triggering
   815  				// relocation has been found and fixed.
   816  				if currSymSrcFile.name == "" {
   817  					currSymSrcFile.name = ldr.SymPkg(x)
   818  					f.writeSymbolNewFile(ctxt, "go_functions", uint64(ldr.SymValue(x)), xfile.getXCOFFscnum(ldr.SymSect(x)))
   819  				}
   820  			}
   821  
   822  		}
   823  	}
   824  
   825  	s := &XcoffSymEnt64{
   826  		Nsclass: C_EXT,
   827  		Noffset: uint32(xfile.stringTable.add(ldr.SymExtname(x))),
   828  		Nvalue:  uint64(ldr.SymValue(x)),
   829  		Nscnum:  f.getXCOFFscnum(ldr.SymSect(x)),
   830  		Ntype:   SYM_TYPE_FUNC,
   831  		Nnumaux: 2,
   832  	}
   833  
   834  	if ldr.IsFileLocal(x) || ldr.AttrVisibilityHidden(x) || ldr.AttrLocal(x) {
   835  		s.Nsclass = C_HIDEXT
   836  	}
   837  
   838  	ldr.SetSymDynid(x, int32(xfile.symbolCount))
   839  	syms = append(syms, s)
   840  
   841  	// Keep track of the section size by tracking the VA range. Individual
   842  	// alignment differences may introduce a few extra bytes of padding
   843  	// which are not fully accounted for by ldr.SymSize(x).
   844  	sv := ldr.SymValue(x) + ldr.SymSize(x)
   845  	if currSymSrcFile.csectVAEnd < sv {
   846  		currSymSrcFile.csectVAEnd = sv
   847  	}
   848  
   849  	// create auxiliary entries
   850  	a2 := &XcoffAuxFcn64{
   851  		Xfsize:   uint32(ldr.SymSize(x)),
   852  		Xlnnoptr: 0,                     // TODO
   853  		Xendndx:  xfile.symbolCount + 3, // this symbol + 2 aux entries
   854  		Xauxtype: _AUX_FCN,
   855  	}
   856  	syms = append(syms, a2)
   857  
   858  	a4 := &XcoffAuxCSect64{
   859  		Xscnlenlo: uint32(currSymSrcFile.csectSymNb & 0xFFFFFFFF),
   860  		Xscnlenhi: uint32(currSymSrcFile.csectSymNb >> 32),
   861  		Xsmclas:   XMC_PR, // Program Code
   862  		Xsmtyp:    XTY_LD, // label definition (based on C)
   863  		Xauxtype:  _AUX_CSECT,
   864  	}
   865  	a4.Xsmtyp |= uint8(xcoffAlign(ldr, x, TextSym) << 3)
   866  
   867  	syms = append(syms, a4)
   868  	return syms
   869  }
   870  
   871  // put function used by genasmsym to write symbol table
   872  func putaixsym(ctxt *Link, x loader.Sym, t SymbolType) {
   873  	// All XCOFF symbols generated by this GO symbols
   874  	// Can be a symbol entry or a auxiliary entry
   875  	syms := []xcoffSym{}
   876  
   877  	ldr := ctxt.loader
   878  	name := ldr.SymName(x)
   879  	if t == UndefinedSym {
   880  		name = ldr.SymExtname(x)
   881  	}
   882  
   883  	switch t {
   884  	default:
   885  		return
   886  
   887  	case TextSym:
   888  		if ldr.SymPkg(x) != "" || strings.Contains(name, "-tramp") || strings.HasPrefix(name, "runtime.text.") {
   889  			// Function within a file
   890  			syms = xfile.writeSymbolFunc(ctxt, x)
   891  		} else {
   892  			// Only runtime.text and runtime.etext come through this way
   893  			if name != "runtime.text" && name != "runtime.etext" && name != "go.buildid" {
   894  				Exitf("putaixsym: unknown text symbol %s", name)
   895  			}
   896  			s := &XcoffSymEnt64{
   897  				Nsclass: C_HIDEXT,
   898  				Noffset: uint32(xfile.stringTable.add(name)),
   899  				Nvalue:  uint64(ldr.SymValue(x)),
   900  				Nscnum:  xfile.getXCOFFscnum(ldr.SymSect(x)),
   901  				Ntype:   SYM_TYPE_FUNC,
   902  				Nnumaux: 1,
   903  			}
   904  			ldr.SetSymDynid(x, int32(xfile.symbolCount))
   905  			syms = append(syms, s)
   906  
   907  			size := uint64(ldr.SymSize(x))
   908  			a4 := &XcoffAuxCSect64{
   909  				Xauxtype:  _AUX_CSECT,
   910  				Xscnlenlo: uint32(size & 0xFFFFFFFF),
   911  				Xscnlenhi: uint32(size >> 32),
   912  				Xsmclas:   XMC_PR,
   913  				Xsmtyp:    XTY_SD,
   914  			}
   915  			a4.Xsmtyp |= uint8(xcoffAlign(ldr, x, TextSym) << 3)
   916  			syms = append(syms, a4)
   917  		}
   918  
   919  	case DataSym, BSSSym:
   920  		s := &XcoffSymEnt64{
   921  			Nsclass: C_EXT,
   922  			Noffset: uint32(xfile.stringTable.add(name)),
   923  			Nvalue:  uint64(ldr.SymValue(x)),
   924  			Nscnum:  xfile.getXCOFFscnum(ldr.SymSect(x)),
   925  			Nnumaux: 1,
   926  		}
   927  
   928  		if ldr.IsFileLocal(x) || ldr.AttrVisibilityHidden(x) || ldr.AttrLocal(x) {
   929  			// There is more symbols in the case of a global data
   930  			// which are related to the assembly generated
   931  			// to access such symbols.
   932  			// But as Golang as its own way to check if a symbol is
   933  			// global or local (the capital letter), we don't need to
   934  			// implement them yet.
   935  			s.Nsclass = C_HIDEXT
   936  		}
   937  
   938  		ldr.SetSymDynid(x, int32(xfile.symbolCount))
   939  		syms = append(syms, s)
   940  
   941  		// Create auxiliary entry
   942  
   943  		// Normally, size should be the size of csect containing all
   944  		// the data and bss symbols of one file/package.
   945  		// However, it's easier to just have a csect for each symbol.
   946  		// It might change
   947  		size := uint64(ldr.SymSize(x))
   948  		a4 := &XcoffAuxCSect64{
   949  			Xauxtype:  _AUX_CSECT,
   950  			Xscnlenlo: uint32(size & 0xFFFFFFFF),
   951  			Xscnlenhi: uint32(size >> 32),
   952  		}
   953  
   954  		if ty := ldr.SymType(x); ty >= sym.STYPE && ty <= sym.SPCLNTAB {
   955  			if ctxt.IsExternal() && strings.HasPrefix(ldr.SymSect(x).Name, ".data.rel.ro") {
   956  				// During external linking, read-only datas with relocation
   957  				// must be in .data.
   958  				a4.Xsmclas = XMC_RW
   959  			} else {
   960  				// Read only data
   961  				a4.Xsmclas = XMC_RO
   962  			}
   963  		} else if /*ty == sym.SDATA &&*/ strings.HasPrefix(ldr.SymName(x), "TOC.") && ctxt.IsExternal() {
   964  			a4.Xsmclas = XMC_TC
   965  		} else if ldr.SymName(x) == "TOC" {
   966  			a4.Xsmclas = XMC_TC0
   967  		} else {
   968  			a4.Xsmclas = XMC_RW
   969  		}
   970  		if t == DataSym {
   971  			a4.Xsmtyp |= XTY_SD
   972  		} else {
   973  			a4.Xsmtyp |= XTY_CM
   974  		}
   975  
   976  		a4.Xsmtyp |= uint8(xcoffAlign(ldr, x, t) << 3)
   977  
   978  		syms = append(syms, a4)
   979  
   980  	case UndefinedSym:
   981  		if ty := ldr.SymType(x); ty != sym.SDYNIMPORT && ty != sym.SHOSTOBJ && ty != sym.SUNDEFEXT {
   982  			return
   983  		}
   984  		s := &XcoffSymEnt64{
   985  			Nsclass: C_EXT,
   986  			Noffset: uint32(xfile.stringTable.add(name)),
   987  			Nnumaux: 1,
   988  		}
   989  		ldr.SetSymDynid(x, int32(xfile.symbolCount))
   990  		syms = append(syms, s)
   991  
   992  		a4 := &XcoffAuxCSect64{
   993  			Xauxtype: _AUX_CSECT,
   994  			Xsmclas:  XMC_DS,
   995  			Xsmtyp:   XTY_ER | XTY_IMP,
   996  		}
   997  
   998  		if ldr.SymName(x) == "__n_pthreads" {
   999  			// Currently, all imported symbols made by cgo_import_dynamic are
  1000  			// syscall functions, except __n_pthreads which is a variable.
  1001  			// TODO(aix): Find a way to detect variables imported by cgo.
  1002  			a4.Xsmclas = XMC_RW
  1003  		}
  1004  
  1005  		syms = append(syms, a4)
  1006  
  1007  	case TLSSym:
  1008  		s := &XcoffSymEnt64{
  1009  			Nsclass: C_EXT,
  1010  			Noffset: uint32(xfile.stringTable.add(name)),
  1011  			Nscnum:  xfile.getXCOFFscnum(ldr.SymSect(x)),
  1012  			Nvalue:  uint64(ldr.SymValue(x)),
  1013  			Nnumaux: 1,
  1014  		}
  1015  
  1016  		ldr.SetSymDynid(x, int32(xfile.symbolCount))
  1017  		syms = append(syms, s)
  1018  
  1019  		size := uint64(ldr.SymSize(x))
  1020  		a4 := &XcoffAuxCSect64{
  1021  			Xauxtype:  _AUX_CSECT,
  1022  			Xsmclas:   XMC_UL,
  1023  			Xsmtyp:    XTY_CM,
  1024  			Xscnlenlo: uint32(size & 0xFFFFFFFF),
  1025  			Xscnlenhi: uint32(size >> 32),
  1026  		}
  1027  
  1028  		syms = append(syms, a4)
  1029  	}
  1030  
  1031  	for _, s := range syms {
  1032  		xfile.addSymbol(s)
  1033  	}
  1034  }
  1035  
  1036  // Generate XCOFF Symbol table.
  1037  // It will be written in out file in Asmbxcoff, because it must be
  1038  // at the very end, especially after relocation sections which needs symbols' index.
  1039  func (f *xcoffFile) asmaixsym(ctxt *Link) {
  1040  	ldr := ctxt.loader
  1041  	// Get correct size for symbols wrapping others symbols like go.string.*
  1042  	// sym.Size can be used directly as the symbols have already been written.
  1043  	for name, size := range outerSymSize {
  1044  		sym := ldr.Lookup(name, 0)
  1045  		if sym == 0 {
  1046  			Errorf(nil, "unknown outer symbol with name %s", name)
  1047  		} else {
  1048  			s := ldr.MakeSymbolUpdater(sym)
  1049  			s.SetSize(size)
  1050  		}
  1051  	}
  1052  
  1053  	// These symbols won't show up in the first loop below because we
  1054  	// skip sym.STEXT symbols. Normal sym.STEXT symbols are emitted by walking textp.
  1055  	s := ldr.Lookup("runtime.text", 0)
  1056  	if ldr.SymType(s) == sym.STEXT {
  1057  		// We've already included this symbol in ctxt.Textp on AIX with external linker.
  1058  		// See data.go:/textaddress
  1059  		if !ctxt.IsExternal() {
  1060  			putaixsym(ctxt, s, TextSym)
  1061  		}
  1062  	}
  1063  
  1064  	n := 1
  1065  	// Generate base addresses for all text sections if there are multiple
  1066  	for _, sect := range Segtext.Sections[1:] {
  1067  		if sect.Name != ".text" || ctxt.IsExternal() {
  1068  			// On AIX, runtime.text.X are symbols already in the symtab.
  1069  			break
  1070  		}
  1071  		s = ldr.Lookup(fmt.Sprintf("runtime.text.%d", n), 0)
  1072  		if s == 0 {
  1073  			break
  1074  		}
  1075  		if ldr.SymType(s) == sym.STEXT {
  1076  			putaixsym(ctxt, s, TextSym)
  1077  		}
  1078  		n++
  1079  	}
  1080  
  1081  	s = ldr.Lookup("runtime.etext", 0)
  1082  	if ldr.SymType(s) == sym.STEXT {
  1083  		// We've already included this symbol in ctxt.Textp
  1084  		// on AIX with external linker.
  1085  		// See data.go:/textaddress
  1086  		if !ctxt.IsExternal() {
  1087  			putaixsym(ctxt, s, TextSym)
  1088  		}
  1089  	}
  1090  
  1091  	shouldBeInSymbolTable := func(s loader.Sym, name string) bool {
  1092  		if name == ".go.buildinfo" {
  1093  			// On AIX, .go.buildinfo must be in the symbol table as
  1094  			// it has relocations.
  1095  			return true
  1096  		}
  1097  		if ldr.AttrNotInSymbolTable(s) {
  1098  			return false
  1099  		}
  1100  		if (name == "" || name[0] == '.') && !ldr.IsFileLocal(s) && name != ".TOC." {
  1101  			return false
  1102  		}
  1103  		return true
  1104  	}
  1105  
  1106  	for s, nsym := loader.Sym(1), loader.Sym(ldr.NSym()); s < nsym; s++ {
  1107  		if !shouldBeInSymbolTable(s, ldr.SymName(s)) {
  1108  			continue
  1109  		}
  1110  		st := ldr.SymType(s)
  1111  		switch {
  1112  		case st == sym.STLSBSS:
  1113  			if ctxt.IsExternal() {
  1114  				putaixsym(ctxt, s, TLSSym)
  1115  			}
  1116  
  1117  		case st == sym.SBSS, st == sym.SNOPTRBSS, st == sym.SLIBFUZZER_EXTRA_COUNTER:
  1118  			if ldr.AttrReachable(s) {
  1119  				data := ldr.Data(s)
  1120  				if len(data) > 0 {
  1121  					ldr.Errorf(s, "should not be bss (size=%d type=%v special=%v)", len(data), ldr.SymType(s), ldr.AttrSpecial(s))
  1122  				}
  1123  				putaixsym(ctxt, s, BSSSym)
  1124  			}
  1125  
  1126  		case st >= sym.SELFRXSECT && st < sym.SXREF: // data sections handled in dodata
  1127  			if ldr.AttrReachable(s) {
  1128  				putaixsym(ctxt, s, DataSym)
  1129  			}
  1130  
  1131  		case st == sym.SUNDEFEXT:
  1132  			putaixsym(ctxt, s, UndefinedSym)
  1133  
  1134  		case st == sym.SDYNIMPORT:
  1135  			if ldr.AttrReachable(s) {
  1136  				putaixsym(ctxt, s, UndefinedSym)
  1137  			}
  1138  		}
  1139  	}
  1140  
  1141  	for _, s := range ctxt.Textp {
  1142  		putaixsym(ctxt, s, TextSym)
  1143  	}
  1144  
  1145  	if ctxt.Debugvlog != 0 || *flagN {
  1146  		ctxt.Logf("symsize = %d\n", uint32(symSize))
  1147  	}
  1148  	xfile.updatePreviousFile(ctxt, true)
  1149  }
  1150  
  1151  func (f *xcoffFile) genDynSym(ctxt *Link) {
  1152  	ldr := ctxt.loader
  1153  	var dynsyms []loader.Sym
  1154  	for s := loader.Sym(1); s < loader.Sym(ldr.NSym()); s++ {
  1155  		if !ldr.AttrReachable(s) {
  1156  			continue
  1157  		}
  1158  		if t := ldr.SymType(s); t != sym.SHOSTOBJ && t != sym.SDYNIMPORT {
  1159  			continue
  1160  		}
  1161  		dynsyms = append(dynsyms, s)
  1162  	}
  1163  
  1164  	for _, s := range dynsyms {
  1165  		f.adddynimpsym(ctxt, s)
  1166  
  1167  		if _, ok := f.dynLibraries[ldr.SymDynimplib(s)]; !ok {
  1168  			f.dynLibraries[ldr.SymDynimplib(s)] = len(f.dynLibraries)
  1169  		}
  1170  	}
  1171  }
  1172  
  1173  // (*xcoffFile)adddynimpsym adds the dynamic symbol "s" to a XCOFF file.
  1174  // A new symbol named s.Extname() is created to be the actual dynamic symbol
  1175  // in the .loader section and in the symbol table as an External Reference.
  1176  // The symbol "s" is transformed to SXCOFFTOC to end up in .data section.
  1177  // However, there is no writing protection on those symbols and
  1178  // it might need to be added.
  1179  // TODO(aix): Handles dynamic symbols without library.
  1180  func (f *xcoffFile) adddynimpsym(ctxt *Link, s loader.Sym) {
  1181  	// Check that library name is given.
  1182  	// Pattern is already checked when compiling.
  1183  	ldr := ctxt.loader
  1184  	if ctxt.IsInternal() && ldr.SymDynimplib(s) == "" {
  1185  		ctxt.Errorf(s, "imported symbol must have a given library")
  1186  	}
  1187  
  1188  	sb := ldr.MakeSymbolUpdater(s)
  1189  	sb.SetReachable(true)
  1190  	sb.SetType(sym.SXCOFFTOC)
  1191  
  1192  	// Create new dynamic symbol
  1193  	extsym := ldr.CreateSymForUpdate(ldr.SymExtname(s), 0)
  1194  	extsym.SetType(sym.SDYNIMPORT)
  1195  	extsym.SetDynimplib(ldr.SymDynimplib(s))
  1196  	extsym.SetExtname(ldr.SymExtname(s))
  1197  	extsym.SetDynimpvers(ldr.SymDynimpvers(s))
  1198  
  1199  	// Add loader symbol
  1200  	lds := &xcoffLoaderSymbol{
  1201  		sym:    extsym.Sym(),
  1202  		smtype: XTY_IMP,
  1203  		smclas: XMC_DS,
  1204  	}
  1205  	if ldr.SymName(s) == "__n_pthreads" {
  1206  		// Currently, all imported symbols made by cgo_import_dynamic are
  1207  		// syscall functions, except __n_pthreads which is a variable.
  1208  		// TODO(aix): Find a way to detect variables imported by cgo.
  1209  		lds.smclas = XMC_RW
  1210  	}
  1211  	f.loaderSymbols = append(f.loaderSymbols, lds)
  1212  
  1213  	// Relocation to retrieve the external address
  1214  	sb.AddBytes(make([]byte, 8))
  1215  	r, _ := sb.AddRel(objabi.R_ADDR)
  1216  	r.SetSym(extsym.Sym())
  1217  	r.SetSiz(uint8(ctxt.Arch.PtrSize))
  1218  	// TODO: maybe this could be
  1219  	// sb.SetSize(0)
  1220  	// sb.SetData(nil)
  1221  	// sb.AddAddr(ctxt.Arch, extsym.Sym())
  1222  	// If the size is not 0 to begin with, I don't think the added 8 bytes
  1223  	// of zeros are necessary.
  1224  }
  1225  
  1226  // Xcoffadddynrel adds a dynamic relocation in a XCOFF file.
  1227  // This relocation will be made by the loader.
  1228  func Xcoffadddynrel(target *Target, ldr *loader.Loader, syms *ArchSyms, s loader.Sym, r loader.Reloc, rIdx int) bool {
  1229  	if target.IsExternal() {
  1230  		return true
  1231  	}
  1232  	if ldr.SymType(s) <= sym.SPCLNTAB {
  1233  		ldr.Errorf(s, "cannot have a relocation to %s in a text section symbol", ldr.SymName(r.Sym()))
  1234  		return false
  1235  	}
  1236  
  1237  	xldr := &xcoffLoaderReloc{
  1238  		sym:  s,
  1239  		roff: r.Off(),
  1240  	}
  1241  	targ := ldr.ResolveABIAlias(r.Sym())
  1242  	var targType sym.SymKind
  1243  	if targ != 0 {
  1244  		targType = ldr.SymType(targ)
  1245  	}
  1246  
  1247  	switch r.Type() {
  1248  	default:
  1249  		ldr.Errorf(s, "unexpected .loader relocation to symbol: %s (type: %s)", ldr.SymName(targ), r.Type().String())
  1250  		return false
  1251  	case objabi.R_ADDR:
  1252  		if ldr.SymType(s) == sym.SXCOFFTOC && targType == sym.SDYNIMPORT {
  1253  			// Imported symbol relocation
  1254  			for i, dynsym := range xfile.loaderSymbols {
  1255  				if ldr.SymName(dynsym.sym) == ldr.SymName(targ) {
  1256  					xldr.symndx = int32(i + 3) // +3 because of 3 section symbols
  1257  					break
  1258  				}
  1259  			}
  1260  		} else if t := ldr.SymType(s); t == sym.SDATA || t == sym.SNOPTRDATA || t == sym.SBUILDINFO || t == sym.SXCOFFTOC {
  1261  			switch ldr.SymSect(targ).Seg {
  1262  			default:
  1263  				ldr.Errorf(s, "unknown segment for .loader relocation with symbol %s", ldr.SymName(targ))
  1264  			case &Segtext:
  1265  			case &Segrodata:
  1266  				xldr.symndx = 0 // .text
  1267  			case &Segdata:
  1268  				if targType == sym.SBSS || targType == sym.SNOPTRBSS {
  1269  					xldr.symndx = 2 // .bss
  1270  				} else {
  1271  					xldr.symndx = 1 // .data
  1272  				}
  1273  			}
  1274  
  1275  		} else {
  1276  			ldr.Errorf(s, "unexpected type for .loader relocation R_ADDR for symbol %s: %s to %s", ldr.SymName(targ), ldr.SymType(s), ldr.SymType(targ))
  1277  			return false
  1278  		}
  1279  
  1280  		xldr.rtype = 0x3F<<8 + XCOFF_R_POS
  1281  	}
  1282  
  1283  	xfile.Lock()
  1284  	xfile.loaderReloc = append(xfile.loaderReloc, xldr)
  1285  	xfile.Unlock()
  1286  	return true
  1287  }
  1288  
  1289  func (ctxt *Link) doxcoff() {
  1290  	if *FlagD {
  1291  		// All XCOFF files have dynamic symbols because of the syscalls.
  1292  		Exitf("-d is not available on AIX")
  1293  	}
  1294  	ldr := ctxt.loader
  1295  
  1296  	// TOC
  1297  	toc := ldr.CreateSymForUpdate("TOC", 0)
  1298  	toc.SetType(sym.SXCOFFTOC)
  1299  	toc.SetVisibilityHidden(true)
  1300  
  1301  	// Add entry point to .loader symbols.
  1302  	ep := ldr.Lookup(*flagEntrySymbol, 0)
  1303  	if ep == 0 || !ldr.AttrReachable(ep) {
  1304  		Exitf("wrong entry point")
  1305  	}
  1306  
  1307  	xfile.loaderSymbols = append(xfile.loaderSymbols, &xcoffLoaderSymbol{
  1308  		sym:    ep,
  1309  		smtype: XTY_ENT | XTY_SD,
  1310  		smclas: XMC_DS,
  1311  	})
  1312  
  1313  	xfile.genDynSym(ctxt)
  1314  
  1315  	for s := loader.Sym(1); s < loader.Sym(ldr.NSym()); s++ {
  1316  		if strings.HasPrefix(ldr.SymName(s), "TOC.") {
  1317  			sb := ldr.MakeSymbolUpdater(s)
  1318  			sb.SetType(sym.SXCOFFTOC)
  1319  		}
  1320  	}
  1321  
  1322  	if ctxt.IsExternal() {
  1323  		// Change rt0_go name to match name in runtime/cgo:main().
  1324  		rt0 := ldr.Lookup("runtime.rt0_go", 0)
  1325  		ldr.SetSymExtname(rt0, "runtime_rt0_go")
  1326  
  1327  		nsym := loader.Sym(ldr.NSym())
  1328  		for s := loader.Sym(1); s < nsym; s++ {
  1329  			if !ldr.AttrCgoExport(s) {
  1330  				continue
  1331  			}
  1332  			if ldr.IsFileLocal(s) {
  1333  				panic("cgo_export on static symbol")
  1334  			}
  1335  
  1336  			if ldr.SymType(s) == sym.STEXT || ldr.SymType(s) == sym.SABIALIAS {
  1337  				// On AIX, a exported function must have two symbols:
  1338  				// - a .text symbol which must start with a ".".
  1339  				// - a .data symbol which is a function descriptor.
  1340  				name := ldr.SymExtname(s)
  1341  				ldr.SetSymExtname(s, "."+name)
  1342  
  1343  				desc := ldr.MakeSymbolUpdater(ldr.CreateExtSym(name, 0))
  1344  				desc.SetReachable(true)
  1345  				desc.SetType(sym.SNOPTRDATA)
  1346  				desc.AddAddr(ctxt.Arch, s)
  1347  				desc.AddAddr(ctxt.Arch, toc.Sym())
  1348  				desc.AddUint64(ctxt.Arch, 0)
  1349  			}
  1350  		}
  1351  	}
  1352  }
  1353  
  1354  // Loader section
  1355  // Currently, this section is created from scratch when assembling the XCOFF file
  1356  // according to information retrieved in xfile object.
  1357  
  1358  // Create loader section and returns its size
  1359  func Loaderblk(ctxt *Link, off uint64) {
  1360  	xfile.writeLdrScn(ctxt, off)
  1361  }
  1362  
  1363  func (f *xcoffFile) writeLdrScn(ctxt *Link, globalOff uint64) {
  1364  	var symtab []*XcoffLdSym64
  1365  	var strtab []*XcoffLdStr64
  1366  	var importtab []*XcoffLdImportFile64
  1367  	var reloctab []*XcoffLdRel64
  1368  	var dynimpreloc []*XcoffLdRel64
  1369  
  1370  	// As the string table is updated in any loader subsection,
  1371  	//  its length must be computed at the same time.
  1372  	stlen := uint32(0)
  1373  
  1374  	// Loader Header
  1375  	hdr := &XcoffLdHdr64{
  1376  		Lversion: 2,
  1377  		Lsymoff:  LDHDRSZ_64,
  1378  	}
  1379  
  1380  	ldr := ctxt.loader
  1381  	/* Symbol table */
  1382  	for _, s := range f.loaderSymbols {
  1383  		lds := &XcoffLdSym64{
  1384  			Loffset: uint32(stlen + 2),
  1385  			Lsmtype: s.smtype,
  1386  			Lsmclas: s.smclas,
  1387  		}
  1388  		sym := s.sym
  1389  		switch s.smtype {
  1390  		default:
  1391  			ldr.Errorf(sym, "unexpected loader symbol type: 0x%x", s.smtype)
  1392  		case XTY_ENT | XTY_SD:
  1393  			lds.Lvalue = uint64(ldr.SymValue(sym))
  1394  			lds.Lscnum = f.getXCOFFscnum(ldr.SymSect(sym))
  1395  		case XTY_IMP:
  1396  			lds.Lifile = int32(f.dynLibraries[ldr.SymDynimplib(sym)] + 1)
  1397  		}
  1398  		ldstr := &XcoffLdStr64{
  1399  			size: uint16(len(ldr.SymName(sym)) + 1), // + null terminator
  1400  			name: ldr.SymName(sym),
  1401  		}
  1402  		stlen += uint32(2 + ldstr.size) // 2 = sizeof ldstr.size
  1403  		symtab = append(symtab, lds)
  1404  		strtab = append(strtab, ldstr)
  1405  
  1406  	}
  1407  
  1408  	hdr.Lnsyms = int32(len(symtab))
  1409  	hdr.Lrldoff = hdr.Lsymoff + uint64(24*hdr.Lnsyms) // 24 = sizeof one symbol
  1410  	off := hdr.Lrldoff                                // current offset is the same of reloc offset
  1411  
  1412  	/* Reloc */
  1413  	// Ensure deterministic order
  1414  	sort.Slice(f.loaderReloc, func(i, j int) bool {
  1415  		r1, r2 := f.loaderReloc[i], f.loaderReloc[j]
  1416  		if r1.sym != r2.sym {
  1417  			return r1.sym < r2.sym
  1418  		}
  1419  		if r1.roff != r2.roff {
  1420  			return r1.roff < r2.roff
  1421  		}
  1422  		if r1.rtype != r2.rtype {
  1423  			return r1.rtype < r2.rtype
  1424  		}
  1425  		return r1.symndx < r2.symndx
  1426  	})
  1427  
  1428  	ep := ldr.Lookup(*flagEntrySymbol, 0)
  1429  	xldr := &XcoffLdRel64{
  1430  		Lvaddr:  uint64(ldr.SymValue(ep)),
  1431  		Lrtype:  0x3F00,
  1432  		Lrsecnm: f.getXCOFFscnum(ldr.SymSect(ep)),
  1433  		Lsymndx: 0,
  1434  	}
  1435  	off += 16
  1436  	reloctab = append(reloctab, xldr)
  1437  
  1438  	off += uint64(16 * len(f.loaderReloc))
  1439  	for _, r := range f.loaderReloc {
  1440  		symp := r.sym
  1441  		if symp == 0 {
  1442  			panic("unexpected 0 sym value")
  1443  		}
  1444  		xldr = &XcoffLdRel64{
  1445  			Lvaddr:  uint64(ldr.SymValue(symp) + int64(r.roff)),
  1446  			Lrtype:  r.rtype,
  1447  			Lsymndx: r.symndx,
  1448  		}
  1449  
  1450  		if ldr.SymSect(symp) != nil {
  1451  			xldr.Lrsecnm = f.getXCOFFscnum(ldr.SymSect(symp))
  1452  		}
  1453  
  1454  		reloctab = append(reloctab, xldr)
  1455  	}
  1456  
  1457  	off += uint64(16 * len(dynimpreloc))
  1458  	reloctab = append(reloctab, dynimpreloc...)
  1459  
  1460  	hdr.Lnreloc = int32(len(reloctab))
  1461  	hdr.Limpoff = off
  1462  
  1463  	/* Import */
  1464  	// Default import: /usr/lib:/lib
  1465  	ldimpf := &XcoffLdImportFile64{
  1466  		Limpidpath: "/usr/lib:/lib",
  1467  	}
  1468  	off += uint64(len(ldimpf.Limpidpath) + len(ldimpf.Limpidbase) + len(ldimpf.Limpidmem) + 3) // + null delimiter
  1469  	importtab = append(importtab, ldimpf)
  1470  
  1471  	// The map created by adddynimpsym associates the name to a number
  1472  	// This number represents the librairie index (- 1) in this import files section
  1473  	// Therefore, they must be sorted before being put inside the section
  1474  	libsOrdered := make([]string, len(f.dynLibraries))
  1475  	for key, val := range f.dynLibraries {
  1476  		if libsOrdered[val] != "" {
  1477  			continue
  1478  		}
  1479  		libsOrdered[val] = key
  1480  	}
  1481  
  1482  	for _, lib := range libsOrdered {
  1483  		// lib string is defined as base.a/mem.o or path/base.a/mem.o
  1484  		n := strings.Split(lib, "/")
  1485  		path := ""
  1486  		base := n[len(n)-2]
  1487  		mem := n[len(n)-1]
  1488  		if len(n) > 2 {
  1489  			path = lib[:len(lib)-len(base)-len(mem)-2]
  1490  
  1491  		}
  1492  		ldimpf = &XcoffLdImportFile64{
  1493  			Limpidpath: path,
  1494  			Limpidbase: base,
  1495  			Limpidmem:  mem,
  1496  		}
  1497  		off += uint64(len(ldimpf.Limpidpath) + len(ldimpf.Limpidbase) + len(ldimpf.Limpidmem) + 3) // + null delimiter
  1498  		importtab = append(importtab, ldimpf)
  1499  	}
  1500  
  1501  	hdr.Lnimpid = int32(len(importtab))
  1502  	hdr.Listlen = uint32(off - hdr.Limpoff)
  1503  	hdr.Lstoff = off
  1504  	hdr.Lstlen = stlen
  1505  
  1506  	/* Writing */
  1507  	ctxt.Out.SeekSet(int64(globalOff))
  1508  	binary.Write(ctxt.Out, ctxt.Arch.ByteOrder, hdr)
  1509  
  1510  	for _, s := range symtab {
  1511  		binary.Write(ctxt.Out, ctxt.Arch.ByteOrder, s)
  1512  
  1513  	}
  1514  	for _, r := range reloctab {
  1515  		binary.Write(ctxt.Out, ctxt.Arch.ByteOrder, r)
  1516  	}
  1517  	for _, f := range importtab {
  1518  		ctxt.Out.WriteString(f.Limpidpath)
  1519  		ctxt.Out.Write8(0)
  1520  		ctxt.Out.WriteString(f.Limpidbase)
  1521  		ctxt.Out.Write8(0)
  1522  		ctxt.Out.WriteString(f.Limpidmem)
  1523  		ctxt.Out.Write8(0)
  1524  	}
  1525  	for _, s := range strtab {
  1526  		ctxt.Out.Write16(s.size)
  1527  		ctxt.Out.WriteString(s.name)
  1528  		ctxt.Out.Write8(0) // null terminator
  1529  	}
  1530  
  1531  	f.loaderSize = off + uint64(stlen)
  1532  }
  1533  
  1534  // XCOFF assembling and writing file
  1535  
  1536  func (f *xcoffFile) writeFileHeader(ctxt *Link) {
  1537  	// File header
  1538  	f.xfhdr.Fmagic = U64_TOCMAGIC
  1539  	f.xfhdr.Fnscns = uint16(len(f.sections))
  1540  	f.xfhdr.Ftimedat = 0
  1541  
  1542  	if !*FlagS {
  1543  		f.xfhdr.Fsymptr = uint64(f.symtabOffset)
  1544  		f.xfhdr.Fnsyms = int32(f.symbolCount)
  1545  	}
  1546  
  1547  	if ctxt.BuildMode == BuildModeExe && ctxt.LinkMode == LinkInternal {
  1548  		ldr := ctxt.loader
  1549  		f.xfhdr.Fopthdr = AOUTHSZ_EXEC64
  1550  		f.xfhdr.Fflags = F_EXEC
  1551  
  1552  		// auxiliary header
  1553  		f.xahdr.Ovstamp = 1 // based on dump -o
  1554  		f.xahdr.Omagic = 0x10b
  1555  		copy(f.xahdr.Omodtype[:], "1L")
  1556  		entry := ldr.Lookup(*flagEntrySymbol, 0)
  1557  		f.xahdr.Oentry = uint64(ldr.SymValue(entry))
  1558  		f.xahdr.Osnentry = f.getXCOFFscnum(ldr.SymSect(entry))
  1559  		toc := ldr.Lookup("TOC", 0)
  1560  		f.xahdr.Otoc = uint64(ldr.SymValue(toc))
  1561  		f.xahdr.Osntoc = f.getXCOFFscnum(ldr.SymSect(toc))
  1562  
  1563  		f.xahdr.Oalgntext = int16(logBase2(int(XCOFFSECTALIGN)))
  1564  		f.xahdr.Oalgndata = 0x5
  1565  
  1566  		binary.Write(ctxt.Out, binary.BigEndian, &f.xfhdr)
  1567  		binary.Write(ctxt.Out, binary.BigEndian, &f.xahdr)
  1568  	} else {
  1569  		f.xfhdr.Fopthdr = 0
  1570  		binary.Write(ctxt.Out, binary.BigEndian, &f.xfhdr)
  1571  	}
  1572  
  1573  }
  1574  
  1575  func xcoffwrite(ctxt *Link) {
  1576  	ctxt.Out.SeekSet(0)
  1577  
  1578  	xfile.writeFileHeader(ctxt)
  1579  
  1580  	for _, sect := range xfile.sections {
  1581  		sect.write(ctxt)
  1582  	}
  1583  }
  1584  
  1585  // Generate XCOFF assembly file
  1586  func asmbXcoff(ctxt *Link) {
  1587  	ctxt.Out.SeekSet(0)
  1588  	fileoff := int64(Segdwarf.Fileoff + Segdwarf.Filelen)
  1589  	fileoff = int64(Rnd(int64(fileoff), int64(*FlagRound)))
  1590  
  1591  	xfile.sectNameToScnum = make(map[string]int16)
  1592  
  1593  	// Add sections
  1594  	s := xfile.addSection(".text", Segtext.Vaddr, Segtext.Length, Segtext.Fileoff, STYP_TEXT)
  1595  	xfile.xahdr.Otextstart = s.Svaddr
  1596  	xfile.xahdr.Osntext = xfile.sectNameToScnum[".text"]
  1597  	xfile.xahdr.Otsize = s.Ssize
  1598  	xfile.sectText = s
  1599  
  1600  	segdataVaddr := Segdata.Vaddr
  1601  	segdataFilelen := Segdata.Filelen
  1602  	segdataFileoff := Segdata.Fileoff
  1603  	segbssFilelen := Segdata.Length - Segdata.Filelen
  1604  	if len(Segrelrodata.Sections) > 0 {
  1605  		// Merge relro segment to data segment as
  1606  		// relro data are inside data segment on AIX.
  1607  		segdataVaddr = Segrelrodata.Vaddr
  1608  		segdataFileoff = Segrelrodata.Fileoff
  1609  		segdataFilelen = Segdata.Vaddr + Segdata.Filelen - Segrelrodata.Vaddr
  1610  	}
  1611  
  1612  	s = xfile.addSection(".data", segdataVaddr, segdataFilelen, segdataFileoff, STYP_DATA)
  1613  	xfile.xahdr.Odatastart = s.Svaddr
  1614  	xfile.xahdr.Osndata = xfile.sectNameToScnum[".data"]
  1615  	xfile.xahdr.Odsize = s.Ssize
  1616  	xfile.sectData = s
  1617  
  1618  	s = xfile.addSection(".bss", segdataVaddr+segdataFilelen, segbssFilelen, 0, STYP_BSS)
  1619  	xfile.xahdr.Osnbss = xfile.sectNameToScnum[".bss"]
  1620  	xfile.xahdr.Obsize = s.Ssize
  1621  	xfile.sectBss = s
  1622  
  1623  	if ctxt.LinkMode == LinkExternal {
  1624  		var tbss *sym.Section
  1625  		for _, s := range Segdata.Sections {
  1626  			if s.Name == ".tbss" {
  1627  				tbss = s
  1628  				break
  1629  			}
  1630  		}
  1631  		s = xfile.addSection(".tbss", tbss.Vaddr, tbss.Length, 0, STYP_TBSS)
  1632  	}
  1633  
  1634  	// add dwarf sections
  1635  	for _, sect := range Segdwarf.Sections {
  1636  		xfile.addDwarfSection(sect)
  1637  	}
  1638  
  1639  	// add and write remaining sections
  1640  	if ctxt.LinkMode == LinkInternal {
  1641  		// Loader section
  1642  		if ctxt.BuildMode == BuildModeExe {
  1643  			Loaderblk(ctxt, uint64(fileoff))
  1644  			s = xfile.addSection(".loader", 0, xfile.loaderSize, uint64(fileoff), STYP_LOADER)
  1645  			xfile.xahdr.Osnloader = xfile.sectNameToScnum[".loader"]
  1646  
  1647  			// Update fileoff for symbol table
  1648  			fileoff += int64(xfile.loaderSize)
  1649  		}
  1650  	}
  1651  
  1652  	// Create Symbol table
  1653  	xfile.asmaixsym(ctxt)
  1654  
  1655  	if ctxt.LinkMode == LinkExternal {
  1656  		xfile.emitRelocations(ctxt, fileoff)
  1657  	}
  1658  
  1659  	// Write Symbol table
  1660  	xfile.symtabOffset = ctxt.Out.Offset()
  1661  	for _, s := range xfile.symtabSym {
  1662  		binary.Write(ctxt.Out, ctxt.Arch.ByteOrder, s)
  1663  	}
  1664  	// write string table
  1665  	xfile.stringTable.write(ctxt.Out)
  1666  
  1667  	// write headers
  1668  	xcoffwrite(ctxt)
  1669  }
  1670  
  1671  // emitRelocations emits relocation entries for go.o in external linking.
  1672  func (f *xcoffFile) emitRelocations(ctxt *Link, fileoff int64) {
  1673  	ctxt.Out.SeekSet(fileoff)
  1674  	for ctxt.Out.Offset()&7 != 0 {
  1675  		ctxt.Out.Write8(0)
  1676  	}
  1677  
  1678  	ldr := ctxt.loader
  1679  	// relocsect relocates symbols from first in section sect, and returns
  1680  	// the total number of relocations emitted.
  1681  	relocsect := func(sect *sym.Section, syms []loader.Sym, base uint64) uint32 {
  1682  		// ctxt.Logf("%s 0x%x\n", sect.Name, sect.Vaddr)
  1683  		// If main section has no bits, nothing to relocate.
  1684  		if sect.Vaddr >= sect.Seg.Vaddr+sect.Seg.Filelen {
  1685  			return 0
  1686  		}
  1687  		sect.Reloff = uint64(ctxt.Out.Offset())
  1688  		for i, s := range syms {
  1689  			if !ldr.AttrReachable(s) {
  1690  				continue
  1691  			}
  1692  			if uint64(ldr.SymValue(s)) >= sect.Vaddr {
  1693  				syms = syms[i:]
  1694  				break
  1695  			}
  1696  		}
  1697  		eaddr := int64(sect.Vaddr + sect.Length)
  1698  		for _, s := range syms {
  1699  			if !ldr.AttrReachable(s) {
  1700  				continue
  1701  			}
  1702  			if ldr.SymValue(s) >= int64(eaddr) {
  1703  				break
  1704  			}
  1705  
  1706  			// Compute external relocations on the go, and pass to Xcoffreloc1 to stream out.
  1707  			// Relocation must be ordered by address, so create a list of sorted indices.
  1708  			relocs := ldr.Relocs(s)
  1709  			sorted := make([]int, relocs.Count())
  1710  			for i := 0; i < relocs.Count(); i++ {
  1711  				sorted[i] = i
  1712  			}
  1713  			sort.Slice(sorted, func(i, j int) bool {
  1714  				return relocs.At(sorted[i]).Off() < relocs.At(sorted[j]).Off()
  1715  			})
  1716  
  1717  			for _, ri := range sorted {
  1718  				r := relocs.At(ri)
  1719  				rr, ok := extreloc(ctxt, ldr, s, r)
  1720  				if !ok {
  1721  					continue
  1722  				}
  1723  				if rr.Xsym == 0 {
  1724  					ldr.Errorf(s, "missing xsym in relocation")
  1725  					continue
  1726  				}
  1727  				if ldr.SymDynid(rr.Xsym) < 0 {
  1728  					ldr.Errorf(s, "reloc %s to non-coff symbol %s (outer=%s) %d %d", r.Type(), ldr.SymName(r.Sym()), ldr.SymName(rr.Xsym), ldr.SymType(r.Sym()), ldr.SymDynid(rr.Xsym))
  1729  				}
  1730  				if !thearch.Xcoffreloc1(ctxt.Arch, ctxt.Out, ldr, s, rr, int64(uint64(ldr.SymValue(s)+int64(r.Off()))-base)) {
  1731  					ldr.Errorf(s, "unsupported obj reloc %d(%s)/%d to %s", r.Type(), r.Type(), r.Siz(), ldr.SymName(r.Sym()))
  1732  				}
  1733  			}
  1734  		}
  1735  		sect.Rellen = uint64(ctxt.Out.Offset()) - sect.Reloff
  1736  		return uint32(sect.Rellen) / RELSZ_64
  1737  	}
  1738  	sects := []struct {
  1739  		xcoffSect *XcoffScnHdr64
  1740  		segs      []*sym.Segment
  1741  	}{
  1742  		{f.sectText, []*sym.Segment{&Segtext}},
  1743  		{f.sectData, []*sym.Segment{&Segrelrodata, &Segdata}},
  1744  	}
  1745  	for _, s := range sects {
  1746  		s.xcoffSect.Srelptr = uint64(ctxt.Out.Offset())
  1747  		n := uint32(0)
  1748  		for _, seg := range s.segs {
  1749  			for _, sect := range seg.Sections {
  1750  				if sect.Name == ".text" {
  1751  					n += relocsect(sect, ctxt.Textp, 0)
  1752  				} else {
  1753  					n += relocsect(sect, ctxt.datap, 0)
  1754  				}
  1755  			}
  1756  		}
  1757  		s.xcoffSect.Snreloc += n
  1758  	}
  1759  
  1760  dwarfLoop:
  1761  	for i := 0; i < len(Segdwarf.Sections); i++ {
  1762  		sect := Segdwarf.Sections[i]
  1763  		si := dwarfp[i]
  1764  		if si.secSym() != loader.Sym(sect.Sym) ||
  1765  			ldr.SymSect(si.secSym()) != sect {
  1766  			panic("inconsistency between dwarfp and Segdwarf")
  1767  		}
  1768  		for _, xcoffSect := range f.sections {
  1769  			_, subtyp := xcoffGetDwarfSubtype(sect.Name)
  1770  			if xcoffSect.Sflags&0xF0000 == subtyp {
  1771  				xcoffSect.Srelptr = uint64(ctxt.Out.Offset())
  1772  				xcoffSect.Snreloc = relocsect(sect, si.syms, sect.Vaddr)
  1773  				continue dwarfLoop
  1774  			}
  1775  		}
  1776  		Errorf(nil, "emitRelocations: could not find %q section", sect.Name)
  1777  	}
  1778  }
  1779  
  1780  // xcoffCreateExportFile creates a file with exported symbols for
  1781  // -Wl,-bE option.
  1782  // ld won't export symbols unless they are listed in an export file.
  1783  func xcoffCreateExportFile(ctxt *Link) (fname string) {
  1784  	fname = filepath.Join(*flagTmpdir, "export_file.exp")
  1785  	var buf bytes.Buffer
  1786  
  1787  	ldr := ctxt.loader
  1788  	for s, nsym := loader.Sym(1), loader.Sym(ldr.NSym()); s < nsym; s++ {
  1789  		if !ldr.AttrCgoExport(s) {
  1790  			continue
  1791  		}
  1792  		extname := ldr.SymExtname(s)
  1793  		if !strings.HasPrefix(extname, "._cgoexp_") {
  1794  			continue
  1795  		}
  1796  		if ldr.IsFileLocal(s) {
  1797  			continue // Only export non-static symbols
  1798  		}
  1799  
  1800  		// Retrieve the name of the initial symbol
  1801  		// exported by cgo.
  1802  		// The corresponding Go symbol is:
  1803  		// _cgoexp_hashcode_symname.
  1804  		name := strings.SplitN(extname, "_", 4)[3]
  1805  
  1806  		buf.Write([]byte(name + "\n"))
  1807  	}
  1808  
  1809  	err := ioutil.WriteFile(fname, buf.Bytes(), 0666)
  1810  	if err != nil {
  1811  		Errorf(nil, "WriteFile %s failed: %v", fname, err)
  1812  	}
  1813  
  1814  	return fname
  1815  }
  1816  

View as plain text