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.
10 "cmd/link/internal/loader"
11 "cmd/link/internal/sym"
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.
28 // Total amount of space to reserve at the start of the file
29 // for File Header, Auxiliary Header, and Section Headers.
31 XCOFFHDRRESERVE = FILHSZ_64 + AOUTHSZ_EXEC64 + SCNHSZ_64*23
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
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
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
58 U64_TOCMAGIC = 0767 // AIX 64-bit XCOFF
61 // Flags that describe the type of the object file.
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
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
125 // Flags defining the section type.
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
168 // Type representing all XCOFF symbols.
169 type xcoffSym interface {
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
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
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
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
234 Xftype uint8 // Source file string type
236 Xauxtype uint8 // Type of auxiliary entry
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
245 Xauxtype uint8 // Type of auxiliary entry
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
257 Xauxtype uint8 // Type of auxiliary entry
260 // DWARF Auxiliary Entry
261 type XcoffAuxDWARF64 struct {
262 Xscnlen uint64 // Length of this symbol section
264 Xauxtype uint8 // Type of auxiliary entry
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/
286 // Symbol type field.
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
298 // Storage-mapping class.
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
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
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
346 type xcoffLoaderSymbol struct {
352 type XcoffLdImportFile64 struct {
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
365 // xcoffLoaderReloc holds information about a relocation made by the loader.
366 type xcoffLoaderReloc struct {
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.
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
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
398 XCOFF_R_TOCU = 0x30 // Relative to TOC - high order bits
399 XCOFF_R_TOCL = 0x31 // Relative to TOC - low order bits
402 type XcoffLdStr64 struct {
407 // xcoffFile is used to build XCOFF file.
408 type xcoffFile struct {
411 sections []*XcoffScnHdr64
412 sectText *XcoffScnHdr64
413 sectData *XcoffScnHdr64
414 sectBss *XcoffScnHdr64
415 stringTable xcoffStringTable
416 sectNameToScnum map[string]int16
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
427 // Var used by XCOFF Generation algorithms
432 // xcoffStringTable is a XCOFF string table.
433 type xcoffStringTable struct {
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
444 // add adds string str to string table t.
445 func (t *xcoffStringTable) add(str string) int {
447 t.strings = append(t.strings, str)
448 t.stringsLen += len(str) + 1 // each string will have 0 appended to it
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 {
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
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{
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))
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)
490 // xcoffGetDwarfSubtype returns the XCOFF name of the DWARF section str
491 // and its subtype constant.
492 func xcoffGetDwarfSubtype(str string) (string, uint32) {
495 Exitf("unknown DWARF section name for XCOFF: %s", str)
496 case ".debug_abbrev":
497 return ".dwabrev", SSUBTYP_DWABREV
499 return ".dwinfo", SSUBTYP_DWINFO
501 return ".dwframe", SSUBTYP_DWFRAME
503 return ".dwline", SSUBTYP_DWLINE
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
517 // getXCOFFscnum returns the XCOFF section number of a Go section.
518 func (f *xcoffFile) getXCOFFscnum(sect *sym.Section) int16 {
521 return f.sectNameToScnum[".text"]
523 if sect.Name == ".noptrbss" || sect.Name == ".bss" {
524 return f.sectNameToScnum[".bss"]
526 if sect.Name == ".tbss" {
527 return f.sectNameToScnum[".tbss"]
529 return f.sectNameToScnum[".data"]
531 name, _ := xcoffGetDwarfSubtype(sect.Name)
532 return f.sectNameToScnum[name]
534 return f.sectNameToScnum[".data"]
536 Errorf(nil, "getXCOFFscnum not implemented for section %s", sect.Name)
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)
545 HEADR = int32(Rnd(XCOFFHDRRESERVE, XCOFFSECTALIGN))
546 if *FlagTextAddr != -1 {
547 Errorf(nil, "-T not available on AIX")
549 *FlagTextAddr = XCOFFTEXTBASE + int64(HEADR)
550 if *FlagRound != -1 {
551 Errorf(nil, "-R not available on AIX")
553 *FlagRound = int(XCOFFSECTALIGN)
559 // type records C_FILE information needed for genasmsym in XCOFF.
560 type xcoffSymSrcFile struct {
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
570 currDwscnoff = make(map[string]uint64) // Needed to create C_DWARF symbols
571 currSymSrcFile xcoffSymSrcFile
572 outerSymSize = make(map[string]int64)
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) {
581 // TODO: use CarrierSymByType
586 Errorf(nil, "unknown XCOFF outer symbol for type %s", stype.String())
587 case sym.SRODATA, sym.SRODATARELRO, sym.SFUNCTAB, sym.SSTRING:
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
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
604 outerSymSize["go:string.*"] = size
606 if !ctxt.DynlinkingGo() {
607 outerSymSize["go:func.*"] = size
609 case sym.SGOFUNCRELRO:
610 outerSymSize["go:funcrel.*"] = size
612 outerSymSize["runtime.gcbits.*"] = size
614 outerSymSize["runtime.pclntab"] = size
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)
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)
629 align = int32(Funcalign)
631 align = symalign(ldr, x)
634 return logBase2(int(align))
637 // logBase2 returns the log in base 2 of a.
638 func logBase2(a int) uint8 {
639 return uint8(bits.Len(uint(a)) - 1)
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.
648 // Currently, a new file is in fact a new package. It seems to be OK, but it might change
650 func (f *xcoffFile) writeSymbolNewFile(ctxt *Link, name string, firstEntry uint64, extnum int16) {
654 Noffset: uint32(f.stringTable.add(".file")),
657 Ntype: 0, // Go isn't inside predefined language.
661 currSymSrcFile.file = s
663 // Auxiliary entry for file name.
664 auxf := &XcoffAuxFile64{
665 Xoffset: uint32(f.stringTable.add(name)),
672 for _, sect := range Segdwarf.Sections {
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)))
684 // There is only one .FILE with external linking.
689 name, _ := xcoffGetDwarfSubtype(sect.Name)
691 Nvalue: currDwscnoff[sect.Name],
692 Noffset: uint32(f.stringTable.add(name)),
694 Nscnum: f.getXCOFFscnum(sect),
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))
704 if sect.Name == ".debug_frame" && ctxt.LinkMode != LinkExternal {
705 // CIE size must be added to the first package.
712 // update the DWARF section offset in this file
713 if sect.Name != ".debug_abbrev" {
714 currDwscnoff[sect.Name] += dwsize
717 // Auxiliary dwarf section
718 auxd := &XcoffAuxDWARF64{
727 // Check if extnum is in text.
728 // This is temporary and only here to check if this algorithm is correct.
730 Exitf("XCOFF symtab: A new file was detected with its first symbol not in .text")
733 currSymSrcFile.csectSymNb = uint64(f.symbolCount)
735 // No offset because no name
740 Ntype: 0, // check visibility ?
745 aux := &XcoffAuxCSect64{
747 Xsmtyp: XTY_SD | logBase2(Funcalign)<<3,
748 Xauxtype: _AUX_CSECT,
752 currSymSrcFile.csectAux = aux
753 currSymSrcFile.csectVAStart = int64(firstEntry)
754 currSymSrcFile.csectVAEnd = int64(firstEntry)
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) {
762 if currSymSrcFile.file == nil {
767 cfile := currSymSrcFile.file
769 cfile.Nvalue = 0xFFFFFFFFFFFFFFFF
771 cfile.Nvalue = uint64(f.symbolCount)
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)
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.
788 // Check if a new file is detected.
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")
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)))
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
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)))
825 name = ldr.SymExtname(x)
826 name = mangleABIName(ctxt, ldr, x, name)
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,
837 if ldr.IsFileLocal(x) || ldr.AttrVisibilityHidden(x) || ldr.AttrLocal(x) {
841 ldr.SetSymDynid(x, int32(xfile.symbolCount))
842 syms = append(syms, s)
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
852 // create auxiliary entries
853 a2 := &XcoffAuxFcn64{
854 Xfsize: uint32(ldr.SymSize(x)),
856 Xendndx: xfile.symbolCount + 3, // this symbol + 2 aux entries
859 syms = append(syms, a2)
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,
868 a4.Xsmtyp |= uint8(xcoffAlign(ldr, x, TextSym) << 3)
870 syms = append(syms, a4)
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
881 name := ldr.SymName(x)
882 if t == UndefinedSym {
883 name = ldr.SymExtname(x)
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)
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)
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,
907 ldr.SetSymDynid(x, int32(xfile.symbolCount))
908 syms = append(syms, s)
910 size := uint64(ldr.SymSize(x))
911 a4 := &XcoffAuxCSect64{
912 Xauxtype: _AUX_CSECT,
913 Xscnlenlo: uint32(size & 0xFFFFFFFF),
914 Xscnlenhi: uint32(size >> 32),
918 a4.Xsmtyp |= uint8(xcoffAlign(ldr, x, TextSym) << 3)
919 syms = append(syms, a4)
922 case DataSym, BSSSym:
925 Noffset: uint32(xfile.stringTable.add(name)),
926 Nvalue: uint64(ldr.SymValue(x)),
927 Nscnum: xfile.getXCOFFscnum(ldr.SymSect(x)),
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.
941 ldr.SetSymDynid(x, int32(xfile.symbolCount))
942 syms = append(syms, s)
944 // Create auxiliary entry
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.
950 size := uint64(ldr.SymSize(x))
951 a4 := &XcoffAuxCSect64{
952 Xauxtype: _AUX_CSECT,
953 Xscnlenlo: uint32(size & 0xFFFFFFFF),
954 Xscnlenhi: uint32(size >> 32),
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
966 } else if /*ty == sym.SDATA &&*/ strings.HasPrefix(ldr.SymName(x), "TOC.") && ctxt.IsExternal() {
968 } else if ldr.SymName(x) == "TOC" {
979 a4.Xsmtyp |= uint8(xcoffAlign(ldr, x, t) << 3)
981 syms = append(syms, a4)
984 if ty := ldr.SymType(x); ty != sym.SDYNIMPORT && ty != sym.SHOSTOBJ && ty != sym.SUNDEFEXT {
989 Noffset: uint32(xfile.stringTable.add(name)),
992 ldr.SetSymDynid(x, int32(xfile.symbolCount))
993 syms = append(syms, s)
995 a4 := &XcoffAuxCSect64{
996 Xauxtype: _AUX_CSECT,
998 Xsmtyp: XTY_ER | XTY_IMP,
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.
1008 syms = append(syms, a4)
1011 s := &XcoffSymEnt64{
1013 Noffset: uint32(xfile.stringTable.add(name)),
1014 Nscnum: xfile.getXCOFFscnum(ldr.SymSect(x)),
1015 Nvalue: uint64(ldr.SymValue(x)),
1019 ldr.SetSymDynid(x, int32(xfile.symbolCount))
1020 syms = append(syms, s)
1022 size := uint64(ldr.SymSize(x))
1023 a4 := &XcoffAuxCSect64{
1024 Xauxtype: _AUX_CSECT,
1027 Xscnlenlo: uint32(size & 0xFFFFFFFF),
1028 Xscnlenhi: uint32(size >> 32),
1031 syms = append(syms, a4)
1034 for _, s := range syms {
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) {
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)
1049 Errorf(nil, "unknown outer symbol with name %s", name)
1051 s := ldr.MakeSymbolUpdater(sym)
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)
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.
1074 s = ldr.Lookup(fmt.Sprintf("runtime.text.%d", n), 0)
1078 if ldr.SymType(s) == sym.STEXT {
1079 putaixsym(ctxt, s, TextSym)
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)
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.
1100 if ldr.AttrNotInSymbolTable(s) {
1103 if (name == "" || name[0] == '.') && !ldr.IsFileLocal(s) && name != ".TOC." {
1109 for s, nsym := loader.Sym(1), loader.Sym(ldr.NSym()); s < nsym; s++ {
1110 if !shouldBeInSymbolTable(s, ldr.SymName(s)) {
1113 st := ldr.SymType(s)
1115 case st == sym.STLSBSS:
1116 if ctxt.IsExternal() {
1117 putaixsym(ctxt, s, TLSSym)
1120 case st == sym.SBSS, st == sym.SNOPTRBSS, st == sym.SLIBFUZZER_8BIT_COUNTER:
1121 if ldr.AttrReachable(s) {
1124 ldr.Errorf(s, "should not be bss (size=%d type=%v special=%v)", len(data), ldr.SymType(s), ldr.AttrSpecial(s))
1126 putaixsym(ctxt, s, BSSSym)
1129 case st >= sym.SELFRXSECT && st < sym.SXREF: // data sections handled in dodata
1130 if ldr.AttrReachable(s) {
1131 putaixsym(ctxt, s, DataSym)
1134 case st == sym.SUNDEFEXT:
1135 putaixsym(ctxt, s, UndefinedSym)
1137 case st == sym.SDYNIMPORT:
1138 if ldr.AttrReachable(s) {
1139 putaixsym(ctxt, s, UndefinedSym)
1144 for _, s := range ctxt.Textp {
1145 putaixsym(ctxt, s, TextSym)
1148 if ctxt.Debugvlog != 0 || *flagN {
1149 ctxt.Logf("symsize = %d\n", uint32(symSize))
1151 xfile.updatePreviousFile(ctxt, true)
1154 func (f *xcoffFile) genDynSym(ctxt *Link) {
1156 var dynsyms []loader.Sym
1157 for s := loader.Sym(1); s < loader.Sym(ldr.NSym()); s++ {
1158 if !ldr.AttrReachable(s) {
1161 if t := ldr.SymType(s); t != sym.SHOSTOBJ && t != sym.SDYNIMPORT {
1164 dynsyms = append(dynsyms, s)
1167 for _, s := range dynsyms {
1168 f.adddynimpsym(ctxt, s)
1170 if _, ok := f.dynLibraries[ldr.SymDynimplib(s)]; !ok {
1171 f.dynLibraries[ldr.SymDynimplib(s)] = len(f.dynLibraries)
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.
1187 if ctxt.IsInternal() && ldr.SymDynimplib(s) == "" {
1188 ctxt.Errorf(s, "imported symbol must have a given library")
1191 sb := ldr.MakeSymbolUpdater(s)
1192 sb.SetReachable(true)
1193 sb.SetType(sym.SXCOFFTOC)
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))
1202 // Add loader symbol
1203 lds := &xcoffLoaderSymbol{
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.
1214 f.loaderSymbols = append(f.loaderSymbols, lds)
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
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.
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() {
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()))
1240 xldr := &xcoffLoaderReloc{
1245 var targType sym.SymKind
1247 targType = ldr.SymType(targ)
1252 ldr.Errorf(s, "unexpected .loader relocation to symbol: %s (type: %s)", ldr.SymName(targ), r.Type().String())
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
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 {
1266 ldr.Errorf(s, "unknown segment for .loader relocation with symbol %s", ldr.SymName(targ))
1269 xldr.symndx = 0 // .text
1271 if targType == sym.SBSS || targType == sym.SNOPTRBSS {
1272 xldr.symndx = 2 // .bss
1274 xldr.symndx = 1 // .data
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))
1283 xldr.rtype = 0x3F<<8 + XCOFF_R_POS
1287 xfile.loaderReloc = append(xfile.loaderReloc, xldr)
1292 func (ctxt *Link) doxcoff() {
1296 toc := ldr.CreateSymForUpdate("TOC", 0)
1297 toc.SetType(sym.SXCOFFTOC)
1298 toc.SetVisibilityHidden(true)
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")
1306 xfile.loaderSymbols = append(xfile.loaderSymbols, &xcoffLoaderSymbol{
1308 smtype: XTY_ENT | XTY_SD,
1312 xfile.genDynSym(ctxt)
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)
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")
1326 nsym := loader.Sym(ldr.NSym())
1327 for s := loader.Sym(1); s < nsym; s++ {
1328 if !ldr.AttrCgoExport(s) {
1331 if ldr.IsFileLocal(s) {
1332 panic("cgo_export on static symbol")
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)
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)
1354 // Currently, this section is created from scratch when assembling the XCOFF file
1355 // according to information retrieved in xfile object.
1357 // Create loader section and returns its size
1358 func Loaderblk(ctxt *Link, off uint64) {
1359 xfile.writeLdrScn(ctxt, off)
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
1369 // As the string table is updated in any loader subsection,
1370 // its length must be computed at the same time.
1374 hdr := &XcoffLdHdr64{
1376 Lsymoff: LDHDRSZ_64,
1381 for _, s := range f.loaderSymbols {
1382 lds := &XcoffLdSym64{
1383 Loffset: uint32(stlen + 2),
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))
1395 lds.Lifile = int32(f.dynLibraries[ldr.SymDynimplib(sym)] + 1)
1397 ldstr := &XcoffLdStr64{
1398 size: uint16(len(ldr.SymName(sym)) + 1), // + null terminator
1399 name: ldr.SymName(sym),
1401 stlen += uint32(2 + ldstr.size) // 2 = sizeof ldstr.size
1402 symtab = append(symtab, lds)
1403 strtab = append(strtab, ldstr)
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
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
1418 if r1.roff != r2.roff {
1419 return r1.roff < r2.roff
1421 if r1.rtype != r2.rtype {
1422 return r1.rtype < r2.rtype
1424 return r1.symndx < r2.symndx
1427 ep := ldr.Lookup(*flagEntrySymbol, 0)
1428 xldr := &XcoffLdRel64{
1429 Lvaddr: uint64(ldr.SymValue(ep)),
1431 Lrsecnm: f.getXCOFFscnum(ldr.SymSect(ep)),
1435 reloctab = append(reloctab, xldr)
1437 off += uint64(16 * len(f.loaderReloc))
1438 for _, r := range f.loaderReloc {
1441 panic("unexpected 0 sym value")
1443 xldr = &XcoffLdRel64{
1444 Lvaddr: uint64(ldr.SymValue(symp) + int64(r.roff)),
1449 if ldr.SymSect(symp) != nil {
1450 xldr.Lrsecnm = f.getXCOFFscnum(ldr.SymSect(symp))
1453 reloctab = append(reloctab, xldr)
1456 off += uint64(16 * len(dynimpreloc))
1457 reloctab = append(reloctab, dynimpreloc...)
1459 hdr.Lnreloc = int32(len(reloctab))
1463 // Default import: /usr/lib:/lib
1464 ldimpf := &XcoffLdImportFile64{
1465 Limpidpath: "/usr/lib:/lib",
1467 off += uint64(len(ldimpf.Limpidpath) + len(ldimpf.Limpidbase) + len(ldimpf.Limpidmem) + 3) // + null delimiter
1468 importtab = append(importtab, ldimpf)
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] != "" {
1478 libsOrdered[val] = key
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, "/")
1488 path = lib[:len(lib)-len(base)-len(mem)-2]
1491 ldimpf = &XcoffLdImportFile64{
1496 off += uint64(len(ldimpf.Limpidpath) + len(ldimpf.Limpidbase) + len(ldimpf.Limpidmem) + 3) // + null delimiter
1497 importtab = append(importtab, ldimpf)
1500 hdr.Lnimpid = int32(len(importtab))
1501 hdr.Listlen = uint32(off - hdr.Limpoff)
1506 ctxt.Out.SeekSet(int64(globalOff))
1507 binary.Write(ctxt.Out, ctxt.Arch.ByteOrder, hdr)
1509 for _, s := range symtab {
1510 binary.Write(ctxt.Out, ctxt.Arch.ByteOrder, s)
1513 for _, r := range reloctab {
1514 binary.Write(ctxt.Out, ctxt.Arch.ByteOrder, r)
1516 for _, f := range importtab {
1517 ctxt.Out.WriteString(f.Limpidpath)
1519 ctxt.Out.WriteString(f.Limpidbase)
1521 ctxt.Out.WriteString(f.Limpidmem)
1524 for _, s := range strtab {
1525 ctxt.Out.Write16(s.size)
1526 ctxt.Out.WriteString(s.name)
1527 ctxt.Out.Write8(0) // null terminator
1530 f.loaderSize = off + uint64(stlen)
1533 // XCOFF assembling and writing file
1535 func (f *xcoffFile) writeFileHeader(ctxt *Link) {
1537 f.xfhdr.Fmagic = U64_TOCMAGIC
1538 f.xfhdr.Fnscns = uint16(len(f.sections))
1539 f.xfhdr.Ftimedat = 0
1542 f.xfhdr.Fsymptr = uint64(f.symtabOffset)
1543 f.xfhdr.Fnsyms = int32(f.symbolCount)
1546 if ctxt.BuildMode == BuildModeExe && ctxt.LinkMode == LinkInternal {
1548 f.xfhdr.Fopthdr = AOUTHSZ_EXEC64
1549 f.xfhdr.Fflags = F_EXEC
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))
1562 f.xahdr.Oalgntext = int16(logBase2(int(XCOFFSECTALIGN)))
1563 f.xahdr.Oalgndata = 0x5
1565 binary.Write(ctxt.Out, binary.BigEndian, &f.xfhdr)
1566 binary.Write(ctxt.Out, binary.BigEndian, &f.xahdr)
1569 binary.Write(ctxt.Out, binary.BigEndian, &f.xfhdr)
1574 func xcoffwrite(ctxt *Link) {
1577 xfile.writeFileHeader(ctxt)
1579 for _, sect := range xfile.sections {
1584 // Generate XCOFF assembly file
1585 func asmbXcoff(ctxt *Link) {
1587 fileoff := int64(Segdwarf.Fileoff + Segdwarf.Filelen)
1588 fileoff = int64(Rnd(int64(fileoff), int64(*FlagRound)))
1590 xfile.sectNameToScnum = make(map[string]int16)
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
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
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
1617 s = xfile.addSection(".bss", segdataVaddr+segdataFilelen, segbssFilelen, 0, STYP_BSS)
1618 xfile.xahdr.Osnbss = xfile.sectNameToScnum[".bss"]
1619 xfile.xahdr.Obsize = s.Ssize
1622 if ctxt.LinkMode == LinkExternal {
1623 var tbss *sym.Section
1624 for _, s := range Segdata.Sections {
1625 if s.Name == ".tbss" {
1630 s = xfile.addSection(".tbss", tbss.Vaddr, tbss.Length, 0, STYP_TBSS)
1633 // add dwarf sections
1634 for _, sect := range Segdwarf.Sections {
1635 xfile.addDwarfSection(sect)
1638 // add and write remaining sections
1639 if ctxt.LinkMode == LinkInternal {
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"]
1646 // Update fileoff for symbol table
1647 fileoff += int64(xfile.loaderSize)
1651 // Create Symbol table
1652 xfile.asmaixsym(ctxt)
1654 if ctxt.LinkMode == LinkExternal {
1655 xfile.emitRelocations(ctxt, fileoff)
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)
1663 // write string table
1664 xfile.stringTable.write(ctxt.Out)
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 {
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 {
1686 sect.Reloff = uint64(ctxt.Out.Offset())
1687 for i, s := range syms {
1688 if !ldr.AttrReachable(s) {
1691 if uint64(ldr.SymValue(s)) >= sect.Vaddr {
1696 eaddr := int64(sect.Vaddr + sect.Length)
1697 for _, s := range syms {
1698 if !ldr.AttrReachable(s) {
1701 if ldr.SymValue(s) >= int64(eaddr) {
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++ {
1712 sort.Slice(sorted, func(i, j int) bool {
1713 return relocs.At(sorted[i]).Off() < relocs.At(sorted[j]).Off()
1716 for _, ri := range sorted {
1718 rr, ok := extreloc(ctxt, ldr, s, r)
1723 ldr.Errorf(s, "missing xsym in relocation")
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))
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()))
1734 sect.Rellen = uint64(ctxt.Out.Offset()) - sect.Reloff
1735 return uint32(sect.Rellen) / RELSZ_64
1738 xcoffSect *XcoffScnHdr64
1741 {f.sectText, []*sym.Segment{&Segtext}},
1742 {f.sectData, []*sym.Segment{&Segrelrodata, &Segdata}},
1744 for _, s := range sects {
1745 s.xcoffSect.Srelptr = uint64(ctxt.Out.Offset())
1747 for _, seg := range s.segs {
1748 for _, sect := range seg.Sections {
1749 if sect.Name == ".text" {
1750 n += relocsect(sect, ctxt.Textp, 0)
1752 n += relocsect(sect, ctxt.datap, 0)
1756 s.xcoffSect.Snreloc += n
1760 for i := 0; i < len(Segdwarf.Sections); i++ {
1761 sect := Segdwarf.Sections[i]
1763 if si.secSym() != loader.Sym(sect.Sym) ||
1764 ldr.SymSect(si.secSym()) != sect {
1765 panic("inconsistency between dwarfp and Segdwarf")
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)
1775 Errorf(nil, "emitRelocations: could not find %q section", sect.Name)
1779 // xcoffCreateExportFile creates a file with exported symbols for
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
1787 for s, nsym := loader.Sym(1), loader.Sym(ldr.NSym()); s < nsym; s++ {
1788 if !ldr.AttrCgoExport(s) {
1791 extname := ldr.SymExtname(s)
1792 if !strings.HasPrefix(extname, "._cgoexp_") {
1795 if ldr.IsFileLocal(s) {
1796 continue // Only export non-static symbols
1799 // Retrieve the name of the initial symbol
1801 // The corresponding Go symbol is:
1802 // _cgoexp_hashcode_symname.
1803 name := strings.SplitN(extname, "_", 4)[3]
1805 buf.Write([]byte(name + "\n"))
1808 err := ioutil.WriteFile(fname, buf.Bytes(), 0666)
1810 Errorf(nil, "WriteFile %s failed: %v", fname, err)