Source file src/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/loader"
    13  	"cmd/link/internal/sym"
    14  	"errors"
    15  	"fmt"
    16  	"internal/xcoff"
    17  )
    18  
    19  // ldSection is an XCOFF section with its symbols.
    20  type ldSection struct {
    21  	xcoff.Section
    22  	sym loader.Sym
    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  // loads the Xcoff file pn from f.
    43  // Symbols are written into loader, and a slice of the text symbols is returned.
    44  func Load(l *loader.Loader, arch *sys.Arch, localSymVersion int, input *bio.Reader, pkg string, length int64, pn string) (textp []loader.Sym, err error) {
    45  	errorf := func(str string, args ...interface{}) ([]loader.Sym, error) {
    46  		return nil, fmt.Errorf("loadxcoff: %v: %v", pn, fmt.Sprintf(str, args...))
    47  	}
    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  		symbol := l.LookupOrCreateSym(name, localSymVersion)
    66  		s := l.MakeSymbolUpdater(symbol)
    67  
    68  		switch lds.Type {
    69  		default:
    70  			return errorf("unrecognized section type 0x%x", lds.Type)
    71  		case xcoff.STYP_TEXT:
    72  			s.SetType(sym.STEXT)
    73  		case xcoff.STYP_DATA:
    74  			s.SetType(sym.SNOPTRDATA)
    75  		case xcoff.STYP_BSS:
    76  			s.SetType(sym.SNOPTRBSS)
    77  		}
    78  
    79  		s.SetSize(int64(lds.Size))
    80  		if s.Type() != sym.SNOPTRBSS {
    81  			data, err := lds.Section.Data()
    82  			if err != nil {
    83  				return nil, err
    84  			}
    85  			s.SetData(data)
    86  		}
    87  
    88  		lds.sym = symbol
    89  		ldSections = append(ldSections, lds)
    90  	}
    91  
    92  	// sx = symbol from file
    93  	// s = symbol for loader
    94  	for _, sx := range f.Symbols {
    95  		// get symbol type
    96  		stype, errmsg := getSymbolType(f, sx)
    97  		if errmsg != "" {
    98  			return errorf("error reading symbol %s: %s", sx.Name, errmsg)
    99  		}
   100  		if stype == sym.Sxxx {
   101  			continue
   102  		}
   103  
   104  		s := l.LookupOrCreateSym(sx.Name, 0)
   105  
   106  		// Text symbol
   107  		if l.SymType(s).IsText() {
   108  			if l.AttrOnList(s) {
   109  				return errorf("symbol %s listed multiple times", l.SymName(s))
   110  			}
   111  			l.SetAttrOnList(s, true)
   112  			textp = append(textp, s)
   113  		}
   114  	}
   115  
   116  	// Read relocations
   117  	for _, sect := range ldSections {
   118  		// TODO(aix): Dwarf section relocation if needed
   119  		if sect.Type != xcoff.STYP_TEXT && sect.Type != xcoff.STYP_DATA {
   120  			continue
   121  		}
   122  		sb := l.MakeSymbolUpdater(sect.sym)
   123  		for _, rx := range sect.Relocs {
   124  			rSym := l.LookupOrCreateCgoExport(rx.Symbol.Name, 0)
   125  			if uint64(int32(rx.VirtualAddress)) != rx.VirtualAddress {
   126  				return errorf("virtual address of a relocation is too big: 0x%x", rx.VirtualAddress)
   127  			}
   128  			rOff := int32(rx.VirtualAddress)
   129  			var rSize uint8
   130  			var rType objabi.RelocType
   131  			var rAdd int64
   132  			switch rx.Type {
   133  			default:
   134  				return errorf("section %s: unknown relocation of type 0x%x", sect.Name, rx.Type)
   135  			case xcoff.R_POS:
   136  				// Reloc the address of r.Sym
   137  				// Length should be 64
   138  				if rx.Length != 64 {
   139  					return errorf("section %s: relocation R_POS has length different from 64: %d", sect.Name, rx.Length)
   140  				}
   141  				rSize = 8
   142  				rType = objabi.R_CONST
   143  				rAdd = int64(rx.Symbol.Value)
   144  
   145  			case xcoff.R_RBR:
   146  				rSize = 4
   147  				rType = objabi.R_CALLPOWER
   148  				rAdd = 0
   149  			}
   150  			r, _ := sb.AddRel(rType)
   151  			r.SetOff(rOff)
   152  			r.SetSiz(rSize)
   153  			r.SetSym(rSym)
   154  			r.SetAdd(rAdd)
   155  		}
   156  	}
   157  	return textp, nil
   158  }
   159  
   160  // Convert symbol xcoff type to sym.SymKind
   161  // Returns nil if this shouldn't be added into loader (like .file or .dw symbols )
   162  func getSymbolType(f *xcoff.File, s *xcoff.Symbol) (stype sym.SymKind, err string) {
   163  	// .file symbol
   164  	if s.SectionNumber == -2 {
   165  		if s.StorageClass == xcoff.C_FILE {
   166  			return sym.Sxxx, ""
   167  		}
   168  		return sym.Sxxx, "unrecognised StorageClass for sectionNumber = -2"
   169  	}
   170  
   171  	// extern symbols
   172  	// TODO(aix)
   173  	if s.SectionNumber == 0 {
   174  		return sym.Sxxx, ""
   175  	}
   176  
   177  	sectType := f.Sections[s.SectionNumber-1].SectionHeader.Type
   178  	switch sectType {
   179  	default:
   180  		return sym.Sxxx, fmt.Sprintf("getSymbolType for Section type 0x%x not implemented", sectType)
   181  	case xcoff.STYP_DWARF, xcoff.STYP_DEBUG:
   182  		return sym.Sxxx, ""
   183  	case xcoff.STYP_DATA, xcoff.STYP_BSS, xcoff.STYP_TEXT:
   184  	}
   185  
   186  	switch s.StorageClass {
   187  	default:
   188  		return sym.Sxxx, fmt.Sprintf("getSymbolType for Storage class 0x%x not implemented", s.StorageClass)
   189  	case xcoff.C_HIDEXT, xcoff.C_EXT, xcoff.C_WEAKEXT:
   190  		switch s.AuxCSect.StorageMappingClass {
   191  		default:
   192  			return sym.Sxxx, fmt.Sprintf("getSymbolType for Storage class 0x%x and Storage Map 0x%x not implemented", s.StorageClass, s.AuxCSect.StorageMappingClass)
   193  
   194  		// Program Code
   195  		case xcoff.XMC_PR:
   196  			if sectType == xcoff.STYP_TEXT {
   197  				return sym.STEXT, ""
   198  			}
   199  			return sym.Sxxx, fmt.Sprintf("unrecognised Section Type 0x%x for Storage Class 0x%x with Storage Map XMC_PR", sectType, s.StorageClass)
   200  
   201  		// Read/Write Data
   202  		case xcoff.XMC_RW:
   203  			if sectType == xcoff.STYP_DATA {
   204  				return sym.SDATA, ""
   205  			}
   206  			if sectType == xcoff.STYP_BSS {
   207  				return sym.SBSS, ""
   208  			}
   209  			return sym.Sxxx, fmt.Sprintf("unrecognised Section Type 0x%x for Storage Class 0x%x with Storage Map XMC_RW", sectType, s.StorageClass)
   210  
   211  		// Function descriptor
   212  		case xcoff.XMC_DS:
   213  			if sectType == xcoff.STYP_DATA {
   214  				return sym.SDATA, ""
   215  			}
   216  			return sym.Sxxx, fmt.Sprintf("unrecognised Section Type 0x%x for Storage Class 0x%x with Storage Map XMC_DS", sectType, s.StorageClass)
   217  
   218  		// TOC anchor and TOC entry
   219  		case xcoff.XMC_TC0, xcoff.XMC_TE:
   220  			if sectType == xcoff.STYP_DATA {
   221  				return sym.SXCOFFTOC, ""
   222  			}
   223  			return sym.Sxxx, fmt.Sprintf("unrecognised Section Type 0x%x for Storage Class 0x%x with Storage Map XMC_DS", sectType, s.StorageClass)
   224  
   225  		}
   226  	}
   227  }
   228  

View as plain text