github.com/megatontech/mynoteforgo@v0.0.0-20200507084910-5d0c6ea6e890/源码/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  	"cmd/internal/objabi"
    10  	"cmd/link/internal/sym"
    11  	"encoding/binary"
    12  	"strings"
    13  )
    14  
    15  // This file handles all algorithms related to XCOFF files generation.
    16  // Most of them are adaptations of the ones in  cmd/link/internal/pe.go
    17  // as PE and XCOFF are based on COFF files.
    18  // XCOFF files generated are 64 bits.
    19  
    20  const (
    21  	// Total amount of space to reserve at the start of the file
    22  	// for File Header, Auxiliary Header, and Section Headers.
    23  	// May waste some.
    24  	XCOFFHDRRESERVE       = FILHSZ_64 + AOUTHSZ_EXEC64 + SCNHSZ_64*23
    25  	XCOFFSECTALIGN  int64 = 32 // base on dump -o
    26  
    27  	// XCOFF binaries should normally have all its sections position-independent.
    28  	// However, this is not yet possible for .text because of some R_ADDR relocations
    29  	// inside RODATA symbols.
    30  	// .data and .bss are position-independent so their address start inside a unreachable
    31  	// segment during execution to force segfault if something is wrong.
    32  	XCOFFTEXTBASE = 0x100000000 // Start of text address
    33  	XCOFFDATABASE = 0x200000000 // Start of data address
    34  )
    35  
    36  // File Header
    37  type XcoffFileHdr64 struct {
    38  	Fmagic   uint16 // Target machine
    39  	Fnscns   uint16 // Number of sections
    40  	Ftimedat int32  // Time and date of file creation
    41  	Fsymptr  uint64 // Byte offset to symbol table start
    42  	Fopthdr  uint16 // Number of bytes in optional header
    43  	Fflags   uint16 // Flags
    44  	Fnsyms   int32  // Number of entries in symbol table
    45  }
    46  
    47  const (
    48  	U64_TOCMAGIC = 0767 // AIX 64-bit XCOFF
    49  )
    50  
    51  // Flags that describe the type of the object file.
    52  const (
    53  	F_RELFLG    = 0x0001
    54  	F_EXEC      = 0x0002
    55  	F_LNNO      = 0x0004
    56  	F_FDPR_PROF = 0x0010
    57  	F_FDPR_OPTI = 0x0020
    58  	F_DSA       = 0x0040
    59  	F_VARPG     = 0x0100
    60  	F_DYNLOAD   = 0x1000
    61  	F_SHROBJ    = 0x2000
    62  	F_LOADONLY  = 0x4000
    63  )
    64  
    65  // Auxiliary Header
    66  type XcoffAoutHdr64 struct {
    67  	Omagic      int16    // Flags - Ignored If Vstamp Is 1
    68  	Ovstamp     int16    // Version
    69  	Odebugger   uint32   // Reserved For Debugger
    70  	Otextstart  uint64   // Virtual Address Of Text
    71  	Odatastart  uint64   // Virtual Address Of Data
    72  	Otoc        uint64   // Toc Address
    73  	Osnentry    int16    // Section Number For Entry Point
    74  	Osntext     int16    // Section Number For Text
    75  	Osndata     int16    // Section Number For Data
    76  	Osntoc      int16    // Section Number For Toc
    77  	Osnloader   int16    // Section Number For Loader
    78  	Osnbss      int16    // Section Number For Bss
    79  	Oalgntext   int16    // Max Text Alignment
    80  	Oalgndata   int16    // Max Data Alignment
    81  	Omodtype    [2]byte  // Module Type Field
    82  	Ocpuflag    uint8    // Bit Flags - Cputypes Of Objects
    83  	Ocputype    uint8    // Reserved for CPU type
    84  	Otextpsize  uint8    // Requested text page size
    85  	Odatapsize  uint8    // Requested data page size
    86  	Ostackpsize uint8    // Requested stack page size
    87  	Oflags      uint8    // Flags And TLS Alignment
    88  	Otsize      uint64   // Text Size In Bytes
    89  	Odsize      uint64   // Data Size In Bytes
    90  	Obsize      uint64   // Bss Size In Bytes
    91  	Oentry      uint64   // Entry Point Address
    92  	Omaxstack   uint64   // Max Stack Size Allowed
    93  	Omaxdata    uint64   // Max Data Size Allowed
    94  	Osntdata    int16    // Section Number For Tdata Section
    95  	Osntbss     int16    // Section Number For Tbss Section
    96  	Ox64flags   uint16   // Additional Flags For 64-Bit Objects
    97  	Oresv3a     int16    // Reserved
    98  	Oresv3      [2]int32 // Reserved
    99  
   100  }
   101  
   102  // Section Header
   103  type XcoffScnHdr64 struct {
   104  	Sname    [8]byte // Section Name
   105  	Spaddr   uint64  // Physical Address
   106  	Svaddr   uint64  // Virtual Address
   107  	Ssize    uint64  // Section Size
   108  	Sscnptr  uint64  // File Offset To Raw Data
   109  	Srelptr  uint64  // File Offset To Relocation
   110  	Slnnoptr uint64  // File Offset To Line Numbers
   111  	Snreloc  uint32  // Number Of Relocation Entries
   112  	Snlnno   uint32  // Number Of Line Number Entries
   113  	Sflags   uint32  // flags
   114  }
   115  
   116  // Flags defining the section type.
   117  const (
   118  	STYP_DWARF  = 0x0010
   119  	STYP_TEXT   = 0x0020
   120  	STYP_DATA   = 0x0040
   121  	STYP_BSS    = 0x0080
   122  	STYP_EXCEPT = 0x0100
   123  	STYP_INFO   = 0x0200
   124  	STYP_TDATA  = 0x0400
   125  	STYP_TBSS   = 0x0800
   126  	STYP_LOADER = 0x1000
   127  	STYP_DEBUG  = 0x2000
   128  	STYP_TYPCHK = 0x4000
   129  	STYP_OVRFLO = 0x8000
   130  )
   131  const (
   132  	SSUBTYP_DWINFO  = 0x10000 // DWARF info section
   133  	SSUBTYP_DWLINE  = 0x20000 // DWARF line-number section
   134  	SSUBTYP_DWPBNMS = 0x30000 // DWARF public names section
   135  	SSUBTYP_DWPBTYP = 0x40000 // DWARF public types section
   136  	SSUBTYP_DWARNGE = 0x50000 // DWARF aranges section
   137  	SSUBTYP_DWABREV = 0x60000 // DWARF abbreviation section
   138  	SSUBTYP_DWSTR   = 0x70000 // DWARF strings section
   139  	SSUBTYP_DWRNGES = 0x80000 // DWARF ranges section
   140  	SSUBTYP_DWLOC   = 0x90000 // DWARF location lists section
   141  	SSUBTYP_DWFRAME = 0xA0000 // DWARF frames section
   142  	SSUBTYP_DWMAC   = 0xB0000 // DWARF macros section
   143  )
   144  
   145  // Headers size
   146  const (
   147  	FILHSZ_32      = 20
   148  	FILHSZ_64      = 24
   149  	AOUTHSZ_EXEC32 = 72
   150  	AOUTHSZ_EXEC64 = 120
   151  	SCNHSZ_32      = 40
   152  	SCNHSZ_64      = 72
   153  	LDHDRSZ_32     = 32
   154  	LDHDRSZ_64     = 56
   155  	LDSYMSZ_64     = 24
   156  )
   157  
   158  // Symbol Table Entry
   159  type XcoffSymEnt64 struct {
   160  	Nvalue  uint64 // Symbol value
   161  	Noffset uint32 // Offset of the name in string table or .debug section
   162  	Nscnum  int16  // Section number of symbol
   163  	Ntype   uint16 // Basic and derived type specification
   164  	Nsclass uint8  // Storage class of symbol
   165  	Nnumaux int8   // Number of auxiliary entries
   166  }
   167  
   168  const SYMESZ = 18
   169  
   170  const (
   171  	// Nscnum
   172  	N_DEBUG = -2
   173  	N_ABS   = -1
   174  	N_UNDEF = 0
   175  
   176  	//Ntype
   177  	SYM_V_INTERNAL  = 0x1000
   178  	SYM_V_HIDDEN    = 0x2000
   179  	SYM_V_PROTECTED = 0x3000
   180  	SYM_V_EXPORTED  = 0x4000
   181  	SYM_TYPE_FUNC   = 0x0020 // is function
   182  )
   183  
   184  // Storage Class.
   185  const (
   186  	C_NULL    = 0   // Symbol table entry marked for deletion
   187  	C_EXT     = 2   // External symbol
   188  	C_STAT    = 3   // Static symbol
   189  	C_BLOCK   = 100 // Beginning or end of inner block
   190  	C_FCN     = 101 // Beginning or end of function
   191  	C_FILE    = 103 // Source file name and compiler information
   192  	C_HIDEXT  = 107 // Unnamed external symbol
   193  	C_BINCL   = 108 // Beginning of include file
   194  	C_EINCL   = 109 // End of include file
   195  	C_WEAKEXT = 111 // Weak external symbol
   196  	C_DWARF   = 112 // DWARF symbol
   197  	C_GSYM    = 128 // Global variable
   198  	C_LSYM    = 129 // Automatic variable allocated on stack
   199  	C_PSYM    = 130 // Argument to subroutine allocated on stack
   200  	C_RSYM    = 131 // Register variable
   201  	C_RPSYM   = 132 // Argument to function or procedure stored in register
   202  	C_STSYM   = 133 // Statically allocated symbol
   203  	C_BCOMM   = 135 // Beginning of common block
   204  	C_ECOML   = 136 // Local member of common block
   205  	C_ECOMM   = 137 // End of common block
   206  	C_DECL    = 140 // Declaration of object
   207  	C_ENTRY   = 141 // Alternate entry
   208  	C_FUN     = 142 // Function or procedure
   209  	C_BSTAT   = 143 // Beginning of static block
   210  	C_ESTAT   = 144 // End of static block
   211  	C_GTLS    = 145 // Global thread-local variable
   212  	C_STTLS   = 146 // Static thread-local variable
   213  )
   214  
   215  // File Auxiliary Entry
   216  type XcoffAuxFile64 struct {
   217  	Xfname   [8]byte // Name or offset inside string table
   218  	Xftype   uint8   // Source file string type
   219  	Xauxtype uint8   // Type of auxiliary entry
   220  }
   221  
   222  // Function Auxiliary Entry
   223  type XcoffAuxFcn64 struct {
   224  	Xlnnoptr uint64 // File pointer to line number
   225  	Xfsize   uint32 // Size of function in bytes
   226  	Xendndx  uint32 // Symbol table index of next entry
   227  	Xpad     uint8  // Unused
   228  	Xauxtype uint8  // Type of auxiliary entry
   229  }
   230  
   231  // csect Auxiliary Entry.
   232  type XcoffAuxCSect64 struct {
   233  	Xscnlenlo uint32 // Lower 4 bytes of length or symbol table index
   234  	Xparmhash uint32 // Offset of parameter type-check string
   235  	Xsnhash   uint16 // .typchk section number
   236  	Xsmtyp    uint8  // Symbol alignment and type
   237  	Xsmclas   uint8  // Storage-mapping class
   238  	Xscnlenhi uint32 // Upper 4 bytes of length or symbol table index
   239  	Xpad      uint8  // Unused
   240  	Xauxtype  uint8  // Type of auxiliary entry
   241  }
   242  
   243  // Auxiliary type
   244  const (
   245  	_AUX_EXCEPT = 255
   246  	_AUX_FCN    = 254
   247  	_AUX_SYM    = 253
   248  	_AUX_FILE   = 252
   249  	_AUX_CSECT  = 251
   250  	_AUX_SECT   = 250
   251  )
   252  
   253  // Xftype field
   254  const (
   255  	XFT_FN = 0   // Source File Name
   256  	XFT_CT = 1   // Compile Time Stamp
   257  	XFT_CV = 2   // Compiler Version Number
   258  	XFT_CD = 128 // Compiler Defined Information/
   259  
   260  )
   261  
   262  // Symbol type field.
   263  const (
   264  	XTY_ER  = 0    // External reference
   265  	XTY_SD  = 1    // Section definition
   266  	XTY_LD  = 2    // Label definition
   267  	XTY_CM  = 3    // Common csect definition
   268  	XTY_WK  = 0x8  // Weak symbol
   269  	XTY_EXP = 0x10 // Exported symbol
   270  	XTY_ENT = 0x20 // Entry point symbol
   271  	XTY_IMP = 0x40 // Imported symbol
   272  )
   273  
   274  // Storage-mapping class.
   275  const (
   276  	XMC_PR     = 0  // Program code
   277  	XMC_RO     = 1  // Read-only constant
   278  	XMC_DB     = 2  // Debug dictionary table
   279  	XMC_TC     = 3  // TOC entry
   280  	XMC_UA     = 4  // Unclassified
   281  	XMC_RW     = 5  // Read/Write data
   282  	XMC_GL     = 6  // Global linkage
   283  	XMC_XO     = 7  // Extended operation
   284  	XMC_SV     = 8  // 32-bit supervisor call descriptor
   285  	XMC_BS     = 9  // BSS class
   286  	XMC_DS     = 10 // Function descriptor
   287  	XMC_UC     = 11 // Unnamed FORTRAN common
   288  	XMC_TC0    = 15 // TOC anchor
   289  	XMC_TD     = 16 // Scalar data entry in the TOC
   290  	XMC_SV64   = 17 // 64-bit supervisor call descriptor
   291  	XMC_SV3264 = 18 // Supervisor call descriptor for both 32-bit and 64-bit
   292  	XMC_TL     = 20 // Read/Write thread-local data
   293  	XMC_UL     = 21 // Read/Write thread-local data (.tbss)
   294  	XMC_TE     = 22 // TOC entry
   295  )
   296  
   297  // Loader Header
   298  type XcoffLdHdr64 struct {
   299  	Lversion int32  // Loader section version number
   300  	Lnsyms   int32  // Number of symbol table entries
   301  	Lnreloc  int32  // Number of relocation table entries
   302  	Listlen  uint32 // Length of import file ID string table
   303  	Lnimpid  int32  // Number of import file IDs
   304  	Lstlen   uint32 // Length of string table
   305  	Limpoff  uint64 // Offset to start of import file IDs
   306  	Lstoff   uint64 // Offset to start of string table
   307  	Lsymoff  uint64 // Offset to start of symbol table
   308  	Lrldoff  uint64 // Offset to start of relocation entries
   309  }
   310  
   311  // Loader Symbol
   312  type XcoffLdSym64 struct {
   313  	Lvalue  uint64 // Address field
   314  	Loffset uint32 // Byte offset into string table of symbol name
   315  	Lscnum  int16  // Section number containing symbol
   316  	Lsmtype int8   // Symbol type, export, import flags
   317  	Lsmclas int8   // Symbol storage class
   318  	Lifile  int32  // Import file ID; ordinal of import file IDs
   319  	Lparm   uint32 // Parameter type-check field
   320  }
   321  
   322  type xcoffLoaderSymbol struct {
   323  	sym    *sym.Symbol
   324  	smtype int8
   325  	smclas int8
   326  }
   327  
   328  type XcoffLdImportFile64 struct {
   329  	Limpidpath string
   330  	Limpidbase string
   331  	Limpidmem  string
   332  }
   333  
   334  type XcoffLdRel64 struct {
   335  	Lvaddr  uint64 // Address Field
   336  	Lrtype  uint16 // Relocation Size and Type
   337  	Lrsecnm int16  // Section Number being relocated
   338  	Lsymndx int32  // Loader-Section symbol table index
   339  }
   340  
   341  // xcoffLoaderReloc holds information about a relocation made by the loader.
   342  type xcoffLoaderReloc struct {
   343  	sym    *sym.Symbol
   344  	rel    *sym.Reloc
   345  	rtype  uint16
   346  	symndx int32
   347  }
   348  
   349  const (
   350  	XCOFF_R_POS = 0x00 // A(sym) Positive Relocation
   351  )
   352  
   353  type XcoffLdStr64 struct {
   354  	size uint16
   355  	name string
   356  }
   357  
   358  // xcoffFile is used to build XCOFF file.
   359  type xcoffFile struct {
   360  	xfhdr           XcoffFileHdr64
   361  	xahdr           XcoffAoutHdr64
   362  	sections        []*XcoffScnHdr64
   363  	stringTable     xcoffStringTable
   364  	sectNameToScnum map[string]int16
   365  	loaderSize      uint64
   366  	symtabOffset    int64                // offset to the start of symbol table
   367  	symbolCount     uint32               // number of symbol table records written
   368  	dynLibraries    map[string]int       // Dynamic libraries in .loader section. The integer represents its import file number (- 1)
   369  	loaderSymbols   []*xcoffLoaderSymbol // symbols inside .loader symbol table
   370  	loaderReloc     []*xcoffLoaderReloc  // Reloc that must be made inside loader
   371  }
   372  
   373  // Var used by XCOFF Generation algorithms
   374  var (
   375  	xfile xcoffFile
   376  )
   377  
   378  // xcoffStringTable is a XCOFF string table.
   379  type xcoffStringTable struct {
   380  	strings    []string
   381  	stringsLen int
   382  }
   383  
   384  // size returns size of string table t.
   385  func (t *xcoffStringTable) size() int {
   386  	// string table starts with 4-byte length at the beginning
   387  	return t.stringsLen + 4
   388  }
   389  
   390  // add adds string str to string table t.
   391  func (t *xcoffStringTable) add(str string) int {
   392  	off := t.size()
   393  	t.strings = append(t.strings, str)
   394  	t.stringsLen += len(str) + 1 // each string will have 0 appended to it
   395  	return off
   396  }
   397  
   398  // write writes string table t into the output file.
   399  func (t *xcoffStringTable) write(out *OutBuf) {
   400  	out.Write32(uint32(t.size()))
   401  	for _, s := range t.strings {
   402  		out.WriteString(s)
   403  		out.Write8(0)
   404  	}
   405  }
   406  
   407  // write writes XCOFF section sect into the output file.
   408  func (sect *XcoffScnHdr64) write(ctxt *Link) {
   409  	binary.Write(ctxt.Out, binary.BigEndian, sect)
   410  	ctxt.Out.Write32(0) // Add 4 empty bytes at the end to match alignment
   411  }
   412  
   413  // addSection adds section to the XCOFF file f.
   414  func (f *xcoffFile) addSection(name string, addr uint64, size uint64, fileoff uint64, flags uint32) *XcoffScnHdr64 {
   415  	sect := &XcoffScnHdr64{
   416  		Spaddr:  addr,
   417  		Svaddr:  addr,
   418  		Ssize:   size,
   419  		Sscnptr: fileoff,
   420  		Sflags:  flags,
   421  	}
   422  	copy(sect.Sname[:], name) // copy string to [8]byte
   423  	f.sections = append(f.sections, sect)
   424  	f.sectNameToScnum[name] = int16(len(f.sections))
   425  	return sect
   426  }
   427  
   428  // addDwarfSection adds a dwarf section to the XCOFF file f.
   429  // This function is similar to addSection, but Dwarf section names
   430  // must be modified to conventional names and they are various subtypes.
   431  func (f *xcoffFile) addDwarfSection(s *sym.Section) *XcoffScnHdr64 {
   432  	newName, subtype := xcoffGetDwarfSubtype(s.Name)
   433  	return f.addSection(newName, 0, s.Length, s.Seg.Fileoff+s.Vaddr-s.Seg.Vaddr, STYP_DWARF|subtype)
   434  }
   435  
   436  // xcoffGetDwarfSubtype returns the XCOFF name of the DWARF section str
   437  // and its subtype constant.
   438  func xcoffGetDwarfSubtype(str string) (string, uint32) {
   439  	switch str {
   440  	default:
   441  		Exitf("unknown DWARF section name for XCOFF: %s", str)
   442  	case ".debug_abbrev":
   443  		return ".dwabrev", SSUBTYP_DWABREV
   444  	case ".debug_info":
   445  		return ".dwinfo", SSUBTYP_DWINFO
   446  	case ".debug_frame":
   447  		return ".dwframe", SSUBTYP_DWFRAME
   448  	case ".debug_line":
   449  		return ".dwline", SSUBTYP_DWLINE
   450  	case ".debug_loc":
   451  		return ".dwloc", SSUBTYP_DWLOC
   452  	case ".debug_pubnames":
   453  		return ".dwpbnms", SSUBTYP_DWPBNMS
   454  	case ".debug_pubtypes":
   455  		return ".dwpbtyp", SSUBTYP_DWPBTYP
   456  	case ".debug_ranges":
   457  		return ".dwrnge", SSUBTYP_DWRNGES
   458  	}
   459  	// never used
   460  	return "", 0
   461  }
   462  
   463  // getXCOFFscnum returns the XCOFF section number of a Go section.
   464  func (f *xcoffFile) getXCOFFscnum(sect *sym.Section) int16 {
   465  	switch sect.Seg {
   466  	case &Segtext:
   467  		return f.sectNameToScnum[".text"]
   468  	case &Segdata:
   469  		if sect.Name == ".noptrdata" || sect.Name == ".data" {
   470  			return f.sectNameToScnum[".data"]
   471  		}
   472  		if sect.Name == ".noptrbss" || sect.Name == ".bss" {
   473  			return f.sectNameToScnum[".bss"]
   474  		}
   475  		Errorf(nil, "unknown XCOFF segment data section: %s", sect.Name)
   476  	case &Segdwarf:
   477  		name, _ := xcoffGetDwarfSubtype(sect.Name)
   478  		return f.sectNameToScnum[name]
   479  	}
   480  	Errorf(nil, "getXCOFFscnum not implemented for section %s", sect.Name)
   481  	return -1
   482  }
   483  
   484  // Xcoffinit initialised some internal value and setups
   485  // already known header information
   486  func Xcoffinit(ctxt *Link) {
   487  	xfile.dynLibraries = make(map[string]int)
   488  
   489  	HEADR = int32(Rnd(XCOFFHDRRESERVE, XCOFFSECTALIGN))
   490  	if *FlagTextAddr != -1 {
   491  		Errorf(nil, "-T not available on AIX")
   492  	}
   493  	*FlagTextAddr = XCOFFTEXTBASE + int64(HEADR)
   494  	*FlagDataAddr = 0
   495  	if *FlagRound != -1 {
   496  		Errorf(nil, "-R not available on AIX")
   497  	}
   498  	*FlagRound = int(XCOFFSECTALIGN)
   499  
   500  }
   501  
   502  // SYMBOL TABLE
   503  
   504  // type records C_FILE information needed for genasmsym in XCOFF.
   505  type xcoffSymSrcFile struct {
   506  	name       string
   507  	fileSymNb  uint32 // Symbol number of this C_FILE
   508  	csectSymNb uint64 // Symbol number for the current .csect
   509  	csectSize  int64
   510  }
   511  
   512  var (
   513  	currDwscnoff   = make(map[string]uint64) // Needed to create C_DWARF symbols
   514  	currSymSrcFile xcoffSymSrcFile
   515  )
   516  
   517  // writeSymbol writes a symbol or an auxiliary symbol entry on ctxt.out.
   518  func (f *xcoffFile) writeSymbol(out *OutBuf, byteOrder binary.ByteOrder, sym interface{}) {
   519  	binary.Write(out, byteOrder, sym)
   520  	f.symbolCount++
   521  }
   522  
   523  // Write symbols needed when a new file appared :
   524  // - a C_FILE with one auxiliary entry for its name
   525  // - C_DWARF symbols to provide debug information
   526  // - a C_HIDEXT which will be a csect containing all of its functions
   527  // It needs several parameters to create .csect symbols such as its entry point and its section number.
   528  //
   529  // Currently, a new file is in fact a new package. It seems to be OK, but it might change
   530  // in the future.
   531  func (f *xcoffFile) writeSymbolNewFile(ctxt *Link, name string, firstEntry uint64, extnum int16) {
   532  	/* C_FILE */
   533  	s := &XcoffSymEnt64{
   534  		Noffset: uint32(f.stringTable.add(".file")),
   535  		Nsclass: C_FILE,
   536  		Nscnum:  N_DEBUG,
   537  		Ntype:   0, // Go isn't inside predefined language.
   538  		Nnumaux: 1,
   539  	}
   540  	f.writeSymbol(ctxt.Out, ctxt.Arch.ByteOrder, s)
   541  
   542  	// Auxiliary entry for file name.
   543  	ctxt.Out.Write32(0)
   544  	ctxt.Out.Write32(uint32(f.stringTable.add(name)))
   545  	ctxt.Out.Write32(0) // 6 bytes empty
   546  	ctxt.Out.Write16(0)
   547  	ctxt.Out.Write8(XFT_FN)
   548  	ctxt.Out.Write16(0) // 2 bytes empty
   549  	ctxt.Out.Write8(_AUX_FILE)
   550  	f.symbolCount++
   551  
   552  	/* Dwarf */
   553  	for _, sect := range Segdwarf.Sections {
   554  		// Find the size of this corresponding package DWARF compilation unit.
   555  		// This size is set during DWARF generation (see dwarf.go).
   556  		dwsize := getDwsectCUSize(sect.Name, name)
   557  		// .debug_abbrev is commun to all packages and not found with the previous function
   558  		if sect.Name == ".debug_abbrev" {
   559  			s := ctxt.Syms.Lookup(sect.Name, 0)
   560  			dwsize = uint64(s.Size)
   561  		}
   562  
   563  		// get XCOFF name
   564  		name, _ := xcoffGetDwarfSubtype(sect.Name)
   565  		s := &XcoffSymEnt64{
   566  			Nvalue:  currDwscnoff[sect.Name],
   567  			Noffset: uint32(f.stringTable.add(name)),
   568  			Nsclass: C_DWARF,
   569  			Nscnum:  f.getXCOFFscnum(sect),
   570  			Nnumaux: 1,
   571  		}
   572  		f.writeSymbol(ctxt.Out, ctxt.Arch.ByteOrder, s)
   573  
   574  		// update the DWARF section offset in this file
   575  		if sect.Name != ".debug_abbrev" {
   576  			currDwscnoff[sect.Name] += dwsize
   577  		}
   578  
   579  		// Auxiliary dwarf section
   580  		ctxt.Out.Write64(dwsize) // section length
   581  		ctxt.Out.Write64(0)      // nreloc
   582  		ctxt.Out.Write8(0)       // pad
   583  		ctxt.Out.Write8(_AUX_SECT)
   584  		f.symbolCount++
   585  	}
   586  
   587  	/* .csect */
   588  	// Check if extnum is in text.
   589  	// This is temporary and only here to check if this algorithm is correct.
   590  	if extnum != 1 {
   591  		Exitf("XCOFF symtab: A new file was detected with its first symbol not in .text")
   592  	}
   593  
   594  	currSymSrcFile.csectSymNb = uint64(f.symbolCount)
   595  	currSymSrcFile.csectSize = 0
   596  
   597  	// No offset because no name
   598  	s = &XcoffSymEnt64{
   599  		Nvalue:  firstEntry,
   600  		Nscnum:  extnum,
   601  		Nsclass: C_HIDEXT,
   602  		Ntype:   0, // check visibility ?
   603  		Nnumaux: 1,
   604  	}
   605  	f.writeSymbol(ctxt.Out, ctxt.Arch.ByteOrder, s)
   606  
   607  	aux := &XcoffAuxCSect64{
   608  		Xsmclas:  XMC_PR,
   609  		Xsmtyp:   XTY_SD | 5<<3, // align = 5
   610  		Xauxtype: _AUX_CSECT,
   611  	}
   612  	f.writeSymbol(ctxt.Out, ctxt.Arch.ByteOrder, aux)
   613  
   614  }
   615  
   616  // Update values for the previous package.
   617  //  - Svalue of the C_FILE symbol: if it is the last one, this Svalue must be -1
   618  //  - Xsclen of the csect symbol.
   619  func (f *xcoffFile) updatePreviousFile(ctxt *Link, last bool) {
   620  	// first file
   621  	if currSymSrcFile.fileSymNb == 0 {
   622  		return
   623  	}
   624  
   625  	prevOff := f.symtabOffset + int64(currSymSrcFile.fileSymNb*SYMESZ)
   626  	currOff := ctxt.Out.Offset()
   627  
   628  	// Update C_FILE
   629  	ctxt.Out.SeekSet(prevOff)
   630  	if last {
   631  		ctxt.Out.Write64(0xFFFFFFFFFFFFFFFF)
   632  	} else {
   633  		ctxt.Out.Write64(uint64(f.symbolCount))
   634  	}
   635  
   636  	// update csect scnlen in this auxiliary entry
   637  	prevOff = f.symtabOffset + int64((currSymSrcFile.csectSymNb+1)*SYMESZ)
   638  	ctxt.Out.SeekSet(prevOff)
   639  	ctxt.Out.Write32(uint32(currSymSrcFile.csectSize & 0xFFFFFFFF))
   640  	prevOff += 12
   641  	ctxt.Out.SeekSet(prevOff)
   642  	ctxt.Out.Write32(uint32(currSymSrcFile.csectSize >> 32))
   643  
   644  	ctxt.Out.SeekSet(currOff)
   645  
   646  }
   647  
   648  // Write symbol representing a .text function.
   649  // The symbol table is split with C_FILE corresponding to each package
   650  // and not to each source file as it should be.
   651  func (f *xcoffFile) writeSymbolFunc(ctxt *Link, x *sym.Symbol) []interface{} {
   652  	// New XCOFF symbols which will be written.
   653  	syms := []interface{}{}
   654  
   655  	// Check if a new file is detected.
   656  	if x.File == "" { // Undefined global symbol
   657  		// If this happens, the algorithme must be redone.
   658  		if currSymSrcFile.name != "" {
   659  			Exitf("undefined global symbol found inside another file")
   660  		}
   661  	} else {
   662  		// Current file has changed. New C_FILE, C_DWARF, etc must be generated.
   663  		if currSymSrcFile.name != x.File {
   664  			// update previous file values
   665  			xfile.updatePreviousFile(ctxt, false)
   666  			currSymSrcFile.name = x.File
   667  			currSymSrcFile.fileSymNb = f.symbolCount
   668  			f.writeSymbolNewFile(ctxt, x.File, uint64(x.Value), xfile.getXCOFFscnum(x.Sect))
   669  		}
   670  	}
   671  
   672  	s := &XcoffSymEnt64{
   673  		Nsclass: C_EXT,
   674  		Noffset: uint32(xfile.stringTable.add(x.Name)),
   675  		Nvalue:  uint64(x.Value),
   676  		Nscnum:  f.getXCOFFscnum(x.Sect),
   677  		Ntype:   SYM_TYPE_FUNC,
   678  		Nnumaux: 2,
   679  	}
   680  
   681  	if x.Version != 0 || x.Attr.VisibilityHidden() || x.Attr.Local() {
   682  		s.Nsclass = C_HIDEXT
   683  	}
   684  
   685  	syms = append(syms, s)
   686  
   687  	// Update current csect size
   688  	currSymSrcFile.csectSize += x.Size
   689  
   690  	// create auxiliary entries
   691  	a2 := &XcoffAuxFcn64{
   692  		Xfsize:   uint32(x.Size),
   693  		Xlnnoptr: 0,                     // TODO
   694  		Xendndx:  xfile.symbolCount + 3, // this symbol + 2 aux entries
   695  		Xauxtype: _AUX_FCN,
   696  	}
   697  	syms = append(syms, a2)
   698  
   699  	a4 := &XcoffAuxCSect64{
   700  		Xscnlenlo: uint32(currSymSrcFile.csectSymNb & 0xFFFFFFFF),
   701  		Xscnlenhi: uint32(currSymSrcFile.csectSymNb >> 32),
   702  		Xsmclas:   XMC_PR, // Program Code
   703  		Xsmtyp:    XTY_LD, // label definition (based on C)
   704  		Xauxtype:  _AUX_CSECT,
   705  	}
   706  	syms = append(syms, a4)
   707  	return syms
   708  }
   709  
   710  // put function used by genasmsym to write symbol table
   711  func putaixsym(ctxt *Link, x *sym.Symbol, str string, t SymbolType, addr int64, go_ *sym.Symbol) {
   712  
   713  	// All XCOFF symbols generated by this GO symbols
   714  	// Can be a symbol entry or a auxiliary entry
   715  	syms := []interface{}{}
   716  
   717  	switch t {
   718  	default:
   719  		return
   720  
   721  	case TextSym:
   722  		if x.FuncInfo != nil {
   723  			// Function within a file
   724  			syms = xfile.writeSymbolFunc(ctxt, x)
   725  		} else {
   726  			// Only runtime.text and runtime.etext come through this way
   727  			if x.Name != "runtime.text" && x.Name != "runtime.etext" && x.Name != "go.buildid" {
   728  				Exitf("putaixsym: unknown text symbol %s", x.Name)
   729  			}
   730  			s := &XcoffSymEnt64{
   731  				Nsclass: C_HIDEXT,
   732  				Noffset: uint32(xfile.stringTable.add(str)),
   733  				Nvalue:  uint64(x.Value),
   734  				Nscnum:  xfile.getXCOFFscnum(x.Sect),
   735  				Ntype:   SYM_TYPE_FUNC,
   736  				Nnumaux: 1,
   737  			}
   738  			syms = append(syms, s)
   739  
   740  			size := uint64(x.Size)
   741  			a4 := &XcoffAuxCSect64{
   742  				Xauxtype:  _AUX_CSECT,
   743  				Xscnlenlo: uint32(size & 0xFFFFFFFF),
   744  				Xscnlenhi: uint32(size >> 32),
   745  				Xsmclas:   XMC_PR,
   746  				Xsmtyp:    XTY_SD,
   747  			}
   748  			syms = append(syms, a4)
   749  
   750  		}
   751  
   752  	case DataSym, BSSSym:
   753  		s := &XcoffSymEnt64{
   754  			Nsclass: C_EXT,
   755  			Noffset: uint32(xfile.stringTable.add(str)),
   756  			Nvalue:  uint64(x.Value),
   757  			Nscnum:  xfile.getXCOFFscnum(x.Sect),
   758  			Nnumaux: 1,
   759  		}
   760  
   761  		if x.Version != 0 || x.Attr.VisibilityHidden() || x.Attr.Local() {
   762  			// There is more symbols in the case of a global data
   763  			// which are related to the assembly generated
   764  			// to access such symbols.
   765  			// But as Golang as its own way to check if a symbol is
   766  			// global or local (the capital letter), we don't need to
   767  			// implement them yet.
   768  			s.Nsclass = C_HIDEXT
   769  		}
   770  
   771  		syms = append(syms, s)
   772  
   773  		// Create auxiliary entry
   774  
   775  		// Normally, size should be the size of csect containing all
   776  		// the data and bss symbols of one file/package.
   777  		// However, it's easier to just have a csect for each symbol.
   778  		// It might change
   779  		size := uint64(x.Size)
   780  		a4 := &XcoffAuxCSect64{
   781  			Xauxtype:  _AUX_CSECT,
   782  			Xscnlenlo: uint32(size & 0xFFFFFFFF),
   783  			Xscnlenhi: uint32(size >> 32),
   784  		}
   785  		// Read only data
   786  		if x.Type >= sym.STYPE && x.Type <= sym.SPCLNTAB {
   787  			a4.Xsmclas = XMC_RO
   788  		} else {
   789  			a4.Xsmclas = XMC_RW
   790  		}
   791  		if t == DataSym {
   792  			a4.Xsmtyp |= XTY_SD
   793  		} else {
   794  			a4.Xsmtyp |= XTY_CM
   795  		}
   796  
   797  		syms = append(syms, a4)
   798  
   799  	case UndefinedSym:
   800  		if x.Type != sym.SDYNIMPORT && x.Type != sym.SHOSTOBJ {
   801  			return
   802  		}
   803  		s := &XcoffSymEnt64{
   804  			Nsclass: C_EXT,
   805  			Noffset: uint32(xfile.stringTable.add(str)),
   806  			Nnumaux: 1,
   807  		}
   808  		syms = append(syms, s)
   809  
   810  		a4 := &XcoffAuxCSect64{
   811  			Xauxtype: _AUX_CSECT,
   812  			Xsmclas:  XMC_DS,
   813  			Xsmtyp:   XTY_ER | XTY_IMP,
   814  		}
   815  
   816  		if x.Name == "__n_pthreads" {
   817  			// Currently, all imported symbols made by cgo_import_dynamic are
   818  			// syscall functions, except __n_pthreads which is a variable.
   819  			// TODO(aix): Find a way to detect variables imported by cgo.
   820  			a4.Xsmclas = XMC_RW
   821  		}
   822  
   823  		syms = append(syms, a4)
   824  	}
   825  
   826  	for _, s := range syms {
   827  		xfile.writeSymbol(ctxt.Out, ctxt.Arch.ByteOrder, s)
   828  	}
   829  }
   830  
   831  // Generate XCOFF Symbol table and XCOFF String table
   832  func (f *xcoffFile) asmaixsym(ctxt *Link) {
   833  	// write symbol table
   834  	genasmsym(ctxt, putaixsym)
   835  
   836  	// update last file Svalue
   837  	xfile.updatePreviousFile(ctxt, true)
   838  
   839  	// write string table
   840  	xfile.stringTable.write(ctxt.Out)
   841  }
   842  
   843  func (f *xcoffFile) genDynSym(ctxt *Link) {
   844  	var dynsyms []*sym.Symbol
   845  	for _, s := range ctxt.Syms.Allsym {
   846  		if s.Type != sym.SHOSTOBJ && s.Type != sym.SDYNIMPORT {
   847  			continue
   848  		}
   849  		dynsyms = append(dynsyms, s)
   850  	}
   851  
   852  	for _, s := range dynsyms {
   853  		f.adddynimpsym(ctxt, s)
   854  
   855  		if _, ok := f.dynLibraries[s.Dynimplib()]; !ok {
   856  			f.dynLibraries[s.Dynimplib()] = len(f.dynLibraries)
   857  		}
   858  
   859  	}
   860  
   861  }
   862  
   863  // (*xcoffFile)adddynimpsym adds the dynamic symbol "s" to a XCOFF file.
   864  // A new symbol named s.Extname() is created to be the actual dynamic symbol
   865  // in the .loader section and in the symbol table as an External Reference.
   866  // The symbol "s" is transformed to SXCOFFTOC to end up in .data section.
   867  // However, there is no writing protection on those symbols and
   868  // it might need to be added.
   869  // TODO(aix): Handles dynamic symbols without library.
   870  func (f *xcoffFile) adddynimpsym(ctxt *Link, s *sym.Symbol) {
   871  	// Check that library name is given.
   872  	// Pattern is already checked when compiling.
   873  	if s.Dynimplib() == "" {
   874  		Errorf(s, "imported symbol must have a given library")
   875  	}
   876  
   877  	s.Type = sym.SXCOFFTOC
   878  
   879  	// Create new dynamic symbol
   880  	extsym := ctxt.Syms.Lookup(s.Extname(), 0)
   881  	extsym.Type = sym.SDYNIMPORT
   882  	extsym.Attr |= sym.AttrReachable
   883  	extsym.SetDynimplib(s.Dynimplib())
   884  	extsym.SetExtname(s.Extname())
   885  	extsym.SetDynimpvers(s.Dynimpvers())
   886  
   887  	// Add loader symbol
   888  	lds := &xcoffLoaderSymbol{
   889  		sym:    extsym,
   890  		smtype: XTY_IMP,
   891  		smclas: XMC_DS,
   892  	}
   893  	if s.Name == "__n_pthreads" {
   894  		// Currently, all imported symbols made by cgo_import_dynamic are
   895  		// syscall functions, except __n_pthreads which is a variable.
   896  		// TODO(aix): Find a way to detect variables imported by cgo.
   897  		lds.smclas = XMC_RW
   898  	}
   899  	f.loaderSymbols = append(f.loaderSymbols, lds)
   900  
   901  	// Relocation to retrieve the external address
   902  	s.AddBytes(make([]byte, 8))
   903  	s.SetAddr(ctxt.Arch, 0, extsym)
   904  
   905  }
   906  
   907  // Xcoffadddynrel adds a dynamic relocation in a XCOFF file.
   908  // This relocation will be made by the loader.
   909  func Xcoffadddynrel(ctxt *Link, s *sym.Symbol, r *sym.Reloc) bool {
   910  	if s.Type <= sym.SPCLNTAB {
   911  		Errorf(s, "cannot have a relocation to %s in a text section symbol", r.Sym.Name)
   912  		return false
   913  	}
   914  
   915  	ldr := &xcoffLoaderReloc{
   916  		sym: s,
   917  		rel: r,
   918  	}
   919  
   920  	switch r.Type {
   921  	default:
   922  		Errorf(s, "unexpected .loader relocation to symbol: %s (type: %s)", r.Sym.Name, r.Type.String())
   923  		return false
   924  	case objabi.R_ADDR:
   925  		if s.Type == sym.SXCOFFTOC && r.Sym.Type == sym.SDYNIMPORT {
   926  			// Imported symbol relocation
   927  			for i, dynsym := range xfile.loaderSymbols {
   928  				if dynsym.sym.Name == r.Sym.Name {
   929  					ldr.symndx = int32(i + 3) // +3 because of 3 section symbols
   930  					break
   931  				}
   932  			}
   933  		} else if s.Type == sym.SDATA {
   934  			switch r.Sym.Sect.Seg {
   935  			default:
   936  				Errorf(s, "unknown segment for .loader relocation with symbol %s", r.Sym.Name)
   937  			case &Segtext:
   938  			case &Segrodata:
   939  				ldr.symndx = 0 // .text
   940  			case &Segdata:
   941  				if r.Sym.Type == sym.SBSS || r.Sym.Type == sym.SNOPTRBSS {
   942  					ldr.symndx = 2 // .bss
   943  				} else {
   944  					ldr.symndx = 1 // .data
   945  				}
   946  
   947  			}
   948  
   949  		} else {
   950  			Errorf(s, "unexpected type for .loader relocation R_ADDR for symbol %s: %s to %s", r.Sym.Name, s.Type, r.Sym.Type)
   951  			return false
   952  		}
   953  
   954  		ldr.rtype = 0x3F<<8 + XCOFF_R_POS
   955  	}
   956  
   957  	xfile.loaderReloc = append(xfile.loaderReloc, ldr)
   958  	return true
   959  }
   960  
   961  func (ctxt *Link) doxcoff() {
   962  	if *FlagD {
   963  		// All XCOFF files have dynamic symbols because of the syscalls.
   964  		Exitf("-d is not available on AIX")
   965  	}
   966  
   967  	// Initial map used to store compilation unit size for each DWARF section (see dwarf.go).
   968  	dwsectCUSize = make(map[string]uint64)
   969  
   970  	// TOC
   971  	toc := ctxt.Syms.Lookup("TOC", 0)
   972  	toc.Type = sym.SXCOFFTOC
   973  	toc.Attr |= sym.AttrReachable
   974  
   975  	// XCOFF does not allow relocations of data symbol address to a text symbol.
   976  	// Such case occurs when a RODATA symbol retrieves a data symbol address.
   977  	// When it happens, this RODATA symbol is moved to .data section.
   978  	// runtime.algarray is a readonly symbol but stored inside .data section.
   979  	// If it stays in .data, all type symbols will be moved to .data which
   980  	// cannot be done.
   981  	algarray := ctxt.Syms.Lookup("runtime.algarray", 0)
   982  	algarray.Type = sym.SRODATA
   983  	for {
   984  		again := false
   985  		for _, s := range ctxt.Syms.Allsym {
   986  			if s.Type != sym.SRODATA {
   987  				continue
   988  			}
   989  			for ri := range s.R {
   990  				r := &s.R[ri]
   991  				if r.Type != objabi.R_ADDR {
   992  					continue
   993  				}
   994  				if r.Sym.Type != sym.Sxxx && r.Sym.Type != sym.STEXT && r.Sym.Type != sym.SRODATA {
   995  					s.Type = sym.SDATA
   996  					again = true
   997  					break
   998  				}
   999  			}
  1000  
  1001  		}
  1002  		if !again {
  1003  			break
  1004  		}
  1005  	}
  1006  
  1007  	// Add entry point to .loader symbols.
  1008  	ep := ctxt.Syms.ROLookup(*flagEntrySymbol, 0)
  1009  	if !ep.Attr.Reachable() {
  1010  		Exitf("wrong entry point")
  1011  	}
  1012  	xfile.loaderSymbols = append(xfile.loaderSymbols, &xcoffLoaderSymbol{
  1013  		sym:    ep,
  1014  		smtype: XTY_ENT | XTY_SD,
  1015  		smclas: XMC_DS,
  1016  	})
  1017  
  1018  	xfile.genDynSym(ctxt)
  1019  
  1020  	for _, s := range ctxt.Syms.Allsym {
  1021  		if strings.HasPrefix(s.Name, "TOC.") {
  1022  			s.Type = sym.SXCOFFTOC
  1023  		}
  1024  	}
  1025  }
  1026  
  1027  // Loader section
  1028  // Currently, this section is created from scratch when assembling the XCOFF file
  1029  // according to information retrieved in xfile object.
  1030  
  1031  // Create loader section and returns its size
  1032  func Loaderblk(ctxt *Link, off uint64) {
  1033  	xfile.writeLdrScn(ctxt, off)
  1034  }
  1035  
  1036  func (f *xcoffFile) writeLdrScn(ctxt *Link, globalOff uint64) {
  1037  	var symtab []*XcoffLdSym64
  1038  	var strtab []*XcoffLdStr64
  1039  	var importtab []*XcoffLdImportFile64
  1040  	var reloctab []*XcoffLdRel64
  1041  	var dynimpreloc []*XcoffLdRel64
  1042  
  1043  	// As the string table is updated in any loader subsection,
  1044  	//  its length must be computed at the same time.
  1045  	stlen := uint32(0)
  1046  
  1047  	// Loader Header
  1048  	hdr := &XcoffLdHdr64{
  1049  		Lversion: 2,
  1050  		Lsymoff:  LDHDRSZ_64,
  1051  	}
  1052  
  1053  	/* Symbol table */
  1054  	for _, s := range f.loaderSymbols {
  1055  		lds := &XcoffLdSym64{
  1056  			Loffset: uint32(stlen + 2),
  1057  			Lsmtype: s.smtype,
  1058  			Lsmclas: s.smclas,
  1059  		}
  1060  		switch s.smtype {
  1061  		default:
  1062  			Errorf(s.sym, "unexpected loader symbol type: 0x%x", s.smtype)
  1063  		case XTY_ENT | XTY_SD:
  1064  			lds.Lvalue = uint64(s.sym.Value)
  1065  			lds.Lscnum = f.getXCOFFscnum(s.sym.Sect)
  1066  		case XTY_IMP:
  1067  			lds.Lifile = int32(f.dynLibraries[s.sym.Dynimplib()] + 1)
  1068  		}
  1069  		ldstr := &XcoffLdStr64{
  1070  			size: uint16(len(s.sym.Name) + 1), // + null terminator
  1071  			name: s.sym.Name,
  1072  		}
  1073  		stlen += uint32(2 + ldstr.size) // 2 = sizeof ldstr.size
  1074  		symtab = append(symtab, lds)
  1075  		strtab = append(strtab, ldstr)
  1076  
  1077  	}
  1078  
  1079  	hdr.Lnsyms = int32(len(symtab))
  1080  	hdr.Lrldoff = hdr.Lsymoff + uint64(24*hdr.Lnsyms) // 24 = sizeof one symbol
  1081  	off := hdr.Lrldoff                                // current offset is the same of reloc offset
  1082  
  1083  	/* Reloc */
  1084  	ep := ctxt.Syms.ROLookup(*flagEntrySymbol, 0)
  1085  	ldr := &XcoffLdRel64{
  1086  		Lvaddr:  uint64(ep.Value),
  1087  		Lrtype:  0x3F00,
  1088  		Lrsecnm: f.getXCOFFscnum(ep.Sect),
  1089  		Lsymndx: 0,
  1090  	}
  1091  	off += 16
  1092  	reloctab = append(reloctab, ldr)
  1093  
  1094  	off += uint64(16 * len(f.loaderReloc))
  1095  	for _, r := range f.loaderReloc {
  1096  		ldr = &XcoffLdRel64{
  1097  			Lvaddr:  uint64(r.sym.Value + int64(r.rel.Off)),
  1098  			Lrtype:  r.rtype,
  1099  			Lsymndx: r.symndx,
  1100  		}
  1101  
  1102  		if r.sym.Sect != nil {
  1103  			ldr.Lrsecnm = f.getXCOFFscnum(r.sym.Sect)
  1104  		}
  1105  
  1106  		reloctab = append(reloctab, ldr)
  1107  	}
  1108  
  1109  	off += uint64(16 * len(dynimpreloc))
  1110  	reloctab = append(reloctab, dynimpreloc...)
  1111  
  1112  	hdr.Lnreloc = int32(len(reloctab))
  1113  	hdr.Limpoff = off
  1114  
  1115  	/* Import */
  1116  	// Default import: /usr/lib:/lib
  1117  	ldimpf := &XcoffLdImportFile64{
  1118  		Limpidpath: "/usr/lib:/lib",
  1119  	}
  1120  	off += uint64(len(ldimpf.Limpidpath) + len(ldimpf.Limpidbase) + len(ldimpf.Limpidmem) + 3) // + null delimiter
  1121  	importtab = append(importtab, ldimpf)
  1122  
  1123  	// The map created by adddynimpsym associates the name to a number
  1124  	// This number represents the librairie index (- 1) in this import files section
  1125  	// Therefore, they must be sorted before being put inside the section
  1126  	libsOrdered := make([]string, len(f.dynLibraries))
  1127  	for key, val := range f.dynLibraries {
  1128  		if libsOrdered[val] != "" {
  1129  			continue
  1130  		}
  1131  		libsOrdered[val] = key
  1132  	}
  1133  
  1134  	for _, lib := range libsOrdered {
  1135  		// lib string is defined as base.a/mem.o or path/base.a/mem.o
  1136  		n := strings.Split(lib, "/")
  1137  		path := ""
  1138  		base := n[len(n)-2]
  1139  		mem := n[len(n)-1]
  1140  		if len(n) > 2 {
  1141  			path = lib[:len(lib)-len(base)-len(mem)-2]
  1142  
  1143  		}
  1144  		ldimpf = &XcoffLdImportFile64{
  1145  			Limpidpath: path,
  1146  			Limpidbase: base,
  1147  			Limpidmem:  mem,
  1148  		}
  1149  		off += uint64(len(ldimpf.Limpidpath) + len(ldimpf.Limpidbase) + len(ldimpf.Limpidmem) + 3) // + null delimiter
  1150  		importtab = append(importtab, ldimpf)
  1151  	}
  1152  
  1153  	hdr.Lnimpid = int32(len(importtab))
  1154  	hdr.Listlen = uint32(off - hdr.Limpoff)
  1155  	hdr.Lstoff = off
  1156  	hdr.Lstlen = stlen
  1157  
  1158  	/* Writing */
  1159  	ctxt.Out.SeekSet(int64(globalOff))
  1160  	binary.Write(ctxt.Out, ctxt.Arch.ByteOrder, hdr)
  1161  
  1162  	for _, s := range symtab {
  1163  		binary.Write(ctxt.Out, ctxt.Arch.ByteOrder, s)
  1164  
  1165  	}
  1166  	for _, r := range reloctab {
  1167  		binary.Write(ctxt.Out, ctxt.Arch.ByteOrder, r)
  1168  	}
  1169  	for _, f := range importtab {
  1170  		ctxt.Out.WriteString(f.Limpidpath)
  1171  		ctxt.Out.Write8(0)
  1172  		ctxt.Out.WriteString(f.Limpidbase)
  1173  		ctxt.Out.Write8(0)
  1174  		ctxt.Out.WriteString(f.Limpidmem)
  1175  		ctxt.Out.Write8(0)
  1176  	}
  1177  	for _, s := range strtab {
  1178  		ctxt.Out.Write16(s.size)
  1179  		ctxt.Out.WriteString(s.name)
  1180  		ctxt.Out.Write8(0) // null terminator
  1181  	}
  1182  
  1183  	f.loaderSize = off + uint64(stlen)
  1184  	ctxt.Out.Flush()
  1185  
  1186  	/* again for printing */
  1187  	if !*flagA {
  1188  		return
  1189  	}
  1190  
  1191  	ctxt.Logf("\n.loader section")
  1192  	// write in buf
  1193  	var buf bytes.Buffer
  1194  
  1195  	binary.Write(&buf, ctxt.Arch.ByteOrder, hdr)
  1196  	for _, s := range symtab {
  1197  		binary.Write(&buf, ctxt.Arch.ByteOrder, s)
  1198  
  1199  	}
  1200  	for _, f := range importtab {
  1201  		buf.WriteString(f.Limpidpath)
  1202  		buf.WriteByte(0)
  1203  		buf.WriteString(f.Limpidbase)
  1204  		buf.WriteByte(0)
  1205  		buf.WriteString(f.Limpidmem)
  1206  		buf.WriteByte(0)
  1207  	}
  1208  	for _, s := range strtab {
  1209  		binary.Write(&buf, ctxt.Arch.ByteOrder, s.size)
  1210  		buf.WriteString(s.name)
  1211  		buf.WriteByte(0) // null terminator
  1212  	}
  1213  
  1214  	// Log buffer
  1215  	ctxt.Logf("\n\t%.8x|", globalOff)
  1216  	for i, b := range buf.Bytes() {
  1217  		if i > 0 && i%16 == 0 {
  1218  			ctxt.Logf("\n\t%.8x|", uint64(globalOff)+uint64(i))
  1219  		}
  1220  		ctxt.Logf(" %.2x", b)
  1221  	}
  1222  	ctxt.Logf("\n")
  1223  
  1224  }
  1225  
  1226  // XCOFF assembling and writing file
  1227  
  1228  func (f *xcoffFile) writeFileHeader(ctxt *Link) {
  1229  	// File header
  1230  	f.xfhdr.Fmagic = U64_TOCMAGIC
  1231  	f.xfhdr.Fnscns = uint16(len(f.sections))
  1232  	f.xfhdr.Ftimedat = 0
  1233  
  1234  	if !*FlagS {
  1235  		f.xfhdr.Fsymptr = uint64(f.symtabOffset)
  1236  		f.xfhdr.Fnsyms = int32(f.symbolCount)
  1237  	}
  1238  
  1239  	if ctxt.BuildMode == BuildModeExe {
  1240  		f.xfhdr.Fopthdr = AOUTHSZ_EXEC64
  1241  		f.xfhdr.Fflags = F_EXEC
  1242  
  1243  		// auxiliary header
  1244  		f.xahdr.Ovstamp = 1 // based on dump -o
  1245  		f.xahdr.Omagic = 0x10b
  1246  		copy(f.xahdr.Omodtype[:], "1L")
  1247  		entry := ctxt.Syms.ROLookup(*flagEntrySymbol, 0)
  1248  		f.xahdr.Oentry = uint64(entry.Value)
  1249  		f.xahdr.Osnentry = f.getXCOFFscnum(entry.Sect)
  1250  		toc := ctxt.Syms.ROLookup("TOC", 0)
  1251  		f.xahdr.Otoc = uint64(toc.Value)
  1252  		f.xahdr.Osntoc = f.getXCOFFscnum(toc.Sect)
  1253  
  1254  		// Based on dump -o
  1255  		f.xahdr.Oalgntext = 0x5
  1256  		f.xahdr.Oalgndata = 0x5
  1257  
  1258  		binary.Write(ctxt.Out, binary.BigEndian, &f.xfhdr)
  1259  		binary.Write(ctxt.Out, binary.BigEndian, &f.xahdr)
  1260  	} else {
  1261  		f.xfhdr.Fopthdr = 0
  1262  		binary.Write(ctxt.Out, binary.BigEndian, &f.xfhdr)
  1263  	}
  1264  
  1265  }
  1266  
  1267  func xcoffwrite(ctxt *Link) {
  1268  	ctxt.Out.SeekSet(0)
  1269  
  1270  	xfile.writeFileHeader(ctxt)
  1271  
  1272  	for _, sect := range xfile.sections {
  1273  		sect.write(ctxt)
  1274  	}
  1275  }
  1276  
  1277  // Generate XCOFF assembly file
  1278  func Asmbxcoff(ctxt *Link, fileoff int64) {
  1279  	xfile.sectNameToScnum = make(map[string]int16)
  1280  
  1281  	// Add sections
  1282  	s := xfile.addSection(".text", Segtext.Vaddr, Segtext.Length, Segtext.Fileoff, STYP_TEXT)
  1283  	xfile.xahdr.Otextstart = s.Svaddr
  1284  	xfile.xahdr.Osntext = xfile.sectNameToScnum[".text"]
  1285  	xfile.xahdr.Otsize = s.Ssize
  1286  
  1287  	s = xfile.addSection(".data", Segdata.Vaddr, Segdata.Filelen, Segdata.Fileoff, STYP_DATA)
  1288  	xfile.xahdr.Odatastart = s.Svaddr
  1289  	xfile.xahdr.Osndata = xfile.sectNameToScnum[".data"]
  1290  	xfile.xahdr.Odsize = s.Ssize
  1291  
  1292  	s = xfile.addSection(".bss", Segdata.Vaddr+Segdata.Filelen, Segdata.Length-Segdata.Filelen, 0, STYP_BSS)
  1293  	xfile.xahdr.Osnbss = xfile.sectNameToScnum[".bss"]
  1294  	xfile.xahdr.Obsize = s.Ssize
  1295  
  1296  	// add dwarf sections
  1297  	for _, sect := range Segdwarf.Sections {
  1298  		xfile.addDwarfSection(sect)
  1299  	}
  1300  
  1301  	// add and write remaining sections
  1302  	if ctxt.LinkMode == LinkInternal {
  1303  		// Loader section
  1304  		if ctxt.BuildMode == BuildModeExe {
  1305  			Loaderblk(ctxt, uint64(fileoff))
  1306  			s = xfile.addSection(".loader", 0, xfile.loaderSize, uint64(fileoff), STYP_LOADER)
  1307  			xfile.xahdr.Osnloader = xfile.sectNameToScnum[".loader"]
  1308  		}
  1309  	} else {
  1310  		// TODO: Relocation
  1311  	}
  1312  
  1313  	// Write symbol table
  1314  	symo := Rnd(ctxt.Out.Offset(), int64(*FlagRound))
  1315  	xfile.symtabOffset = symo
  1316  	ctxt.Out.SeekSet(int64(symo))
  1317  	xfile.asmaixsym(ctxt)
  1318  
  1319  	// write headers
  1320  	xcoffwrite(ctxt)
  1321  }