github.com/gagliardetto/golang-go@v0.0.0-20201020153340-53909ea70814/cmd/link/internal/ld/xcoff.go (about)

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