|  | // Copyright 2018 The Go Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style | 
|  | // license that can be found in the LICENSE file. | 
|  |  | 
|  | package ld | 
|  |  | 
|  | import ( | 
|  | "bytes" | 
|  | "cmd/internal/objabi" | 
|  | "cmd/link/internal/sym" | 
|  | "encoding/binary" | 
|  | "io/ioutil" | 
|  | "math/bits" | 
|  | "path/filepath" | 
|  | "sort" | 
|  | "strings" | 
|  | ) | 
|  |  | 
|  | // This file handles all algorithms related to XCOFF files generation. | 
|  | // Most of them are adaptations of the ones in  cmd/link/internal/pe.go | 
|  | // as PE and XCOFF are based on COFF files. | 
|  | // XCOFF files generated are 64 bits. | 
|  |  | 
|  | const ( | 
|  | // Total amount of space to reserve at the start of the file | 
|  | // for File Header, Auxiliary Header, and Section Headers. | 
|  | // May waste some. | 
|  | XCOFFHDRRESERVE       = FILHSZ_64 + AOUTHSZ_EXEC64 + SCNHSZ_64*23 | 
|  | XCOFFSECTALIGN  int64 = 32 // base on dump -o | 
|  |  | 
|  | // XCOFF binaries should normally have all its sections position-independent. | 
|  | // However, this is not yet possible for .text because of some R_ADDR relocations | 
|  | // inside RODATA symbols. | 
|  | // .data and .bss are position-independent so their address start inside a unreachable | 
|  | // segment during execution to force segfault if something is wrong. | 
|  | XCOFFTEXTBASE = 0x100000000 // Start of text address | 
|  | XCOFFDATABASE = 0x200000000 // Start of data address | 
|  | ) | 
|  |  | 
|  | // File Header | 
|  | type XcoffFileHdr64 struct { | 
|  | Fmagic   uint16 // Target machine | 
|  | Fnscns   uint16 // Number of sections | 
|  | Ftimedat int32  // Time and date of file creation | 
|  | Fsymptr  uint64 // Byte offset to symbol table start | 
|  | Fopthdr  uint16 // Number of bytes in optional header | 
|  | Fflags   uint16 // Flags | 
|  | Fnsyms   int32  // Number of entries in symbol table | 
|  | } | 
|  |  | 
|  | const ( | 
|  | U64_TOCMAGIC = 0767 // AIX 64-bit XCOFF | 
|  | ) | 
|  |  | 
|  | // Flags that describe the type of the object file. | 
|  | const ( | 
|  | F_RELFLG    = 0x0001 | 
|  | F_EXEC      = 0x0002 | 
|  | F_LNNO      = 0x0004 | 
|  | F_FDPR_PROF = 0x0010 | 
|  | F_FDPR_OPTI = 0x0020 | 
|  | F_DSA       = 0x0040 | 
|  | F_VARPG     = 0x0100 | 
|  | F_DYNLOAD   = 0x1000 | 
|  | F_SHROBJ    = 0x2000 | 
|  | F_LOADONLY  = 0x4000 | 
|  | ) | 
|  |  | 
|  | // Auxiliary Header | 
|  | type XcoffAoutHdr64 struct { | 
|  | Omagic      int16    // Flags - Ignored If Vstamp Is 1 | 
|  | Ovstamp     int16    // Version | 
|  | Odebugger   uint32   // Reserved For Debugger | 
|  | Otextstart  uint64   // Virtual Address Of Text | 
|  | Odatastart  uint64   // Virtual Address Of Data | 
|  | Otoc        uint64   // Toc Address | 
|  | Osnentry    int16    // Section Number For Entry Point | 
|  | Osntext     int16    // Section Number For Text | 
|  | Osndata     int16    // Section Number For Data | 
|  | Osntoc      int16    // Section Number For Toc | 
|  | Osnloader   int16    // Section Number For Loader | 
|  | Osnbss      int16    // Section Number For Bss | 
|  | Oalgntext   int16    // Max Text Alignment | 
|  | Oalgndata   int16    // Max Data Alignment | 
|  | Omodtype    [2]byte  // Module Type Field | 
|  | Ocpuflag    uint8    // Bit Flags - Cputypes Of Objects | 
|  | Ocputype    uint8    // Reserved for CPU type | 
|  | Otextpsize  uint8    // Requested text page size | 
|  | Odatapsize  uint8    // Requested data page size | 
|  | Ostackpsize uint8    // Requested stack page size | 
|  | Oflags      uint8    // Flags And TLS Alignment | 
|  | Otsize      uint64   // Text Size In Bytes | 
|  | Odsize      uint64   // Data Size In Bytes | 
|  | Obsize      uint64   // Bss Size In Bytes | 
|  | Oentry      uint64   // Entry Point Address | 
|  | Omaxstack   uint64   // Max Stack Size Allowed | 
|  | Omaxdata    uint64   // Max Data Size Allowed | 
|  | Osntdata    int16    // Section Number For Tdata Section | 
|  | Osntbss     int16    // Section Number For Tbss Section | 
|  | Ox64flags   uint16   // Additional Flags For 64-Bit Objects | 
|  | Oresv3a     int16    // Reserved | 
|  | Oresv3      [2]int32 // Reserved | 
|  | } | 
|  |  | 
|  | // Section Header | 
|  | type XcoffScnHdr64 struct { | 
|  | Sname    [8]byte // Section Name | 
|  | Spaddr   uint64  // Physical Address | 
|  | Svaddr   uint64  // Virtual Address | 
|  | Ssize    uint64  // Section Size | 
|  | Sscnptr  uint64  // File Offset To Raw Data | 
|  | Srelptr  uint64  // File Offset To Relocation | 
|  | Slnnoptr uint64  // File Offset To Line Numbers | 
|  | Snreloc  uint32  // Number Of Relocation Entries | 
|  | Snlnno   uint32  // Number Of Line Number Entries | 
|  | Sflags   uint32  // flags | 
|  | } | 
|  |  | 
|  | // Flags defining the section type. | 
|  | const ( | 
|  | STYP_DWARF  = 0x0010 | 
|  | STYP_TEXT   = 0x0020 | 
|  | STYP_DATA   = 0x0040 | 
|  | STYP_BSS    = 0x0080 | 
|  | STYP_EXCEPT = 0x0100 | 
|  | STYP_INFO   = 0x0200 | 
|  | STYP_TDATA  = 0x0400 | 
|  | STYP_TBSS   = 0x0800 | 
|  | STYP_LOADER = 0x1000 | 
|  | STYP_DEBUG  = 0x2000 | 
|  | STYP_TYPCHK = 0x4000 | 
|  | STYP_OVRFLO = 0x8000 | 
|  | ) | 
|  | const ( | 
|  | SSUBTYP_DWINFO  = 0x10000 // DWARF info section | 
|  | SSUBTYP_DWLINE  = 0x20000 // DWARF line-number section | 
|  | SSUBTYP_DWPBNMS = 0x30000 // DWARF public names section | 
|  | SSUBTYP_DWPBTYP = 0x40000 // DWARF public types section | 
|  | SSUBTYP_DWARNGE = 0x50000 // DWARF aranges section | 
|  | SSUBTYP_DWABREV = 0x60000 // DWARF abbreviation section | 
|  | SSUBTYP_DWSTR   = 0x70000 // DWARF strings section | 
|  | SSUBTYP_DWRNGES = 0x80000 // DWARF ranges section | 
|  | SSUBTYP_DWLOC   = 0x90000 // DWARF location lists section | 
|  | SSUBTYP_DWFRAME = 0xA0000 // DWARF frames section | 
|  | SSUBTYP_DWMAC   = 0xB0000 // DWARF macros section | 
|  | ) | 
|  |  | 
|  | // Headers size | 
|  | const ( | 
|  | FILHSZ_32      = 20 | 
|  | FILHSZ_64      = 24 | 
|  | AOUTHSZ_EXEC32 = 72 | 
|  | AOUTHSZ_EXEC64 = 120 | 
|  | SCNHSZ_32      = 40 | 
|  | SCNHSZ_64      = 72 | 
|  | LDHDRSZ_32     = 32 | 
|  | LDHDRSZ_64     = 56 | 
|  | LDSYMSZ_64     = 24 | 
|  | RELSZ_64       = 14 | 
|  | ) | 
|  |  | 
|  | // Type representing all XCOFF symbols. | 
|  | type xcoffSym interface { | 
|  | } | 
|  |  | 
|  | // Symbol Table Entry | 
|  | type XcoffSymEnt64 struct { | 
|  | Nvalue  uint64 // Symbol value | 
|  | Noffset uint32 // Offset of the name in string table or .debug section | 
|  | Nscnum  int16  // Section number of symbol | 
|  | Ntype   uint16 // Basic and derived type specification | 
|  | Nsclass uint8  // Storage class of symbol | 
|  | Nnumaux int8   // Number of auxiliary entries | 
|  | } | 
|  |  | 
|  | const SYMESZ = 18 | 
|  |  | 
|  | const ( | 
|  | // Nscnum | 
|  | N_DEBUG = -2 | 
|  | N_ABS   = -1 | 
|  | N_UNDEF = 0 | 
|  |  | 
|  | //Ntype | 
|  | SYM_V_INTERNAL  = 0x1000 | 
|  | SYM_V_HIDDEN    = 0x2000 | 
|  | SYM_V_PROTECTED = 0x3000 | 
|  | SYM_V_EXPORTED  = 0x4000 | 
|  | SYM_TYPE_FUNC   = 0x0020 // is function | 
|  | ) | 
|  |  | 
|  | // Storage Class. | 
|  | const ( | 
|  | C_NULL    = 0   // Symbol table entry marked for deletion | 
|  | C_EXT     = 2   // External symbol | 
|  | C_STAT    = 3   // Static symbol | 
|  | C_BLOCK   = 100 // Beginning or end of inner block | 
|  | C_FCN     = 101 // Beginning or end of function | 
|  | C_FILE    = 103 // Source file name and compiler information | 
|  | C_HIDEXT  = 107 // Unnamed external symbol | 
|  | C_BINCL   = 108 // Beginning of include file | 
|  | C_EINCL   = 109 // End of include file | 
|  | C_WEAKEXT = 111 // Weak external symbol | 
|  | C_DWARF   = 112 // DWARF symbol | 
|  | C_GSYM    = 128 // Global variable | 
|  | C_LSYM    = 129 // Automatic variable allocated on stack | 
|  | C_PSYM    = 130 // Argument to subroutine allocated on stack | 
|  | C_RSYM    = 131 // Register variable | 
|  | C_RPSYM   = 132 // Argument to function or procedure stored in register | 
|  | C_STSYM   = 133 // Statically allocated symbol | 
|  | C_BCOMM   = 135 // Beginning of common block | 
|  | C_ECOML   = 136 // Local member of common block | 
|  | C_ECOMM   = 137 // End of common block | 
|  | C_DECL    = 140 // Declaration of object | 
|  | C_ENTRY   = 141 // Alternate entry | 
|  | C_FUN     = 142 // Function or procedure | 
|  | C_BSTAT   = 143 // Beginning of static block | 
|  | C_ESTAT   = 144 // End of static block | 
|  | C_GTLS    = 145 // Global thread-local variable | 
|  | C_STTLS   = 146 // Static thread-local variable | 
|  | ) | 
|  |  | 
|  | // File Auxiliary Entry | 
|  | type XcoffAuxFile64 struct { | 
|  | Xzeroes  uint32 // The name is always in the string table | 
|  | Xoffset  uint32 // Offset in the string table | 
|  | X_pad1   [6]byte | 
|  | Xftype   uint8 // Source file string type | 
|  | X_pad2   [2]byte | 
|  | Xauxtype uint8 // Type of auxiliary entry | 
|  | } | 
|  |  | 
|  | // Function Auxiliary Entry | 
|  | type XcoffAuxFcn64 struct { | 
|  | Xlnnoptr uint64 // File pointer to line number | 
|  | Xfsize   uint32 // Size of function in bytes | 
|  | Xendndx  uint32 // Symbol table index of next entry | 
|  | Xpad     uint8  // Unused | 
|  | Xauxtype uint8  // Type of auxiliary entry | 
|  | } | 
|  |  | 
|  | // csect Auxiliary Entry. | 
|  | type XcoffAuxCSect64 struct { | 
|  | Xscnlenlo uint32 // Lower 4 bytes of length or symbol table index | 
|  | Xparmhash uint32 // Offset of parameter type-check string | 
|  | Xsnhash   uint16 // .typchk section number | 
|  | Xsmtyp    uint8  // Symbol alignment and type | 
|  | Xsmclas   uint8  // Storage-mapping class | 
|  | Xscnlenhi uint32 // Upper 4 bytes of length or symbol table index | 
|  | Xpad      uint8  // Unused | 
|  | Xauxtype  uint8  // Type of auxiliary entry | 
|  | } | 
|  |  | 
|  | // DWARF Auxiliary Entry | 
|  | type XcoffAuxDWARF64 struct { | 
|  | Xscnlen  uint64 // Length of this symbol section | 
|  | X_pad    [9]byte | 
|  | Xauxtype uint8 // Type of auxiliary entry | 
|  | } | 
|  |  | 
|  | // Auxiliary type | 
|  | const ( | 
|  | _AUX_EXCEPT = 255 | 
|  | _AUX_FCN    = 254 | 
|  | _AUX_SYM    = 253 | 
|  | _AUX_FILE   = 252 | 
|  | _AUX_CSECT  = 251 | 
|  | _AUX_SECT   = 250 | 
|  | ) | 
|  |  | 
|  | // Xftype field | 
|  | const ( | 
|  | XFT_FN = 0   // Source File Name | 
|  | XFT_CT = 1   // Compile Time Stamp | 
|  | XFT_CV = 2   // Compiler Version Number | 
|  | XFT_CD = 128 // Compiler Defined Information/ | 
|  |  | 
|  | ) | 
|  |  | 
|  | // Symbol type field. | 
|  | const ( | 
|  | XTY_ER  = 0    // External reference | 
|  | XTY_SD  = 1    // Section definition | 
|  | XTY_LD  = 2    // Label definition | 
|  | XTY_CM  = 3    // Common csect definition | 
|  | XTY_WK  = 0x8  // Weak symbol | 
|  | XTY_EXP = 0x10 // Exported symbol | 
|  | XTY_ENT = 0x20 // Entry point symbol | 
|  | XTY_IMP = 0x40 // Imported symbol | 
|  | ) | 
|  |  | 
|  | // Storage-mapping class. | 
|  | const ( | 
|  | XMC_PR     = 0  // Program code | 
|  | XMC_RO     = 1  // Read-only constant | 
|  | XMC_DB     = 2  // Debug dictionary table | 
|  | XMC_TC     = 3  // TOC entry | 
|  | XMC_UA     = 4  // Unclassified | 
|  | XMC_RW     = 5  // Read/Write data | 
|  | XMC_GL     = 6  // Global linkage | 
|  | XMC_XO     = 7  // Extended operation | 
|  | XMC_SV     = 8  // 32-bit supervisor call descriptor | 
|  | XMC_BS     = 9  // BSS class | 
|  | XMC_DS     = 10 // Function descriptor | 
|  | XMC_UC     = 11 // Unnamed FORTRAN common | 
|  | XMC_TC0    = 15 // TOC anchor | 
|  | XMC_TD     = 16 // Scalar data entry in the TOC | 
|  | XMC_SV64   = 17 // 64-bit supervisor call descriptor | 
|  | XMC_SV3264 = 18 // Supervisor call descriptor for both 32-bit and 64-bit | 
|  | XMC_TL     = 20 // Read/Write thread-local data | 
|  | XMC_UL     = 21 // Read/Write thread-local data (.tbss) | 
|  | XMC_TE     = 22 // TOC entry | 
|  | ) | 
|  |  | 
|  | // Loader Header | 
|  | type XcoffLdHdr64 struct { | 
|  | Lversion int32  // Loader section version number | 
|  | Lnsyms   int32  // Number of symbol table entries | 
|  | Lnreloc  int32  // Number of relocation table entries | 
|  | Listlen  uint32 // Length of import file ID string table | 
|  | Lnimpid  int32  // Number of import file IDs | 
|  | Lstlen   uint32 // Length of string table | 
|  | Limpoff  uint64 // Offset to start of import file IDs | 
|  | Lstoff   uint64 // Offset to start of string table | 
|  | Lsymoff  uint64 // Offset to start of symbol table | 
|  | Lrldoff  uint64 // Offset to start of relocation entries | 
|  | } | 
|  |  | 
|  | // Loader Symbol | 
|  | type XcoffLdSym64 struct { | 
|  | Lvalue  uint64 // Address field | 
|  | Loffset uint32 // Byte offset into string table of symbol name | 
|  | Lscnum  int16  // Section number containing symbol | 
|  | Lsmtype int8   // Symbol type, export, import flags | 
|  | Lsmclas int8   // Symbol storage class | 
|  | Lifile  int32  // Import file ID; ordinal of import file IDs | 
|  | Lparm   uint32 // Parameter type-check field | 
|  | } | 
|  |  | 
|  | type xcoffLoaderSymbol struct { | 
|  | sym    *sym.Symbol | 
|  | smtype int8 | 
|  | smclas int8 | 
|  | } | 
|  |  | 
|  | type XcoffLdImportFile64 struct { | 
|  | Limpidpath string | 
|  | Limpidbase string | 
|  | Limpidmem  string | 
|  | } | 
|  |  | 
|  | type XcoffLdRel64 struct { | 
|  | Lvaddr  uint64 // Address Field | 
|  | Lrtype  uint16 // Relocation Size and Type | 
|  | Lrsecnm int16  // Section Number being relocated | 
|  | Lsymndx int32  // Loader-Section symbol table index | 
|  | } | 
|  |  | 
|  | // xcoffLoaderReloc holds information about a relocation made by the loader. | 
|  | type xcoffLoaderReloc struct { | 
|  | sym    *sym.Symbol | 
|  | rel    *sym.Reloc | 
|  | rtype  uint16 | 
|  | symndx int32 | 
|  | } | 
|  |  | 
|  | const ( | 
|  | XCOFF_R_POS = 0x00 // A(sym) Positive Relocation | 
|  | XCOFF_R_NEG = 0x01 // -A(sym) Negative Relocation | 
|  | XCOFF_R_REL = 0x02 // A(sym-*) Relative to self | 
|  | XCOFF_R_TOC = 0x03 // A(sym-TOC) Relative to TOC | 
|  | XCOFF_R_TRL = 0x12 // A(sym-TOC) TOC Relative indirect load. | 
|  |  | 
|  | XCOFF_R_TRLA = 0x13 // A(sym-TOC) TOC Rel load address. modifiable inst | 
|  | XCOFF_R_GL   = 0x05 // A(external TOC of sym) Global Linkage | 
|  | XCOFF_R_TCL  = 0x06 // A(local TOC of sym) Local object TOC address | 
|  | XCOFF_R_RL   = 0x0C // A(sym) Pos indirect load. modifiable instruction | 
|  | XCOFF_R_RLA  = 0x0D // A(sym) Pos Load Address. modifiable instruction | 
|  | XCOFF_R_REF  = 0x0F // AL0(sym) Non relocating ref. No garbage collect | 
|  | XCOFF_R_BA   = 0x08 // A(sym) Branch absolute. Cannot modify instruction | 
|  | XCOFF_R_RBA  = 0x18 // A(sym) Branch absolute. modifiable instruction | 
|  | XCOFF_R_BR   = 0x0A // A(sym-*) Branch rel to self. non modifiable | 
|  | XCOFF_R_RBR  = 0x1A // A(sym-*) Branch rel to self. modifiable instr | 
|  |  | 
|  | XCOFF_R_TLS    = 0x20 // General-dynamic reference to TLS symbol | 
|  | XCOFF_R_TLS_IE = 0x21 // Initial-exec reference to TLS symbol | 
|  | XCOFF_R_TLS_LD = 0x22 // Local-dynamic reference to TLS symbol | 
|  | XCOFF_R_TLS_LE = 0x23 // Local-exec reference to TLS symbol | 
|  | XCOFF_R_TLSM   = 0x24 // Module reference to TLS symbol | 
|  | XCOFF_R_TLSML  = 0x25 // Module reference to local (own) module | 
|  |  | 
|  | XCOFF_R_TOCU = 0x30 // Relative to TOC - high order bits | 
|  | XCOFF_R_TOCL = 0x31 // Relative to TOC - low order bits | 
|  | ) | 
|  |  | 
|  | type XcoffLdStr64 struct { | 
|  | size uint16 | 
|  | name string | 
|  | } | 
|  |  | 
|  | // xcoffFile is used to build XCOFF file. | 
|  | type xcoffFile struct { | 
|  | xfhdr           XcoffFileHdr64 | 
|  | xahdr           XcoffAoutHdr64 | 
|  | sections        []*XcoffScnHdr64 | 
|  | sectText        *XcoffScnHdr64 | 
|  | sectData        *XcoffScnHdr64 | 
|  | sectBss         *XcoffScnHdr64 | 
|  | stringTable     xcoffStringTable | 
|  | sectNameToScnum map[string]int16 | 
|  | loaderSize      uint64 | 
|  | symtabOffset    int64                // offset to the start of symbol table | 
|  | symbolCount     uint32               // number of symbol table records written | 
|  | symtabSym       []xcoffSym           // XCOFF symbols for the symbol table | 
|  | dynLibraries    map[string]int       // Dynamic libraries in .loader section. The integer represents its import file number (- 1) | 
|  | loaderSymbols   []*xcoffLoaderSymbol // symbols inside .loader symbol table | 
|  | loaderReloc     []*xcoffLoaderReloc  // Reloc that must be made inside loader | 
|  | } | 
|  |  | 
|  | // Var used by XCOFF Generation algorithms | 
|  | var ( | 
|  | xfile xcoffFile | 
|  | ) | 
|  |  | 
|  | // xcoffStringTable is a XCOFF string table. | 
|  | type xcoffStringTable struct { | 
|  | strings    []string | 
|  | stringsLen int | 
|  | } | 
|  |  | 
|  | // size returns size of string table t. | 
|  | func (t *xcoffStringTable) size() int { | 
|  | // string table starts with 4-byte length at the beginning | 
|  | return t.stringsLen + 4 | 
|  | } | 
|  |  | 
|  | // add adds string str to string table t. | 
|  | func (t *xcoffStringTable) add(str string) int { | 
|  | off := t.size() | 
|  | t.strings = append(t.strings, str) | 
|  | t.stringsLen += len(str) + 1 // each string will have 0 appended to it | 
|  | return off | 
|  | } | 
|  |  | 
|  | // write writes string table t into the output file. | 
|  | func (t *xcoffStringTable) write(out *OutBuf) { | 
|  | out.Write32(uint32(t.size())) | 
|  | for _, s := range t.strings { | 
|  | out.WriteString(s) | 
|  | out.Write8(0) | 
|  | } | 
|  | } | 
|  |  | 
|  | // write writes XCOFF section sect into the output file. | 
|  | func (sect *XcoffScnHdr64) write(ctxt *Link) { | 
|  | binary.Write(ctxt.Out, binary.BigEndian, sect) | 
|  | ctxt.Out.Write32(0) // Add 4 empty bytes at the end to match alignment | 
|  | } | 
|  |  | 
|  | // addSection adds section to the XCOFF file f. | 
|  | func (f *xcoffFile) addSection(name string, addr uint64, size uint64, fileoff uint64, flags uint32) *XcoffScnHdr64 { | 
|  | sect := &XcoffScnHdr64{ | 
|  | Spaddr:  addr, | 
|  | Svaddr:  addr, | 
|  | Ssize:   size, | 
|  | Sscnptr: fileoff, | 
|  | Sflags:  flags, | 
|  | } | 
|  | copy(sect.Sname[:], name) // copy string to [8]byte | 
|  | f.sections = append(f.sections, sect) | 
|  | f.sectNameToScnum[name] = int16(len(f.sections)) | 
|  | return sect | 
|  | } | 
|  |  | 
|  | // addDwarfSection adds a dwarf section to the XCOFF file f. | 
|  | // This function is similar to addSection, but Dwarf section names | 
|  | // must be modified to conventional names and they are various subtypes. | 
|  | func (f *xcoffFile) addDwarfSection(s *sym.Section) *XcoffScnHdr64 { | 
|  | newName, subtype := xcoffGetDwarfSubtype(s.Name) | 
|  | return f.addSection(newName, 0, s.Length, s.Seg.Fileoff+s.Vaddr-s.Seg.Vaddr, STYP_DWARF|subtype) | 
|  | } | 
|  |  | 
|  | // xcoffGetDwarfSubtype returns the XCOFF name of the DWARF section str | 
|  | // and its subtype constant. | 
|  | func xcoffGetDwarfSubtype(str string) (string, uint32) { | 
|  | switch str { | 
|  | default: | 
|  | Exitf("unknown DWARF section name for XCOFF: %s", str) | 
|  | case ".debug_abbrev": | 
|  | return ".dwabrev", SSUBTYP_DWABREV | 
|  | case ".debug_info": | 
|  | return ".dwinfo", SSUBTYP_DWINFO | 
|  | case ".debug_frame": | 
|  | return ".dwframe", SSUBTYP_DWFRAME | 
|  | case ".debug_line": | 
|  | return ".dwline", SSUBTYP_DWLINE | 
|  | case ".debug_loc": | 
|  | return ".dwloc", SSUBTYP_DWLOC | 
|  | case ".debug_pubnames": | 
|  | return ".dwpbnms", SSUBTYP_DWPBNMS | 
|  | case ".debug_pubtypes": | 
|  | return ".dwpbtyp", SSUBTYP_DWPBTYP | 
|  | case ".debug_ranges": | 
|  | return ".dwrnges", SSUBTYP_DWRNGES | 
|  | } | 
|  | // never used | 
|  | return "", 0 | 
|  | } | 
|  |  | 
|  | // getXCOFFscnum returns the XCOFF section number of a Go section. | 
|  | func (f *xcoffFile) getXCOFFscnum(sect *sym.Section) int16 { | 
|  | switch sect.Seg { | 
|  | case &Segtext: | 
|  | return f.sectNameToScnum[".text"] | 
|  | case &Segdata: | 
|  | if sect.Name == ".noptrbss" || sect.Name == ".bss" { | 
|  | return f.sectNameToScnum[".bss"] | 
|  | } | 
|  | if sect.Name == ".tbss" { | 
|  | return f.sectNameToScnum[".tbss"] | 
|  | } | 
|  | return f.sectNameToScnum[".data"] | 
|  | case &Segdwarf: | 
|  | name, _ := xcoffGetDwarfSubtype(sect.Name) | 
|  | return f.sectNameToScnum[name] | 
|  | case &Segrelrodata: | 
|  | return f.sectNameToScnum[".data"] | 
|  | } | 
|  | Errorf(nil, "getXCOFFscnum not implemented for section %s", sect.Name) | 
|  | return -1 | 
|  | } | 
|  |  | 
|  | // Xcoffinit initialised some internal value and setups | 
|  | // already known header information | 
|  | func Xcoffinit(ctxt *Link) { | 
|  | xfile.dynLibraries = make(map[string]int) | 
|  |  | 
|  | HEADR = int32(Rnd(XCOFFHDRRESERVE, XCOFFSECTALIGN)) | 
|  | if *FlagTextAddr != -1 { | 
|  | Errorf(nil, "-T not available on AIX") | 
|  | } | 
|  | *FlagTextAddr = XCOFFTEXTBASE + int64(HEADR) | 
|  | if *FlagRound != -1 { | 
|  | Errorf(nil, "-R not available on AIX") | 
|  | } | 
|  | *FlagRound = int(XCOFFSECTALIGN) | 
|  |  | 
|  | } | 
|  |  | 
|  | // SYMBOL TABLE | 
|  |  | 
|  | // type records C_FILE information needed for genasmsym in XCOFF. | 
|  | type xcoffSymSrcFile struct { | 
|  | name       string | 
|  | file       *XcoffSymEnt64   // Symbol of this C_FILE | 
|  | csectAux   *XcoffAuxCSect64 // Symbol for the current .csect | 
|  | csectSymNb uint64           // Symbol number for the current .csect | 
|  | csectSize  int64 | 
|  | } | 
|  |  | 
|  | var ( | 
|  | currDwscnoff   = make(map[string]uint64) // Needed to create C_DWARF symbols | 
|  | currSymSrcFile xcoffSymSrcFile | 
|  | outerSymSize   = make(map[string]int64) | 
|  | ) | 
|  |  | 
|  | // xcoffUpdateOuterSize stores the size of outer symbols in order to have it | 
|  | // in the symbol table. | 
|  | func xcoffUpdateOuterSize(ctxt *Link, size int64, stype sym.SymKind) { | 
|  | if size == 0 { | 
|  | return | 
|  | } | 
|  |  | 
|  | switch stype { | 
|  | default: | 
|  | Errorf(nil, "unknown XCOFF outer symbol for type %s", stype.String()) | 
|  | case sym.SRODATA, sym.SRODATARELRO, sym.SFUNCTAB, sym.SSTRING: | 
|  | // Nothing to do | 
|  | case sym.STYPERELRO: | 
|  | if ctxt.UseRelro() && (ctxt.BuildMode == BuildModeCArchive || ctxt.BuildMode == BuildModeCShared || ctxt.BuildMode == BuildModePIE) { | 
|  | // runtime.types size must be removed, as it's a real symbol. | 
|  | outerSymSize["typerel.*"] = size - ctxt.Syms.ROLookup("runtime.types", 0).Size | 
|  | return | 
|  | } | 
|  | fallthrough | 
|  | case sym.STYPE: | 
|  | if !ctxt.DynlinkingGo() { | 
|  | // runtime.types size must be removed, as it's a real symbol. | 
|  | outerSymSize["type.*"] = size - ctxt.Syms.ROLookup("runtime.types", 0).Size | 
|  | } | 
|  | case sym.SGOSTRING: | 
|  | outerSymSize["go.string.*"] = size | 
|  | case sym.SGOFUNC: | 
|  | if !ctxt.DynlinkingGo() { | 
|  | outerSymSize["go.func.*"] = size | 
|  | } | 
|  | case sym.SGOFUNCRELRO: | 
|  | outerSymSize["go.funcrel.*"] = size | 
|  | case sym.SGCBITS: | 
|  | outerSymSize["runtime.gcbits.*"] = size | 
|  | case sym.SITABLINK: | 
|  | outerSymSize["runtime.itablink"] = size | 
|  |  | 
|  | } | 
|  |  | 
|  | } | 
|  |  | 
|  | // addSymbol writes a symbol or an auxiliary symbol entry on ctxt.out. | 
|  | func (f *xcoffFile) addSymbol(sym xcoffSym) { | 
|  | f.symtabSym = append(f.symtabSym, sym) | 
|  | f.symbolCount++ | 
|  | } | 
|  |  | 
|  | // xcoffAlign returns the log base 2 of the symbol's alignment. | 
|  | func xcoffAlign(x *sym.Symbol, t SymbolType) uint8 { | 
|  | align := x.Align | 
|  | if align == 0 { | 
|  | if t == TextSym { | 
|  | align = int32(Funcalign) | 
|  | } else { | 
|  | align = symalign(x) | 
|  | } | 
|  | } | 
|  | return logBase2(int(align)) | 
|  | } | 
|  |  | 
|  | // logBase2 returns the log in base 2 of a. | 
|  | func logBase2(a int) uint8 { | 
|  | return uint8(bits.Len(uint(a)) - 1) | 
|  | } | 
|  |  | 
|  | // Write symbols needed when a new file appeared: | 
|  | // - a C_FILE with one auxiliary entry for its name | 
|  | // - C_DWARF symbols to provide debug information | 
|  | // - a C_HIDEXT which will be a csect containing all of its functions | 
|  | // It needs several parameters to create .csect symbols such as its entry point and its section number. | 
|  | // | 
|  | // Currently, a new file is in fact a new package. It seems to be OK, but it might change | 
|  | // in the future. | 
|  | func (f *xcoffFile) writeSymbolNewFile(ctxt *Link, name string, firstEntry uint64, extnum int16) { | 
|  | /* C_FILE */ | 
|  | s := &XcoffSymEnt64{ | 
|  | Noffset: uint32(f.stringTable.add(".file")), | 
|  | Nsclass: C_FILE, | 
|  | Nscnum:  N_DEBUG, | 
|  | Ntype:   0, // Go isn't inside predefined language. | 
|  | Nnumaux: 1, | 
|  | } | 
|  | f.addSymbol(s) | 
|  | currSymSrcFile.file = s | 
|  |  | 
|  | // Auxiliary entry for file name. | 
|  | auxf := &XcoffAuxFile64{ | 
|  | Xoffset:  uint32(f.stringTable.add(name)), | 
|  | Xftype:   XFT_FN, | 
|  | Xauxtype: _AUX_FILE, | 
|  | } | 
|  | f.addSymbol(auxf) | 
|  |  | 
|  | /* Dwarf */ | 
|  | for _, sect := range Segdwarf.Sections { | 
|  | var dwsize uint64 | 
|  | if ctxt.LinkMode == LinkInternal { | 
|  | // Find the size of this corresponding package DWARF compilation unit. | 
|  | // This size is set during DWARF generation (see dwarf.go). | 
|  | dwsize = getDwsectCUSize(sect.Name, name) | 
|  | // .debug_abbrev is common to all packages and not found with the previous function | 
|  | if sect.Name == ".debug_abbrev" { | 
|  | s := ctxt.Syms.ROLookup(sect.Name, 0) | 
|  | dwsize = uint64(s.Size) | 
|  |  | 
|  | } | 
|  | } else { | 
|  | // There is only one .FILE with external linking. | 
|  | dwsize = sect.Length | 
|  | } | 
|  |  | 
|  | // get XCOFF name | 
|  | name, _ := xcoffGetDwarfSubtype(sect.Name) | 
|  | s := &XcoffSymEnt64{ | 
|  | Nvalue:  currDwscnoff[sect.Name], | 
|  | Noffset: uint32(f.stringTable.add(name)), | 
|  | Nsclass: C_DWARF, | 
|  | Nscnum:  f.getXCOFFscnum(sect), | 
|  | Nnumaux: 1, | 
|  | } | 
|  |  | 
|  | if currSymSrcFile.csectAux == nil { | 
|  | // Dwarf relocations need the symbol number of .dw* symbols. | 
|  | // It doesn't need to know it for each package, one is enough. | 
|  | // currSymSrcFile.csectAux == nil means first package. | 
|  | dws := ctxt.Syms.Lookup(sect.Name, 0) | 
|  | dws.Dynid = int32(f.symbolCount) | 
|  |  | 
|  | if sect.Name == ".debug_frame" && ctxt.LinkMode != LinkExternal { | 
|  | // CIE size must be added to the first package. | 
|  | dwsize += 48 | 
|  | } | 
|  | } | 
|  |  | 
|  | f.addSymbol(s) | 
|  |  | 
|  | // update the DWARF section offset in this file | 
|  | if sect.Name != ".debug_abbrev" { | 
|  | currDwscnoff[sect.Name] += dwsize | 
|  | } | 
|  |  | 
|  | // Auxiliary dwarf section | 
|  | auxd := &XcoffAuxDWARF64{ | 
|  | Xscnlen:  dwsize, | 
|  | Xauxtype: _AUX_SECT, | 
|  | } | 
|  |  | 
|  | f.addSymbol(auxd) | 
|  | } | 
|  |  | 
|  | /* .csect */ | 
|  | // Check if extnum is in text. | 
|  | // This is temporary and only here to check if this algorithm is correct. | 
|  | if extnum != 1 { | 
|  | Exitf("XCOFF symtab: A new file was detected with its first symbol not in .text") | 
|  | } | 
|  |  | 
|  | currSymSrcFile.csectSymNb = uint64(f.symbolCount) | 
|  |  | 
|  | // No offset because no name | 
|  | s = &XcoffSymEnt64{ | 
|  | Nvalue:  firstEntry, | 
|  | Nscnum:  extnum, | 
|  | Nsclass: C_HIDEXT, | 
|  | Ntype:   0, // check visibility ? | 
|  | Nnumaux: 1, | 
|  | } | 
|  | f.addSymbol(s) | 
|  |  | 
|  | aux := &XcoffAuxCSect64{ | 
|  | Xsmclas:  XMC_PR, | 
|  | Xsmtyp:   XTY_SD | logBase2(Funcalign)<<3, | 
|  | Xauxtype: _AUX_CSECT, | 
|  | } | 
|  | f.addSymbol(aux) | 
|  |  | 
|  | currSymSrcFile.csectAux = aux | 
|  | currSymSrcFile.csectSize = 0 | 
|  | } | 
|  |  | 
|  | // Update values for the previous package. | 
|  | //  - Svalue of the C_FILE symbol: if it is the last one, this Svalue must be -1 | 
|  | //  - Xsclen of the csect symbol. | 
|  | func (f *xcoffFile) updatePreviousFile(ctxt *Link, last bool) { | 
|  | // first file | 
|  | if currSymSrcFile.file == nil { | 
|  | return | 
|  | } | 
|  |  | 
|  | // Update C_FILE | 
|  | cfile := currSymSrcFile.file | 
|  | if last { | 
|  | cfile.Nvalue = 0xFFFFFFFFFFFFFFFF | 
|  | } else { | 
|  | cfile.Nvalue = uint64(f.symbolCount) | 
|  | } | 
|  |  | 
|  | // update csect scnlen in this auxiliary entry | 
|  | aux := currSymSrcFile.csectAux | 
|  | aux.Xscnlenlo = uint32(currSymSrcFile.csectSize & 0xFFFFFFFF) | 
|  | aux.Xscnlenhi = uint32(currSymSrcFile.csectSize >> 32) | 
|  | } | 
|  |  | 
|  | // Write symbol representing a .text function. | 
|  | // The symbol table is split with C_FILE corresponding to each package | 
|  | // and not to each source file as it should be. | 
|  | func (f *xcoffFile) writeSymbolFunc(ctxt *Link, x *sym.Symbol) []xcoffSym { | 
|  | // New XCOFF symbols which will be written. | 
|  | syms := []xcoffSym{} | 
|  |  | 
|  | // Check if a new file is detected. | 
|  | if strings.Contains(x.Name, "-tramp") || strings.HasPrefix(x.Name, "runtime.text.") { | 
|  | // Trampoline don't have a FILE so there are considered | 
|  | // in the current file. | 
|  | // Same goes for runtime.text.X symbols. | 
|  | } else if x.File == "" { // Undefined global symbol | 
|  | // If this happens, the algorithm must be redone. | 
|  | if currSymSrcFile.name != "" { | 
|  | Exitf("undefined global symbol found inside another file") | 
|  | } | 
|  | } else { | 
|  | // Current file has changed. New C_FILE, C_DWARF, etc must be generated. | 
|  | if currSymSrcFile.name != x.File { | 
|  | if ctxt.LinkMode == LinkInternal { | 
|  | // update previous file values | 
|  | xfile.updatePreviousFile(ctxt, false) | 
|  | currSymSrcFile.name = x.File | 
|  | f.writeSymbolNewFile(ctxt, x.File, uint64(x.Value), xfile.getXCOFFscnum(x.Sect)) | 
|  | } else { | 
|  | // With external linking, ld will crash if there is several | 
|  | // .FILE and DWARF debugging enable, somewhere during | 
|  | // the relocation phase. | 
|  | // Therefore, all packages are merged under a fake .FILE | 
|  | // "go_functions". | 
|  | // TODO(aix); remove once ld has been fixed or the triggering | 
|  | // relocation has been found and fixed. | 
|  | if currSymSrcFile.name == "" { | 
|  | currSymSrcFile.name = x.File | 
|  | f.writeSymbolNewFile(ctxt, "go_functions", uint64(x.Value), xfile.getXCOFFscnum(x.Sect)) | 
|  | } | 
|  | } | 
|  |  | 
|  | } | 
|  | } | 
|  |  | 
|  | s := &XcoffSymEnt64{ | 
|  | Nsclass: C_EXT, | 
|  | Noffset: uint32(xfile.stringTable.add(x.Extname())), | 
|  | Nvalue:  uint64(x.Value), | 
|  | Nscnum:  f.getXCOFFscnum(x.Sect), | 
|  | Ntype:   SYM_TYPE_FUNC, | 
|  | Nnumaux: 2, | 
|  | } | 
|  |  | 
|  | if x.Version != 0 || x.Attr.VisibilityHidden() || x.Attr.Local() { | 
|  | s.Nsclass = C_HIDEXT | 
|  | } | 
|  |  | 
|  | x.Dynid = int32(xfile.symbolCount) | 
|  | syms = append(syms, s) | 
|  |  | 
|  | // Update current csect size | 
|  | currSymSrcFile.csectSize += x.Size | 
|  |  | 
|  | // create auxiliary entries | 
|  | a2 := &XcoffAuxFcn64{ | 
|  | Xfsize:   uint32(x.Size), | 
|  | Xlnnoptr: 0,                     // TODO | 
|  | Xendndx:  xfile.symbolCount + 3, // this symbol + 2 aux entries | 
|  | Xauxtype: _AUX_FCN, | 
|  | } | 
|  | syms = append(syms, a2) | 
|  |  | 
|  | a4 := &XcoffAuxCSect64{ | 
|  | Xscnlenlo: uint32(currSymSrcFile.csectSymNb & 0xFFFFFFFF), | 
|  | Xscnlenhi: uint32(currSymSrcFile.csectSymNb >> 32), | 
|  | Xsmclas:   XMC_PR, // Program Code | 
|  | Xsmtyp:    XTY_LD, // label definition (based on C) | 
|  | Xauxtype:  _AUX_CSECT, | 
|  | } | 
|  | a4.Xsmtyp |= uint8(xcoffAlign(x, TextSym) << 3) | 
|  |  | 
|  | syms = append(syms, a4) | 
|  | return syms | 
|  | } | 
|  |  | 
|  | // put function used by genasmsym to write symbol table | 
|  | func putaixsym(ctxt *Link, x *sym.Symbol, str string, t SymbolType, addr int64, go_ *sym.Symbol) { | 
|  |  | 
|  | // All XCOFF symbols generated by this GO symbols | 
|  | // Can be a symbol entry or a auxiliary entry | 
|  | syms := []xcoffSym{} | 
|  |  | 
|  | switch t { | 
|  | default: | 
|  | return | 
|  |  | 
|  | case TextSym: | 
|  | if x.FuncInfo != nil || strings.Contains(x.Name, "-tramp") || strings.HasPrefix(x.Name, "runtime.text.") { | 
|  | // Function within a file | 
|  | syms = xfile.writeSymbolFunc(ctxt, x) | 
|  | } else { | 
|  | // Only runtime.text and runtime.etext come through this way | 
|  | if x.Name != "runtime.text" && x.Name != "runtime.etext" && x.Name != "go.buildid" { | 
|  | Exitf("putaixsym: unknown text symbol %s", x.Name) | 
|  | } | 
|  | s := &XcoffSymEnt64{ | 
|  | Nsclass: C_HIDEXT, | 
|  | Noffset: uint32(xfile.stringTable.add(str)), | 
|  | Nvalue:  uint64(x.Value), | 
|  | Nscnum:  xfile.getXCOFFscnum(x.Sect), | 
|  | Ntype:   SYM_TYPE_FUNC, | 
|  | Nnumaux: 1, | 
|  | } | 
|  | x.Dynid = int32(xfile.symbolCount) | 
|  | syms = append(syms, s) | 
|  |  | 
|  | size := uint64(x.Size) | 
|  | a4 := &XcoffAuxCSect64{ | 
|  | Xauxtype:  _AUX_CSECT, | 
|  | Xscnlenlo: uint32(size & 0xFFFFFFFF), | 
|  | Xscnlenhi: uint32(size >> 32), | 
|  | Xsmclas:   XMC_PR, | 
|  | Xsmtyp:    XTY_SD, | 
|  | } | 
|  | a4.Xsmtyp |= uint8(xcoffAlign(x, TextSym) << 3) | 
|  | syms = append(syms, a4) | 
|  |  | 
|  | } | 
|  |  | 
|  | case DataSym, BSSSym: | 
|  | s := &XcoffSymEnt64{ | 
|  | Nsclass: C_EXT, | 
|  | Noffset: uint32(xfile.stringTable.add(str)), | 
|  | Nvalue:  uint64(x.Value), | 
|  | Nscnum:  xfile.getXCOFFscnum(x.Sect), | 
|  | Nnumaux: 1, | 
|  | } | 
|  |  | 
|  | if x.Version != 0 || x.Attr.VisibilityHidden() || x.Attr.Local() { | 
|  | // There is more symbols in the case of a global data | 
|  | // which are related to the assembly generated | 
|  | // to access such symbols. | 
|  | // But as Golang as its own way to check if a symbol is | 
|  | // global or local (the capital letter), we don't need to | 
|  | // implement them yet. | 
|  | s.Nsclass = C_HIDEXT | 
|  | } | 
|  |  | 
|  | x.Dynid = int32(xfile.symbolCount) | 
|  | syms = append(syms, s) | 
|  |  | 
|  | // Create auxiliary entry | 
|  |  | 
|  | // Normally, size should be the size of csect containing all | 
|  | // the data and bss symbols of one file/package. | 
|  | // However, it's easier to just have a csect for each symbol. | 
|  | // It might change | 
|  | size := uint64(x.Size) | 
|  | a4 := &XcoffAuxCSect64{ | 
|  | Xauxtype:  _AUX_CSECT, | 
|  | Xscnlenlo: uint32(size & 0xFFFFFFFF), | 
|  | Xscnlenhi: uint32(size >> 32), | 
|  | } | 
|  |  | 
|  | if x.Type >= sym.STYPE && x.Type <= sym.SPCLNTAB { | 
|  | if ctxt.LinkMode == LinkExternal && strings.HasPrefix(x.Sect.Name, ".data.rel.ro") { | 
|  | // During external linking, read-only datas with relocation | 
|  | // must be in .data. | 
|  | a4.Xsmclas = XMC_RW | 
|  | } else { | 
|  | // Read only data | 
|  | a4.Xsmclas = XMC_RO | 
|  | } | 
|  | } else if x.Type == sym.SDATA && strings.HasPrefix(x.Name, "TOC.") && ctxt.LinkMode == LinkExternal { | 
|  | a4.Xsmclas = XMC_TC | 
|  | } else if x.Name == "TOC" { | 
|  | a4.Xsmclas = XMC_TC0 | 
|  | } else { | 
|  | a4.Xsmclas = XMC_RW | 
|  | } | 
|  | if t == DataSym { | 
|  | a4.Xsmtyp |= XTY_SD | 
|  | } else { | 
|  | a4.Xsmtyp |= XTY_CM | 
|  | } | 
|  |  | 
|  | a4.Xsmtyp |= uint8(xcoffAlign(x, t) << 3) | 
|  |  | 
|  | syms = append(syms, a4) | 
|  |  | 
|  | case UndefinedSym: | 
|  | if x.Type != sym.SDYNIMPORT && x.Type != sym.SHOSTOBJ && x.Type != sym.SUNDEFEXT { | 
|  | return | 
|  | } | 
|  | s := &XcoffSymEnt64{ | 
|  | Nsclass: C_EXT, | 
|  | Noffset: uint32(xfile.stringTable.add(str)), | 
|  | Nnumaux: 1, | 
|  | } | 
|  | x.Dynid = int32(xfile.symbolCount) | 
|  | syms = append(syms, s) | 
|  |  | 
|  | a4 := &XcoffAuxCSect64{ | 
|  | Xauxtype: _AUX_CSECT, | 
|  | Xsmclas:  XMC_DS, | 
|  | Xsmtyp:   XTY_ER | XTY_IMP, | 
|  | } | 
|  |  | 
|  | if x.Name == "__n_pthreads" { | 
|  | // Currently, all imported symbols made by cgo_import_dynamic are | 
|  | // syscall functions, except __n_pthreads which is a variable. | 
|  | // TODO(aix): Find a way to detect variables imported by cgo. | 
|  | a4.Xsmclas = XMC_RW | 
|  | } | 
|  |  | 
|  | syms = append(syms, a4) | 
|  |  | 
|  | case TLSSym: | 
|  | s := &XcoffSymEnt64{ | 
|  | Nsclass: C_EXT, | 
|  | Noffset: uint32(xfile.stringTable.add(str)), | 
|  | Nscnum:  xfile.getXCOFFscnum(x.Sect), | 
|  | Nvalue:  uint64(x.Value), | 
|  | Nnumaux: 1, | 
|  | } | 
|  |  | 
|  | x.Dynid = int32(xfile.symbolCount) | 
|  | syms = append(syms, s) | 
|  |  | 
|  | size := uint64(x.Size) | 
|  | a4 := &XcoffAuxCSect64{ | 
|  | Xauxtype:  _AUX_CSECT, | 
|  | Xsmclas:   XMC_UL, | 
|  | Xsmtyp:    XTY_CM, | 
|  | Xscnlenlo: uint32(size & 0xFFFFFFFF), | 
|  | Xscnlenhi: uint32(size >> 32), | 
|  | } | 
|  |  | 
|  | syms = append(syms, a4) | 
|  | } | 
|  |  | 
|  | for _, s := range syms { | 
|  | xfile.addSymbol(s) | 
|  | } | 
|  | } | 
|  |  | 
|  | // Generate XCOFF Symbol table. | 
|  | // It will be written in out file in Asmbxcoff, because it must be | 
|  | // at the very end, especially after relocation sections which needs symbols' index. | 
|  | func (f *xcoffFile) asmaixsym(ctxt *Link) { | 
|  | // Get correct size for symbols wrapping others symbols like go.string.* | 
|  | // sym.Size can be used directly as the symbols have already been written. | 
|  | for name, size := range outerSymSize { | 
|  | sym := ctxt.Syms.ROLookup(name, 0) | 
|  | if sym == nil { | 
|  | Errorf(nil, "unknown outer symbol with name %s", name) | 
|  | } else { | 
|  | sym.Size = size | 
|  | } | 
|  | } | 
|  |  | 
|  | genasmsym(ctxt, putaixsym) | 
|  | xfile.updatePreviousFile(ctxt, true) | 
|  | } | 
|  |  | 
|  | func (f *xcoffFile) genDynSym(ctxt *Link) { | 
|  | var dynsyms []*sym.Symbol | 
|  | for _, s := range ctxt.Syms.Allsym { | 
|  | if s.Type != sym.SHOSTOBJ && s.Type != sym.SDYNIMPORT { | 
|  | continue | 
|  | } | 
|  | dynsyms = append(dynsyms, s) | 
|  | } | 
|  |  | 
|  | for _, s := range dynsyms { | 
|  | f.adddynimpsym(ctxt, s) | 
|  |  | 
|  | if _, ok := f.dynLibraries[s.Dynimplib()]; !ok { | 
|  | f.dynLibraries[s.Dynimplib()] = len(f.dynLibraries) | 
|  | } | 
|  |  | 
|  | } | 
|  |  | 
|  | } | 
|  |  | 
|  | // (*xcoffFile)adddynimpsym adds the dynamic symbol "s" to a XCOFF file. | 
|  | // A new symbol named s.Extname() is created to be the actual dynamic symbol | 
|  | // in the .loader section and in the symbol table as an External Reference. | 
|  | // The symbol "s" is transformed to SXCOFFTOC to end up in .data section. | 
|  | // However, there is no writing protection on those symbols and | 
|  | // it might need to be added. | 
|  | // TODO(aix): Handles dynamic symbols without library. | 
|  | func (f *xcoffFile) adddynimpsym(ctxt *Link, s *sym.Symbol) { | 
|  | // Check that library name is given. | 
|  | // Pattern is already checked when compiling. | 
|  | if ctxt.LinkMode == LinkInternal && s.Dynimplib() == "" { | 
|  | Errorf(s, "imported symbol must have a given library") | 
|  | } | 
|  |  | 
|  | s.Type = sym.SXCOFFTOC | 
|  |  | 
|  | // Create new dynamic symbol | 
|  | extsym := ctxt.Syms.Lookup(s.Extname(), 0) | 
|  | extsym.Type = sym.SDYNIMPORT | 
|  | extsym.Attr |= sym.AttrReachable | 
|  | extsym.SetDynimplib(s.Dynimplib()) | 
|  | extsym.SetExtname(s.Extname()) | 
|  | extsym.SetDynimpvers(s.Dynimpvers()) | 
|  |  | 
|  | // Add loader symbol | 
|  | lds := &xcoffLoaderSymbol{ | 
|  | sym:    extsym, | 
|  | smtype: XTY_IMP, | 
|  | smclas: XMC_DS, | 
|  | } | 
|  | if s.Name == "__n_pthreads" { | 
|  | // Currently, all imported symbols made by cgo_import_dynamic are | 
|  | // syscall functions, except __n_pthreads which is a variable. | 
|  | // TODO(aix): Find a way to detect variables imported by cgo. | 
|  | lds.smclas = XMC_RW | 
|  | } | 
|  | f.loaderSymbols = append(f.loaderSymbols, lds) | 
|  |  | 
|  | // Relocation to retrieve the external address | 
|  | s.AddBytes(make([]byte, 8)) | 
|  | s.SetAddr(ctxt.Arch, 0, extsym) | 
|  |  | 
|  | } | 
|  |  | 
|  | // Xcoffadddynrel adds a dynamic relocation in a XCOFF file. | 
|  | // This relocation will be made by the loader. | 
|  | func Xcoffadddynrel(ctxt *Link, s *sym.Symbol, r *sym.Reloc) bool { | 
|  | if ctxt.LinkMode == LinkExternal { | 
|  | return true | 
|  | } | 
|  | if s.Type <= sym.SPCLNTAB { | 
|  | Errorf(s, "cannot have a relocation to %s in a text section symbol", r.Sym.Name) | 
|  | return false | 
|  | } | 
|  |  | 
|  | ldr := &xcoffLoaderReloc{ | 
|  | sym: s, | 
|  | rel: r, | 
|  | } | 
|  |  | 
|  | switch r.Type { | 
|  | default: | 
|  | Errorf(s, "unexpected .loader relocation to symbol: %s (type: %s)", r.Sym.Name, r.Type.String()) | 
|  | return false | 
|  | case objabi.R_ADDR: | 
|  | if s.Type == sym.SXCOFFTOC && r.Sym.Type == sym.SDYNIMPORT { | 
|  | // Imported symbol relocation | 
|  | for i, dynsym := range xfile.loaderSymbols { | 
|  | if dynsym.sym.Name == r.Sym.Name { | 
|  | ldr.symndx = int32(i + 3) // +3 because of 3 section symbols | 
|  | break | 
|  | } | 
|  | } | 
|  | } else if s.Type == sym.SDATA { | 
|  | switch r.Sym.Sect.Seg { | 
|  | default: | 
|  | Errorf(s, "unknown segment for .loader relocation with symbol %s", r.Sym.Name) | 
|  | case &Segtext: | 
|  | case &Segrodata: | 
|  | ldr.symndx = 0 // .text | 
|  | case &Segdata: | 
|  | if r.Sym.Type == sym.SBSS || r.Sym.Type == sym.SNOPTRBSS { | 
|  | ldr.symndx = 2 // .bss | 
|  | } else { | 
|  | ldr.symndx = 1 // .data | 
|  | } | 
|  |  | 
|  | } | 
|  |  | 
|  | } else { | 
|  | Errorf(s, "unexpected type for .loader relocation R_ADDR for symbol %s: %s to %s", r.Sym.Name, s.Type, r.Sym.Type) | 
|  | return false | 
|  | } | 
|  |  | 
|  | ldr.rtype = 0x3F<<8 + XCOFF_R_POS | 
|  | } | 
|  |  | 
|  | xfile.loaderReloc = append(xfile.loaderReloc, ldr) | 
|  | return true | 
|  | } | 
|  |  | 
|  | func (ctxt *Link) doxcoff() { | 
|  | if *FlagD { | 
|  | // All XCOFF files have dynamic symbols because of the syscalls. | 
|  | Exitf("-d is not available on AIX") | 
|  | } | 
|  |  | 
|  | // TOC | 
|  | toc := ctxt.Syms.Lookup("TOC", 0) | 
|  | toc.Type = sym.SXCOFFTOC | 
|  | toc.Attr |= sym.AttrReachable | 
|  | toc.Attr |= sym.AttrVisibilityHidden | 
|  |  | 
|  | // Add entry point to .loader symbols. | 
|  | ep := ctxt.Syms.ROLookup(*flagEntrySymbol, 0) | 
|  | if !ep.Attr.Reachable() { | 
|  | Exitf("wrong entry point") | 
|  | } | 
|  |  | 
|  | xfile.loaderSymbols = append(xfile.loaderSymbols, &xcoffLoaderSymbol{ | 
|  | sym:    ep, | 
|  | smtype: XTY_ENT | XTY_SD, | 
|  | smclas: XMC_DS, | 
|  | }) | 
|  |  | 
|  | xfile.genDynSym(ctxt) | 
|  |  | 
|  | for _, s := range ctxt.Syms.Allsym { | 
|  | if strings.HasPrefix(s.Name, "TOC.") { | 
|  | s.Type = sym.SXCOFFTOC | 
|  | } | 
|  | } | 
|  |  | 
|  | if ctxt.LinkMode == LinkExternal { | 
|  | // Change rt0_go name to match name in runtime/cgo:main(). | 
|  | rt0 := ctxt.Syms.ROLookup("runtime.rt0_go", 0) | 
|  | ctxt.Syms.Rename(rt0.Name, "runtime_rt0_go", 0, ctxt.Reachparent) | 
|  |  | 
|  | for _, s := range ctxt.Syms.Allsym { | 
|  | if !s.Attr.CgoExport() { | 
|  | continue | 
|  | } | 
|  |  | 
|  | name := s.Extname() | 
|  | if s.Type == sym.STEXT { | 
|  | // On AIX, a exported function must have two symbols: | 
|  | // - a .text symbol which must start with a ".". | 
|  | // - a .data symbol which is a function descriptor. | 
|  | ctxt.Syms.Rename(s.Name, "."+name, 0, ctxt.Reachparent) | 
|  |  | 
|  | desc := ctxt.Syms.Lookup(name, 0) | 
|  | desc.Type = sym.SNOPTRDATA | 
|  | desc.AddAddr(ctxt.Arch, s) | 
|  | desc.AddAddr(ctxt.Arch, toc) | 
|  | desc.AddUint64(ctxt.Arch, 0) | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | // Loader section | 
|  | // Currently, this section is created from scratch when assembling the XCOFF file | 
|  | // according to information retrieved in xfile object. | 
|  |  | 
|  | // Create loader section and returns its size | 
|  | func Loaderblk(ctxt *Link, off uint64) { | 
|  | xfile.writeLdrScn(ctxt, off) | 
|  | } | 
|  |  | 
|  | func (f *xcoffFile) writeLdrScn(ctxt *Link, globalOff uint64) { | 
|  | var symtab []*XcoffLdSym64 | 
|  | var strtab []*XcoffLdStr64 | 
|  | var importtab []*XcoffLdImportFile64 | 
|  | var reloctab []*XcoffLdRel64 | 
|  | var dynimpreloc []*XcoffLdRel64 | 
|  |  | 
|  | // As the string table is updated in any loader subsection, | 
|  | //  its length must be computed at the same time. | 
|  | stlen := uint32(0) | 
|  |  | 
|  | // Loader Header | 
|  | hdr := &XcoffLdHdr64{ | 
|  | Lversion: 2, | 
|  | Lsymoff:  LDHDRSZ_64, | 
|  | } | 
|  |  | 
|  | /* Symbol table */ | 
|  | for _, s := range f.loaderSymbols { | 
|  | lds := &XcoffLdSym64{ | 
|  | Loffset: uint32(stlen + 2), | 
|  | Lsmtype: s.smtype, | 
|  | Lsmclas: s.smclas, | 
|  | } | 
|  | switch s.smtype { | 
|  | default: | 
|  | Errorf(s.sym, "unexpected loader symbol type: 0x%x", s.smtype) | 
|  | case XTY_ENT | XTY_SD: | 
|  | lds.Lvalue = uint64(s.sym.Value) | 
|  | lds.Lscnum = f.getXCOFFscnum(s.sym.Sect) | 
|  | case XTY_IMP: | 
|  | lds.Lifile = int32(f.dynLibraries[s.sym.Dynimplib()] + 1) | 
|  | } | 
|  | ldstr := &XcoffLdStr64{ | 
|  | size: uint16(len(s.sym.Name) + 1), // + null terminator | 
|  | name: s.sym.Name, | 
|  | } | 
|  | stlen += uint32(2 + ldstr.size) // 2 = sizeof ldstr.size | 
|  | symtab = append(symtab, lds) | 
|  | strtab = append(strtab, ldstr) | 
|  |  | 
|  | } | 
|  |  | 
|  | hdr.Lnsyms = int32(len(symtab)) | 
|  | hdr.Lrldoff = hdr.Lsymoff + uint64(24*hdr.Lnsyms) // 24 = sizeof one symbol | 
|  | off := hdr.Lrldoff                                // current offset is the same of reloc offset | 
|  |  | 
|  | /* Reloc */ | 
|  | ep := ctxt.Syms.ROLookup(*flagEntrySymbol, 0) | 
|  | ldr := &XcoffLdRel64{ | 
|  | Lvaddr:  uint64(ep.Value), | 
|  | Lrtype:  0x3F00, | 
|  | Lrsecnm: f.getXCOFFscnum(ep.Sect), | 
|  | Lsymndx: 0, | 
|  | } | 
|  | off += 16 | 
|  | reloctab = append(reloctab, ldr) | 
|  |  | 
|  | off += uint64(16 * len(f.loaderReloc)) | 
|  | for _, r := range f.loaderReloc { | 
|  | ldr = &XcoffLdRel64{ | 
|  | Lvaddr:  uint64(r.sym.Value + int64(r.rel.Off)), | 
|  | Lrtype:  r.rtype, | 
|  | Lsymndx: r.symndx, | 
|  | } | 
|  |  | 
|  | if r.sym.Sect != nil { | 
|  | ldr.Lrsecnm = f.getXCOFFscnum(r.sym.Sect) | 
|  | } | 
|  |  | 
|  | reloctab = append(reloctab, ldr) | 
|  | } | 
|  |  | 
|  | off += uint64(16 * len(dynimpreloc)) | 
|  | reloctab = append(reloctab, dynimpreloc...) | 
|  |  | 
|  | hdr.Lnreloc = int32(len(reloctab)) | 
|  | hdr.Limpoff = off | 
|  |  | 
|  | /* Import */ | 
|  | // Default import: /usr/lib:/lib | 
|  | ldimpf := &XcoffLdImportFile64{ | 
|  | Limpidpath: "/usr/lib:/lib", | 
|  | } | 
|  | off += uint64(len(ldimpf.Limpidpath) + len(ldimpf.Limpidbase) + len(ldimpf.Limpidmem) + 3) // + null delimiter | 
|  | importtab = append(importtab, ldimpf) | 
|  |  | 
|  | // The map created by adddynimpsym associates the name to a number | 
|  | // This number represents the librairie index (- 1) in this import files section | 
|  | // Therefore, they must be sorted before being put inside the section | 
|  | libsOrdered := make([]string, len(f.dynLibraries)) | 
|  | for key, val := range f.dynLibraries { | 
|  | if libsOrdered[val] != "" { | 
|  | continue | 
|  | } | 
|  | libsOrdered[val] = key | 
|  | } | 
|  |  | 
|  | for _, lib := range libsOrdered { | 
|  | // lib string is defined as base.a/mem.o or path/base.a/mem.o | 
|  | n := strings.Split(lib, "/") | 
|  | path := "" | 
|  | base := n[len(n)-2] | 
|  | mem := n[len(n)-1] | 
|  | if len(n) > 2 { | 
|  | path = lib[:len(lib)-len(base)-len(mem)-2] | 
|  |  | 
|  | } | 
|  | ldimpf = &XcoffLdImportFile64{ | 
|  | Limpidpath: path, | 
|  | Limpidbase: base, | 
|  | Limpidmem:  mem, | 
|  | } | 
|  | off += uint64(len(ldimpf.Limpidpath) + len(ldimpf.Limpidbase) + len(ldimpf.Limpidmem) + 3) // + null delimiter | 
|  | importtab = append(importtab, ldimpf) | 
|  | } | 
|  |  | 
|  | hdr.Lnimpid = int32(len(importtab)) | 
|  | hdr.Listlen = uint32(off - hdr.Limpoff) | 
|  | hdr.Lstoff = off | 
|  | hdr.Lstlen = stlen | 
|  |  | 
|  | /* Writing */ | 
|  | ctxt.Out.SeekSet(int64(globalOff)) | 
|  | binary.Write(ctxt.Out, ctxt.Arch.ByteOrder, hdr) | 
|  |  | 
|  | for _, s := range symtab { | 
|  | binary.Write(ctxt.Out, ctxt.Arch.ByteOrder, s) | 
|  |  | 
|  | } | 
|  | for _, r := range reloctab { | 
|  | binary.Write(ctxt.Out, ctxt.Arch.ByteOrder, r) | 
|  | } | 
|  | for _, f := range importtab { | 
|  | ctxt.Out.WriteString(f.Limpidpath) | 
|  | ctxt.Out.Write8(0) | 
|  | ctxt.Out.WriteString(f.Limpidbase) | 
|  | ctxt.Out.Write8(0) | 
|  | ctxt.Out.WriteString(f.Limpidmem) | 
|  | ctxt.Out.Write8(0) | 
|  | } | 
|  | for _, s := range strtab { | 
|  | ctxt.Out.Write16(s.size) | 
|  | ctxt.Out.WriteString(s.name) | 
|  | ctxt.Out.Write8(0) // null terminator | 
|  | } | 
|  |  | 
|  | f.loaderSize = off + uint64(stlen) | 
|  | ctxt.Out.Flush() | 
|  |  | 
|  | /* again for printing */ | 
|  | if !*flagA { | 
|  | return | 
|  | } | 
|  |  | 
|  | ctxt.Logf("\n.loader section") | 
|  | // write in buf | 
|  | var buf bytes.Buffer | 
|  |  | 
|  | binary.Write(&buf, ctxt.Arch.ByteOrder, hdr) | 
|  | for _, s := range symtab { | 
|  | binary.Write(&buf, ctxt.Arch.ByteOrder, s) | 
|  |  | 
|  | } | 
|  | for _, f := range importtab { | 
|  | buf.WriteString(f.Limpidpath) | 
|  | buf.WriteByte(0) | 
|  | buf.WriteString(f.Limpidbase) | 
|  | buf.WriteByte(0) | 
|  | buf.WriteString(f.Limpidmem) | 
|  | buf.WriteByte(0) | 
|  | } | 
|  | for _, s := range strtab { | 
|  | binary.Write(&buf, ctxt.Arch.ByteOrder, s.size) | 
|  | buf.WriteString(s.name) | 
|  | buf.WriteByte(0) // null terminator | 
|  | } | 
|  |  | 
|  | // Log buffer | 
|  | ctxt.Logf("\n\t%.8x|", globalOff) | 
|  | for i, b := range buf.Bytes() { | 
|  | if i > 0 && i%16 == 0 { | 
|  | ctxt.Logf("\n\t%.8x|", uint64(globalOff)+uint64(i)) | 
|  | } | 
|  | ctxt.Logf(" %.2x", b) | 
|  | } | 
|  | ctxt.Logf("\n") | 
|  |  | 
|  | } | 
|  |  | 
|  | // XCOFF assembling and writing file | 
|  |  | 
|  | func (f *xcoffFile) writeFileHeader(ctxt *Link) { | 
|  | // File header | 
|  | f.xfhdr.Fmagic = U64_TOCMAGIC | 
|  | f.xfhdr.Fnscns = uint16(len(f.sections)) | 
|  | f.xfhdr.Ftimedat = 0 | 
|  |  | 
|  | if !*FlagS { | 
|  | f.xfhdr.Fsymptr = uint64(f.symtabOffset) | 
|  | f.xfhdr.Fnsyms = int32(f.symbolCount) | 
|  | } | 
|  |  | 
|  | if ctxt.BuildMode == BuildModeExe && ctxt.LinkMode == LinkInternal { | 
|  | f.xfhdr.Fopthdr = AOUTHSZ_EXEC64 | 
|  | f.xfhdr.Fflags = F_EXEC | 
|  |  | 
|  | // auxiliary header | 
|  | f.xahdr.Ovstamp = 1 // based on dump -o | 
|  | f.xahdr.Omagic = 0x10b | 
|  | copy(f.xahdr.Omodtype[:], "1L") | 
|  | entry := ctxt.Syms.ROLookup(*flagEntrySymbol, 0) | 
|  | f.xahdr.Oentry = uint64(entry.Value) | 
|  | f.xahdr.Osnentry = f.getXCOFFscnum(entry.Sect) | 
|  | toc := ctxt.Syms.ROLookup("TOC", 0) | 
|  | f.xahdr.Otoc = uint64(toc.Value) | 
|  | f.xahdr.Osntoc = f.getXCOFFscnum(toc.Sect) | 
|  |  | 
|  | f.xahdr.Oalgntext = int16(logBase2(int(Funcalign))) | 
|  | f.xahdr.Oalgndata = 0x5 | 
|  |  | 
|  | binary.Write(ctxt.Out, binary.BigEndian, &f.xfhdr) | 
|  | binary.Write(ctxt.Out, binary.BigEndian, &f.xahdr) | 
|  | } else { | 
|  | f.xfhdr.Fopthdr = 0 | 
|  | binary.Write(ctxt.Out, binary.BigEndian, &f.xfhdr) | 
|  | } | 
|  |  | 
|  | } | 
|  |  | 
|  | func xcoffwrite(ctxt *Link) { | 
|  | ctxt.Out.SeekSet(0) | 
|  |  | 
|  | xfile.writeFileHeader(ctxt) | 
|  |  | 
|  | for _, sect := range xfile.sections { | 
|  | sect.write(ctxt) | 
|  | } | 
|  | } | 
|  |  | 
|  | // Generate XCOFF assembly file | 
|  | func Asmbxcoff(ctxt *Link, fileoff int64) { | 
|  | xfile.sectNameToScnum = make(map[string]int16) | 
|  |  | 
|  | // Add sections | 
|  | s := xfile.addSection(".text", Segtext.Vaddr, Segtext.Length, Segtext.Fileoff, STYP_TEXT) | 
|  | xfile.xahdr.Otextstart = s.Svaddr | 
|  | xfile.xahdr.Osntext = xfile.sectNameToScnum[".text"] | 
|  | xfile.xahdr.Otsize = s.Ssize | 
|  | xfile.sectText = s | 
|  |  | 
|  | segdataVaddr := Segdata.Vaddr | 
|  | segdataFilelen := Segdata.Filelen | 
|  | segdataFileoff := Segdata.Fileoff | 
|  | segbssFilelen := Segdata.Length - Segdata.Filelen | 
|  | if len(Segrelrodata.Sections) > 0 { | 
|  | // Merge relro segment to data segment as | 
|  | // relro data are inside data segment on AIX. | 
|  | segdataVaddr = Segrelrodata.Vaddr | 
|  | segdataFileoff = Segrelrodata.Fileoff | 
|  | segdataFilelen = Segdata.Vaddr + Segdata.Filelen - Segrelrodata.Vaddr | 
|  | } | 
|  |  | 
|  | s = xfile.addSection(".data", segdataVaddr, segdataFilelen, segdataFileoff, STYP_DATA) | 
|  | xfile.xahdr.Odatastart = s.Svaddr | 
|  | xfile.xahdr.Osndata = xfile.sectNameToScnum[".data"] | 
|  | xfile.xahdr.Odsize = s.Ssize | 
|  | xfile.sectData = s | 
|  |  | 
|  | s = xfile.addSection(".bss", segdataVaddr+segdataFilelen, segbssFilelen, 0, STYP_BSS) | 
|  | xfile.xahdr.Osnbss = xfile.sectNameToScnum[".bss"] | 
|  | xfile.xahdr.Obsize = s.Ssize | 
|  | xfile.sectBss = s | 
|  |  | 
|  | if ctxt.LinkMode == LinkExternal { | 
|  | var tbss *sym.Section | 
|  | for _, s := range Segdata.Sections { | 
|  | if s.Name == ".tbss" { | 
|  | tbss = s | 
|  | break | 
|  | } | 
|  | } | 
|  | s = xfile.addSection(".tbss", tbss.Vaddr, tbss.Length, 0, STYP_TBSS) | 
|  | } | 
|  |  | 
|  | // add dwarf sections | 
|  | for _, sect := range Segdwarf.Sections { | 
|  | xfile.addDwarfSection(sect) | 
|  | } | 
|  |  | 
|  | // add and write remaining sections | 
|  | if ctxt.LinkMode == LinkInternal { | 
|  | // Loader section | 
|  | if ctxt.BuildMode == BuildModeExe { | 
|  | Loaderblk(ctxt, uint64(fileoff)) | 
|  | s = xfile.addSection(".loader", 0, xfile.loaderSize, uint64(fileoff), STYP_LOADER) | 
|  | xfile.xahdr.Osnloader = xfile.sectNameToScnum[".loader"] | 
|  |  | 
|  | // Update fileoff for symbol table | 
|  | fileoff += int64(xfile.loaderSize) | 
|  | } | 
|  | } | 
|  |  | 
|  | // Create Symbol table | 
|  | xfile.asmaixsym(ctxt) | 
|  |  | 
|  | if ctxt.LinkMode == LinkExternal { | 
|  | xfile.emitRelocations(ctxt, fileoff) | 
|  | } | 
|  |  | 
|  | // Write Symbol table | 
|  | xfile.symtabOffset = ctxt.Out.Offset() | 
|  | for _, s := range xfile.symtabSym { | 
|  | binary.Write(ctxt.Out, ctxt.Arch.ByteOrder, s) | 
|  | } | 
|  | // write string table | 
|  | xfile.stringTable.write(ctxt.Out) | 
|  |  | 
|  | ctxt.Out.Flush() | 
|  |  | 
|  | // write headers | 
|  | xcoffwrite(ctxt) | 
|  | } | 
|  |  | 
|  | // byOffset is used to sort relocations by offset | 
|  | type byOffset []sym.Reloc | 
|  |  | 
|  | func (x byOffset) Len() int { return len(x) } | 
|  |  | 
|  | func (x byOffset) Swap(i, j int) { | 
|  | x[i], x[j] = x[j], x[i] | 
|  | } | 
|  |  | 
|  | func (x byOffset) Less(i, j int) bool { | 
|  | return x[i].Off < x[j].Off | 
|  | } | 
|  |  | 
|  | // emitRelocations emits relocation entries for go.o in external linking. | 
|  | func (f *xcoffFile) emitRelocations(ctxt *Link, fileoff int64) { | 
|  | ctxt.Out.SeekSet(fileoff) | 
|  | for ctxt.Out.Offset()&7 != 0 { | 
|  | ctxt.Out.Write8(0) | 
|  | } | 
|  |  | 
|  | // relocsect relocates symbols from first in section sect, and returns | 
|  | // the total number of relocations emitted. | 
|  | relocsect := func(sect *sym.Section, syms []*sym.Symbol, base uint64) uint32 { | 
|  | // ctxt.Logf("%s 0x%x\n", sect.Name, sect.Vaddr) | 
|  | // If main section has no bits, nothing to relocate. | 
|  | if sect.Vaddr >= sect.Seg.Vaddr+sect.Seg.Filelen { | 
|  | return 0 | 
|  | } | 
|  | sect.Reloff = uint64(ctxt.Out.Offset()) | 
|  | for i, s := range syms { | 
|  | if !s.Attr.Reachable() { | 
|  | continue | 
|  | } | 
|  | if uint64(s.Value) >= sect.Vaddr { | 
|  | syms = syms[i:] | 
|  | break | 
|  | } | 
|  | } | 
|  | eaddr := int64(sect.Vaddr + sect.Length) | 
|  | for _, s := range syms { | 
|  | if !s.Attr.Reachable() { | 
|  | continue | 
|  | } | 
|  | if s.Value >= int64(eaddr) { | 
|  | break | 
|  | } | 
|  |  | 
|  | // Relocation must be ordered by address, so s.R is ordered by Off. | 
|  | sort.Sort(byOffset(s.R)) | 
|  |  | 
|  | for ri := range s.R { | 
|  |  | 
|  | r := &s.R[ri] | 
|  |  | 
|  | if r.Done { | 
|  | continue | 
|  | } | 
|  | if r.Xsym == nil { | 
|  | Errorf(s, "missing xsym in relocation") | 
|  | continue | 
|  | } | 
|  | if r.Xsym.Dynid < 0 { | 
|  | 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) | 
|  | } | 
|  | if !thearch.Xcoffreloc1(ctxt.Arch, ctxt.Out, s, r, int64(uint64(s.Value+int64(r.Off))-base)) { | 
|  | Errorf(s, "unsupported obj reloc %d(%s)/%d to %s", r.Type, r.Type.String(), r.Siz, r.Sym.Name) | 
|  | } | 
|  | } | 
|  | } | 
|  | sect.Rellen = uint64(ctxt.Out.Offset()) - sect.Reloff | 
|  | return uint32(sect.Rellen) / RELSZ_64 | 
|  | } | 
|  | sects := []struct { | 
|  | xcoffSect *XcoffScnHdr64 | 
|  | segs      []*sym.Segment | 
|  | }{ | 
|  | {f.sectText, []*sym.Segment{&Segtext}}, | 
|  | {f.sectData, []*sym.Segment{&Segrelrodata, &Segdata}}, | 
|  | } | 
|  | for _, s := range sects { | 
|  | s.xcoffSect.Srelptr = uint64(ctxt.Out.Offset()) | 
|  | n := uint32(0) | 
|  | for _, seg := range s.segs { | 
|  | for _, sect := range seg.Sections { | 
|  | if sect.Name == ".text" { | 
|  | n += relocsect(sect, ctxt.Textp, 0) | 
|  | } else { | 
|  | n += relocsect(sect, datap, 0) | 
|  | } | 
|  | } | 
|  | } | 
|  | s.xcoffSect.Snreloc += n | 
|  | } | 
|  |  | 
|  | dwarfLoop: | 
|  | for _, sect := range Segdwarf.Sections { | 
|  | for _, xcoffSect := range f.sections { | 
|  | _, subtyp := xcoffGetDwarfSubtype(sect.Name) | 
|  | if xcoffSect.Sflags&0xF0000 == subtyp { | 
|  | xcoffSect.Srelptr = uint64(ctxt.Out.Offset()) | 
|  | xcoffSect.Snreloc = relocsect(sect, dwarfp, sect.Vaddr) | 
|  | continue dwarfLoop | 
|  | } | 
|  | } | 
|  | Errorf(nil, "emitRelocations: could not find %q section", sect.Name) | 
|  | } | 
|  | } | 
|  |  | 
|  | // xcoffCreateExportFile creates a file with exported symbols for | 
|  | // -Wl,-bE option. | 
|  | // ld won't export symbols unless they are listed in an export file. | 
|  | func xcoffCreateExportFile(ctxt *Link) (fname string) { | 
|  | fname = filepath.Join(*flagTmpdir, "export_file.exp") | 
|  | var buf bytes.Buffer | 
|  |  | 
|  | for _, s := range ctxt.Syms.Allsym { | 
|  | if !s.Attr.CgoExport() { | 
|  | continue | 
|  | } | 
|  | if !strings.HasPrefix(s.String(), "_cgoexp_") { | 
|  | continue | 
|  | } | 
|  |  | 
|  | // Retrieve the name of the initial symbol | 
|  | // exported by cgo. | 
|  | // The corresponding Go symbol is: | 
|  | // _cgoexp_hashcode_symname. | 
|  | name := strings.SplitN(s.Extname(), "_", 4)[3] | 
|  |  | 
|  | buf.Write([]byte(name + "\n")) | 
|  | } | 
|  |  | 
|  | err := ioutil.WriteFile(fname, buf.Bytes(), 0666) | 
|  | if err != nil { | 
|  | Errorf(nil, "WriteFile %s failed: %v", fname, err) | 
|  | } | 
|  |  | 
|  | return fname | 
|  |  | 
|  | } |