summaryrefslogtreecommitdiffstats
path: root/src/internal/xcoff
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-16 19:25:22 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-16 19:25:22 +0000
commitf6ad4dcef54c5ce997a4bad5a6d86de229015700 (patch)
tree7cfa4e31ace5c2bd95c72b154d15af494b2bcbef /src/internal/xcoff
parentInitial commit. (diff)
downloadgolang-1.22-f6ad4dcef54c5ce997a4bad5a6d86de229015700.tar.xz
golang-1.22-f6ad4dcef54c5ce997a4bad5a6d86de229015700.zip
Adding upstream version 1.22.1.upstream/1.22.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/internal/xcoff')
-rw-r--r--src/internal/xcoff/ar.go226
-rw-r--r--src/internal/xcoff/ar_test.go79
-rw-r--r--src/internal/xcoff/file.go697
-rw-r--r--src/internal/xcoff/file_test.go102
-rw-r--r--src/internal/xcoff/testdata/bigar-empty2
-rw-r--r--src/internal/xcoff/testdata/bigar-ppc64bin0 -> 2468 bytes
-rw-r--r--src/internal/xcoff/testdata/gcc-ppc32-aix-dwarf2-execbin0 -> 54694 bytes
-rw-r--r--src/internal/xcoff/testdata/gcc-ppc64-aix-dwarf2-execbin0 -> 57152 bytes
-rw-r--r--src/internal/xcoff/testdata/hello.c7
-rw-r--r--src/internal/xcoff/testdata/printbye.c5
-rw-r--r--src/internal/xcoff/testdata/printhello.c5
-rw-r--r--src/internal/xcoff/xcoff.go367
12 files changed, 1490 insertions, 0 deletions
diff --git a/src/internal/xcoff/ar.go b/src/internal/xcoff/ar.go
new file mode 100644
index 0000000..9cbd50d
--- /dev/null
+++ b/src/internal/xcoff/ar.go
@@ -0,0 +1,226 @@
+// 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 xcoff
+
+import (
+ "encoding/binary"
+ "fmt"
+ "io"
+ "os"
+ "strconv"
+ "strings"
+)
+
+const (
+ SAIAMAG = 0x8
+ AIAFMAG = "`\n"
+ AIAMAG = "<aiaff>\n"
+ AIAMAGBIG = "<bigaf>\n"
+
+ // Sizeof
+ FL_HSZ_BIG = 0x80
+ AR_HSZ_BIG = 0x70
+)
+
+type bigarFileHeader struct {
+ Flmagic [SAIAMAG]byte // Archive magic string
+ Flmemoff [20]byte // Member table offset
+ Flgstoff [20]byte // 32-bits global symtab offset
+ Flgst64off [20]byte // 64-bits global symtab offset
+ Flfstmoff [20]byte // First member offset
+ Fllstmoff [20]byte // Last member offset
+ Flfreeoff [20]byte // First member on free list offset
+}
+
+type bigarMemberHeader struct {
+ Arsize [20]byte // File member size
+ Arnxtmem [20]byte // Next member pointer
+ Arprvmem [20]byte // Previous member pointer
+ Ardate [12]byte // File member date
+ Aruid [12]byte // File member uid
+ Argid [12]byte // File member gid
+ Armode [12]byte // File member mode (octal)
+ Arnamlen [4]byte // File member name length
+ // _ar_nam is removed because it's easier to get name without it.
+}
+
+// Archive represents an open AIX big archive.
+type Archive struct {
+ ArchiveHeader
+ Members []*Member
+
+ closer io.Closer
+}
+
+// MemberHeader holds information about a big archive file header
+type ArchiveHeader struct {
+ magic string
+}
+
+// Member represents a member of an AIX big archive.
+type Member struct {
+ MemberHeader
+ sr *io.SectionReader
+}
+
+// MemberHeader holds information about a big archive member
+type MemberHeader struct {
+ Name string
+ Size uint64
+}
+
+// OpenArchive opens the named archive using os.Open and prepares it for use
+// as an AIX big archive.
+func OpenArchive(name string) (*Archive, error) {
+ f, err := os.Open(name)
+ if err != nil {
+ return nil, err
+ }
+ arch, err := NewArchive(f)
+ if err != nil {
+ f.Close()
+ return nil, err
+ }
+ arch.closer = f
+ return arch, nil
+}
+
+// Close closes the Archive.
+// If the Archive was created using NewArchive directly instead of OpenArchive,
+// Close has no effect.
+func (a *Archive) Close() error {
+ var err error
+ if a.closer != nil {
+ err = a.closer.Close()
+ a.closer = nil
+ }
+ return err
+}
+
+// NewArchive creates a new Archive for accessing an AIX big archive in an underlying reader.
+func NewArchive(r io.ReaderAt) (*Archive, error) {
+ parseDecimalBytes := func(b []byte) (int64, error) {
+ return strconv.ParseInt(strings.TrimSpace(string(b)), 10, 64)
+ }
+ sr := io.NewSectionReader(r, 0, 1<<63-1)
+
+ // Read File Header
+ var magic [SAIAMAG]byte
+ if _, err := sr.ReadAt(magic[:], 0); err != nil {
+ return nil, err
+ }
+
+ arch := new(Archive)
+ switch string(magic[:]) {
+ case AIAMAGBIG:
+ arch.magic = string(magic[:])
+ case AIAMAG:
+ return nil, fmt.Errorf("small AIX archive not supported")
+ default:
+ return nil, fmt.Errorf("unrecognised archive magic: 0x%x", magic)
+ }
+
+ var fhdr bigarFileHeader
+ if _, err := sr.Seek(0, io.SeekStart); err != nil {
+ return nil, err
+ }
+ if err := binary.Read(sr, binary.BigEndian, &fhdr); err != nil {
+ return nil, err
+ }
+
+ off, err := parseDecimalBytes(fhdr.Flfstmoff[:])
+ if err != nil {
+ return nil, fmt.Errorf("error parsing offset of first member in archive header(%q); %v", fhdr, err)
+ }
+
+ if off == 0 {
+ // Occurs if the archive is empty.
+ return arch, nil
+ }
+
+ lastoff, err := parseDecimalBytes(fhdr.Fllstmoff[:])
+ if err != nil {
+ return nil, fmt.Errorf("error parsing offset of first member in archive header(%q); %v", fhdr, err)
+ }
+
+ // Read members
+ for {
+ // Read Member Header
+ // The member header is normally 2 bytes larger. But it's easier
+ // to read the name if the header is read without _ar_nam.
+ // However, AIAFMAG must be read afterward.
+ if _, err := sr.Seek(off, io.SeekStart); err != nil {
+ return nil, err
+ }
+
+ var mhdr bigarMemberHeader
+ if err := binary.Read(sr, binary.BigEndian, &mhdr); err != nil {
+ return nil, err
+ }
+
+ member := new(Member)
+ arch.Members = append(arch.Members, member)
+
+ size, err := parseDecimalBytes(mhdr.Arsize[:])
+ if err != nil {
+ return nil, fmt.Errorf("error parsing size in member header(%q); %v", mhdr, err)
+ }
+ member.Size = uint64(size)
+
+ // Read name
+ namlen, err := parseDecimalBytes(mhdr.Arnamlen[:])
+ if err != nil {
+ return nil, fmt.Errorf("error parsing name length in member header(%q); %v", mhdr, err)
+ }
+ name := make([]byte, namlen)
+ if err := binary.Read(sr, binary.BigEndian, name); err != nil {
+ return nil, err
+ }
+ member.Name = string(name)
+
+ fileoff := off + AR_HSZ_BIG + namlen
+ if fileoff&1 != 0 {
+ fileoff++
+ if _, err := sr.Seek(1, io.SeekCurrent); err != nil {
+ return nil, err
+ }
+ }
+
+ // Read AIAFMAG string
+ var fmag [2]byte
+ if err := binary.Read(sr, binary.BigEndian, &fmag); err != nil {
+ return nil, err
+ }
+ if string(fmag[:]) != AIAFMAG {
+ return nil, fmt.Errorf("AIAFMAG not found after member header")
+ }
+
+ fileoff += 2 // Add the two bytes of AIAFMAG
+ member.sr = io.NewSectionReader(sr, fileoff, size)
+
+ if off == lastoff {
+ break
+ }
+ off, err = parseDecimalBytes(mhdr.Arnxtmem[:])
+ if err != nil {
+ return nil, fmt.Errorf("error parsing offset of first member in archive header(%q); %v", fhdr, err)
+ }
+
+ }
+
+ return arch, nil
+}
+
+// GetFile returns the XCOFF file defined by member name.
+// FIXME: This doesn't work if an archive has two members with the same
+// name which can occur if an archive has both 32-bits and 64-bits files.
+func (arch *Archive) GetFile(name string) (*File, error) {
+ for _, mem := range arch.Members {
+ if mem.Name == name {
+ return NewFile(mem.sr)
+ }
+ }
+ return nil, fmt.Errorf("unknown member %s in archive", name)
+}
diff --git a/src/internal/xcoff/ar_test.go b/src/internal/xcoff/ar_test.go
new file mode 100644
index 0000000..83333d6
--- /dev/null
+++ b/src/internal/xcoff/ar_test.go
@@ -0,0 +1,79 @@
+// 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 xcoff
+
+import (
+ "reflect"
+ "testing"
+)
+
+type archiveTest struct {
+ file string
+ hdr ArchiveHeader
+ members []*MemberHeader
+ membersFileHeader []FileHeader
+}
+
+var archTest = []archiveTest{
+ {
+ "testdata/bigar-ppc64",
+ ArchiveHeader{AIAMAGBIG},
+ []*MemberHeader{
+ {"printbye.o", 836},
+ {"printhello.o", 860},
+ },
+ []FileHeader{
+ {U64_TOCMAGIC},
+ {U64_TOCMAGIC},
+ },
+ },
+ {
+ "testdata/bigar-empty",
+ ArchiveHeader{AIAMAGBIG},
+ []*MemberHeader{},
+ []FileHeader{},
+ },
+}
+
+func TestOpenArchive(t *testing.T) {
+ for i := range archTest {
+ tt := &archTest[i]
+ arch, err := OpenArchive(tt.file)
+ if err != nil {
+ t.Error(err)
+ continue
+ }
+ if !reflect.DeepEqual(arch.ArchiveHeader, tt.hdr) {
+ t.Errorf("open archive %s:\n\thave %#v\n\twant %#v\n", tt.file, arch.ArchiveHeader, tt.hdr)
+ continue
+ }
+
+ for i, mem := range arch.Members {
+ if i >= len(tt.members) {
+ break
+ }
+ have := &mem.MemberHeader
+ want := tt.members[i]
+ if !reflect.DeepEqual(have, want) {
+ t.Errorf("open %s, member %d:\n\thave %#v\n\twant %#v\n", tt.file, i, have, want)
+ }
+
+ f, err := arch.GetFile(mem.Name)
+ if err != nil {
+ t.Error(err)
+ continue
+ }
+ if !reflect.DeepEqual(f.FileHeader, tt.membersFileHeader[i]) {
+ t.Errorf("open %s, member file header %d:\n\thave %#v\n\twant %#v\n", tt.file, i, f.FileHeader, tt.membersFileHeader[i])
+ }
+ }
+ tn := len(tt.members)
+ an := len(arch.Members)
+ if tn != an {
+ t.Errorf("open %s: len(Members) = %d, want %d", tt.file, an, tn)
+ }
+
+ }
+}
diff --git a/src/internal/xcoff/file.go b/src/internal/xcoff/file.go
new file mode 100644
index 0000000..12f78cc
--- /dev/null
+++ b/src/internal/xcoff/file.go
@@ -0,0 +1,697 @@
+// 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 xcoff implements access to XCOFF (Extended Common Object File Format) files.
+package xcoff
+
+import (
+ "debug/dwarf"
+ "encoding/binary"
+ "fmt"
+ "internal/saferio"
+ "io"
+ "os"
+ "strings"
+)
+
+// SectionHeader holds information about an XCOFF section header.
+type SectionHeader struct {
+ Name string
+ VirtualAddress uint64
+ Size uint64
+ Type uint32
+ Relptr uint64
+ Nreloc uint32
+}
+
+type Section struct {
+ SectionHeader
+ Relocs []Reloc
+ io.ReaderAt
+ sr *io.SectionReader
+}
+
+// AuxiliaryCSect holds information about an XCOFF symbol in an AUX_CSECT entry.
+type AuxiliaryCSect struct {
+ Length int64
+ StorageMappingClass int
+ SymbolType int
+}
+
+// AuxiliaryFcn holds information about an XCOFF symbol in an AUX_FCN entry.
+type AuxiliaryFcn struct {
+ Size int64
+}
+
+type Symbol struct {
+ Name string
+ Value uint64
+ SectionNumber int
+ StorageClass int
+ AuxFcn AuxiliaryFcn
+ AuxCSect AuxiliaryCSect
+}
+
+type Reloc struct {
+ VirtualAddress uint64
+ Symbol *Symbol
+ Signed bool
+ InstructionFixed bool
+ Length uint8
+ Type uint8
+}
+
+// ImportedSymbol holds information about an imported XCOFF symbol.
+type ImportedSymbol struct {
+ Name string
+ Library string
+}
+
+// FileHeader holds information about an XCOFF file header.
+type FileHeader struct {
+ TargetMachine uint16
+}
+
+// A File represents an open XCOFF file.
+type File struct {
+ FileHeader
+ Sections []*Section
+ Symbols []*Symbol
+ StringTable []byte
+ LibraryPaths []string
+
+ closer io.Closer
+}
+
+// Open opens the named file using os.Open and prepares it for use as an XCOFF binary.
+func Open(name string) (*File, error) {
+ f, err := os.Open(name)
+ if err != nil {
+ return nil, err
+ }
+ ff, err := NewFile(f)
+ if err != nil {
+ f.Close()
+ return nil, err
+ }
+ ff.closer = f
+ return ff, nil
+}
+
+// Close closes the File.
+// If the File was created using NewFile directly instead of Open,
+// Close has no effect.
+func (f *File) Close() error {
+ var err error
+ if f.closer != nil {
+ err = f.closer.Close()
+ f.closer = nil
+ }
+ return err
+}
+
+// Section returns the first section with the given name, or nil if no such
+// section exists.
+// Xcoff have section's name limited to 8 bytes. Some sections like .gosymtab
+// can be trunked but this method will still find them.
+func (f *File) Section(name string) *Section {
+ for _, s := range f.Sections {
+ if s.Name == name || (len(name) > 8 && s.Name == name[:8]) {
+ return s
+ }
+ }
+ return nil
+}
+
+// SectionByType returns the first section in f with the
+// given type, or nil if there is no such section.
+func (f *File) SectionByType(typ uint32) *Section {
+ for _, s := range f.Sections {
+ if s.Type == typ {
+ return s
+ }
+ }
+ return nil
+}
+
+// cstring converts ASCII byte sequence b to string.
+// It stops once it finds 0 or reaches end of b.
+func cstring(b []byte) string {
+ var i int
+ for i = 0; i < len(b) && b[i] != 0; i++ {
+ }
+ return string(b[:i])
+}
+
+// getString extracts a string from an XCOFF string table.
+func getString(st []byte, offset uint32) (string, bool) {
+ if offset < 4 || int(offset) >= len(st) {
+ return "", false
+ }
+ return cstring(st[offset:]), true
+}
+
+// NewFile creates a new File for accessing an XCOFF binary in an underlying reader.
+func NewFile(r io.ReaderAt) (*File, error) {
+ sr := io.NewSectionReader(r, 0, 1<<63-1)
+ // Read XCOFF target machine
+ var magic uint16
+ if err := binary.Read(sr, binary.BigEndian, &magic); err != nil {
+ return nil, err
+ }
+ if magic != U802TOCMAGIC && magic != U64_TOCMAGIC {
+ return nil, fmt.Errorf("unrecognised XCOFF magic: 0x%x", magic)
+ }
+
+ f := new(File)
+ f.TargetMachine = magic
+
+ // Read XCOFF file header
+ if _, err := sr.Seek(0, io.SeekStart); err != nil {
+ return nil, err
+ }
+ var nscns uint16
+ var symptr uint64
+ var nsyms uint32
+ var opthdr uint16
+ var hdrsz int
+ switch f.TargetMachine {
+ case U802TOCMAGIC:
+ fhdr := new(FileHeader32)
+ if err := binary.Read(sr, binary.BigEndian, fhdr); err != nil {
+ return nil, err
+ }
+ nscns = fhdr.Fnscns
+ symptr = uint64(fhdr.Fsymptr)
+ nsyms = fhdr.Fnsyms
+ opthdr = fhdr.Fopthdr
+ hdrsz = FILHSZ_32
+ case U64_TOCMAGIC:
+ fhdr := new(FileHeader64)
+ if err := binary.Read(sr, binary.BigEndian, fhdr); err != nil {
+ return nil, err
+ }
+ nscns = fhdr.Fnscns
+ symptr = fhdr.Fsymptr
+ nsyms = fhdr.Fnsyms
+ opthdr = fhdr.Fopthdr
+ hdrsz = FILHSZ_64
+ }
+
+ if symptr == 0 || nsyms <= 0 {
+ return nil, fmt.Errorf("no symbol table")
+ }
+
+ // Read string table (located right after symbol table).
+ offset := symptr + uint64(nsyms)*SYMESZ
+ if _, err := sr.Seek(int64(offset), io.SeekStart); err != nil {
+ return nil, err
+ }
+ // The first 4 bytes contain the length (in bytes).
+ var l uint32
+ if err := binary.Read(sr, binary.BigEndian, &l); err != nil {
+ return nil, err
+ }
+ if l > 4 {
+ st, err := saferio.ReadDataAt(sr, uint64(l), int64(offset))
+ if err != nil {
+ return nil, err
+ }
+ f.StringTable = st
+ }
+
+ // Read section headers
+ if _, err := sr.Seek(int64(hdrsz)+int64(opthdr), io.SeekStart); err != nil {
+ return nil, err
+ }
+ c := saferio.SliceCap[*Section](uint64(nscns))
+ if c < 0 {
+ return nil, fmt.Errorf("too many XCOFF sections (%d)", nscns)
+ }
+ f.Sections = make([]*Section, 0, c)
+ for i := 0; i < int(nscns); i++ {
+ var scnptr uint64
+ s := new(Section)
+ switch f.TargetMachine {
+ case U802TOCMAGIC:
+ shdr := new(SectionHeader32)
+ if err := binary.Read(sr, binary.BigEndian, shdr); err != nil {
+ return nil, err
+ }
+ s.Name = cstring(shdr.Sname[:])
+ s.VirtualAddress = uint64(shdr.Svaddr)
+ s.Size = uint64(shdr.Ssize)
+ scnptr = uint64(shdr.Sscnptr)
+ s.Type = shdr.Sflags
+ s.Relptr = uint64(shdr.Srelptr)
+ s.Nreloc = uint32(shdr.Snreloc)
+ case U64_TOCMAGIC:
+ shdr := new(SectionHeader64)
+ if err := binary.Read(sr, binary.BigEndian, shdr); err != nil {
+ return nil, err
+ }
+ s.Name = cstring(shdr.Sname[:])
+ s.VirtualAddress = shdr.Svaddr
+ s.Size = shdr.Ssize
+ scnptr = shdr.Sscnptr
+ s.Type = shdr.Sflags
+ s.Relptr = shdr.Srelptr
+ s.Nreloc = shdr.Snreloc
+ }
+ r2 := r
+ if scnptr == 0 { // .bss must have all 0s
+ r2 = zeroReaderAt{}
+ }
+ s.sr = io.NewSectionReader(r2, int64(scnptr), int64(s.Size))
+ s.ReaderAt = s.sr
+ f.Sections = append(f.Sections, s)
+ }
+
+ // Symbol map needed by relocation
+ var idxToSym = make(map[int]*Symbol)
+
+ // Read symbol table
+ if _, err := sr.Seek(int64(symptr), io.SeekStart); err != nil {
+ return nil, err
+ }
+ f.Symbols = make([]*Symbol, 0)
+ for i := 0; i < int(nsyms); i++ {
+ var numaux int
+ var ok, needAuxFcn bool
+ sym := new(Symbol)
+ switch f.TargetMachine {
+ case U802TOCMAGIC:
+ se := new(SymEnt32)
+ if err := binary.Read(sr, binary.BigEndian, se); err != nil {
+ return nil, err
+ }
+ numaux = int(se.Nnumaux)
+ sym.SectionNumber = int(se.Nscnum)
+ sym.StorageClass = int(se.Nsclass)
+ sym.Value = uint64(se.Nvalue)
+ needAuxFcn = se.Ntype&SYM_TYPE_FUNC != 0 && numaux > 1
+ zeroes := binary.BigEndian.Uint32(se.Nname[:4])
+ if zeroes != 0 {
+ sym.Name = cstring(se.Nname[:])
+ } else {
+ offset := binary.BigEndian.Uint32(se.Nname[4:])
+ sym.Name, ok = getString(f.StringTable, offset)
+ if !ok {
+ goto skip
+ }
+ }
+ case U64_TOCMAGIC:
+ se := new(SymEnt64)
+ if err := binary.Read(sr, binary.BigEndian, se); err != nil {
+ return nil, err
+ }
+ numaux = int(se.Nnumaux)
+ sym.SectionNumber = int(se.Nscnum)
+ sym.StorageClass = int(se.Nsclass)
+ sym.Value = se.Nvalue
+ needAuxFcn = se.Ntype&SYM_TYPE_FUNC != 0 && numaux > 1
+ sym.Name, ok = getString(f.StringTable, se.Noffset)
+ if !ok {
+ goto skip
+ }
+ }
+ if sym.StorageClass != C_EXT && sym.StorageClass != C_WEAKEXT && sym.StorageClass != C_HIDEXT {
+ goto skip
+ }
+ // Must have at least one csect auxiliary entry.
+ if numaux < 1 || i+numaux >= int(nsyms) {
+ goto skip
+ }
+
+ if sym.SectionNumber > int(nscns) {
+ goto skip
+ }
+ if sym.SectionNumber == 0 {
+ sym.Value = 0
+ } else {
+ sym.Value -= f.Sections[sym.SectionNumber-1].VirtualAddress
+ }
+
+ idxToSym[i] = sym
+
+ // If this symbol is a function, it must retrieve its size from
+ // its AUX_FCN entry.
+ // It can happen that a function symbol doesn't have any AUX_FCN.
+ // In this case, needAuxFcn is false and their size will be set to 0.
+ if needAuxFcn {
+ switch f.TargetMachine {
+ case U802TOCMAGIC:
+ aux := new(AuxFcn32)
+ if err := binary.Read(sr, binary.BigEndian, aux); err != nil {
+ return nil, err
+ }
+ sym.AuxFcn.Size = int64(aux.Xfsize)
+ case U64_TOCMAGIC:
+ aux := new(AuxFcn64)
+ if err := binary.Read(sr, binary.BigEndian, aux); err != nil {
+ return nil, err
+ }
+ sym.AuxFcn.Size = int64(aux.Xfsize)
+ }
+ }
+
+ // Read csect auxiliary entry (by convention, it is the last).
+ if !needAuxFcn {
+ if _, err := sr.Seek(int64(numaux-1)*SYMESZ, io.SeekCurrent); err != nil {
+ return nil, err
+ }
+ }
+ i += numaux
+ numaux = 0
+ switch f.TargetMachine {
+ case U802TOCMAGIC:
+ aux := new(AuxCSect32)
+ if err := binary.Read(sr, binary.BigEndian, aux); err != nil {
+ return nil, err
+ }
+ sym.AuxCSect.SymbolType = int(aux.Xsmtyp & 0x7)
+ sym.AuxCSect.StorageMappingClass = int(aux.Xsmclas)
+ sym.AuxCSect.Length = int64(aux.Xscnlen)
+ case U64_TOCMAGIC:
+ aux := new(AuxCSect64)
+ if err := binary.Read(sr, binary.BigEndian, aux); err != nil {
+ return nil, err
+ }
+ sym.AuxCSect.SymbolType = int(aux.Xsmtyp & 0x7)
+ sym.AuxCSect.StorageMappingClass = int(aux.Xsmclas)
+ sym.AuxCSect.Length = int64(aux.Xscnlenhi)<<32 | int64(aux.Xscnlenlo)
+ }
+ f.Symbols = append(f.Symbols, sym)
+ skip:
+ i += numaux // Skip auxiliary entries
+ if _, err := sr.Seek(int64(numaux)*SYMESZ, io.SeekCurrent); err != nil {
+ return nil, err
+ }
+ }
+
+ // Read relocations
+ // Only for .data or .text section
+ for sectNum, sect := range f.Sections {
+ if sect.Type != STYP_TEXT && sect.Type != STYP_DATA {
+ continue
+ }
+ if sect.Relptr == 0 {
+ continue
+ }
+ c := saferio.SliceCap[Reloc](uint64(sect.Nreloc))
+ if c < 0 {
+ return nil, fmt.Errorf("too many relocs (%d) for section %d", sect.Nreloc, sectNum)
+ }
+ sect.Relocs = make([]Reloc, 0, c)
+ if _, err := sr.Seek(int64(sect.Relptr), io.SeekStart); err != nil {
+ return nil, err
+ }
+ for i := uint32(0); i < sect.Nreloc; i++ {
+ var reloc Reloc
+ switch f.TargetMachine {
+ case U802TOCMAGIC:
+ rel := new(Reloc32)
+ if err := binary.Read(sr, binary.BigEndian, rel); err != nil {
+ return nil, err
+ }
+ reloc.VirtualAddress = uint64(rel.Rvaddr)
+ reloc.Symbol = idxToSym[int(rel.Rsymndx)]
+ reloc.Type = rel.Rtype
+ reloc.Length = rel.Rsize&0x3F + 1
+
+ if rel.Rsize&0x80 != 0 {
+ reloc.Signed = true
+ }
+ if rel.Rsize&0x40 != 0 {
+ reloc.InstructionFixed = true
+ }
+
+ case U64_TOCMAGIC:
+ rel := new(Reloc64)
+ if err := binary.Read(sr, binary.BigEndian, rel); err != nil {
+ return nil, err
+ }
+ reloc.VirtualAddress = rel.Rvaddr
+ reloc.Symbol = idxToSym[int(rel.Rsymndx)]
+ reloc.Type = rel.Rtype
+ reloc.Length = rel.Rsize&0x3F + 1
+ if rel.Rsize&0x80 != 0 {
+ reloc.Signed = true
+ }
+ if rel.Rsize&0x40 != 0 {
+ reloc.InstructionFixed = true
+ }
+ }
+
+ sect.Relocs = append(sect.Relocs, reloc)
+ }
+ }
+
+ return f, nil
+}
+
+// zeroReaderAt is ReaderAt that reads 0s.
+type zeroReaderAt struct{}
+
+// ReadAt writes len(p) 0s into p.
+func (w zeroReaderAt) ReadAt(p []byte, off int64) (n int, err error) {
+ for i := range p {
+ p[i] = 0
+ }
+ return len(p), nil
+}
+
+// Data reads and returns the contents of the XCOFF section s.
+func (s *Section) Data() ([]byte, error) {
+ dat := make([]byte, s.sr.Size())
+ n, err := s.sr.ReadAt(dat, 0)
+ if n == len(dat) {
+ err = nil
+ }
+ return dat[:n], err
+}
+
+// CSect reads and returns the contents of a csect.
+func (f *File) CSect(name string) []byte {
+ for _, sym := range f.Symbols {
+ if sym.Name == name && sym.AuxCSect.SymbolType == XTY_SD {
+ if i := sym.SectionNumber - 1; 0 <= i && i < len(f.Sections) {
+ s := f.Sections[i]
+ if sym.Value+uint64(sym.AuxCSect.Length) <= s.Size {
+ dat := make([]byte, sym.AuxCSect.Length)
+ _, err := s.sr.ReadAt(dat, int64(sym.Value))
+ if err != nil {
+ return nil
+ }
+ return dat
+ }
+ }
+ break
+ }
+ }
+ return nil
+}
+
+func (f *File) DWARF() (*dwarf.Data, error) {
+ // There are many other DWARF sections, but these
+ // are the ones the debug/dwarf package uses.
+ // Don't bother loading others.
+ var subtypes = [...]uint32{SSUBTYP_DWABREV, SSUBTYP_DWINFO, SSUBTYP_DWLINE, SSUBTYP_DWRNGES, SSUBTYP_DWSTR}
+ var dat [len(subtypes)][]byte
+ for i, subtype := range subtypes {
+ s := f.SectionByType(STYP_DWARF | subtype)
+ if s != nil {
+ b, err := s.Data()
+ if err != nil && uint64(len(b)) < s.Size {
+ return nil, err
+ }
+ dat[i] = b
+ }
+ }
+
+ abbrev, info, line, ranges, str := dat[0], dat[1], dat[2], dat[3], dat[4]
+ return dwarf.New(abbrev, nil, nil, info, line, nil, ranges, str)
+}
+
+// readImportID returns the import file IDs stored inside the .loader section.
+// Library name pattern is either path/base/member or base/member
+func (f *File) readImportIDs(s *Section) ([]string, error) {
+ // Read loader header
+ if _, err := s.sr.Seek(0, io.SeekStart); err != nil {
+ return nil, err
+ }
+ var istlen uint32
+ var nimpid uint32
+ var impoff uint64
+ switch f.TargetMachine {
+ case U802TOCMAGIC:
+ lhdr := new(LoaderHeader32)
+ if err := binary.Read(s.sr, binary.BigEndian, lhdr); err != nil {
+ return nil, err
+ }
+ istlen = lhdr.Listlen
+ nimpid = lhdr.Lnimpid
+ impoff = uint64(lhdr.Limpoff)
+ case U64_TOCMAGIC:
+ lhdr := new(LoaderHeader64)
+ if err := binary.Read(s.sr, binary.BigEndian, lhdr); err != nil {
+ return nil, err
+ }
+ istlen = lhdr.Listlen
+ nimpid = lhdr.Lnimpid
+ impoff = lhdr.Limpoff
+ }
+
+ // Read loader import file ID table
+ if _, err := s.sr.Seek(int64(impoff), io.SeekStart); err != nil {
+ return nil, err
+ }
+ table := make([]byte, istlen)
+ if _, err := io.ReadFull(s.sr, table); err != nil {
+ return nil, err
+ }
+
+ offset := 0
+ // First import file ID is the default LIBPATH value
+ libpath := cstring(table[offset:])
+ f.LibraryPaths = strings.Split(libpath, ":")
+ offset += len(libpath) + 3 // 3 null bytes
+ all := make([]string, 0)
+ for i := 1; i < int(nimpid); i++ {
+ impidpath := cstring(table[offset:])
+ offset += len(impidpath) + 1
+ impidbase := cstring(table[offset:])
+ offset += len(impidbase) + 1
+ impidmem := cstring(table[offset:])
+ offset += len(impidmem) + 1
+ var path string
+ if len(impidpath) > 0 {
+ path = impidpath + "/" + impidbase + "/" + impidmem
+ } else {
+ path = impidbase + "/" + impidmem
+ }
+ all = append(all, path)
+ }
+
+ return all, nil
+}
+
+// ImportedSymbols returns the names of all symbols
+// referred to by the binary f that are expected to be
+// satisfied by other libraries at dynamic load time.
+// It does not return weak symbols.
+func (f *File) ImportedSymbols() ([]ImportedSymbol, error) {
+ s := f.SectionByType(STYP_LOADER)
+ if s == nil {
+ return nil, nil
+ }
+ // Read loader header
+ if _, err := s.sr.Seek(0, io.SeekStart); err != nil {
+ return nil, err
+ }
+ var stlen uint32
+ var stoff uint64
+ var nsyms uint32
+ var symoff uint64
+ switch f.TargetMachine {
+ case U802TOCMAGIC:
+ lhdr := new(LoaderHeader32)
+ if err := binary.Read(s.sr, binary.BigEndian, lhdr); err != nil {
+ return nil, err
+ }
+ stlen = lhdr.Lstlen
+ stoff = uint64(lhdr.Lstoff)
+ nsyms = lhdr.Lnsyms
+ symoff = LDHDRSZ_32
+ case U64_TOCMAGIC:
+ lhdr := new(LoaderHeader64)
+ if err := binary.Read(s.sr, binary.BigEndian, lhdr); err != nil {
+ return nil, err
+ }
+ stlen = lhdr.Lstlen
+ stoff = lhdr.Lstoff
+ nsyms = lhdr.Lnsyms
+ symoff = lhdr.Lsymoff
+ }
+
+ // Read loader section string table
+ if _, err := s.sr.Seek(int64(stoff), io.SeekStart); err != nil {
+ return nil, err
+ }
+ st := make([]byte, stlen)
+ if _, err := io.ReadFull(s.sr, st); err != nil {
+ return nil, err
+ }
+
+ // Read imported libraries
+ libs, err := f.readImportIDs(s)
+ if err != nil {
+ return nil, err
+ }
+
+ // Read loader symbol table
+ if _, err := s.sr.Seek(int64(symoff), io.SeekStart); err != nil {
+ return nil, err
+ }
+ all := make([]ImportedSymbol, 0)
+ for i := 0; i < int(nsyms); i++ {
+ var name string
+ var ifile uint32
+ var ok bool
+ switch f.TargetMachine {
+ case U802TOCMAGIC:
+ ldsym := new(LoaderSymbol32)
+ if err := binary.Read(s.sr, binary.BigEndian, ldsym); err != nil {
+ return nil, err
+ }
+ if ldsym.Lsmtype&0x40 == 0 {
+ continue // Imported symbols only
+ }
+ zeroes := binary.BigEndian.Uint32(ldsym.Lname[:4])
+ if zeroes != 0 {
+ name = cstring(ldsym.Lname[:])
+ } else {
+ offset := binary.BigEndian.Uint32(ldsym.Lname[4:])
+ name, ok = getString(st, offset)
+ if !ok {
+ continue
+ }
+ }
+ ifile = ldsym.Lifile
+ case U64_TOCMAGIC:
+ ldsym := new(LoaderSymbol64)
+ if err := binary.Read(s.sr, binary.BigEndian, ldsym); err != nil {
+ return nil, err
+ }
+ if ldsym.Lsmtype&0x40 == 0 {
+ continue // Imported symbols only
+ }
+ name, ok = getString(st, ldsym.Loffset)
+ if !ok {
+ continue
+ }
+ ifile = ldsym.Lifile
+ }
+ var sym ImportedSymbol
+ sym.Name = name
+ if ifile >= 1 && int(ifile) <= len(libs) {
+ sym.Library = libs[ifile-1]
+ }
+ all = append(all, sym)
+ }
+
+ return all, nil
+}
+
+// ImportedLibraries returns the names of all libraries
+// referred to by the binary f that are expected to be
+// linked with the binary at dynamic link time.
+func (f *File) ImportedLibraries() ([]string, error) {
+ s := f.SectionByType(STYP_LOADER)
+ if s == nil {
+ return nil, nil
+ }
+ all, err := f.readImportIDs(s)
+ return all, err
+}
diff --git a/src/internal/xcoff/file_test.go b/src/internal/xcoff/file_test.go
new file mode 100644
index 0000000..a6722e9
--- /dev/null
+++ b/src/internal/xcoff/file_test.go
@@ -0,0 +1,102 @@
+// 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 xcoff
+
+import (
+ "reflect"
+ "testing"
+)
+
+type fileTest struct {
+ file string
+ hdr FileHeader
+ sections []*SectionHeader
+ needed []string
+}
+
+var fileTests = []fileTest{
+ {
+ "testdata/gcc-ppc32-aix-dwarf2-exec",
+ FileHeader{U802TOCMAGIC},
+ []*SectionHeader{
+ {".text", 0x10000290, 0x00000bbd, STYP_TEXT, 0x7ae6, 0x36},
+ {".data", 0x20000e4d, 0x00000437, STYP_DATA, 0x7d02, 0x2b},
+ {".bss", 0x20001284, 0x0000021c, STYP_BSS, 0, 0},
+ {".loader", 0x00000000, 0x000004b3, STYP_LOADER, 0, 0},
+ {".dwline", 0x00000000, 0x000000df, STYP_DWARF | SSUBTYP_DWLINE, 0x7eb0, 0x7},
+ {".dwinfo", 0x00000000, 0x00000314, STYP_DWARF | SSUBTYP_DWINFO, 0x7ef6, 0xa},
+ {".dwabrev", 0x00000000, 0x000000d6, STYP_DWARF | SSUBTYP_DWABREV, 0, 0},
+ {".dwarnge", 0x00000000, 0x00000020, STYP_DWARF | SSUBTYP_DWARNGE, 0x7f5a, 0x2},
+ {".dwloc", 0x00000000, 0x00000074, STYP_DWARF | SSUBTYP_DWLOC, 0, 0},
+ {".debug", 0x00000000, 0x00005e4f, STYP_DEBUG, 0, 0},
+ },
+ []string{"libc.a/shr.o"},
+ },
+ {
+ "testdata/gcc-ppc64-aix-dwarf2-exec",
+ FileHeader{U64_TOCMAGIC},
+ []*SectionHeader{
+ {".text", 0x10000480, 0x00000afd, STYP_TEXT, 0x8322, 0x34},
+ {".data", 0x20000f7d, 0x000002f3, STYP_DATA, 0x85fa, 0x25},
+ {".bss", 0x20001270, 0x00000428, STYP_BSS, 0, 0},
+ {".loader", 0x00000000, 0x00000535, STYP_LOADER, 0, 0},
+ {".dwline", 0x00000000, 0x000000b4, STYP_DWARF | SSUBTYP_DWLINE, 0x8800, 0x4},
+ {".dwinfo", 0x00000000, 0x0000036a, STYP_DWARF | SSUBTYP_DWINFO, 0x8838, 0x7},
+ {".dwabrev", 0x00000000, 0x000000b5, STYP_DWARF | SSUBTYP_DWABREV, 0, 0},
+ {".dwarnge", 0x00000000, 0x00000040, STYP_DWARF | SSUBTYP_DWARNGE, 0x889a, 0x2},
+ {".dwloc", 0x00000000, 0x00000062, STYP_DWARF | SSUBTYP_DWLOC, 0, 0},
+ {".debug", 0x00000000, 0x00006605, STYP_DEBUG, 0, 0},
+ },
+ []string{"libc.a/shr_64.o"},
+ },
+}
+
+func TestOpen(t *testing.T) {
+ for i := range fileTests {
+ tt := &fileTests[i]
+
+ f, err := Open(tt.file)
+ if err != nil {
+ t.Error(err)
+ continue
+ }
+ if !reflect.DeepEqual(f.FileHeader, tt.hdr) {
+ t.Errorf("open %s:\n\thave %#v\n\twant %#v\n", tt.file, f.FileHeader, tt.hdr)
+ continue
+ }
+
+ for i, sh := range f.Sections {
+ if i >= len(tt.sections) {
+ break
+ }
+ have := &sh.SectionHeader
+ want := tt.sections[i]
+ if !reflect.DeepEqual(have, want) {
+ t.Errorf("open %s, section %d:\n\thave %#v\n\twant %#v\n", tt.file, i, have, want)
+ }
+ }
+ tn := len(tt.sections)
+ fn := len(f.Sections)
+ if tn != fn {
+ t.Errorf("open %s: len(Sections) = %d, want %d", tt.file, fn, tn)
+ }
+ tl := tt.needed
+ fl, err := f.ImportedLibraries()
+ if err != nil {
+ t.Error(err)
+ }
+ if !reflect.DeepEqual(tl, fl) {
+ t.Errorf("open %s: loader import = %v, want %v", tt.file, tl, fl)
+ }
+ }
+}
+
+func TestOpenFailure(t *testing.T) {
+ filename := "file.go" // not an XCOFF object file
+ _, err := Open(filename) // don't crash
+ if err == nil {
+ t.Errorf("open %s: succeeded unexpectedly", filename)
+ }
+}
diff --git a/src/internal/xcoff/testdata/bigar-empty b/src/internal/xcoff/testdata/bigar-empty
new file mode 100644
index 0000000..851ccc5
--- /dev/null
+++ b/src/internal/xcoff/testdata/bigar-empty
@@ -0,0 +1,2 @@
+<bigaf>
+0 0 0 0 0 0 \ No newline at end of file
diff --git a/src/internal/xcoff/testdata/bigar-ppc64 b/src/internal/xcoff/testdata/bigar-ppc64
new file mode 100644
index 0000000..a8d4979
--- /dev/null
+++ b/src/internal/xcoff/testdata/bigar-ppc64
Binary files differ
diff --git a/src/internal/xcoff/testdata/gcc-ppc32-aix-dwarf2-exec b/src/internal/xcoff/testdata/gcc-ppc32-aix-dwarf2-exec
new file mode 100644
index 0000000..810e21a
--- /dev/null
+++ b/src/internal/xcoff/testdata/gcc-ppc32-aix-dwarf2-exec
Binary files differ
diff --git a/src/internal/xcoff/testdata/gcc-ppc64-aix-dwarf2-exec b/src/internal/xcoff/testdata/gcc-ppc64-aix-dwarf2-exec
new file mode 100644
index 0000000..707d01e
--- /dev/null
+++ b/src/internal/xcoff/testdata/gcc-ppc64-aix-dwarf2-exec
Binary files differ
diff --git a/src/internal/xcoff/testdata/hello.c b/src/internal/xcoff/testdata/hello.c
new file mode 100644
index 0000000..34d9ee7
--- /dev/null
+++ b/src/internal/xcoff/testdata/hello.c
@@ -0,0 +1,7 @@
+#include <stdio.h>
+
+void
+main(int argc, char *argv[])
+{
+ printf("hello, world\n");
+}
diff --git a/src/internal/xcoff/testdata/printbye.c b/src/internal/xcoff/testdata/printbye.c
new file mode 100644
index 0000000..9045079
--- /dev/null
+++ b/src/internal/xcoff/testdata/printbye.c
@@ -0,0 +1,5 @@
+#include <stdio.h>
+
+void printbye(){
+ printf("Goodbye\n");
+}
diff --git a/src/internal/xcoff/testdata/printhello.c b/src/internal/xcoff/testdata/printhello.c
new file mode 100644
index 0000000..182aa09
--- /dev/null
+++ b/src/internal/xcoff/testdata/printhello.c
@@ -0,0 +1,5 @@
+#include <stdio.h>
+
+void printhello(){
+ printf("Helloworld\n");
+}
diff --git a/src/internal/xcoff/xcoff.go b/src/internal/xcoff/xcoff.go
new file mode 100644
index 0000000..db81542
--- /dev/null
+++ b/src/internal/xcoff/xcoff.go
@@ -0,0 +1,367 @@
+// 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 xcoff
+
+// File Header.
+type FileHeader32 struct {
+ Fmagic uint16 // Target machine
+ Fnscns uint16 // Number of sections
+ Ftimedat uint32 // Time and date of file creation
+ Fsymptr uint32 // Byte offset to symbol table start
+ Fnsyms uint32 // Number of entries in symbol table
+ Fopthdr uint16 // Number of bytes in optional header
+ Fflags uint16 // Flags
+}
+
+type FileHeader64 struct {
+ Fmagic uint16 // Target machine
+ Fnscns uint16 // Number of sections
+ Ftimedat uint32 // 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 uint32 // Number of entries in symbol table
+}
+
+const (
+ FILHSZ_32 = 20
+ FILHSZ_64 = 24
+)
+const (
+ U802TOCMAGIC = 0737 // AIX 32-bit XCOFF
+ 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
+)
+
+// Section Header.
+type SectionHeader32 struct {
+ Sname [8]byte // Section name
+ Spaddr uint32 // Physical address
+ Svaddr uint32 // Virtual address
+ Ssize uint32 // Section size
+ Sscnptr uint32 // Offset in file to raw data for section
+ Srelptr uint32 // Offset in file to relocation entries for section
+ Slnnoptr uint32 // Offset in file to line number entries for section
+ Snreloc uint16 // Number of relocation entries
+ Snlnno uint16 // Number of line number entries
+ Sflags uint32 // Flags to define the section type
+}
+
+type SectionHeader64 struct {
+ Sname [8]byte // Section name
+ Spaddr uint64 // Physical address
+ Svaddr uint64 // Virtual address
+ Ssize uint64 // Section size
+ Sscnptr uint64 // Offset in file to raw data for section
+ Srelptr uint64 // Offset in file to relocation entries for section
+ Slnnoptr uint64 // Offset in file to line number entries for section
+ Snreloc uint32 // Number of relocation entries
+ Snlnno uint32 // Number of line number entries
+ Sflags uint32 // Flags to define the section type
+ Spad uint32 // Needs to be 72 bytes long
+}
+
+// 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
+)
+
+// Symbol Table Entry.
+type SymEnt32 struct {
+ Nname [8]byte // Symbol name
+ Nvalue uint32 // Symbol value
+ Nscnum uint16 // Section number of symbol
+ Ntype uint16 // Basic and derived type specification
+ Nsclass uint8 // Storage class of symbol
+ Nnumaux uint8 // Number of auxiliary entries
+}
+
+type SymEnt64 struct {
+ Nvalue uint64 // Symbol value
+ Noffset uint32 // Offset of the name in string table or .debug section
+ Nscnum uint16 // Section number of symbol
+ Ntype uint16 // Basic and derived type specification
+ Nsclass uint8 // Storage class of symbol
+ Nnumaux uint8 // 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 AuxFile64 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 AuxFcn32 struct {
+ Xexptr uint32 // File offset to exception table entry
+ Xfsize uint32 // Size of function in bytes
+ Xlnnoptr uint32 // File pointer to line number
+ Xendndx uint32 // Symbol table index of next entry
+ Xpad uint16 // Unused
+}
+type AuxFcn64 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
+}
+
+type AuxSect64 struct {
+ Xscnlen uint64 // section length
+ Xnreloc uint64 // Num RLDs
+ pad uint8
+ Xauxtype uint8 // Type of auxiliary entry
+}
+
+// csect Auxiliary Entry.
+type AuxCSect32 struct {
+ Xscnlen uint32 // 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
+ Xstab uint32 // Reserved
+ Xsnstab uint16 // Reserved
+}
+
+type AuxCSect64 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
+)
+
+// 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
+)
+
+// Defines for File auxiliary definitions: x_ftype field of x_file
+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
+)
+
+// 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 LoaderHeader32 struct {
+ Lversion uint32 // Loader section version number
+ Lnsyms uint32 // Number of symbol table entries
+ Lnreloc uint32 // Number of relocation table entries
+ Listlen uint32 // Length of import file ID string table
+ Lnimpid uint32 // Number of import file IDs
+ Limpoff uint32 // Offset to start of import file IDs
+ Lstlen uint32 // Length of string table
+ Lstoff uint32 // Offset to start of string table
+}
+
+type LoaderHeader64 struct {
+ Lversion uint32 // Loader section version number
+ Lnsyms uint32 // Number of symbol table entries
+ Lnreloc uint32 // Number of relocation table entries
+ Listlen uint32 // Length of import file ID string table
+ Lnimpid uint32 // 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
+}
+
+const (
+ LDHDRSZ_32 = 32
+ LDHDRSZ_64 = 56
+)
+
+// Loader Symbol.
+type LoaderSymbol32 struct {
+ Lname [8]byte // Symbol name or byte offset into string table
+ Lvalue uint32 // Address field
+ Lscnum uint16 // Section number containing symbol
+ Lsmtype uint8 // Symbol type, export, import flags
+ Lsmclas uint8 // Symbol storage class
+ Lifile uint32 // Import file ID; ordinal of import file IDs
+ Lparm uint32 // Parameter type-check field
+}
+
+type LoaderSymbol64 struct {
+ Lvalue uint64 // Address field
+ Loffset uint32 // Byte offset into string table of symbol name
+ Lscnum uint16 // Section number containing symbol
+ Lsmtype uint8 // Symbol type, export, import flags
+ Lsmclas uint8 // Symbol storage class
+ Lifile uint32 // Import file ID; ordinal of import file IDs
+ Lparm uint32 // Parameter type-check field
+}
+
+type Reloc32 struct {
+ Rvaddr uint32 // (virtual) address of reference
+ Rsymndx uint32 // Index into symbol table
+ Rsize uint8 // Sign and reloc bit len
+ Rtype uint8 // Toc relocation type
+}
+
+type Reloc64 struct {
+ Rvaddr uint64 // (virtual) address of reference
+ Rsymndx uint32 // Index into symbol table
+ Rsize uint8 // Sign and reloc bit len
+ Rtype uint8 // Toc relocation type
+}
+
+const (
+ R_POS = 0x00 // A(sym) Positive Relocation
+ R_NEG = 0x01 // -A(sym) Negative Relocation
+ R_REL = 0x02 // A(sym-*) Relative to self
+ R_TOC = 0x03 // A(sym-TOC) Relative to TOC
+ R_TRL = 0x12 // A(sym-TOC) TOC Relative indirect load.
+
+ R_TRLA = 0x13 // A(sym-TOC) TOC Rel load address. modifiable inst
+ R_GL = 0x05 // A(external TOC of sym) Global Linkage
+ R_TCL = 0x06 // A(local TOC of sym) Local object TOC address
+ R_RL = 0x0C // A(sym) Pos indirect load. modifiable instruction
+ R_RLA = 0x0D // A(sym) Pos Load Address. modifiable instruction
+ R_REF = 0x0F // AL0(sym) Non relocating ref. No garbage collect
+ R_BA = 0x08 // A(sym) Branch absolute. Cannot modify instruction
+ R_RBA = 0x18 // A(sym) Branch absolute. modifiable instruction
+ R_BR = 0x0A // A(sym-*) Branch rel to self. non modifiable
+ R_RBR = 0x1A // A(sym-*) Branch rel to self. modifiable instr
+
+ R_TLS = 0x20 // General-dynamic reference to TLS symbol
+ R_TLS_IE = 0x21 // Initial-exec reference to TLS symbol
+ R_TLS_LD = 0x22 // Local-dynamic reference to TLS symbol
+ R_TLS_LE = 0x23 // Local-exec reference to TLS symbol
+ R_TLSM = 0x24 // Module reference to TLS symbol
+ R_TLSML = 0x25 // Module reference to local (own) module
+
+ R_TOCU = 0x30 // Relative to TOC - high order bits
+ R_TOCL = 0x31 // Relative to TOC - low order bits
+)