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
5package ld
6
7import (
8	"bytes"
9	"encoding/binary"
10	"fmt"
11	"math/bits"
12	"os"
13	"path/filepath"
14	"sort"
15	"strings"
16	"sync"
17
18	"cmd/internal/objabi"
19	"cmd/link/internal/loader"
20	"cmd/link/internal/sym"
21)
22
23// This file handles all algorithms related to XCOFF files generation.
24// Most of them are adaptations of the ones in  cmd/link/internal/pe.go
25// as PE and XCOFF are based on COFF files.
26// XCOFF files generated are 64 bits.
27
28const (
29	// Total amount of space to reserve at the start of the file
30	// for File Header, Auxiliary Header, and Section Headers.
31	// May waste some.
32	XCOFFHDRRESERVE = FILHSZ_64 + AOUTHSZ_EXEC64 + SCNHSZ_64*23
33
34	// base on dump -o, then rounded from 32B to 64B to
35	// match worst case elf text section alignment on ppc64.
36	XCOFFSECTALIGN int64 = 64
37
38	// XCOFF binaries should normally have all its sections position-independent.
39	// However, this is not yet possible for .text because of some R_ADDR relocations
40	// inside RODATA symbols.
41	// .data and .bss are position-independent so their address start inside an unreachable
42	// segment during execution to force segfault if something is wrong.
43	XCOFFTEXTBASE = 0x100000000 // Start of text address
44	XCOFFDATABASE = 0x200000000 // Start of data address
45)
46
47// File Header
48type XcoffFileHdr64 struct {
49	Fmagic   uint16 // Target machine
50	Fnscns   uint16 // Number of sections
51	Ftimedat int32  // Time and date of file creation
52	Fsymptr  uint64 // Byte offset to symbol table start
53	Fopthdr  uint16 // Number of bytes in optional header
54	Fflags   uint16 // Flags
55	Fnsyms   int32  // Number of entries in symbol table
56}
57
58const (
59	U64_TOCMAGIC = 0767 // AIX 64-bit XCOFF
60)
61
62// Flags that describe the type of the object file.
63const (
64	F_RELFLG    = 0x0001
65	F_EXEC      = 0x0002
66	F_LNNO      = 0x0004
67	F_FDPR_PROF = 0x0010
68	F_FDPR_OPTI = 0x0020
69	F_DSA       = 0x0040
70	F_VARPG     = 0x0100
71	F_DYNLOAD   = 0x1000
72	F_SHROBJ    = 0x2000
73	F_LOADONLY  = 0x4000
74)
75
76// Auxiliary Header
77type XcoffAoutHdr64 struct {
78	Omagic      int16    // Flags - Ignored If Vstamp Is 1
79	Ovstamp     int16    // Version
80	Odebugger   uint32   // Reserved For Debugger
81	Otextstart  uint64   // Virtual Address Of Text
82	Odatastart  uint64   // Virtual Address Of Data
83	Otoc        uint64   // Toc Address
84	Osnentry    int16    // Section Number For Entry Point
85	Osntext     int16    // Section Number For Text
86	Osndata     int16    // Section Number For Data
87	Osntoc      int16    // Section Number For Toc
88	Osnloader   int16    // Section Number For Loader
89	Osnbss      int16    // Section Number For Bss
90	Oalgntext   int16    // Max Text Alignment
91	Oalgndata   int16    // Max Data Alignment
92	Omodtype    [2]byte  // Module Type Field
93	Ocpuflag    uint8    // Bit Flags - Cputypes Of Objects
94	Ocputype    uint8    // Reserved for CPU type
95	Otextpsize  uint8    // Requested text page size
96	Odatapsize  uint8    // Requested data page size
97	Ostackpsize uint8    // Requested stack page size
98	Oflags      uint8    // Flags And TLS Alignment
99	Otsize      uint64   // Text Size In Bytes
100	Odsize      uint64   // Data Size In Bytes
101	Obsize      uint64   // Bss Size In Bytes
102	Oentry      uint64   // Entry Point Address
103	Omaxstack   uint64   // Max Stack Size Allowed
104	Omaxdata    uint64   // Max Data Size Allowed
105	Osntdata    int16    // Section Number For Tdata Section
106	Osntbss     int16    // Section Number For Tbss Section
107	Ox64flags   uint16   // Additional Flags For 64-Bit Objects
108	Oresv3a     int16    // Reserved
109	Oresv3      [2]int32 // Reserved
110}
111
112// Section Header
113type XcoffScnHdr64 struct {
114	Sname    [8]byte // Section Name
115	Spaddr   uint64  // Physical Address
116	Svaddr   uint64  // Virtual Address
117	Ssize    uint64  // Section Size
118	Sscnptr  uint64  // File Offset To Raw Data
119	Srelptr  uint64  // File Offset To Relocation
120	Slnnoptr uint64  // File Offset To Line Numbers
121	Snreloc  uint32  // Number Of Relocation Entries
122	Snlnno   uint32  // Number Of Line Number Entries
123	Sflags   uint32  // flags
124}
125
126// Flags defining the section type.
127const (
128	STYP_DWARF  = 0x0010
129	STYP_TEXT   = 0x0020
130	STYP_DATA   = 0x0040
131	STYP_BSS    = 0x0080
132	STYP_EXCEPT = 0x0100
133	STYP_INFO   = 0x0200
134	STYP_TDATA  = 0x0400
135	STYP_TBSS   = 0x0800
136	STYP_LOADER = 0x1000
137	STYP_DEBUG  = 0x2000
138	STYP_TYPCHK = 0x4000
139	STYP_OVRFLO = 0x8000
140)
141const (
142	SSUBTYP_DWINFO  = 0x10000 // DWARF info section
143	SSUBTYP_DWLINE  = 0x20000 // DWARF line-number section
144	SSUBTYP_DWPBNMS = 0x30000 // DWARF public names section
145	SSUBTYP_DWPBTYP = 0x40000 // DWARF public types section
146	SSUBTYP_DWARNGE = 0x50000 // DWARF aranges section
147	SSUBTYP_DWABREV = 0x60000 // DWARF abbreviation section
148	SSUBTYP_DWSTR   = 0x70000 // DWARF strings section
149	SSUBTYP_DWRNGES = 0x80000 // DWARF ranges section
150	SSUBTYP_DWLOC   = 0x90000 // DWARF location lists section
151	SSUBTYP_DWFRAME = 0xA0000 // DWARF frames section
152	SSUBTYP_DWMAC   = 0xB0000 // DWARF macros section
153)
154
155// Headers size
156const (
157	FILHSZ_32      = 20
158	FILHSZ_64      = 24
159	AOUTHSZ_EXEC32 = 72
160	AOUTHSZ_EXEC64 = 120
161	SCNHSZ_32      = 40
162	SCNHSZ_64      = 72
163	LDHDRSZ_32     = 32
164	LDHDRSZ_64     = 56
165	LDSYMSZ_64     = 24
166	RELSZ_64       = 14
167)
168
169// Type representing all XCOFF symbols.
170type xcoffSym interface {
171}
172
173// Symbol Table Entry
174type XcoffSymEnt64 struct {
175	Nvalue  uint64 // Symbol value
176	Noffset uint32 // Offset of the name in string table or .debug section
177	Nscnum  int16  // Section number of symbol
178	Ntype   uint16 // Basic and derived type specification
179	Nsclass uint8  // Storage class of symbol
180	Nnumaux int8   // Number of auxiliary entries
181}
182
183const SYMESZ = 18
184
185const (
186	// Nscnum
187	N_DEBUG = -2
188	N_ABS   = -1
189	N_UNDEF = 0
190
191	//Ntype
192	SYM_V_INTERNAL  = 0x1000
193	SYM_V_HIDDEN    = 0x2000
194	SYM_V_PROTECTED = 0x3000
195	SYM_V_EXPORTED  = 0x4000
196	SYM_TYPE_FUNC   = 0x0020 // is function
197)
198
199// Storage Class.
200const (
201	C_NULL    = 0   // Symbol table entry marked for deletion
202	C_EXT     = 2   // External symbol
203	C_STAT    = 3   // Static symbol
204	C_BLOCK   = 100 // Beginning or end of inner block
205	C_FCN     = 101 // Beginning or end of function
206	C_FILE    = 103 // Source file name and compiler information
207	C_HIDEXT  = 107 // Unnamed external symbol
208	C_BINCL   = 108 // Beginning of include file
209	C_EINCL   = 109 // End of include file
210	C_WEAKEXT = 111 // Weak external symbol
211	C_DWARF   = 112 // DWARF symbol
212	C_GSYM    = 128 // Global variable
213	C_LSYM    = 129 // Automatic variable allocated on stack
214	C_PSYM    = 130 // Argument to subroutine allocated on stack
215	C_RSYM    = 131 // Register variable
216	C_RPSYM   = 132 // Argument to function or procedure stored in register
217	C_STSYM   = 133 // Statically allocated symbol
218	C_BCOMM   = 135 // Beginning of common block
219	C_ECOML   = 136 // Local member of common block
220	C_ECOMM   = 137 // End of common block
221	C_DECL    = 140 // Declaration of object
222	C_ENTRY   = 141 // Alternate entry
223	C_FUN     = 142 // Function or procedure
224	C_BSTAT   = 143 // Beginning of static block
225	C_ESTAT   = 144 // End of static block
226	C_GTLS    = 145 // Global thread-local variable
227	C_STTLS   = 146 // Static thread-local variable
228)
229
230// File Auxiliary Entry
231type XcoffAuxFile64 struct {
232	Xzeroes  uint32 // The name is always in the string table
233	Xoffset  uint32 // Offset in the string table
234	X_pad1   [6]byte
235	Xftype   uint8 // Source file string type
236	X_pad2   [2]byte
237	Xauxtype uint8 // Type of auxiliary entry
238}
239
240// Function Auxiliary Entry
241type XcoffAuxFcn64 struct {
242	Xlnnoptr uint64 // File pointer to line number
243	Xfsize   uint32 // Size of function in bytes
244	Xendndx  uint32 // Symbol table index of next entry
245	Xpad     uint8  // Unused
246	Xauxtype uint8  // Type of auxiliary entry
247}
248
249// csect Auxiliary Entry.
250type XcoffAuxCSect64 struct {
251	Xscnlenlo uint32 // Lower 4 bytes of length or symbol table index
252	Xparmhash uint32 // Offset of parameter type-check string
253	Xsnhash   uint16 // .typchk section number
254	Xsmtyp    uint8  // Symbol alignment and type
255	Xsmclas   uint8  // Storage-mapping class
256	Xscnlenhi uint32 // Upper 4 bytes of length or symbol table index
257	Xpad      uint8  // Unused
258	Xauxtype  uint8  // Type of auxiliary entry
259}
260
261// DWARF Auxiliary Entry
262type XcoffAuxDWARF64 struct {
263	Xscnlen  uint64 // Length of this symbol section
264	X_pad    [9]byte
265	Xauxtype uint8 // Type of auxiliary entry
266}
267
268// Auxiliary type
269const (
270	_AUX_EXCEPT = 255
271	_AUX_FCN    = 254
272	_AUX_SYM    = 253
273	_AUX_FILE   = 252
274	_AUX_CSECT  = 251
275	_AUX_SECT   = 250
276)
277
278// Xftype field
279const (
280	XFT_FN = 0   // Source File Name
281	XFT_CT = 1   // Compile Time Stamp
282	XFT_CV = 2   // Compiler Version Number
283	XFT_CD = 128 // Compiler Defined Information/
284
285)
286
287// Symbol type field.
288const (
289	XTY_ER  = 0    // External reference
290	XTY_SD  = 1    // Section definition
291	XTY_LD  = 2    // Label definition
292	XTY_CM  = 3    // Common csect definition
293	XTY_WK  = 0x8  // Weak symbol
294	XTY_EXP = 0x10 // Exported symbol
295	XTY_ENT = 0x20 // Entry point symbol
296	XTY_IMP = 0x40 // Imported symbol
297)
298
299// Storage-mapping class.
300const (
301	XMC_PR     = 0  // Program code
302	XMC_RO     = 1  // Read-only constant
303	XMC_DB     = 2  // Debug dictionary table
304	XMC_TC     = 3  // TOC entry
305	XMC_UA     = 4  // Unclassified
306	XMC_RW     = 5  // Read/Write data
307	XMC_GL     = 6  // Global linkage
308	XMC_XO     = 7  // Extended operation
309	XMC_SV     = 8  // 32-bit supervisor call descriptor
310	XMC_BS     = 9  // BSS class
311	XMC_DS     = 10 // Function descriptor
312	XMC_UC     = 11 // Unnamed FORTRAN common
313	XMC_TC0    = 15 // TOC anchor
314	XMC_TD     = 16 // Scalar data entry in the TOC
315	XMC_SV64   = 17 // 64-bit supervisor call descriptor
316	XMC_SV3264 = 18 // Supervisor call descriptor for both 32-bit and 64-bit
317	XMC_TL     = 20 // Read/Write thread-local data
318	XMC_UL     = 21 // Read/Write thread-local data (.tbss)
319	XMC_TE     = 22 // TOC entry
320)
321
322// Loader Header
323type XcoffLdHdr64 struct {
324	Lversion int32  // Loader section version number
325	Lnsyms   int32  // Number of symbol table entries
326	Lnreloc  int32  // Number of relocation table entries
327	Listlen  uint32 // Length of import file ID string table
328	Lnimpid  int32  // Number of import file IDs
329	Lstlen   uint32 // Length of string table
330	Limpoff  uint64 // Offset to start of import file IDs
331	Lstoff   uint64 // Offset to start of string table
332	Lsymoff  uint64 // Offset to start of symbol table
333	Lrldoff  uint64 // Offset to start of relocation entries
334}
335
336// Loader Symbol
337type XcoffLdSym64 struct {
338	Lvalue  uint64 // Address field
339	Loffset uint32 // Byte offset into string table of symbol name
340	Lscnum  int16  // Section number containing symbol
341	Lsmtype int8   // Symbol type, export, import flags
342	Lsmclas int8   // Symbol storage class
343	Lifile  int32  // Import file ID; ordinal of import file IDs
344	Lparm   uint32 // Parameter type-check field
345}
346
347type xcoffLoaderSymbol struct {
348	sym    loader.Sym
349	smtype int8
350	smclas int8
351}
352
353type XcoffLdImportFile64 struct {
354	Limpidpath string
355	Limpidbase string
356	Limpidmem  string
357}
358
359type XcoffLdRel64 struct {
360	Lvaddr  uint64 // Address Field
361	Lrtype  uint16 // Relocation Size and Type
362	Lrsecnm int16  // Section Number being relocated
363	Lsymndx int32  // Loader-Section symbol table index
364}
365
366// xcoffLoaderReloc holds information about a relocation made by the loader.
367type xcoffLoaderReloc struct {
368	sym    loader.Sym
369	roff   int32
370	rtype  uint16
371	symndx int32
372}
373
374const (
375	XCOFF_R_POS = 0x00 // A(sym) Positive Relocation
376	XCOFF_R_NEG = 0x01 // -A(sym) Negative Relocation
377	XCOFF_R_REL = 0x02 // A(sym-*) Relative to self
378	XCOFF_R_TOC = 0x03 // A(sym-TOC) Relative to TOC
379	XCOFF_R_TRL = 0x12 // A(sym-TOC) TOC Relative indirect load.
380
381	XCOFF_R_TRLA = 0x13 // A(sym-TOC) TOC Rel load address. modifiable inst
382	XCOFF_R_GL   = 0x05 // A(external TOC of sym) Global Linkage
383	XCOFF_R_TCL  = 0x06 // A(local TOC of sym) Local object TOC address
384	XCOFF_R_RL   = 0x0C // A(sym) Pos indirect load. modifiable instruction
385	XCOFF_R_RLA  = 0x0D // A(sym) Pos Load Address. modifiable instruction
386	XCOFF_R_REF  = 0x0F // AL0(sym) Non relocating ref. No garbage collect
387	XCOFF_R_BA   = 0x08 // A(sym) Branch absolute. Cannot modify instruction
388	XCOFF_R_RBA  = 0x18 // A(sym) Branch absolute. modifiable instruction
389	XCOFF_R_BR   = 0x0A // A(sym-*) Branch rel to self. non modifiable
390	XCOFF_R_RBR  = 0x1A // A(sym-*) Branch rel to self. modifiable instr
391
392	XCOFF_R_TLS    = 0x20 // General-dynamic reference to TLS symbol
393	XCOFF_R_TLS_IE = 0x21 // Initial-exec reference to TLS symbol
394	XCOFF_R_TLS_LD = 0x22 // Local-dynamic reference to TLS symbol
395	XCOFF_R_TLS_LE = 0x23 // Local-exec reference to TLS symbol
396	XCOFF_R_TLSM   = 0x24 // Module reference to TLS symbol
397	XCOFF_R_TLSML  = 0x25 // Module reference to local (own) module
398
399	XCOFF_R_TOCU = 0x30 // Relative to TOC - high order bits
400	XCOFF_R_TOCL = 0x31 // Relative to TOC - low order bits
401)
402
403type XcoffLdStr64 struct {
404	size uint16
405	name string
406}
407
408// xcoffFile is used to build XCOFF file.
409type xcoffFile struct {
410	xfhdr           XcoffFileHdr64
411	xahdr           XcoffAoutHdr64
412	sections        []*XcoffScnHdr64
413	sectText        *XcoffScnHdr64
414	sectData        *XcoffScnHdr64
415	sectBss         *XcoffScnHdr64
416	stringTable     xcoffStringTable
417	sectNameToScnum map[string]int16
418	loaderSize      uint64
419	symtabOffset    int64                // offset to the start of symbol table
420	symbolCount     uint32               // number of symbol table records written
421	symtabSym       []xcoffSym           // XCOFF symbols for the symbol table
422	dynLibraries    map[string]int       // Dynamic libraries in .loader section. The integer represents its import file number (- 1)
423	loaderSymbols   []*xcoffLoaderSymbol // symbols inside .loader symbol table
424	loaderReloc     []*xcoffLoaderReloc  // Reloc that must be made inside loader
425	sync.Mutex                           // currently protect loaderReloc
426}
427
428// Var used by XCOFF Generation algorithms
429var (
430	xfile xcoffFile
431)
432
433// xcoffStringTable is a XCOFF string table.
434type xcoffStringTable struct {
435	strings    []string
436	stringsLen int
437}
438
439// size returns size of string table t.
440func (t *xcoffStringTable) size() int {
441	// string table starts with 4-byte length at the beginning
442	return t.stringsLen + 4
443}
444
445// add adds string str to string table t.
446func (t *xcoffStringTable) add(str string) int {
447	off := t.size()
448	t.strings = append(t.strings, str)
449	t.stringsLen += len(str) + 1 // each string will have 0 appended to it
450	return off
451}
452
453// write writes string table t into the output file.
454func (t *xcoffStringTable) write(out *OutBuf) {
455	out.Write32(uint32(t.size()))
456	for _, s := range t.strings {
457		out.WriteString(s)
458		out.Write8(0)
459	}
460}
461
462// write writes XCOFF section sect into the output file.
463func (sect *XcoffScnHdr64) write(ctxt *Link) {
464	binary.Write(ctxt.Out, binary.BigEndian, sect)
465	ctxt.Out.Write32(0) // Add 4 empty bytes at the end to match alignment
466}
467
468// addSection adds section to the XCOFF file f.
469func (f *xcoffFile) addSection(name string, addr uint64, size uint64, fileoff uint64, flags uint32) *XcoffScnHdr64 {
470	sect := &XcoffScnHdr64{
471		Spaddr:  addr,
472		Svaddr:  addr,
473		Ssize:   size,
474		Sscnptr: fileoff,
475		Sflags:  flags,
476	}
477	copy(sect.Sname[:], name) // copy string to [8]byte
478	f.sections = append(f.sections, sect)
479	f.sectNameToScnum[name] = int16(len(f.sections))
480	return sect
481}
482
483// addDwarfSection adds a dwarf section to the XCOFF file f.
484// This function is similar to addSection, but Dwarf section names
485// must be modified to conventional names and they are various subtypes.
486func (f *xcoffFile) addDwarfSection(s *sym.Section) *XcoffScnHdr64 {
487	newName, subtype := xcoffGetDwarfSubtype(s.Name)
488	return f.addSection(newName, 0, s.Length, s.Seg.Fileoff+s.Vaddr-s.Seg.Vaddr, STYP_DWARF|subtype)
489}
490
491// xcoffGetDwarfSubtype returns the XCOFF name of the DWARF section str
492// and its subtype constant.
493func xcoffGetDwarfSubtype(str string) (string, uint32) {
494	switch str {
495	default:
496		Exitf("unknown DWARF section name for XCOFF: %s", str)
497	case ".debug_abbrev":
498		return ".dwabrev", SSUBTYP_DWABREV
499	case ".debug_info":
500		return ".dwinfo", SSUBTYP_DWINFO
501	case ".debug_frame":
502		return ".dwframe", SSUBTYP_DWFRAME
503	case ".debug_line":
504		return ".dwline", SSUBTYP_DWLINE
505	case ".debug_loc":
506		return ".dwloc", SSUBTYP_DWLOC
507	case ".debug_pubnames":
508		return ".dwpbnms", SSUBTYP_DWPBNMS
509	case ".debug_pubtypes":
510		return ".dwpbtyp", SSUBTYP_DWPBTYP
511	case ".debug_ranges":
512		return ".dwrnges", SSUBTYP_DWRNGES
513	}
514	// never used
515	return "", 0
516}
517
518// getXCOFFscnum returns the XCOFF section number of a Go section.
519func (f *xcoffFile) getXCOFFscnum(sect *sym.Section) int16 {
520	switch sect.Seg {
521	case &Segtext:
522		return f.sectNameToScnum[".text"]
523	case &Segdata:
524		if sect.Name == ".noptrbss" || sect.Name == ".bss" {
525			return f.sectNameToScnum[".bss"]
526		}
527		if sect.Name == ".tbss" {
528			return f.sectNameToScnum[".tbss"]
529		}
530		return f.sectNameToScnum[".data"]
531	case &Segdwarf:
532		name, _ := xcoffGetDwarfSubtype(sect.Name)
533		return f.sectNameToScnum[name]
534	case &Segrelrodata:
535		return f.sectNameToScnum[".data"]
536	}
537	Errorf(nil, "getXCOFFscnum not implemented for section %s", sect.Name)
538	return -1
539}
540
541// Xcoffinit initialised some internal value and setups
542// already known header information.
543func Xcoffinit(ctxt *Link) {
544	xfile.dynLibraries = make(map[string]int)
545
546	HEADR = int32(Rnd(XCOFFHDRRESERVE, XCOFFSECTALIGN))
547	if *FlagRound != -1 {
548		Errorf(nil, "-R not available on AIX")
549	}
550	*FlagRound = XCOFFSECTALIGN
551	if *FlagTextAddr != -1 {
552		Errorf(nil, "-T not available on AIX")
553	}
554	*FlagTextAddr = Rnd(XCOFFTEXTBASE, *FlagRound) + int64(HEADR)
555}
556
557// SYMBOL TABLE
558
559// type records C_FILE information needed for genasmsym in XCOFF.
560type 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
569var (
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.
577func 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.
619func (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.
625func 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.
638func 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.
650func (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.
760func (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.
784func (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.
875func putaixsym(ctxt *Link, x loader.Sym, t SymbolType) {
876	// All XCOFF symbols generated by this GO symbols
877	// Can be a symbol entry or an 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.
1042func (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 ldr.AttrNotInSymbolTable(s) {
1096			return false
1097		}
1098		if (name == "" || name[0] == '.') && !ldr.IsFileLocal(s) && name != ".TOC." {
1099			return false
1100		}
1101		return true
1102	}
1103
1104	for s, nsym := loader.Sym(1), loader.Sym(ldr.NSym()); s < nsym; s++ {
1105		if !shouldBeInSymbolTable(s, ldr.SymName(s)) {
1106			continue
1107		}
1108		st := ldr.SymType(s)
1109		switch {
1110		case st == sym.STLSBSS:
1111			if ctxt.IsExternal() {
1112				putaixsym(ctxt, s, TLSSym)
1113			}
1114
1115		case st == sym.SBSS, st == sym.SNOPTRBSS, st == sym.SLIBFUZZER_8BIT_COUNTER, st == sym.SCOVERAGE_COUNTER:
1116			if ldr.AttrReachable(s) {
1117				data := ldr.Data(s)
1118				if len(data) > 0 {
1119					ldr.Errorf(s, "should not be bss (size=%d type=%v special=%v)", len(data), ldr.SymType(s), ldr.AttrSpecial(s))
1120				}
1121				putaixsym(ctxt, s, BSSSym)
1122			}
1123
1124		case st >= sym.SELFRXSECT && st < sym.SXREF: // data sections handled in dodata
1125			if ldr.AttrReachable(s) {
1126				putaixsym(ctxt, s, DataSym)
1127			}
1128
1129		case st == sym.SUNDEFEXT:
1130			putaixsym(ctxt, s, UndefinedSym)
1131
1132		case st == sym.SDYNIMPORT:
1133			if ldr.AttrReachable(s) {
1134				putaixsym(ctxt, s, UndefinedSym)
1135			}
1136		}
1137	}
1138
1139	for _, s := range ctxt.Textp {
1140		putaixsym(ctxt, s, TextSym)
1141	}
1142
1143	if ctxt.Debugvlog != 0 {
1144		ctxt.Logf("symsize = %d\n", uint32(symSize))
1145	}
1146	xfile.updatePreviousFile(ctxt, true)
1147}
1148
1149func (f *xcoffFile) genDynSym(ctxt *Link) {
1150	ldr := ctxt.loader
1151	var dynsyms []loader.Sym
1152	for s := loader.Sym(1); s < loader.Sym(ldr.NSym()); s++ {
1153		if !ldr.AttrReachable(s) {
1154			continue
1155		}
1156		if t := ldr.SymType(s); t != sym.SHOSTOBJ && t != sym.SDYNIMPORT {
1157			continue
1158		}
1159		dynsyms = append(dynsyms, s)
1160	}
1161
1162	for _, s := range dynsyms {
1163		f.adddynimpsym(ctxt, s)
1164
1165		if _, ok := f.dynLibraries[ldr.SymDynimplib(s)]; !ok {
1166			f.dynLibraries[ldr.SymDynimplib(s)] = len(f.dynLibraries)
1167		}
1168	}
1169}
1170
1171// (*xcoffFile)adddynimpsym adds the dynamic symbol "s" to a XCOFF file.
1172// A new symbol named s.Extname() is created to be the actual dynamic symbol
1173// in the .loader section and in the symbol table as an External Reference.
1174// The symbol "s" is transformed to SXCOFFTOC to end up in .data section.
1175// However, there is no writing protection on those symbols and
1176// it might need to be added.
1177// TODO(aix): Handles dynamic symbols without library.
1178func (f *xcoffFile) adddynimpsym(ctxt *Link, s loader.Sym) {
1179	// Check that library name is given.
1180	// Pattern is already checked when compiling.
1181	ldr := ctxt.loader
1182	if ctxt.IsInternal() && ldr.SymDynimplib(s) == "" {
1183		ctxt.Errorf(s, "imported symbol must have a given library")
1184	}
1185
1186	sb := ldr.MakeSymbolUpdater(s)
1187	sb.SetReachable(true)
1188	sb.SetType(sym.SXCOFFTOC)
1189
1190	// Create new dynamic symbol
1191	extsym := ldr.CreateSymForUpdate(ldr.SymExtname(s), 0)
1192	extsym.SetType(sym.SDYNIMPORT)
1193	extsym.SetDynimplib(ldr.SymDynimplib(s))
1194	extsym.SetExtname(ldr.SymExtname(s))
1195	extsym.SetDynimpvers(ldr.SymDynimpvers(s))
1196
1197	// Add loader symbol
1198	lds := &xcoffLoaderSymbol{
1199		sym:    extsym.Sym(),
1200		smtype: XTY_IMP,
1201		smclas: XMC_DS,
1202	}
1203	if ldr.SymName(s) == "__n_pthreads" {
1204		// Currently, all imported symbols made by cgo_import_dynamic are
1205		// syscall functions, except __n_pthreads which is a variable.
1206		// TODO(aix): Find a way to detect variables imported by cgo.
1207		lds.smclas = XMC_RW
1208	}
1209	f.loaderSymbols = append(f.loaderSymbols, lds)
1210
1211	// Relocation to retrieve the external address
1212	sb.AddBytes(make([]byte, 8))
1213	r, _ := sb.AddRel(objabi.R_ADDR)
1214	r.SetSym(extsym.Sym())
1215	r.SetSiz(uint8(ctxt.Arch.PtrSize))
1216	// TODO: maybe this could be
1217	// sb.SetSize(0)
1218	// sb.SetData(nil)
1219	// sb.AddAddr(ctxt.Arch, extsym.Sym())
1220	// If the size is not 0 to begin with, I don't think the added 8 bytes
1221	// of zeros are necessary.
1222}
1223
1224// Xcoffadddynrel adds a dynamic relocation in a XCOFF file.
1225// This relocation will be made by the loader.
1226func Xcoffadddynrel(target *Target, ldr *loader.Loader, syms *ArchSyms, s loader.Sym, r loader.Reloc, rIdx int) bool {
1227	if target.IsExternal() {
1228		return true
1229	}
1230	if ldr.SymType(s) <= sym.SPCLNTAB {
1231		ldr.Errorf(s, "cannot have a relocation to %s in a text section symbol", ldr.SymName(r.Sym()))
1232		return false
1233	}
1234
1235	xldr := &xcoffLoaderReloc{
1236		sym:  s,
1237		roff: r.Off(),
1238	}
1239	targ := r.Sym()
1240	var targType sym.SymKind
1241	if targ != 0 {
1242		targType = ldr.SymType(targ)
1243	}
1244
1245	switch r.Type() {
1246	default:
1247		ldr.Errorf(s, "unexpected .loader relocation to symbol: %s (type: %s)", ldr.SymName(targ), r.Type().String())
1248		return false
1249	case objabi.R_ADDR:
1250		if ldr.SymType(s) == sym.SXCOFFTOC && targType == sym.SDYNIMPORT {
1251			// Imported symbol relocation
1252			for i, dynsym := range xfile.loaderSymbols {
1253				if ldr.SymName(dynsym.sym) == ldr.SymName(targ) {
1254					xldr.symndx = int32(i + 3) // +3 because of 3 section symbols
1255					break
1256				}
1257			}
1258		} else if t := ldr.SymType(s); t == sym.SDATA || t == sym.SNOPTRDATA || t == sym.SBUILDINFO || t == sym.SXCOFFTOC {
1259			switch ldr.SymSect(targ).Seg {
1260			default:
1261				ldr.Errorf(s, "unknown segment for .loader relocation with symbol %s", ldr.SymName(targ))
1262			case &Segtext:
1263			case &Segrodata:
1264				xldr.symndx = 0 // .text
1265			case &Segdata:
1266				if targType == sym.SBSS || targType == sym.SNOPTRBSS {
1267					xldr.symndx = 2 // .bss
1268				} else {
1269					xldr.symndx = 1 // .data
1270				}
1271			}
1272
1273		} else {
1274			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))
1275			return false
1276		}
1277
1278		xldr.rtype = 0x3F<<8 + XCOFF_R_POS
1279	}
1280
1281	xfile.Lock()
1282	xfile.loaderReloc = append(xfile.loaderReloc, xldr)
1283	xfile.Unlock()
1284	return true
1285}
1286
1287func (ctxt *Link) doxcoff() {
1288	ldr := ctxt.loader
1289
1290	// TOC
1291	toc := ldr.CreateSymForUpdate("TOC", 0)
1292	toc.SetType(sym.SXCOFFTOC)
1293	toc.SetVisibilityHidden(true)
1294
1295	// Add entry point to .loader symbols.
1296	ep := ldr.Lookup(*flagEntrySymbol, 0)
1297	if ep == 0 || !ldr.AttrReachable(ep) {
1298		Exitf("wrong entry point")
1299	}
1300
1301	xfile.loaderSymbols = append(xfile.loaderSymbols, &xcoffLoaderSymbol{
1302		sym:    ep,
1303		smtype: XTY_ENT | XTY_SD,
1304		smclas: XMC_DS,
1305	})
1306
1307	xfile.genDynSym(ctxt)
1308
1309	for s := loader.Sym(1); s < loader.Sym(ldr.NSym()); s++ {
1310		if strings.HasPrefix(ldr.SymName(s), "TOC.") {
1311			sb := ldr.MakeSymbolUpdater(s)
1312			sb.SetType(sym.SXCOFFTOC)
1313		}
1314	}
1315
1316	if ctxt.IsExternal() {
1317		// Change rt0_go name to match name in runtime/cgo:main().
1318		rt0 := ldr.Lookup("runtime.rt0_go", 0)
1319		ldr.SetSymExtname(rt0, "runtime_rt0_go")
1320
1321		nsym := loader.Sym(ldr.NSym())
1322		for s := loader.Sym(1); s < nsym; s++ {
1323			if !ldr.AttrCgoExport(s) {
1324				continue
1325			}
1326			if ldr.IsFileLocal(s) {
1327				panic("cgo_export on static symbol")
1328			}
1329
1330			if ldr.SymType(s) == sym.STEXT {
1331				// On AIX, an exported function must have two symbols:
1332				// - a .text symbol which must start with a ".".
1333				// - a .data symbol which is a function descriptor.
1334				name := ldr.SymExtname(s)
1335				ldr.SetSymExtname(s, "."+name)
1336
1337				desc := ldr.MakeSymbolUpdater(ldr.CreateExtSym(name, 0))
1338				desc.SetReachable(true)
1339				desc.SetType(sym.SNOPTRDATA)
1340				desc.AddAddr(ctxt.Arch, s)
1341				desc.AddAddr(ctxt.Arch, toc.Sym())
1342				desc.AddUint64(ctxt.Arch, 0)
1343			}
1344		}
1345	}
1346}
1347
1348// Loader section
1349// Currently, this section is created from scratch when assembling the XCOFF file
1350// according to information retrieved in xfile object.
1351
1352// Create loader section and returns its size.
1353func Loaderblk(ctxt *Link, off uint64) {
1354	xfile.writeLdrScn(ctxt, off)
1355}
1356
1357func (f *xcoffFile) writeLdrScn(ctxt *Link, globalOff uint64) {
1358	var symtab []*XcoffLdSym64
1359	var strtab []*XcoffLdStr64
1360	var importtab []*XcoffLdImportFile64
1361	var reloctab []*XcoffLdRel64
1362	var dynimpreloc []*XcoffLdRel64
1363
1364	// As the string table is updated in any loader subsection,
1365	//  its length must be computed at the same time.
1366	stlen := uint32(0)
1367
1368	// Loader Header
1369	hdr := &XcoffLdHdr64{
1370		Lversion: 2,
1371		Lsymoff:  LDHDRSZ_64,
1372	}
1373
1374	ldr := ctxt.loader
1375	/* Symbol table */
1376	for _, s := range f.loaderSymbols {
1377		lds := &XcoffLdSym64{
1378			Loffset: uint32(stlen + 2),
1379			Lsmtype: s.smtype,
1380			Lsmclas: s.smclas,
1381		}
1382		sym := s.sym
1383		switch s.smtype {
1384		default:
1385			ldr.Errorf(sym, "unexpected loader symbol type: 0x%x", s.smtype)
1386		case XTY_ENT | XTY_SD:
1387			lds.Lvalue = uint64(ldr.SymValue(sym))
1388			lds.Lscnum = f.getXCOFFscnum(ldr.SymSect(sym))
1389		case XTY_IMP:
1390			lds.Lifile = int32(f.dynLibraries[ldr.SymDynimplib(sym)] + 1)
1391		}
1392		ldstr := &XcoffLdStr64{
1393			size: uint16(len(ldr.SymName(sym)) + 1), // + null terminator
1394			name: ldr.SymName(sym),
1395		}
1396		stlen += uint32(2 + ldstr.size) // 2 = sizeof ldstr.size
1397		symtab = append(symtab, lds)
1398		strtab = append(strtab, ldstr)
1399
1400	}
1401
1402	hdr.Lnsyms = int32(len(symtab))
1403	hdr.Lrldoff = hdr.Lsymoff + uint64(24*hdr.Lnsyms) // 24 = sizeof one symbol
1404	off := hdr.Lrldoff                                // current offset is the same of reloc offset
1405
1406	/* Reloc */
1407	// Ensure deterministic order
1408	sort.Slice(f.loaderReloc, func(i, j int) bool {
1409		r1, r2 := f.loaderReloc[i], f.loaderReloc[j]
1410		if r1.sym != r2.sym {
1411			return r1.sym < r2.sym
1412		}
1413		if r1.roff != r2.roff {
1414			return r1.roff < r2.roff
1415		}
1416		if r1.rtype != r2.rtype {
1417			return r1.rtype < r2.rtype
1418		}
1419		return r1.symndx < r2.symndx
1420	})
1421
1422	ep := ldr.Lookup(*flagEntrySymbol, 0)
1423	xldr := &XcoffLdRel64{
1424		Lvaddr:  uint64(ldr.SymValue(ep)),
1425		Lrtype:  0x3F00,
1426		Lrsecnm: f.getXCOFFscnum(ldr.SymSect(ep)),
1427		Lsymndx: 0,
1428	}
1429	off += 16
1430	reloctab = append(reloctab, xldr)
1431
1432	off += uint64(16 * len(f.loaderReloc))
1433	for _, r := range f.loaderReloc {
1434		symp := r.sym
1435		if symp == 0 {
1436			panic("unexpected 0 sym value")
1437		}
1438		xldr = &XcoffLdRel64{
1439			Lvaddr:  uint64(ldr.SymValue(symp) + int64(r.roff)),
1440			Lrtype:  r.rtype,
1441			Lsymndx: r.symndx,
1442		}
1443
1444		if ldr.SymSect(symp) != nil {
1445			xldr.Lrsecnm = f.getXCOFFscnum(ldr.SymSect(symp))
1446		}
1447
1448		reloctab = append(reloctab, xldr)
1449	}
1450
1451	off += uint64(16 * len(dynimpreloc))
1452	reloctab = append(reloctab, dynimpreloc...)
1453
1454	hdr.Lnreloc = int32(len(reloctab))
1455	hdr.Limpoff = off
1456
1457	/* Import */
1458	// Default import: /usr/lib:/lib
1459	ldimpf := &XcoffLdImportFile64{
1460		Limpidpath: "/usr/lib:/lib",
1461	}
1462	off += uint64(len(ldimpf.Limpidpath) + len(ldimpf.Limpidbase) + len(ldimpf.Limpidmem) + 3) // + null delimiter
1463	importtab = append(importtab, ldimpf)
1464
1465	// The map created by adddynimpsym associates the name to a number
1466	// This number represents the librairie index (- 1) in this import files section
1467	// Therefore, they must be sorted before being put inside the section
1468	libsOrdered := make([]string, len(f.dynLibraries))
1469	for key, val := range f.dynLibraries {
1470		if libsOrdered[val] != "" {
1471			continue
1472		}
1473		libsOrdered[val] = key
1474	}
1475
1476	for _, lib := range libsOrdered {
1477		// lib string is defined as base.a/mem.o or path/base.a/mem.o
1478		n := strings.Split(lib, "/")
1479		path := ""
1480		base := n[len(n)-2]
1481		mem := n[len(n)-1]
1482		if len(n) > 2 {
1483			path = lib[:len(lib)-len(base)-len(mem)-2]
1484
1485		}
1486		ldimpf = &XcoffLdImportFile64{
1487			Limpidpath: path,
1488			Limpidbase: base,
1489			Limpidmem:  mem,
1490		}
1491		off += uint64(len(ldimpf.Limpidpath) + len(ldimpf.Limpidbase) + len(ldimpf.Limpidmem) + 3) // + null delimiter
1492		importtab = append(importtab, ldimpf)
1493	}
1494
1495	hdr.Lnimpid = int32(len(importtab))
1496	hdr.Listlen = uint32(off - hdr.Limpoff)
1497	hdr.Lstoff = off
1498	hdr.Lstlen = stlen
1499
1500	/* Writing */
1501	ctxt.Out.SeekSet(int64(globalOff))
1502	binary.Write(ctxt.Out, ctxt.Arch.ByteOrder, hdr)
1503
1504	for _, s := range symtab {
1505		binary.Write(ctxt.Out, ctxt.Arch.ByteOrder, s)
1506
1507	}
1508	for _, r := range reloctab {
1509		binary.Write(ctxt.Out, ctxt.Arch.ByteOrder, r)
1510	}
1511	for _, f := range importtab {
1512		ctxt.Out.WriteString(f.Limpidpath)
1513		ctxt.Out.Write8(0)
1514		ctxt.Out.WriteString(f.Limpidbase)
1515		ctxt.Out.Write8(0)
1516		ctxt.Out.WriteString(f.Limpidmem)
1517		ctxt.Out.Write8(0)
1518	}
1519	for _, s := range strtab {
1520		ctxt.Out.Write16(s.size)
1521		ctxt.Out.WriteString(s.name)
1522		ctxt.Out.Write8(0) // null terminator
1523	}
1524
1525	f.loaderSize = off + uint64(stlen)
1526}
1527
1528// XCOFF assembling and writing file
1529
1530func (f *xcoffFile) writeFileHeader(ctxt *Link) {
1531	// File header
1532	f.xfhdr.Fmagic = U64_TOCMAGIC
1533	f.xfhdr.Fnscns = uint16(len(f.sections))
1534	f.xfhdr.Ftimedat = 0
1535
1536	if !*FlagS {
1537		f.xfhdr.Fsymptr = uint64(f.symtabOffset)
1538		f.xfhdr.Fnsyms = int32(f.symbolCount)
1539	}
1540
1541	if ctxt.BuildMode == BuildModeExe && ctxt.LinkMode == LinkInternal {
1542		ldr := ctxt.loader
1543		f.xfhdr.Fopthdr = AOUTHSZ_EXEC64
1544		f.xfhdr.Fflags = F_EXEC
1545
1546		// auxiliary header
1547		f.xahdr.Ovstamp = 1 // based on dump -o
1548		f.xahdr.Omagic = 0x10b
1549		copy(f.xahdr.Omodtype[:], "1L")
1550		entry := ldr.Lookup(*flagEntrySymbol, 0)
1551		f.xahdr.Oentry = uint64(ldr.SymValue(entry))
1552		f.xahdr.Osnentry = f.getXCOFFscnum(ldr.SymSect(entry))
1553		toc := ldr.Lookup("TOC", 0)
1554		f.xahdr.Otoc = uint64(ldr.SymValue(toc))
1555		f.xahdr.Osntoc = f.getXCOFFscnum(ldr.SymSect(toc))
1556
1557		f.xahdr.Oalgntext = int16(logBase2(int(XCOFFSECTALIGN)))
1558		f.xahdr.Oalgndata = 0x5
1559
1560		binary.Write(ctxt.Out, binary.BigEndian, &f.xfhdr)
1561		binary.Write(ctxt.Out, binary.BigEndian, &f.xahdr)
1562	} else {
1563		f.xfhdr.Fopthdr = 0
1564		binary.Write(ctxt.Out, binary.BigEndian, &f.xfhdr)
1565	}
1566
1567}
1568
1569func xcoffwrite(ctxt *Link) {
1570	ctxt.Out.SeekSet(0)
1571
1572	xfile.writeFileHeader(ctxt)
1573
1574	for _, sect := range xfile.sections {
1575		sect.write(ctxt)
1576	}
1577}
1578
1579// Generate XCOFF assembly file.
1580func asmbXcoff(ctxt *Link) {
1581	ctxt.Out.SeekSet(0)
1582	fileoff := int64(Segdwarf.Fileoff + Segdwarf.Filelen)
1583	fileoff = int64(Rnd(int64(fileoff), *FlagRound))
1584
1585	xfile.sectNameToScnum = make(map[string]int16)
1586
1587	// Add sections
1588	s := xfile.addSection(".text", Segtext.Vaddr, Segtext.Length, Segtext.Fileoff, STYP_TEXT)
1589	xfile.xahdr.Otextstart = s.Svaddr
1590	xfile.xahdr.Osntext = xfile.sectNameToScnum[".text"]
1591	xfile.xahdr.Otsize = s.Ssize
1592	xfile.sectText = s
1593
1594	segdataVaddr := Segdata.Vaddr
1595	segdataFilelen := Segdata.Filelen
1596	segdataFileoff := Segdata.Fileoff
1597	segbssFilelen := Segdata.Length - Segdata.Filelen
1598	if len(Segrelrodata.Sections) > 0 {
1599		// Merge relro segment to data segment as
1600		// relro data are inside data segment on AIX.
1601		segdataVaddr = Segrelrodata.Vaddr
1602		segdataFileoff = Segrelrodata.Fileoff
1603		segdataFilelen = Segdata.Vaddr + Segdata.Filelen - Segrelrodata.Vaddr
1604	}
1605
1606	s = xfile.addSection(".data", segdataVaddr, segdataFilelen, segdataFileoff, STYP_DATA)
1607	xfile.xahdr.Odatastart = s.Svaddr
1608	xfile.xahdr.Osndata = xfile.sectNameToScnum[".data"]
1609	xfile.xahdr.Odsize = s.Ssize
1610	xfile.sectData = s
1611
1612	s = xfile.addSection(".bss", segdataVaddr+segdataFilelen, segbssFilelen, 0, STYP_BSS)
1613	xfile.xahdr.Osnbss = xfile.sectNameToScnum[".bss"]
1614	xfile.xahdr.Obsize = s.Ssize
1615	xfile.sectBss = s
1616
1617	if ctxt.LinkMode == LinkExternal {
1618		var tbss *sym.Section
1619		for _, s := range Segdata.Sections {
1620			if s.Name == ".tbss" {
1621				tbss = s
1622				break
1623			}
1624		}
1625		s = xfile.addSection(".tbss", tbss.Vaddr, tbss.Length, 0, STYP_TBSS)
1626	}
1627
1628	// add dwarf sections
1629	for _, sect := range Segdwarf.Sections {
1630		xfile.addDwarfSection(sect)
1631	}
1632
1633	// add and write remaining sections
1634	if ctxt.LinkMode == LinkInternal {
1635		// Loader section
1636		if ctxt.BuildMode == BuildModeExe {
1637			Loaderblk(ctxt, uint64(fileoff))
1638			s = xfile.addSection(".loader", 0, xfile.loaderSize, uint64(fileoff), STYP_LOADER)
1639			xfile.xahdr.Osnloader = xfile.sectNameToScnum[".loader"]
1640
1641			// Update fileoff for symbol table
1642			fileoff += int64(xfile.loaderSize)
1643		}
1644	}
1645
1646	// Create Symbol table
1647	xfile.asmaixsym(ctxt)
1648
1649	if ctxt.LinkMode == LinkExternal {
1650		xfile.emitRelocations(ctxt, fileoff)
1651	}
1652
1653	// Write Symbol table
1654	xfile.symtabOffset = ctxt.Out.Offset()
1655	for _, s := range xfile.symtabSym {
1656		binary.Write(ctxt.Out, ctxt.Arch.ByteOrder, s)
1657	}
1658	// write string table
1659	xfile.stringTable.write(ctxt.Out)
1660
1661	// write headers
1662	xcoffwrite(ctxt)
1663}
1664
1665// emitRelocations emits relocation entries for go.o in external linking.
1666func (f *xcoffFile) emitRelocations(ctxt *Link, fileoff int64) {
1667	ctxt.Out.SeekSet(fileoff)
1668	for ctxt.Out.Offset()&7 != 0 {
1669		ctxt.Out.Write8(0)
1670	}
1671
1672	ldr := ctxt.loader
1673	// relocsect relocates symbols from first in section sect, and returns
1674	// the total number of relocations emitted.
1675	relocsect := func(sect *sym.Section, syms []loader.Sym, base uint64) uint32 {
1676		// ctxt.Logf("%s 0x%x\n", sect.Name, sect.Vaddr)
1677		// If main section has no bits, nothing to relocate.
1678		if sect.Vaddr >= sect.Seg.Vaddr+sect.Seg.Filelen {
1679			return 0
1680		}
1681		sect.Reloff = uint64(ctxt.Out.Offset())
1682		for i, s := range syms {
1683			if !ldr.AttrReachable(s) {
1684				continue
1685			}
1686			if uint64(ldr.SymValue(s)) >= sect.Vaddr {
1687				syms = syms[i:]
1688				break
1689			}
1690		}
1691		eaddr := int64(sect.Vaddr + sect.Length)
1692		for _, s := range syms {
1693			if !ldr.AttrReachable(s) {
1694				continue
1695			}
1696			if ldr.SymValue(s) >= int64(eaddr) {
1697				break
1698			}
1699
1700			// Compute external relocations on the go, and pass to Xcoffreloc1 to stream out.
1701			// Relocation must be ordered by address, so create a list of sorted indices.
1702			relocs := ldr.Relocs(s)
1703			sorted := make([]int, relocs.Count())
1704			for i := 0; i < relocs.Count(); i++ {
1705				sorted[i] = i
1706			}
1707			sort.Slice(sorted, func(i, j int) bool {
1708				return relocs.At(sorted[i]).Off() < relocs.At(sorted[j]).Off()
1709			})
1710
1711			for _, ri := range sorted {
1712				r := relocs.At(ri)
1713				rr, ok := extreloc(ctxt, ldr, s, r)
1714				if !ok {
1715					continue
1716				}
1717				if rr.Xsym == 0 {
1718					ldr.Errorf(s, "missing xsym in relocation")
1719					continue
1720				}
1721				if ldr.SymDynid(rr.Xsym) < 0 {
1722					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))
1723				}
1724				if !thearch.Xcoffreloc1(ctxt.Arch, ctxt.Out, ldr, s, rr, int64(uint64(ldr.SymValue(s)+int64(r.Off()))-base)) {
1725					ldr.Errorf(s, "unsupported obj reloc %d(%s)/%d to %s", r.Type(), r.Type(), r.Siz(), ldr.SymName(r.Sym()))
1726				}
1727			}
1728		}
1729		sect.Rellen = uint64(ctxt.Out.Offset()) - sect.Reloff
1730		return uint32(sect.Rellen) / RELSZ_64
1731	}
1732	sects := []struct {
1733		xcoffSect *XcoffScnHdr64
1734		segs      []*sym.Segment
1735	}{
1736		{f.sectText, []*sym.Segment{&Segtext}},
1737		{f.sectData, []*sym.Segment{&Segrelrodata, &Segdata}},
1738	}
1739	for _, s := range sects {
1740		s.xcoffSect.Srelptr = uint64(ctxt.Out.Offset())
1741		n := uint32(0)
1742		for _, seg := range s.segs {
1743			for _, sect := range seg.Sections {
1744				if sect.Name == ".text" {
1745					n += relocsect(sect, ctxt.Textp, 0)
1746				} else {
1747					n += relocsect(sect, ctxt.datap, 0)
1748				}
1749			}
1750		}
1751		s.xcoffSect.Snreloc += n
1752	}
1753
1754dwarfLoop:
1755	for i := 0; i < len(Segdwarf.Sections); i++ {
1756		sect := Segdwarf.Sections[i]
1757		si := dwarfp[i]
1758		if si.secSym() != loader.Sym(sect.Sym) ||
1759			ldr.SymSect(si.secSym()) != sect {
1760			panic("inconsistency between dwarfp and Segdwarf")
1761		}
1762		for _, xcoffSect := range f.sections {
1763			_, subtyp := xcoffGetDwarfSubtype(sect.Name)
1764			if xcoffSect.Sflags&0xF0000 == subtyp {
1765				xcoffSect.Srelptr = uint64(ctxt.Out.Offset())
1766				xcoffSect.Snreloc = relocsect(sect, si.syms, sect.Vaddr)
1767				continue dwarfLoop
1768			}
1769		}
1770		Errorf(nil, "emitRelocations: could not find %q section", sect.Name)
1771	}
1772}
1773
1774// xcoffCreateExportFile creates a file with exported symbols for
1775// -Wl,-bE option.
1776// ld won't export symbols unless they are listed in an export file.
1777func xcoffCreateExportFile(ctxt *Link) (fname string) {
1778	fname = filepath.Join(*flagTmpdir, "export_file.exp")
1779	var buf bytes.Buffer
1780
1781	ldr := ctxt.loader
1782	for s, nsym := loader.Sym(1), loader.Sym(ldr.NSym()); s < nsym; s++ {
1783		if !ldr.AttrCgoExport(s) {
1784			continue
1785		}
1786		extname := ldr.SymExtname(s)
1787		if !strings.HasPrefix(extname, "._cgoexp_") {
1788			continue
1789		}
1790		if ldr.IsFileLocal(s) {
1791			continue // Only export non-static symbols
1792		}
1793
1794		// Retrieve the name of the initial symbol
1795		// exported by cgo.
1796		// The corresponding Go symbol is:
1797		// _cgoexp_hashcode_symname.
1798		name := strings.SplitN(extname, "_", 4)[3]
1799
1800		buf.Write([]byte(name + "\n"))
1801	}
1802
1803	err := os.WriteFile(fname, buf.Bytes(), 0666)
1804	if err != nil {
1805		Errorf(nil, "WriteFile %s failed: %v", fname, err)
1806	}
1807
1808	return fname
1809}
1810