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