github.com/gagliardetto/golang-go@v0.0.0-20201020153340-53909ea70814/cmd/link/internal/loadxcoff/ldxcoff.go (about)

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