|
| 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/internal/xcoff" |
| 13 | + "cmd/link/internal/sym" |
| 14 | + "errors" |
| 15 | + "fmt" |
| 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)).Seek(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 | +} |
0 commit comments