...

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

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

View as plain text