From 269e5319172bfb8774d19538e8dfc8ae0650ffec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Chigot?= Date: Fri, 28 Sep 2018 17:02:16 +0200 Subject: [PATCH] cmd/link: add AIX operating system This commit adds AIX operating system to cmd/link package for ppc64 architecture. Updates: #25893 Change-Id: I349e0a2658c31919b72117b62c4c9935c9af07c0 Reviewed-on: https://go-review.googlesource.com/c/138730 Run-TryBot: Ian Lance Taylor TryBot-Result: Gobot Gobot Reviewed-by: Ian Lance Taylor --- src/cmd/link/internal/ld/data.go | 25 + src/cmd/link/internal/ld/go.go | 7 +- src/cmd/link/internal/ld/lib.go | 15 +- src/cmd/link/internal/ld/main.go | 4 + src/cmd/link/internal/ld/sym.go | 2 +- src/cmd/link/internal/ld/xcoff.go | 1232 ++++++++++++++++++++++++++++ src/cmd/link/internal/ppc64/asm.go | 29 + src/cmd/link/internal/ppc64/obj.go | 4 + 8 files changed, 1315 insertions(+), 3 deletions(-) create mode 100644 src/cmd/link/internal/ld/xcoff.go diff --git a/src/cmd/link/internal/ld/data.go b/src/cmd/link/internal/ld/data.go index 3cc9e294d29..f424f1d17b2 100644 --- a/src/cmd/link/internal/ld/data.go +++ b/src/cmd/link/internal/ld/data.go @@ -314,6 +314,18 @@ func relocsym(ctxt *Link, s *sym.Symbol) { break } + // On AIX, if a relocated symbol is in .data, a second relocation + // must be done by the loader, as the section .data will be moved. + // The "default" symbol address is still needed by the loader so + // the current relocation can't be skipped. + // runtime.algarray is different because it will end up in .rodata section + if ctxt.HeadType == objabi.Haix && r.Sym.Sect.Seg == &Segdata && r.Sym.Name != "runtime.algarray" { + // It's not possible to make a loader relocation to a DWARF section. + // FIXME + if s.Sect.Seg != &Segdwarf { + xcoffaddloaderreloc(ctxt, s, r) + } + } o = Symaddr(r.Sym) + r.Add @@ -606,6 +618,7 @@ func dynrelocsym(ctxt *Link, s *sym.Symbol) { thearch.Adddynrel(ctxt, s, r) continue } + if r.Sym != nil && r.Sym.Type == sym.SDYNIMPORT || r.Type >= 256 { if r.Sym != nil && !r.Sym.Attr.Reachable() { Errorf(s, "dynamic relocation to unreachable symbol %s", r.Sym.Name) @@ -1329,6 +1342,14 @@ func (ctxt *Link) dodata() { gc.AddSym(s) datsize += s.Size } + // On AIX, TOC entries must be the last of .data + for _, s := range data[sym.SXCOFFTOC] { + s.Sect = sect + s.Type = sym.SDATA + datsize = aligndatsize(datsize, s) + s.Value = int64(uint64(datsize) - sect.Vaddr) + datsize += s.Size + } checkdatsize(ctxt, datsize, sym.SDATA) sect.Length = uint64(datsize) - sect.Vaddr gc.End(int64(sect.Length)) @@ -1688,6 +1709,10 @@ func (ctxt *Link) dodata() { } for _, sect := range Segdata.Sections { sect.Extnum = int16(n) + if ctxt.HeadType == objabi.Haix && (sect.Name == ".noptrdata" || sect.Name == ".bss") { + // On AIX, "noptr" sections are merged with their "ptr" section + continue + } n++ } for _, sect := range Segdwarf.Sections { diff --git a/src/cmd/link/internal/ld/go.go b/src/cmd/link/internal/ld/go.go index f2dd799922e..d6c6b53a44c 100644 --- a/src/cmd/link/internal/ld/go.go +++ b/src/cmd/link/internal/ld/go.go @@ -163,6 +163,10 @@ func loadcgo(ctxt *Link, file string, pkg string, p string) { } havedynamic = 1 } + if ctxt.HeadType == objabi.Haix { + xcoffadddynimpsym(ctxt, s) + } + continue case "cgo_import_static": @@ -317,7 +321,8 @@ func fieldtrack(ctxt *Link) { } func (ctxt *Link) addexport() { - if ctxt.HeadType == objabi.Hdarwin { + // TODO(aix) + if ctxt.HeadType == objabi.Hdarwin || ctxt.HeadType == objabi.Haix { return } diff --git a/src/cmd/link/internal/ld/lib.go b/src/cmd/link/internal/ld/lib.go index 2284c347dc5..0f5617246be 100644 --- a/src/cmd/link/internal/ld/lib.go +++ b/src/cmd/link/internal/ld/lib.go @@ -39,6 +39,7 @@ import ( "cmd/link/internal/loadelf" "cmd/link/internal/loadmacho" "cmd/link/internal/loadpe" + "cmd/link/internal/loadxcoff" "cmd/link/internal/objfile" "cmd/link/internal/sym" "crypto/sha1" @@ -1517,6 +1518,18 @@ func ldobj(ctxt *Link, f *bio.Reader, lib *sym.Library, length int64, pn string, return ldhostobj(ldpe, ctxt.HeadType, f, pkg, length, pn, file) } + if c1 == 0x01 && (c2 == 0xD7 || c2 == 0xF7) { + ldxcoff := func(ctxt *Link, f *bio.Reader, pkg string, length int64, pn string) { + textp, err := loadxcoff.Load(ctxt.Arch, ctxt.Syms, f, pkg, length, pn) + if err != nil { + Errorf(nil, "%v", err) + return + } + ctxt.Textp = append(ctxt.Textp, textp...) + } + return ldhostobj(ldxcoff, ctxt.HeadType, f, pkg, length, pn, file) + } + /* check the header */ line, err := f.ReadString('\n') if err != nil { @@ -2243,7 +2256,7 @@ func Entryvalue(ctxt *Link) int64 { if s.Type == 0 { return *FlagTextAddr } - if s.Type != sym.STEXT { + if ctxt.HeadType != objabi.Haix && s.Type != sym.STEXT { Errorf(s, "entry not text") } return s.Value diff --git a/src/cmd/link/internal/ld/main.go b/src/cmd/link/internal/ld/main.go index 2c5152f2e3d..b87ee8094fb 100644 --- a/src/cmd/link/internal/ld/main.go +++ b/src/cmd/link/internal/ld/main.go @@ -224,6 +224,10 @@ func Main(arch *sys.Arch, theArch Arch) { ctxt.dope() ctxt.windynrelocsyms() } + if ctxt.HeadType == objabi.Haix { + ctxt.doxcoff() + } + ctxt.addexport() thearch.Gentext(ctxt) // trampolines, call stubs, etc. ctxt.textbuildid() diff --git a/src/cmd/link/internal/ld/sym.go b/src/cmd/link/internal/ld/sym.go index 3aa90c17dc8..a487b5e5f6c 100644 --- a/src/cmd/link/internal/ld/sym.go +++ b/src/cmd/link/internal/ld/sym.go @@ -66,7 +66,7 @@ func (ctxt *Link) computeTLSOffset() { default: log.Fatalf("unknown thread-local storage offset for %v", ctxt.HeadType) - case objabi.Hplan9, objabi.Hwindows, objabi.Hjs: + case objabi.Hplan9, objabi.Hwindows, objabi.Hjs, objabi.Haix: break /* diff --git a/src/cmd/link/internal/ld/xcoff.go b/src/cmd/link/internal/ld/xcoff.go new file mode 100644 index 00000000000..f06b4985944 --- /dev/null +++ b/src/cmd/link/internal/ld/xcoff.go @@ -0,0 +1,1232 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package ld + +import ( + "bytes" + "cmd/internal/objabi" + "cmd/link/internal/sym" + "encoding/binary" + "strings" +) + +// This file handles all algorithms related to XCOFF files generation. +// Most of them are adaptations of the ones in cmd/link/internal/pe.go +// as PE and XCOFF are based on COFF files. +// XCOFF files generated are 64 bits. + +// Total amount of space to reserve at the start of the file +// for FileHeader, Auxiliary Header, and Section Headers. +// May waste some. +// Based on 24(fhdr) + 120(ahdr) + 23(max sections number) * 72(scnhdr) +const ( + XCOFFHDRRESERVE = FILHSZ_64 + AOUTHSZ_EXEC64 + SCNHSZ_64*23 +) + +const ( + XCOFFSECTALIGN int64 = 32 // base on dump -o + XCOFFBASE = 0x100000000 // Address on 64 bits must start at this value. +) + +// File Header +type XcoffFileHdr64 struct { + Fmagic uint16 // Target machine + Fnscns uint16 // Number of sections + Ftimedat int32 // Time and date of file creation + Fsymptr uint64 // Byte offset to symbol table start + Fopthdr uint16 // Number of bytes in optional header + Fflags uint16 // Flags + Fnsyms int32 // Number of entries in symbol table +} + +const ( + U64_TOCMAGIC = 0767 // AIX 64-bit XCOFF +) + +// Flags that describe the type of the object file. +const ( + F_RELFLG = 0x0001 + F_EXEC = 0x0002 + F_LNNO = 0x0004 + F_FDPR_PROF = 0x0010 + F_FDPR_OPTI = 0x0020 + F_DSA = 0x0040 + F_VARPG = 0x0100 + F_DYNLOAD = 0x1000 + F_SHROBJ = 0x2000 + F_LOADONLY = 0x4000 +) + +// Auxiliary Header +type XcoffAoutHdr64 struct { + Omagic int16 // Flags - Ignored If Vstamp Is 1 + Ovstamp int16 // Version + Odebugger uint32 // Reserved For Debugger + Otextstart uint64 // Virtual Address Of Text + Odatastart uint64 // Virtual Address Of Data + Otoc uint64 // Toc Address + Osnentry int16 // Section Number For Entry Point + Osntext int16 // Section Number For Text + Osndata int16 // Section Number For Data + Osntoc int16 // Section Number For Toc + Osnloader int16 // Section Number For Loader + Osnbss int16 // Section Number For Bss + Oalgntext int16 // Max Text Alignment + Oalgndata int16 // Max Data Alignment + Omodtype [2]byte // Module Type Field + Ocpuflag uint8 // Bit Flags - Cputypes Of Objects + Ocputype uint8 // Reserved for CPU type + Otextpsize uint8 // Requested text page size + Odatapsize uint8 // Requested data page size + Ostackpsize uint8 // Requested stack page size + Oflags uint8 // Flags And TLS Alignment + Otsize uint64 // Text Size In Bytes + Odsize uint64 // Data Size In Bytes + Obsize uint64 // Bss Size In Bytes + Oentry uint64 // Entry Point Address + Omaxstack uint64 // Max Stack Size Allowed + Omaxdata uint64 // Max Data Size Allowed + Osntdata int16 // Section Number For Tdata Section + Osntbss int16 // Section Number For Tbss Section + Ox64flags uint16 // Additional Flags For 64-Bit Objects + Oresv3a int16 // Reserved + Oresv3 [2]int32 // Reserved + +} + +// Section Header +type XcoffScnHdr64 struct { + Sname [8]byte // Section Name + Spaddr uint64 // Physical Address + Svaddr uint64 // Virtual Address + Ssize uint64 // Section Size + Sscnptr uint64 // File Offset To Raw Data + Srelptr uint64 // File Offset To Relocation + Slnnoptr uint64 // File Offset To Line Numbers + Snreloc uint32 // Number Of Relocation Entries + Snlnno uint32 // Number Of Line Number Entries + Sflags uint32 // flags +} + +// Flags defining the section type. +const ( + STYP_DWARF = 0x0010 + STYP_TEXT = 0x0020 + STYP_DATA = 0x0040 + STYP_BSS = 0x0080 + STYP_EXCEPT = 0x0100 + STYP_INFO = 0x0200 + STYP_TDATA = 0x0400 + STYP_TBSS = 0x0800 + STYP_LOADER = 0x1000 + STYP_DEBUG = 0x2000 + STYP_TYPCHK = 0x4000 + STYP_OVRFLO = 0x8000 +) +const ( + SSUBTYP_DWINFO = 0x10000 // DWARF info section + SSUBTYP_DWLINE = 0x20000 // DWARF line-number section + SSUBTYP_DWPBNMS = 0x30000 // DWARF public names section + SSUBTYP_DWPBTYP = 0x40000 // DWARF public types section + SSUBTYP_DWARNGE = 0x50000 // DWARF aranges section + SSUBTYP_DWABREV = 0x60000 // DWARF abbreviation section + SSUBTYP_DWSTR = 0x70000 // DWARF strings section + SSUBTYP_DWRNGES = 0x80000 // DWARF ranges section + SSUBTYP_DWLOC = 0x90000 // DWARF location lists section + SSUBTYP_DWFRAME = 0xA0000 // DWARF frames section + SSUBTYP_DWMAC = 0xB0000 // DWARF macros section +) + +// Headers size +const ( + FILHSZ_32 = 20 + FILHSZ_64 = 24 + AOUTHSZ_EXEC32 = 72 + AOUTHSZ_EXEC64 = 120 + SCNHSZ_32 = 40 + SCNHSZ_64 = 72 + LDHDRSZ_32 = 32 + LDHDRSZ_64 = 56 + LDSYMSZ_64 = 24 +) + +// Symbol Table Entry +type XcoffSymEnt64 struct { + Nvalue uint64 // Symbol value + Noffset uint32 // Offset of the name in string table or .debug section + Nscnum int16 // Section number of symbol + Ntype uint16 // Basic and derived type specification + Nsclass uint8 // Storage class of symbol + Nnumaux int8 // Number of auxiliary entries +} + +const SYMESZ = 18 + +const ( + // Nscnum + N_DEBUG = -2 + N_ABS = -1 + N_UNDEF = 0 + + //Ntype + SYM_V_INTERNAL = 0x1000 + SYM_V_HIDDEN = 0x2000 + SYM_V_PROTECTED = 0x3000 + SYM_V_EXPORTED = 0x4000 + SYM_TYPE_FUNC = 0x0020 // is function +) + +// Storage Class. +const ( + C_NULL = 0 // Symbol table entry marked for deletion + C_EXT = 2 // External symbol + C_STAT = 3 // Static symbol + C_BLOCK = 100 // Beginning or end of inner block + C_FCN = 101 // Beginning or end of function + C_FILE = 103 // Source file name and compiler information + C_HIDEXT = 107 // Unnamed external symbol + C_BINCL = 108 // Beginning of include file + C_EINCL = 109 // End of include file + C_WEAKEXT = 111 // Weak external symbol + C_DWARF = 112 // DWARF symbol + C_GSYM = 128 // Global variable + C_LSYM = 129 // Automatic variable allocated on stack + C_PSYM = 130 // Argument to subroutine allocated on stack + C_RSYM = 131 // Register variable + C_RPSYM = 132 // Argument to function or procedure stored in register + C_STSYM = 133 // Statically allocated symbol + C_BCOMM = 135 // Beginning of common block + C_ECOML = 136 // Local member of common block + C_ECOMM = 137 // End of common block + C_DECL = 140 // Declaration of object + C_ENTRY = 141 // Alternate entry + C_FUN = 142 // Function or procedure + C_BSTAT = 143 // Beginning of static block + C_ESTAT = 144 // End of static block + C_GTLS = 145 // Global thread-local variable + C_STTLS = 146 // Static thread-local variable +) + +// File Auxiliary Entry +type XcoffAuxFile64 struct { + Xfname [8]byte // Name or offset inside string table + Xftype uint8 // Source file string type + Xauxtype uint8 // Type of auxiliary entry +} + +// Function Auxiliary Entry +type XcoffAuxFcn64 struct { + Xlnnoptr uint64 // File pointer to line number + Xfsize uint32 // Size of function in bytes + Xendndx uint32 // Symbol table index of next entry + Xpad uint8 // Unused + Xauxtype uint8 // Type of auxiliary entry +} + +// csect Auxiliary Entry. +type XcoffAuxCSect64 struct { + Xscnlenlo uint32 // Lower 4 bytes of length or symbol table index + Xparmhash uint32 // Offset of parameter type-check string + Xsnhash uint16 // .typchk section number + Xsmtyp uint8 // Symbol alignment and type + Xsmclas uint8 // Storage-mapping class + Xscnlenhi uint32 // Upper 4 bytes of length or symbol table index + Xpad uint8 // Unused + Xauxtype uint8 // Type of auxiliary entry +} + +// Auxiliary type +const ( + _AUX_EXCEPT = 255 + _AUX_FCN = 254 + _AUX_SYM = 253 + _AUX_FILE = 252 + _AUX_CSECT = 251 + _AUX_SECT = 250 +) + +// Xftype field +const ( + XFT_FN = 0 // Source File Name + XFT_CT = 1 // Compile Time Stamp + XFT_CV = 2 // Compiler Version Number + XFT_CD = 128 // Compiler Defined Information/ + +) + +// Symbol type field. +const ( + XTY_ER = 0 // External reference + XTY_SD = 1 // Section definition + XTY_LD = 2 // Label definition + XTY_CM = 3 // Common csect definition + XTY_WK = 0x8 // Weak symbol + XTY_EXP = 0x10 // Exported symbol + XTY_ENT = 0x20 // Entry point symbol + XTY_IMP = 0x40 // Imported symbol +) + +// Storage-mapping class. +const ( + XMC_PR = 0 // Program code + XMC_RO = 1 // Read-only constant + XMC_DB = 2 // Debug dictionary table + XMC_TC = 3 // TOC entry + XMC_UA = 4 // Unclassified + XMC_RW = 5 // Read/Write data + XMC_GL = 6 // Global linkage + XMC_XO = 7 // Extended operation + XMC_SV = 8 // 32-bit supervisor call descriptor + XMC_BS = 9 // BSS class + XMC_DS = 10 // Function descriptor + XMC_UC = 11 // Unnamed FORTRAN common + XMC_TC0 = 15 // TOC anchor + XMC_TD = 16 // Scalar data entry in the TOC + XMC_SV64 = 17 // 64-bit supervisor call descriptor + XMC_SV3264 = 18 // Supervisor call descriptor for both 32-bit and 64-bit + XMC_TL = 20 // Read/Write thread-local data + XMC_UL = 21 // Read/Write thread-local data (.tbss) + XMC_TE = 22 // TOC entry +) + +// Loader Header +type XcoffLdHdr64 struct { + Lversion int32 // Loader section version number + Lnsyms int32 // Number of symbol table entries + Lnreloc int32 // Number of relocation table entries + Listlen uint32 // Length of import file ID string table + Lnimpid int32 // Number of import file IDs + Lstlen uint32 // Length of string table + Limpoff uint64 // Offset to start of import file IDs + Lstoff uint64 // Offset to start of string table + Lsymoff uint64 // Offset to start of symbol table + Lrldoff uint64 // Offset to start of relocation entries +} + +// Loader Symbol +type XcoffLdSym64 struct { + Lvalue uint64 // Address field + Loffset uint32 // Byte offset into string table of symbol name + Lscnum int16 // Section number containing symbol + Lsmtype int8 // Symbol type, export, import flags + Lsmclas int8 // Symbol storage class + Lifile int32 // Import file ID; ordinal of import file IDs + Lparm uint32 // Parameter type-check field +} + +type XcoffLdImportFile64 struct { + Limpidpath string + Limpidbase string + Limpidmem string +} + +type XcoffLdRel64 struct { + Lvaddr uint64 // Address Field + Lrtype uint16 // Relocation Size and Type + Lrsecnm int16 // Section Number being relocated + Lsymndx int32 // Loader-Section symbol table index +} + +const ( + XCOFF_R_POS = 0x00 // A(sym) Positive Relocation +) + +type XcoffLdStr64 struct { + size uint16 + name string +} + +// xcoffFile is used to build XCOFF file. +type xcoffFile struct { + xfhdr XcoffFileHdr64 + xahdr XcoffAoutHdr64 + sections []*XcoffScnHdr64 + stringTable xcoffStringTable + textSect *XcoffScnHdr64 + dataSect *XcoffScnHdr64 + bssSect *XcoffScnHdr64 + loaderSect *XcoffScnHdr64 + symtabOffset int64 // offset to the start of symbol table + symbolCount uint32 // number of symbol table records written + dynLibraries map[string]int // Dynamic libraries in .loader section. The integer represents its import file number (- 1) + dynSymbols []*sym.Symbol // Dynamic symbols in .loader section + loaderReloc []*XcoffLdRel64 // Reloc that must be made inside loader +} + +// Those values will latter be computed in XcoffInit +var ( + XCOFFFILEHDR int + XCOFFSECTHDR int +) + +// Var used by XCOFF Generation algorithms +var ( + xfile xcoffFile + loaderOff uint64 + loaderSize uint64 +) + +// xcoffStringTable is a XCOFF string table. +type xcoffStringTable struct { + strings []string + stringsLen int +} + +// size returns size of string table t. +func (t *xcoffStringTable) size() int { + // string table starts with 4-byte length at the beginning + return t.stringsLen + 4 +} + +// add adds string str to string table t. +func (t *xcoffStringTable) add(str string) int { + off := t.size() + t.strings = append(t.strings, str) + t.stringsLen += len(str) + 1 // each string will have 0 appended to it + return off +} + +// write writes string table t into the output file. +func (t *xcoffStringTable) write(out *OutBuf) { + out.Write32(uint32(t.size())) + for _, s := range t.strings { + out.WriteString(s) + out.Write8(0) + } +} + +// write writes XCOFF section sect into the output file. +func (sect *XcoffScnHdr64) write(ctxt *Link) { + binary.Write(ctxt.Out, binary.BigEndian, sect) + ctxt.Out.Write32(0) // Add 4 empty bytes at the end to match alignment +} + +// addSection adds section to the XCOFF file f. +func (f *xcoffFile) addSection(s *sym.Section) *XcoffScnHdr64 { + sect := &XcoffScnHdr64{ + Spaddr: s.Vaddr, + Svaddr: s.Vaddr, + Ssize: s.Length, + Sscnptr: s.Seg.Fileoff + s.Vaddr - s.Seg.Vaddr, + } + copy(sect.Sname[:], s.Name) // copy string to [8]byte ( pb if len(name) > 8 ) + f.sections = append(f.sections, sect) + return sect +} + +// addLoaderSection adds the loader section to the XCOFF file f. +func (f *xcoffFile) addLoaderSection(size uint64, off uint64) *XcoffScnHdr64 { + sect := &XcoffScnHdr64{ + Ssize: size, + Sscnptr: off, + Sflags: STYP_LOADER, + } + copy(sect.Sname[:], ".loader") // copy string to [8]byte ( pb if len(name) > 8 + f.xahdr.Osnloader = int16(len(f.sections) + 1) + f.sections = append(f.sections, sect) + f.loaderSect = sect + return sect +} + +// addDwarfSection adds a dwarf section to the XCOFF file f. +// This function is similar to addSection, but Dwarf section names +// must be modified to conventional names and they are various subtypes. +func (f *xcoffFile) addDwarfSection(s *sym.Section) *XcoffScnHdr64 { + sect := &XcoffScnHdr64{ + Ssize: s.Length, + Sscnptr: s.Seg.Fileoff + s.Vaddr - s.Seg.Vaddr, + Sflags: STYP_DWARF, + } + newName, subtype := xcoffGetDwarfSubtype(s.Name) + copy(sect.Sname[:], newName) + sect.Sflags |= subtype + f.sections = append(f.sections, sect) + return sect +} + +// xcoffGetDwarfSubtype returns the XCOFF name of the DWARF section str +// and its subtype constant. +func xcoffGetDwarfSubtype(str string) (string, uint32) { + switch str { + default: + Exitf("unknown DWARF section name for XCOFF: %s", str) + case ".debug_abbrev": + return ".dwabrev", SSUBTYP_DWABREV + case ".debug_info": + return ".dwinfo", SSUBTYP_DWINFO + case ".debug_frame": + return ".dwframe", SSUBTYP_DWFRAME + case ".debug_line": + return ".dwline", SSUBTYP_DWLINE + case ".debug_loc": + return ".dwloc", SSUBTYP_DWLOC + case ".debug_pubnames": + return ".dwpbnms", SSUBTYP_DWPBNMS + case ".debug_pubtypes": + return ".dwpbtyp", SSUBTYP_DWPBTYP + case ".debug_ranges": + return ".dwrnge", SSUBTYP_DWRNGES + } + // never used + return "", 0 +} + +// Xcoffinit initialised some internal value and setups +// already known header information +func Xcoffinit(ctxt *Link) { + xfile.dynLibraries = make(map[string]int) + + XCOFFFILEHDR = int(Rnd(XCOFFHDRRESERVE, XCOFFSECTALIGN)) + XCOFFSECTHDR = int(Rnd(int64(XCOFFFILEHDR), XCOFFSECTALIGN)) + + HEADR = int32(XCOFFFILEHDR) + if *FlagTextAddr != -1 { + Errorf(nil, "-T not available on AIX") + } + *FlagTextAddr = XCOFFBASE + int64(XCOFFSECTHDR) + *FlagDataAddr = 0 + if *FlagRound != -1 { + Errorf(nil, "-R not available on AIX") + } + *FlagRound = int(XCOFFSECTALIGN) + +} + +// SYMBOL TABLE + +// type records C_FILE information needed for genasmsym in XCOFF. +type xcoffSymSrcFile struct { + name string + fileSymNb uint32 // Symbol number of this C_FILE + csectSymNb uint64 // Symbol number for the current .csect + csectSize int64 +} + +var ( + currDwscnoff = make(map[string]uint64) // Needed to create C_DWARF symbols + currSymSrcFile xcoffSymSrcFile +) + +// writeSymbol writes a symbol or an auxiliary symbol entry on ctxt.out. +func (f *xcoffFile) writeSymbol(out *OutBuf, byteOrder binary.ByteOrder, sym interface{}) { + binary.Write(out, byteOrder, sym) + f.symbolCount++ +} + +// Write symbols needed when a new file appared : +// - a C_FILE with one auxiliary entry for its name +// - C_DWARF symbols to provide debug information +// - a C_HIDEXT which will be a csect containing all of its functions +// It needs several parameters to create .csect symbols such as its entry point and its section number. +// +// Currently, a new file is in fact a new package. It seems to be OK, but it might change +// in the future. +func (f *xcoffFile) writeSymbolNewFile(ctxt *Link, name string, firstEntry uint64, extnum int16) { + /* C_FILE */ + s := &XcoffSymEnt64{ + Noffset: uint32(f.stringTable.add(".file")), + Nsclass: C_FILE, + Nscnum: N_DEBUG, + Ntype: 0, // Go isn't inside predefined language. + Nnumaux: 1, + } + f.writeSymbol(ctxt.Out, ctxt.Arch.ByteOrder, s) + + // Auxiliary entry for file name. + ctxt.Out.Write32(0) + ctxt.Out.Write32(uint32(f.stringTable.add(name))) + ctxt.Out.Write32(0) // 6 bytes empty + ctxt.Out.Write16(0) + ctxt.Out.Write8(XFT_FN) + ctxt.Out.Write16(0) // 2 bytes empty + ctxt.Out.Write8(_AUX_FILE) + f.symbolCount++ + + /* Dwarf */ + for _, sect := range Segdwarf.Sections { + // Find the size of this corresponding package DWARF compilation unit. + // This size is set during DWARF generation (see dwarf.go). + dwsize := getDwsectCUSize(sect.Name, name) + // .debug_abbrev is commun to all packages and not found with the previous function + if sect.Name == ".debug_abbrev" { + s := ctxt.Syms.Lookup(sect.Name, 0) + dwsize = uint64(s.Size) + } + + // get XCOFF name + name, _ := xcoffGetDwarfSubtype(sect.Name) + s := &XcoffSymEnt64{ + Nvalue: currDwscnoff[sect.Name], + Noffset: uint32(f.stringTable.add(name)), + Nsclass: C_DWARF, + Nscnum: sect.Extnum, + Nnumaux: 1, + } + f.writeSymbol(ctxt.Out, ctxt.Arch.ByteOrder, s) + + // update the DWARF section offset in this file + if sect.Name != ".debug_abbrev" { + currDwscnoff[sect.Name] += dwsize + } + + // Auxiliary dwarf section + ctxt.Out.Write64(dwsize) // section length + ctxt.Out.Write64(0) // nreloc + ctxt.Out.Write8(0) // pad + ctxt.Out.Write8(_AUX_SECT) + f.symbolCount++ + } + + /* .csect */ + // Check if extnum is in text. + // This is temporary and only here to check if this algorithm is correct. + if extnum != 1 { + Exitf("XCOFF symtab: A new file was detected with its first symbol not in .text") + } + + currSymSrcFile.csectSymNb = uint64(f.symbolCount) + currSymSrcFile.csectSize = 0 + + // No offset because no name + s = &XcoffSymEnt64{ + Nvalue: firstEntry, + Nscnum: extnum, + Nsclass: C_HIDEXT, + Ntype: 0, // check visibility ? + Nnumaux: 1, + } + f.writeSymbol(ctxt.Out, ctxt.Arch.ByteOrder, s) + + aux := &XcoffAuxCSect64{ + Xsmclas: XMC_PR, + Xsmtyp: XTY_SD | 5<<3, // align = 5 + Xauxtype: _AUX_CSECT, + } + f.writeSymbol(ctxt.Out, ctxt.Arch.ByteOrder, aux) + +} + +// Update values for the previous package. +// - Svalue of the C_FILE symbol: if it is the last one, this Svalue must be -1 +// - Xsclen of the csect symbol. +func (f *xcoffFile) updatePreviousFile(ctxt *Link, last bool) { + // first file + if currSymSrcFile.fileSymNb == 0 { + return + } + + prevOff := f.symtabOffset + int64(currSymSrcFile.fileSymNb*SYMESZ) + currOff := ctxt.Out.Offset() + + // Update C_FILE + ctxt.Out.SeekSet(prevOff) + if last { + ctxt.Out.Write64(0xFFFFFFFFFFFFFFFF) + } else { + ctxt.Out.Write64(uint64(f.symbolCount)) + } + + // update csect scnlen in this auxiliary entry + prevOff = f.symtabOffset + int64((currSymSrcFile.csectSymNb+1)*SYMESZ) + ctxt.Out.SeekSet(prevOff) + ctxt.Out.Write32(uint32(currSymSrcFile.csectSize & 0xFFFFFFFF)) + prevOff += 12 + ctxt.Out.SeekSet(prevOff) + ctxt.Out.Write32(uint32(currSymSrcFile.csectSize >> 32)) + + ctxt.Out.SeekSet(currOff) + +} + +// Write symbol representing a .text function. +// The symbol table is split with C_FILE corresponding to each package +// and not to each source file as it should be. +func (f *xcoffFile) writeSymbolFunc(ctxt *Link, x *sym.Symbol) []interface{} { + // New XCOFF symbols which will be written. + syms := []interface{}{} + + // Check if a new file is detected. + if x.File == "" { // Undefined global symbol + // If this happens, the algorithme must be redone. + if currSymSrcFile.name != "" { + Exitf("undefined global symbol found inside another file") + } + } else { + // Current file has changed. New C_FILE, C_DWARF, etc must be generated. + if currSymSrcFile.name != x.File { + // update previous file values + xfile.updatePreviousFile(ctxt, false) + currSymSrcFile.name = x.File + currSymSrcFile.fileSymNb = f.symbolCount + f.writeSymbolNewFile(ctxt, x.File, uint64(x.Value), x.Sect.Extnum) + } + } + + s := &XcoffSymEnt64{ + Nsclass: C_EXT, + Noffset: uint32(xfile.stringTable.add(x.Name)), + Nvalue: uint64(x.Value), + Nscnum: x.Sect.Extnum, + Ntype: SYM_TYPE_FUNC, + Nnumaux: 2, + } + + if x.Version != 0 || x.Attr.VisibilityHidden() || x.Attr.Local() { + s.Nsclass = C_HIDEXT + } + + syms = append(syms, s) + + // Update current csect size + currSymSrcFile.csectSize += x.Size + + // create auxiliary entries + a2 := &XcoffAuxFcn64{ + Xfsize: uint32(x.Size), + Xlnnoptr: 0, // TODO + Xendndx: xfile.symbolCount + 3, // this symbol + 2 aux entries + Xauxtype: _AUX_FCN, + } + syms = append(syms, a2) + + a4 := &XcoffAuxCSect64{ + Xscnlenlo: uint32(currSymSrcFile.csectSymNb & 0xFFFFFFFF), + Xscnlenhi: uint32(currSymSrcFile.csectSymNb >> 32), + Xsmclas: XMC_PR, // Program Code + Xsmtyp: XTY_LD, // label definition (based on C) + Xauxtype: _AUX_CSECT, + } + syms = append(syms, a4) + return syms +} + +// put function used by genasmsym to write symbol table +func putaixsym(ctxt *Link, x *sym.Symbol, str string, t SymbolType, addr int64, go_ *sym.Symbol) { + + // All XCOFF symbols generated by this GO symbols + // Can be a symbol entry or a auxiliary entry + syms := []interface{}{} + + switch t { + default: + return + + case TextSym: + if x.FuncInfo != nil { + // Function within a file + syms = xfile.writeSymbolFunc(ctxt, x) + } else { + // Only runtime.text and runtime.etext come through this way + if x.Name != "runtime.text" && x.Name != "runtime.etext" && x.Name != "go.buildid" { + Exitf("putaixsym: unknown text symbol %s", x.Name) + } + s := &XcoffSymEnt64{ + Nsclass: C_HIDEXT, + Noffset: uint32(xfile.stringTable.add(str)), + Nvalue: uint64(x.Value), + Nscnum: x.Sect.Extnum, + Ntype: SYM_TYPE_FUNC, + Nnumaux: 1, + } + syms = append(syms, s) + + size := uint64(x.Size) + a4 := &XcoffAuxCSect64{ + Xauxtype: _AUX_CSECT, + Xscnlenlo: uint32(size & 0xFFFFFFFF), + Xscnlenhi: uint32(size >> 32), + Xsmclas: XMC_PR, + Xsmtyp: XTY_SD, + } + syms = append(syms, a4) + + } + + case DataSym, BSSSym: + s := &XcoffSymEnt64{ + Nsclass: C_EXT, + Noffset: uint32(xfile.stringTable.add(str)), + Nvalue: uint64(x.Value), + Nscnum: x.Sect.Extnum, + Nnumaux: 1, + } + + if x.Version != 0 || x.Attr.VisibilityHidden() || x.Attr.Local() { + // There is more symbols in the case of a global data + // which are related to the assembly generated + // to access such symbols. + // But as Golang as its own way to check if a symbol is + // global or local (the capital letter), we don't need to + // implement them yet. + s.Nsclass = C_HIDEXT + } + + syms = append(syms, s) + + // Create auxiliary entry + + // Normally, size should be the size of csect containing all + // the data and bss symbols of one file/package. + // However, it's easier to just have a csect for each symbol. + // It might change + size := uint64(x.Size) + a4 := &XcoffAuxCSect64{ + Xauxtype: _AUX_CSECT, + Xscnlenlo: uint32(size & 0xFFFFFFFF), + Xscnlenhi: uint32(size >> 32), + } + // Read only data + if x.Type >= sym.STYPE && x.Type <= sym.SPCLNTAB { + a4.Xsmclas = XMC_RO + } else { + a4.Xsmclas = XMC_RW + } + if t == DataSym { + a4.Xsmtyp |= XTY_SD + } else { + a4.Xsmtyp |= XTY_CM + } + + syms = append(syms, a4) + + } + for _, s := range syms { + xfile.writeSymbol(ctxt.Out, ctxt.Arch.ByteOrder, s) + } +} + +// Generate XCOFF Symbol table and XCOFF String table +func Asmaixsym(ctxt *Link) { + // write symbol table + xfile.symtabOffset = ctxt.Out.Offset() + genasmsym(ctxt, putaixsym) + + // update last file Svalue + xfile.updatePreviousFile(ctxt, true) + + // write string table + xfile.stringTable.write(ctxt.Out) +} + +// xcoffadddynimpsym adds a dynamic symbol to a XCOFF file +func xcoffadddynimpsym(ctxt *Link, s *sym.Symbol) { + xfile.adddynimpsym(ctxt, s) +} + +// Add a new imported symbol and a new library if needed. +// Currently, dynamic symbols are considered as .data symbols which will receive +// their value by the loader. Their relocation is created during the creation +// of the .loader section, because it needs its symbol index. +// However, there is no writing protection on those symbols and +// it might need to be added. +// TODO(aix): Add writing protection. +// TODO(aix): Handles dynamic symbols without library. +func (f *xcoffFile) adddynimpsym(ctxt *Link, s *sym.Symbol) { + // Check that library name is given. + // Pattern is already checked when compiling. + if s.Dynimplib() == "" { + Errorf(s, "imported symbol must have a given library") + } + + for _, sf := range f.dynSymbols { + if sf == s { + return + } + } + + f.dynSymbols = append(f.dynSymbols, s) + s.Type = sym.SXCOFFTOC + // Function descriptor value + s.AddUint64(ctxt.Arch, 0) + + if _, ok := f.dynLibraries[s.Dynimplib()]; !ok { + f.dynLibraries[s.Dynimplib()] = len(f.dynLibraries) + } +} + +// Add a relocation to .loader relocation section +func xcoffaddloaderreloc(ctxt *Link, s *sym.Symbol, r *sym.Reloc) { + if s.Type <= sym.SPCLNTAB && r.Sym.Type >= sym.SELFSECT && r.Sym.Type <= sym.SXREF { + Errorf(s, "cannot have a relocation in a text section with a data symbol: %s ", r.Sym.Name) + } + + ldr := &XcoffLdRel64{ + Lvaddr: uint64(s.Value + int64(r.Off)), + Lrsecnm: s.Sect.Extnum, + } + + switch r.Type { + case objabi.R_ADDR: + // Relocation of a .data symbol + ldr.Lrtype = 0x3F<<8 + XCOFF_R_POS + ldr.Lsymndx = 1 // .data + default: + Errorf(s, "unexpected .loader relocation to symbol: %s (type: %s)", r.Sym.Name, r.Type.String()) + } + + xfile.loaderReloc = append(xfile.loaderReloc, ldr) + +} + +func (ctxt *Link) doxcoff() { + // Initial map used to store compilation unit size for each DWARF section (see dwarf.go). + dwsectCUSize = make(map[string]uint64) + + // TOC + toc := ctxt.Syms.Lookup("TOC", 0) + toc.Type = sym.SXCOFFTOC + toc.Attr |= sym.AttrReachable +} + +// Loader section +// Currently, this section is created from scratch when assembling the XCOFF file +// according to information retrieved in xfile object. + +// Create loader section and returns its size +func Loaderblk(ctxt *Link, off uint64) uint64 { + xfile.writeLdrScn(ctxt, off) + return loaderSize +} + +func (f *xcoffFile) writeLdrScn(ctxt *Link, globalOff uint64) { + var symtab []*XcoffLdSym64 + var strtab []*XcoffLdStr64 + var importtab []*XcoffLdImportFile64 + var reloctab []*XcoffLdRel64 + var dynimpreloc []*XcoffLdRel64 + + // As the string table is updated in any loader subsection, + // its length must be computed at the same time. + stlen := uint32(0) + + // Loader Header + hdr := &XcoffLdHdr64{ + Lversion: 2, + Lsymoff: LDHDRSZ_64, + } + + /* Symbol table */ + // Entry point symbol + ep := ctxt.Syms.ROLookup(*flagEntrySymbol, 0) + if !ep.Attr.Reachable() { + Exitf("wrong entry point") + } + lds := &XcoffLdSym64{ + Lvalue: uint64(ep.Value), + Loffset: uint32(stlen + 2), // +2 because it must have the first byte of the symbol not its size field + Lscnum: ep.Sect.Extnum, + Lsmtype: XTY_ENT | XTY_SD, + Lsmclas: XMC_DS, + Lifile: 0, + Lparm: 0, + } + ldstr := &XcoffLdStr64{ + size: uint16(len(ep.String()) + 1), // + null terminator + name: ep.String(), + } + stlen += uint32(2 + ldstr.size) // 2 = sizeof ldstr.size + symtab = append(symtab, lds) + strtab = append(strtab, ldstr) + + nbldsym := int32(4) + + // dynamic import + for _, s := range f.dynSymbols { + lds = &XcoffLdSym64{ + Loffset: uint32(stlen + 2), + Lsmtype: XTY_IMP, + Lsmclas: XMC_DS, + Lifile: int32(f.dynLibraries[s.Dynimplib()] + 1), + } + ldstr := &XcoffLdStr64{ + size: uint16(len(s.Extname()) + 1), // + null terminator + name: s.Extname(), + } + stlen += uint32(2 + ldstr.size) // 2 = sizeof ldstr.size + symtab = append(symtab, lds) + strtab = append(strtab, ldstr) + + // Create relocation entry at the same moment to get symndx + ldr := &XcoffLdRel64{ + Lvaddr: uint64(s.Value), + Lrtype: 0x3F00, + Lrsecnm: s.Sect.Extnum, + Lsymndx: int32(nbldsym), + } + dynimpreloc = append(dynimpreloc, ldr) + nbldsym++ + + } + + hdr.Lnsyms = int32(len(symtab)) + hdr.Lrldoff = hdr.Lsymoff + uint64(24*hdr.Lnsyms) // 24 = sizeof one symbol + off := hdr.Lrldoff // current offset is the same of reloc offset + + /* Reloc */ + ldr := &XcoffLdRel64{ + Lvaddr: uint64(ep.Value), + Lrtype: 0x3F00, + Lrsecnm: ep.Sect.Extnum, + Lsymndx: 0, + } + off += 16 + reloctab = append(reloctab, ldr) + + off += uint64(16 * len(f.loaderReloc)) + reloctab = append(reloctab, (f.loaderReloc)...) + + off += uint64(16 * len(dynimpreloc)) + reloctab = append(reloctab, dynimpreloc...) + + hdr.Lnreloc = int32(len(reloctab)) + hdr.Limpoff = off + + /* Import */ + // Default import: /usr/lib:/lib + ldimpf := &XcoffLdImportFile64{ + Limpidpath: "/usr/lib:/lib", + } + off += uint64(len(ldimpf.Limpidpath) + len(ldimpf.Limpidbase) + len(ldimpf.Limpidmem) + 3) // + null delimiter + importtab = append(importtab, ldimpf) + + // The map created by adddynimpsym associates the name to a number + // This number represents the librairie index (- 1) in this import files section + // Therefore, they must be sorted before being put inside the section + libsOrdered := make([]string, len(f.dynLibraries)) + for key, val := range f.dynLibraries { + if libsOrdered[val] != "" { + continue + } + libsOrdered[val] = key + } + + for _, lib := range libsOrdered { + // lib string is defined as base.a/mem.o or path/base.a/mem.o + n := strings.Split(lib, "/") + path := "" + base := n[len(n)-2] + mem := n[len(n)-1] + if len(n) > 2 { + path = lib[:len(lib)-len(base)-len(mem)-2] + + } + ldimpf = &XcoffLdImportFile64{ + Limpidpath: path, + Limpidbase: base, + Limpidmem: mem, + } + off += uint64(len(ldimpf.Limpidpath) + len(ldimpf.Limpidbase) + len(ldimpf.Limpidmem) + 3) // + null delimiter + importtab = append(importtab, ldimpf) + } + + hdr.Lnimpid = int32(len(importtab)) + hdr.Listlen = uint32(off - hdr.Limpoff) + hdr.Lstoff = off + hdr.Lstlen = stlen + + /* Writing */ + ctxt.Out.SeekSet(int64(globalOff)) + binary.Write(ctxt.Out, ctxt.Arch.ByteOrder, hdr) + + for _, s := range symtab { + binary.Write(ctxt.Out, ctxt.Arch.ByteOrder, s) + + } + for _, r := range reloctab { + binary.Write(ctxt.Out, ctxt.Arch.ByteOrder, r) + } + for _, f := range importtab { + ctxt.Out.WriteString(f.Limpidpath) + ctxt.Out.Write8(0) + ctxt.Out.WriteString(f.Limpidbase) + ctxt.Out.Write8(0) + ctxt.Out.WriteString(f.Limpidmem) + ctxt.Out.Write8(0) + } + for _, s := range strtab { + ctxt.Out.Write16(s.size) + ctxt.Out.WriteString(s.name) + ctxt.Out.Write8(0) // null terminator + } + + loaderOff = globalOff + loaderSize = off + uint64(stlen) + ctxt.Out.Flush() + + /* again for printing */ + if !*flagA { + return + } + + ctxt.Logf("\n.loader section") + // write in buf + var buf bytes.Buffer + + binary.Write(&buf, ctxt.Arch.ByteOrder, hdr) + for _, s := range symtab { + binary.Write(&buf, ctxt.Arch.ByteOrder, s) + + } + for _, f := range importtab { + buf.WriteString(f.Limpidpath) + buf.WriteByte(0) + buf.WriteString(f.Limpidbase) + buf.WriteByte(0) + buf.WriteString(f.Limpidmem) + buf.WriteByte(0) + } + for _, s := range strtab { + binary.Write(&buf, ctxt.Arch.ByteOrder, s.size) + buf.WriteString(s.name) + buf.WriteByte(0) // null terminator + } + + // Log buffer + ctxt.Logf("\n\t%.8x|", globalOff) + for i, b := range buf.Bytes() { + if i > 0 && i%16 == 0 { + ctxt.Logf("\n\t%.8x|", uint64(globalOff)+uint64(i)) + } + ctxt.Logf(" %.2x", b) + } + ctxt.Logf("\n") + +} + +// XCOFF assembling and writing file + +func (f *xcoffFile) writeFileHeader(ctxt *Link) { + // File header + f.xfhdr.Fmagic = U64_TOCMAGIC + f.xfhdr.Fnscns = uint16(len(f.sections)) + f.xfhdr.Ftimedat = 0 + + if !*FlagS { + f.xfhdr.Fsymptr = uint64(f.symtabOffset) + f.xfhdr.Fnsyms = int32(f.symbolCount) + } + + if ctxt.BuildMode == BuildModeExe { + f.xfhdr.Fopthdr = AOUTHSZ_EXEC64 + f.xfhdr.Fflags = F_EXEC + + // auxiliary header + f.xahdr.Ovstamp = 1 // based on dump -o + f.xahdr.Omagic = 0x10b + copy(f.xahdr.Omodtype[:], "1L") + f.xahdr.Oentry = uint64(Entryvalue(ctxt)) + f.xahdr.Otoc = uint64(ctxt.Syms.ROLookup("TOC", 0).Value) + + // Based on dump -o + f.xahdr.Oalgntext = 0x5 + f.xahdr.Oalgndata = 0x5 + + binary.Write(ctxt.Out, binary.BigEndian, &f.xfhdr) + binary.Write(ctxt.Out, binary.BigEndian, &f.xahdr) + } else { + f.xfhdr.Fopthdr = 0 + binary.Write(ctxt.Out, binary.BigEndian, &f.xfhdr) + } + +} + +func xcoffwrite(ctxt *Link) { + ctxt.Out.SeekSet(0) + + xfile.writeFileHeader(ctxt) + + for _, sect := range xfile.sections { + sect.write(ctxt) + } +} + +// Generate XCOFF assembly file +func Asmbxcoff(ctxt *Link) { + // initial offset for sections + if ctxt.BuildMode == BuildModeExe { + // search entry section number + eaddr := uint64(Entryvalue(ctxt)) + for _, sect := range append(Segtext.Sections, Segdata.Sections...) { + if eaddr-sect.Vaddr <= sect.Length { + xfile.xahdr.Osnentry = int16(sect.Extnum) + } + } + + // check + if xfile.xahdr.Osnentry == 0 { + Exitf("internal error: Section number for entry point (addr = 0x%x) not found", eaddr) + } + + } + + // add text sections + for _, sect := range Segtext.Sections { + // ctxt.Logf(".text: %s \n", sect.Name) + s := xfile.addSection(sect) + s.Sflags = STYP_TEXT + + // use sect.Name because of convertion inside scnhdr + if sect.Name == ".text" { + xfile.xahdr.Otextstart = s.Spaddr + xfile.xahdr.Otsize = s.Ssize + xfile.xahdr.Osntext = sect.Extnum + } + } + + // add data sections + var ( + snoptrdata, + sdata, + sbss, + snoptrbss *sym.Section + ) + for _, sect := range Segdata.Sections { + if sect.Name == ".noptrdata" { + snoptrdata = sect + } + if sect.Name == ".noptrbss" { + snoptrbss = sect + } + if sect.Name == ".data" { + sdata = sect + } + if sect.Name == ".bss" { + sbss = sect + } + } + + // On AIX, there must be only one data and one bss section. + // Therefore, their noptr section is merged within them. + // The length of the new section must be recomputed to handle defautl gap + // between GO sections as AIX doesn't allow it. + + // Merge .noptrdata inside .data + sdata.Vaddr = snoptrdata.Vaddr + sdata.Length = sbss.Vaddr - sdata.Vaddr + s := xfile.addSection(sdata) + s.Sflags = STYP_DATA + xfile.xahdr.Odatastart = s.Spaddr + xfile.xahdr.Odsize = s.Ssize + xfile.xahdr.Osndata = sdata.Extnum + + // Merge .noptrbss inside .bss + sbss.Length = snoptrbss.Vaddr + snoptrbss.Length - sbss.Vaddr + s = xfile.addSection(sbss) + s.Sflags = STYP_BSS + xfile.xahdr.Obsize = s.Ssize + xfile.xahdr.Osnbss = sbss.Extnum + s.Sscnptr = 0 + + // add dwarf section + for _, sect := range Segdwarf.Sections { + xfile.addDwarfSection(sect) + } + + // Loader section must be add at the end because of sect.Extnum + // in others sections + xfile.addLoaderSection(loaderSize, loaderOff) + + xcoffwrite(ctxt) +} diff --git a/src/cmd/link/internal/ppc64/asm.go b/src/cmd/link/internal/ppc64/asm.go index 3e833b686ea..c4a49c6a1e5 100644 --- a/src/cmd/link/internal/ppc64/asm.go +++ b/src/cmd/link/internal/ppc64/asm.go @@ -692,6 +692,11 @@ func archreloc(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol, val int64) (int64, bo // Runtime Handling" of "Power Architecture 64-Bit ELF V2 ABI // Specification". v := r.Sym.Value - 0x7000 + if ctxt.HeadType == objabi.Haix { + // On AIX, the thread pointer points 0x7800 bytes after + // the TLS. + v -= 0x800 + } if int64(int16(v)) != v { ld.Errorf(s, "TLS offset out of range %d", v) } @@ -941,6 +946,13 @@ func asmb(ctxt *ld.Link) { ctxt.Out.SeekSet(int64(ld.Segdwarf.Fileoff)) ld.Dwarfblk(ctxt, int64(ld.Segdwarf.Vaddr), int64(ld.Segdwarf.Filelen)) + loadersize := uint64(0) + if ctxt.HeadType == objabi.Haix && ctxt.BuildMode == ld.BuildModeExe { + loadero := uint64(ld.Rnd(int64(ld.Segdwarf.Fileoff+ld.Segdwarf.Filelen), int64(*ld.FlagRound))) + ctxt.Out.SeekSet(int64(loadero)) + loadersize = ld.Loaderblk(ctxt, loadero) + } + /* output symbol table */ ld.Symsize = 0 @@ -960,6 +972,16 @@ func asmb(ctxt *ld.Link) { case objabi.Hplan9: symo = uint32(ld.Segdata.Fileoff + ld.Segdata.Filelen) + + case objabi.Haix: + symo = uint32(ld.Segdwarf.Fileoff + ld.Segdwarf.Filelen) + + // Add loader size if needed + if ctxt.BuildMode == ld.BuildModeExe { + symo = uint32(ld.Rnd(int64(symo), int64(*ld.FlagRound))) + symo += uint32(loadersize) + } + symo = uint32(ld.Rnd(int64(symo), int64(*ld.FlagRound))) } ctxt.Out.SeekSet(int64(symo)) @@ -988,6 +1010,10 @@ func asmb(ctxt *ld.Link) { ctxt.Out.Write(sym.P) ctxt.Out.Flush() } + + case objabi.Haix: + ld.Asmaixsym(ctxt) + ctxt.Out.Flush() } } @@ -1013,6 +1039,9 @@ func asmb(ctxt *ld.Link) { objabi.Hopenbsd, objabi.Hnacl: ld.Asmbelf(ctxt, int64(symo)) + + case objabi.Haix: + ld.Asmbxcoff(ctxt) } ctxt.Out.Flush() diff --git a/src/cmd/link/internal/ppc64/obj.go b/src/cmd/link/internal/ppc64/obj.go index 273d9b42cb9..e630f8c062b 100644 --- a/src/cmd/link/internal/ppc64/obj.go +++ b/src/cmd/link/internal/ppc64/obj.go @@ -121,6 +121,10 @@ func archinit(ctxt *ld.Link) { if *ld.FlagRound == -1 { *ld.FlagRound = 0x10000 } + + case objabi.Haix: + ld.Xcoffinit(ctxt) + } if *ld.FlagDataAddr != 0 && *ld.FlagRound != 0 {