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