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