github.com/rsc/go@v0.0.0-20150416155037-e040fd465409/src/cmd/internal/ld/objfile.go (about) 1 // Copyright 2013 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 ld 6 7 import ( 8 "bytes" 9 "fmt" 10 "log" 11 "strconv" 12 "strings" 13 ) 14 15 const ( 16 startmagic = "\x00\x00go13ld" 17 endmagic = "\xff\xffgo13ld" 18 ) 19 20 func ldobjfile(ctxt *Link, f *Biobuf, pkg string, length int64, pn string) { 21 start := Boffset(f) 22 ctxt.Version++ 23 var buf [8]uint8 24 Bread(f, buf[:]) 25 if string(buf[:]) != startmagic { 26 log.Fatalf("%s: invalid file start %x %x %x %x %x %x %x %x", pn, buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]) 27 } 28 c := Bgetc(f) 29 if c != 1 { 30 log.Fatalf("%s: invalid file version number %d", pn, c) 31 } 32 33 var lib string 34 for { 35 lib = rdstring(f) 36 if lib == "" { 37 break 38 } 39 addlib(ctxt, pkg, pn, lib) 40 } 41 42 for { 43 c = Bgetc(f) 44 Bungetc(f) 45 if c == 0xff { 46 break 47 } 48 readsym(ctxt, f, pkg, pn) 49 } 50 51 buf = [8]uint8{} 52 Bread(f, buf[:]) 53 if string(buf[:]) != endmagic { 54 log.Fatalf("%s: invalid file end", pn) 55 } 56 57 if Boffset(f) != start+length { 58 log.Fatalf("%s: unexpected end at %d, want %d", pn, int64(Boffset(f)), int64(start+length)) 59 } 60 } 61 62 var readsym_ndup int 63 64 func readsym(ctxt *Link, f *Biobuf, pkg string, pn string) { 65 if Bgetc(f) != 0xfe { 66 log.Fatalf("readsym out of sync") 67 } 68 t := int(rdint(f)) 69 name := expandpkg(rdstring(f), pkg) 70 v := int(rdint(f)) 71 if v != 0 && v != 1 { 72 log.Fatalf("invalid symbol version %d", v) 73 } 74 dupok := int(rdint(f)) 75 dupok &= 1 76 size := int(rdint(f)) 77 typ := rdsym(ctxt, f, pkg) 78 var data []byte 79 rddata(f, &data) 80 nreloc := int(rdint(f)) 81 82 if v != 0 { 83 v = ctxt.Version 84 } 85 s := Linklookup(ctxt, name, v) 86 var dup *LSym 87 if s.Type != 0 && s.Type != SXREF { 88 if (t == SDATA || t == SBSS || t == SNOPTRBSS) && len(data) == 0 && nreloc == 0 { 89 if s.Size < int64(size) { 90 s.Size = int64(size) 91 } 92 if typ != nil && s.Gotype == nil { 93 s.Gotype = typ 94 } 95 return 96 } 97 98 if (s.Type == SDATA || s.Type == SBSS || s.Type == SNOPTRBSS) && len(s.P) == 0 && len(s.R) == 0 { 99 goto overwrite 100 } 101 if s.Type != SBSS && s.Type != SNOPTRBSS && dupok == 0 && s.Dupok == 0 { 102 log.Fatalf("duplicate symbol %s (types %d and %d) in %s and %s", s.Name, s.Type, t, s.File, pn) 103 } 104 if len(s.P) > 0 { 105 dup = s 106 s = linknewsym(ctxt, ".dup", readsym_ndup) 107 readsym_ndup++ // scratch 108 } 109 } 110 111 overwrite: 112 s.File = pkg 113 s.Dupok = uint8(dupok) 114 if t == SXREF { 115 log.Fatalf("bad sxref") 116 } 117 if t == 0 { 118 log.Fatalf("missing type for %s in %s", name, pn) 119 } 120 if t == SBSS && (s.Type == SRODATA || s.Type == SNOPTRBSS) { 121 t = int(s.Type) 122 } 123 s.Type = int16(t) 124 if s.Size < int64(size) { 125 s.Size = int64(size) 126 } 127 if typ != nil { // if bss sym defined multiple times, take type from any one def 128 s.Gotype = typ 129 } 130 if dup != nil && typ != nil { 131 dup.Gotype = typ 132 } 133 s.P = data 134 s.P = s.P[:len(data)] 135 if nreloc > 0 { 136 s.R = make([]Reloc, nreloc) 137 s.R = s.R[:nreloc] 138 var r *Reloc 139 for i := 0; i < nreloc; i++ { 140 r = &s.R[i] 141 r.Off = int32(rdint(f)) 142 r.Siz = uint8(rdint(f)) 143 r.Type = int32(rdint(f)) 144 r.Add = rdint(f) 145 r.Xadd = rdint(f) 146 r.Sym = rdsym(ctxt, f, pkg) 147 r.Xsym = rdsym(ctxt, f, pkg) 148 } 149 } 150 151 if len(s.P) > 0 && dup != nil && len(dup.P) > 0 && strings.HasPrefix(s.Name, "gclocals·") { 152 // content-addressed garbage collection liveness bitmap symbol. 153 // double check for hash collisions. 154 if !bytes.Equal(s.P, dup.P) { 155 log.Fatalf("dupok hash collision for %s in %s and %s", s.Name, s.File, pn) 156 } 157 } 158 159 if s.Type == STEXT { 160 s.Args = int32(rdint(f)) 161 s.Locals = int32(rdint(f)) 162 s.Nosplit = uint8(rdint(f)) 163 v := int(rdint(f)) 164 s.Leaf = uint8(v & 1) 165 s.Cfunc = uint8(v & 2) 166 n := int(rdint(f)) 167 var a *Auto 168 for i := 0; i < n; i++ { 169 a = new(Auto) 170 a.Asym = rdsym(ctxt, f, pkg) 171 a.Aoffset = int32(rdint(f)) 172 a.Name = int16(rdint(f)) 173 a.Gotype = rdsym(ctxt, f, pkg) 174 a.Link = s.Autom 175 s.Autom = a 176 } 177 178 s.Pcln = new(Pcln) 179 pc := s.Pcln 180 rddata(f, &pc.Pcsp.P) 181 rddata(f, &pc.Pcfile.P) 182 rddata(f, &pc.Pcline.P) 183 n = int(rdint(f)) 184 pc.Pcdata = make([]Pcdata, n) 185 pc.Npcdata = n 186 for i := 0; i < n; i++ { 187 rddata(f, &pc.Pcdata[i].P) 188 } 189 n = int(rdint(f)) 190 pc.Funcdata = make([]*LSym, n) 191 pc.Funcdataoff = make([]int64, n) 192 pc.Nfuncdata = n 193 for i := 0; i < n; i++ { 194 pc.Funcdata[i] = rdsym(ctxt, f, pkg) 195 } 196 for i := 0; i < n; i++ { 197 pc.Funcdataoff[i] = rdint(f) 198 } 199 n = int(rdint(f)) 200 pc.File = make([]*LSym, n) 201 pc.Nfile = n 202 for i := 0; i < n; i++ { 203 pc.File[i] = rdsym(ctxt, f, pkg) 204 } 205 206 if dup == nil { 207 if s.Onlist != 0 { 208 log.Fatalf("symbol %s listed multiple times", s.Name) 209 } 210 s.Onlist = 1 211 if ctxt.Etextp != nil { 212 ctxt.Etextp.Next = s 213 } else { 214 ctxt.Textp = s 215 } 216 ctxt.Etextp = s 217 } 218 } 219 220 if ctxt.Debugasm != 0 { 221 fmt.Fprintf(ctxt.Bso, "%s ", s.Name) 222 if s.Version != 0 { 223 fmt.Fprintf(ctxt.Bso, "v=%d ", s.Version) 224 } 225 if s.Type != 0 { 226 fmt.Fprintf(ctxt.Bso, "t=%d ", s.Type) 227 } 228 if s.Dupok != 0 { 229 fmt.Fprintf(ctxt.Bso, "dupok ") 230 } 231 if s.Cfunc != 0 { 232 fmt.Fprintf(ctxt.Bso, "cfunc ") 233 } 234 if s.Nosplit != 0 { 235 fmt.Fprintf(ctxt.Bso, "nosplit ") 236 } 237 fmt.Fprintf(ctxt.Bso, "size=%d value=%d", int64(s.Size), int64(s.Value)) 238 if s.Type == STEXT { 239 fmt.Fprintf(ctxt.Bso, " args=%#x locals=%#x", uint64(s.Args), uint64(s.Locals)) 240 } 241 fmt.Fprintf(ctxt.Bso, "\n") 242 var c int 243 var j int 244 for i := 0; i < len(s.P); { 245 fmt.Fprintf(ctxt.Bso, "\t%#04x", uint(i)) 246 for j = i; j < i+16 && j < len(s.P); j++ { 247 fmt.Fprintf(ctxt.Bso, " %02x", s.P[j]) 248 } 249 for ; j < i+16; j++ { 250 fmt.Fprintf(ctxt.Bso, " ") 251 } 252 fmt.Fprintf(ctxt.Bso, " ") 253 for j = i; j < i+16 && j < len(s.P); j++ { 254 c = int(s.P[j]) 255 if ' ' <= c && c <= 0x7e { 256 fmt.Fprintf(ctxt.Bso, "%c", c) 257 } else { 258 fmt.Fprintf(ctxt.Bso, ".") 259 } 260 } 261 262 fmt.Fprintf(ctxt.Bso, "\n") 263 i += 16 264 } 265 266 var r *Reloc 267 for i := 0; i < len(s.R); i++ { 268 r = &s.R[i] 269 fmt.Fprintf(ctxt.Bso, "\trel %d+%d t=%d %s+%d\n", int(r.Off), r.Siz, r.Type, r.Sym.Name, int64(r.Add)) 270 } 271 } 272 } 273 274 func rdint(f *Biobuf) int64 { 275 var c int 276 277 uv := uint64(0) 278 for shift := 0; ; shift += 7 { 279 if shift >= 64 { 280 log.Fatalf("corrupt input") 281 } 282 c = Bgetc(f) 283 uv |= uint64(c&0x7F) << uint(shift) 284 if c&0x80 == 0 { 285 break 286 } 287 } 288 289 return int64(uv>>1) ^ (int64(uint64(uv)<<63) >> 63) 290 } 291 292 func rdstring(f *Biobuf) string { 293 n := rdint(f) 294 p := make([]byte, n) 295 Bread(f, p) 296 return string(p) 297 } 298 299 func rddata(f *Biobuf, pp *[]byte) { 300 n := rdint(f) 301 *pp = make([]byte, n) 302 Bread(f, *pp) 303 } 304 305 var symbuf []byte 306 307 func rdsym(ctxt *Link, f *Biobuf, pkg string) *LSym { 308 n := int(rdint(f)) 309 if n == 0 { 310 rdint(f) 311 return nil 312 } 313 314 if len(symbuf) < n { 315 symbuf = make([]byte, n) 316 } 317 Bread(f, symbuf[:n]) 318 p := string(symbuf[:n]) 319 v := int(rdint(f)) 320 if v != 0 { 321 v = ctxt.Version 322 } 323 s := Linklookup(ctxt, expandpkg(p, pkg), v) 324 325 if v == 0 && s.Name[0] == '$' && s.Type == 0 { 326 if strings.HasPrefix(s.Name, "$f32.") { 327 x, _ := strconv.ParseUint(s.Name[5:], 16, 32) 328 i32 := int32(x) 329 s.Type = SRODATA 330 s.Local = true 331 Adduint32(ctxt, s, uint32(i32)) 332 s.Reachable = false 333 } else if strings.HasPrefix(s.Name, "$f64.") || strings.HasPrefix(s.Name, "$i64.") { 334 x, _ := strconv.ParseUint(s.Name[5:], 16, 64) 335 i64 := int64(x) 336 s.Type = SRODATA 337 s.Local = true 338 Adduint64(ctxt, s, uint64(i64)) 339 s.Reachable = false 340 } 341 } 342 343 return s 344 }