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