...

Source file src/pkg/cmd/link/internal/loadxcoff/ldxcoff.go

     1	// Copyright 2018 The Go Authors. All rights reserved.
     2	// Use of this source code is governed by a BSD-style
     3	// license that can be found in the LICENSE file.
     4	
     5	// Package loadxcoff implements a XCOFF file reader.
     6	package loadxcoff
     7	
     8	import (
     9		"cmd/internal/bio"
    10		"cmd/internal/objabi"
    11		"cmd/internal/sys"
    12		"cmd/link/internal/sym"
    13		"errors"
    14		"fmt"
    15		"internal/xcoff"
    16	)
    17	
    18	// ldSection is an XCOFF section with its symbols.
    19	type ldSection struct {
    20		xcoff.Section
    21		sym *sym.Symbol
    22	}
    23	
    24	// TODO(brainman): maybe just add ReadAt method to bio.Reader instead of creating xcoffBiobuf
    25	
    26	// xcoffBiobuf makes bio.Reader look like io.ReaderAt.
    27	type xcoffBiobuf bio.Reader
    28	
    29	func (f *xcoffBiobuf) ReadAt(p []byte, off int64) (int, error) {
    30		ret := ((*bio.Reader)(f)).MustSeek(off, 0)
    31		if ret < 0 {
    32			return 0, errors.New("fail to seek")
    33		}
    34		n, err := f.Read(p)
    35		if err != nil {
    36			return 0, err
    37		}
    38		return n, nil
    39	}
    40	
    41	// Load loads the Xcoff file pn from f.
    42	// Symbols are written into syms, and a slice of the text symbols is returned.
    43	func Load(arch *sys.Arch, syms *sym.Symbols, input *bio.Reader, pkg string, length int64, pn string) (textp []*sym.Symbol, err error) {
    44		errorf := func(str string, args ...interface{}) ([]*sym.Symbol, error) {
    45			return nil, fmt.Errorf("loadxcoff: %v: %v", pn, fmt.Sprintf(str, args...))
    46		}
    47		localSymVersion := syms.IncVersion()
    48	
    49		var ldSections []*ldSection
    50	
    51		f, err := xcoff.NewFile((*xcoffBiobuf)(input))
    52		if err != nil {
    53			return nil, err
    54		}
    55		defer f.Close()
    56	
    57		for _, sect := range f.Sections {
    58			//only text, data and bss section
    59			if sect.Type < xcoff.STYP_TEXT || sect.Type > xcoff.STYP_BSS {
    60				continue
    61			}
    62			lds := new(ldSection)
    63			lds.Section = *sect
    64			name := fmt.Sprintf("%s(%s)", pkg, lds.Name)
    65			s := syms.Lookup(name, localSymVersion)
    66	
    67			switch lds.Type {
    68			default:
    69				return errorf("unrecognized section type 0x%x", lds.Type)
    70			case xcoff.STYP_TEXT:
    71				s.Type = sym.STEXT
    72			case xcoff.STYP_DATA:
    73				s.Type = sym.SNOPTRDATA
    74			case xcoff.STYP_BSS:
    75				s.Type = sym.SNOPTRBSS
    76			}
    77	
    78			s.Size = int64(lds.Size)
    79			if s.Type != sym.SNOPTRBSS {
    80				data, err := lds.Section.Data()
    81				if err != nil {
    82					return nil, err
    83				}
    84				s.P = data
    85			}
    86	
    87			lds.sym = s
    88			ldSections = append(ldSections, lds)
    89		}
    90	
    91		// sx = symbol from file
    92		// s = symbol for syms
    93		for _, sx := range f.Symbols {
    94			// get symbol type
    95			stype, errmsg := getSymbolType(f, sx)
    96			if errmsg != "" {
    97				return errorf("error reading symbol %s: %s", sx.Name, errmsg)
    98			}
    99			if stype == sym.Sxxx {
   100				continue
   101			}
   102	
   103			s := syms.Lookup(sx.Name, 0)
   104	
   105			// Text symbol
   106			if s.Type == sym.STEXT {
   107				if s.Attr.OnList() {
   108					return errorf("symbol %s listed multiple times", s.Name)
   109				}
   110				s.Attr |= sym.AttrOnList
   111				textp = append(textp, s)
   112			}
   113		}
   114	
   115		// Read relocations
   116		for _, sect := range ldSections {
   117			// TODO(aix): Dwarf section relocation if needed
   118			if sect.Type != xcoff.STYP_TEXT && sect.Type != xcoff.STYP_DATA {
   119				continue
   120			}
   121			rs := make([]sym.Reloc, sect.Nreloc)
   122			for i, rx := range sect.Relocs {
   123				r := &rs[i]
   124	
   125				r.Sym = syms.Lookup(rx.Symbol.Name, 0)
   126				if uint64(int32(rx.VirtualAddress)) != rx.VirtualAddress {
   127					return errorf("virtual address of a relocation is too big: 0x%x", rx.VirtualAddress)
   128				}
   129				r.Off = int32(rx.VirtualAddress)
   130				switch rx.Type {
   131				default:
   132					return errorf("section %s: unknown relocation of type 0x%x", sect.Name, rx.Type)
   133				case xcoff.R_POS:
   134					// Reloc the address of r.Sym
   135					// Length should be 64
   136					if rx.Length != 64 {
   137						return errorf("section %s: relocation R_POS has length different from 64: %d", sect.Name, rx.Length)
   138					}
   139					r.Siz = 8
   140					r.Type = objabi.R_CONST
   141					r.Add = int64(rx.Symbol.Value)
   142	
   143				case xcoff.R_RBR:
   144					r.Siz = 4
   145					r.Type = objabi.R_CALLPOWER
   146					r.Add = 0 //
   147	
   148				}
   149			}
   150			s := sect.sym
   151			s.R = rs
   152			s.R = s.R[:sect.Nreloc]
   153		}
   154		return textp, nil
   155	
   156	}
   157	
   158	// Convert symbol xcoff type to sym.SymKind
   159	// Returns nil if this shouldn't be added into syms (like .file or .dw symbols )
   160	func getSymbolType(f *xcoff.File, s *xcoff.Symbol) (stype sym.SymKind, err string) {
   161		// .file symbol
   162		if s.SectionNumber == -2 {
   163			if s.StorageClass == xcoff.C_FILE {
   164				return sym.Sxxx, ""
   165			}
   166			return sym.Sxxx, "unrecognised StorageClass for sectionNumber = -2"
   167		}
   168	
   169		// extern symbols
   170		// TODO(aix)
   171		if s.SectionNumber == 0 {
   172			return sym.Sxxx, ""
   173		}
   174	
   175		sectType := f.Sections[s.SectionNumber-1].SectionHeader.Type
   176		switch sectType {
   177		default:
   178			return sym.Sxxx, fmt.Sprintf("getSymbolType for Section type 0x%x not implemented", sectType)
   179		case xcoff.STYP_DWARF, xcoff.STYP_DEBUG:
   180			return sym.Sxxx, ""
   181		case xcoff.STYP_DATA, xcoff.STYP_BSS, xcoff.STYP_TEXT:
   182		}
   183	
   184		switch s.StorageClass {
   185		default:
   186			return sym.Sxxx, fmt.Sprintf("getSymbolType for Storage class 0x%x not implemented", s.StorageClass)
   187		case xcoff.C_HIDEXT, xcoff.C_EXT, xcoff.C_WEAKEXT:
   188			switch s.AuxCSect.StorageMappingClass {
   189			default:
   190				return sym.Sxxx, fmt.Sprintf("getSymbolType for Storage class 0x%x and Storage Map 0x%x not implemented", s.StorageClass, s.AuxCSect.StorageMappingClass)
   191	
   192			// Program Code
   193			case xcoff.XMC_PR:
   194				if sectType == xcoff.STYP_TEXT {
   195					return sym.STEXT, ""
   196				}
   197				return sym.Sxxx, fmt.Sprintf("unrecognised Section Type 0x%x for Storage Class 0x%x with Storage Map XMC_PR", sectType, s.StorageClass)
   198	
   199			// Read/Write Data
   200			case xcoff.XMC_RW:
   201				if sectType == xcoff.STYP_DATA {
   202					return sym.SDATA, ""
   203				}
   204				if sectType == xcoff.STYP_BSS {
   205					return sym.SBSS, ""
   206				}
   207				return sym.Sxxx, fmt.Sprintf("unrecognised Section Type 0x%x for Storage Class 0x%x with Storage Map XMC_RW", sectType, s.StorageClass)
   208	
   209			// Function descriptor
   210			case xcoff.XMC_DS:
   211				if sectType == xcoff.STYP_DATA {
   212					return sym.SDATA, ""
   213				}
   214				return sym.Sxxx, fmt.Sprintf("unrecognised Section Type 0x%x for Storage Class 0x%x with Storage Map XMC_DS", sectType, s.StorageClass)
   215	
   216			// TOC anchor and TOC entry
   217			case xcoff.XMC_TC0, xcoff.XMC_TE:
   218				if sectType == xcoff.STYP_DATA {
   219					return sym.SXCOFFTOC, ""
   220				}
   221				return sym.Sxxx, fmt.Sprintf("unrecognised Section Type 0x%x for Storage Class 0x%x with Storage Map XMC_DS", sectType, s.StorageClass)
   222	
   223			}
   224		}
   225	}
   226	

View as plain text