Home | History | Annotate | Download | only in obj
      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 // Writing of Go object files.
      6 //
      7 // Originally, Go object files were Plan 9 object files, but no longer.
      8 // Now they are more like standard object files, in that each symbol is defined
      9 // by an associated memory image (bytes) and a list of relocations to apply
     10 // during linking. We do not (yet?) use a standard file format, however.
     11 // For now, the format is chosen to be as simple as possible to read and write.
     12 // It may change for reasons of efficiency, or we may even switch to a
     13 // standard file format if there are compelling benefits to doing so.
     14 // See golang.org/s/go13linker for more background.
     15 //
     16 // The file format is:
     17 //
     18 //	- magic header: "\x00\x00go13ld"
     19 //	- byte 1 - version number
     20 //	- sequence of strings giving dependencies (imported packages)
     21 //	- empty string (marks end of sequence)
     22 //	- sequence of defined symbols
     23 //	- byte 0xff (marks end of sequence)
     24 //	- magic footer: "\xff\xffgo13ld"
     25 //
     26 // All integers are stored in a zigzag varint format.
     27 // See golang.org/s/go12symtab for a definition.
     28 //
     29 // Data blocks and strings are both stored as an integer
     30 // followed by that many bytes.
     31 //
     32 // A symbol reference is a string name followed by a version.
     33 // An empty name corresponds to a nil LSym* pointer.
     34 //
     35 // Each symbol is laid out as the following fields (taken from LSym*):
     36 //
     37 //	- byte 0xfe (sanity check for synchronization)
     38 //	- type [int]
     39 //	- name [string]
     40 //	- version [int]
     41 //	- flags [int]
     42 //		1 dupok
     43 //	- size [int]
     44 //	- gotype [symbol reference]
     45 //	- p [data block]
     46 //	- nr [int]
     47 //	- r [nr relocations, sorted by off]
     48 //
     49 // If type == STEXT, there are a few more fields:
     50 //
     51 //	- args [int]
     52 //	- locals [int]
     53 //	- nosplit [int]
     54 //	- flags [int]
     55 //		1 leaf
     56 //		2 C function
     57 //	- nlocal [int]
     58 //	- local [nlocal automatics]
     59 //	- pcln [pcln table]
     60 //
     61 // Each relocation has the encoding:
     62 //
     63 //	- off [int]
     64 //	- siz [int]
     65 //	- type [int]
     66 //	- add [int]
     67 //	- xadd [int]
     68 //	- sym [symbol reference]
     69 //	- xsym [symbol reference]
     70 //
     71 // Each local has the encoding:
     72 //
     73 //	- asym [symbol reference]
     74 //	- offset [int]
     75 //	- type [int]
     76 //	- gotype [symbol reference]
     77 //
     78 // The pcln table has the encoding:
     79 //
     80 //	- pcsp [data block]
     81 //	- pcfile [data block]
     82 //	- pcline [data block]
     83 //	- npcdata [int]
     84 //	- pcdata [npcdata data blocks]
     85 //	- nfuncdata [int]
     86 //	- funcdata [nfuncdata symbol references]
     87 //	- funcdatasym [nfuncdata ints]
     88 //	- nfile [int]
     89 //	- file [nfile symbol references]
     90 //
     91 // The file layout and meaning of type integers are architecture-independent.
     92 //
     93 // TODO(rsc): The file format is good for a first pass but needs work.
     94 //	- There are SymID in the object file that should really just be strings.
     95 //	- The actual symbol memory images are interlaced with the symbol
     96 //	  metadata. They should be separated, to reduce the I/O required to
     97 //	  load just the metadata.
     98 //	- The symbol references should be shortened, either with a symbol
     99 //	  table or by using a simple backward index to an earlier mentioned symbol.
    100 
    101 package obj
    102 
    103 import (
    104 	"fmt"
    105 	"log"
    106 	"path/filepath"
    107 	"strings"
    108 )
    109 
    110 var outfile string
    111 
    112 // The Go and C compilers, and the assembler, call writeobj to write
    113 // out a Go object file.  The linker does not call this; the linker
    114 // does not write out object files.
    115 func Writeobjdirect(ctxt *Link, b *Biobuf) {
    116 	var flag int
    117 	var s *LSym
    118 	var p *Prog
    119 	var plink *Prog
    120 	var a *Auto
    121 
    122 	// Build list of symbols, and assign instructions to lists.
    123 	// Ignore ctxt->plist boundaries. There are no guarantees there,
    124 	// and the C compilers and assemblers just use one big list.
    125 	var text *LSym
    126 
    127 	var curtext *LSym
    128 	var data *LSym
    129 	var etext *LSym
    130 	var edata *LSym
    131 	for pl := ctxt.Plist; pl != nil; pl = pl.Link {
    132 		for p = pl.Firstpc; p != nil; p = plink {
    133 			if ctxt.Debugasm != 0 && ctxt.Debugvlog != 0 {
    134 				fmt.Printf("obj: %v\n", p)
    135 			}
    136 			plink = p.Link
    137 			p.Link = nil
    138 
    139 			if p.As == AEND {
    140 				continue
    141 			}
    142 
    143 			if p.As == ATYPE {
    144 				// Assume each TYPE instruction describes
    145 				// a different local variable or parameter,
    146 				// so no dedup.
    147 				// Using only the TYPE instructions means
    148 				// that we discard location information about local variables
    149 				// in C and assembly functions; that information is inferred
    150 				// from ordinary references, because there are no TYPE
    151 				// instructions there. Without the type information, gdb can't
    152 				// use the locations, so we don't bother to save them.
    153 				// If something else could use them, we could arrange to
    154 				// preserve them.
    155 				if curtext == nil {
    156 					continue
    157 				}
    158 				a = new(Auto)
    159 				a.Asym = p.From.Sym
    160 				a.Aoffset = int32(p.From.Offset)
    161 				a.Name = int16(p.From.Name)
    162 				a.Gotype = p.From.Gotype
    163 				a.Link = curtext.Autom
    164 				curtext.Autom = a
    165 				continue
    166 			}
    167 
    168 			if p.As == AGLOBL {
    169 				s = p.From.Sym
    170 				tmp6 := s.Seenglobl
    171 				s.Seenglobl++
    172 				if tmp6 != 0 {
    173 					fmt.Printf("duplicate %v\n", p)
    174 				}
    175 				if s.Onlist != 0 {
    176 					log.Fatalf("symbol %s listed multiple times", s.Name)
    177 				}
    178 				s.Onlist = 1
    179 				if data == nil {
    180 					data = s
    181 				} else {
    182 					edata.Next = s
    183 				}
    184 				s.Next = nil
    185 				s.Size = p.To.Offset
    186 				if s.Type == 0 || s.Type == SXREF {
    187 					s.Type = SBSS
    188 				}
    189 				flag = int(p.From3.Offset)
    190 				if flag&DUPOK != 0 {
    191 					s.Dupok = 1
    192 				}
    193 				if flag&RODATA != 0 {
    194 					s.Type = SRODATA
    195 				} else if flag&NOPTR != 0 {
    196 					s.Type = SNOPTRBSS
    197 				}
    198 				edata = s
    199 				continue
    200 			}
    201 
    202 			if p.As == ADATA {
    203 				savedata(ctxt, p.From.Sym, p, "<input>")
    204 				continue
    205 			}
    206 
    207 			if p.As == ATEXT {
    208 				s = p.From.Sym
    209 				if s == nil {
    210 					// func _() { }
    211 					curtext = nil
    212 
    213 					continue
    214 				}
    215 
    216 				if s.Text != nil {
    217 					log.Fatalf("duplicate TEXT for %s", s.Name)
    218 				}
    219 				if s.Onlist != 0 {
    220 					log.Fatalf("symbol %s listed multiple times", s.Name)
    221 				}
    222 				s.Onlist = 1
    223 				if text == nil {
    224 					text = s
    225 				} else {
    226 					etext.Next = s
    227 				}
    228 				etext = s
    229 				flag = int(p.From3Offset())
    230 				if flag&DUPOK != 0 {
    231 					s.Dupok = 1
    232 				}
    233 				if flag&NOSPLIT != 0 {
    234 					s.Nosplit = 1
    235 				}
    236 				s.Next = nil
    237 				s.Type = STEXT
    238 				s.Text = p
    239 				s.Etext = p
    240 				curtext = s
    241 				continue
    242 			}
    243 
    244 			if p.As == AFUNCDATA {
    245 				// Rewrite reference to go_args_stackmap(SB) to the Go-provided declaration information.
    246 				if curtext == nil { // func _() {}
    247 					continue
    248 				}
    249 				if p.To.Sym.Name == "go_args_stackmap" {
    250 					if p.From.Type != TYPE_CONST || p.From.Offset != FUNCDATA_ArgsPointerMaps {
    251 						ctxt.Diag("FUNCDATA use of go_args_stackmap(SB) without FUNCDATA_ArgsPointerMaps")
    252 					}
    253 					p.To.Sym = Linklookup(ctxt, fmt.Sprintf("%s.args_stackmap", curtext.Name), int(curtext.Version))
    254 				}
    255 			}
    256 
    257 			if curtext == nil {
    258 				continue
    259 			}
    260 			s = curtext
    261 			s.Etext.Link = p
    262 			s.Etext = p
    263 		}
    264 	}
    265 
    266 	// Add reference to Go arguments for C or assembly functions without them.
    267 	var found int
    268 	for s := text; s != nil; s = s.Next {
    269 		if !strings.HasPrefix(s.Name, "\"\".") {
    270 			continue
    271 		}
    272 		found = 0
    273 		for p = s.Text; p != nil; p = p.Link {
    274 			if p.As == AFUNCDATA && p.From.Type == TYPE_CONST && p.From.Offset == FUNCDATA_ArgsPointerMaps {
    275 				found = 1
    276 				break
    277 			}
    278 		}
    279 
    280 		if found == 0 {
    281 			p = Appendp(ctxt, s.Text)
    282 			p.As = AFUNCDATA
    283 			p.From.Type = TYPE_CONST
    284 			p.From.Offset = FUNCDATA_ArgsPointerMaps
    285 			p.To.Type = TYPE_MEM
    286 			p.To.Name = NAME_EXTERN
    287 			p.To.Sym = Linklookup(ctxt, fmt.Sprintf("%s.args_stackmap", s.Name), int(s.Version))
    288 		}
    289 	}
    290 
    291 	// Turn functions into machine code images.
    292 	for s := text; s != nil; s = s.Next {
    293 		mkfwd(s)
    294 		linkpatch(ctxt, s)
    295 		ctxt.Arch.Follow(ctxt, s)
    296 		ctxt.Arch.Preprocess(ctxt, s)
    297 		ctxt.Arch.Assemble(ctxt, s)
    298 		linkpcln(ctxt, s)
    299 	}
    300 
    301 	// Emit header.
    302 	Bputc(b, 0)
    303 
    304 	Bputc(b, 0)
    305 	fmt.Fprintf(b, "go13ld")
    306 	Bputc(b, 1) // version
    307 
    308 	// Emit autolib.
    309 	for _, pkg := range ctxt.Imports {
    310 		wrstring(b, pkg)
    311 	}
    312 	wrstring(b, "")
    313 
    314 	// Emit symbols.
    315 	for s := text; s != nil; s = s.Next {
    316 		writesym(ctxt, b, s)
    317 	}
    318 	for s := data; s != nil; s = s.Next {
    319 		writesym(ctxt, b, s)
    320 	}
    321 
    322 	// Emit footer.
    323 	Bputc(b, 0xff)
    324 
    325 	Bputc(b, 0xff)
    326 	fmt.Fprintf(b, "go13ld")
    327 }
    328 
    329 func writesym(ctxt *Link, b *Biobuf, s *LSym) {
    330 	if ctxt.Debugasm != 0 {
    331 		fmt.Fprintf(ctxt.Bso, "%s ", s.Name)
    332 		if s.Version != 0 {
    333 			fmt.Fprintf(ctxt.Bso, "v=%d ", s.Version)
    334 		}
    335 		if s.Type != 0 {
    336 			fmt.Fprintf(ctxt.Bso, "t=%d ", s.Type)
    337 		}
    338 		if s.Dupok != 0 {
    339 			fmt.Fprintf(ctxt.Bso, "dupok ")
    340 		}
    341 		if s.Cfunc != 0 {
    342 			fmt.Fprintf(ctxt.Bso, "cfunc ")
    343 		}
    344 		if s.Nosplit != 0 {
    345 			fmt.Fprintf(ctxt.Bso, "nosplit ")
    346 		}
    347 		fmt.Fprintf(ctxt.Bso, "size=%d value=%d", int64(s.Size), int64(s.Value))
    348 		if s.Type == STEXT {
    349 			fmt.Fprintf(ctxt.Bso, " args=%#x locals=%#x", uint64(s.Args), uint64(s.Locals))
    350 			if s.Leaf != 0 {
    351 				fmt.Fprintf(ctxt.Bso, " leaf")
    352 			}
    353 		}
    354 
    355 		fmt.Fprintf(ctxt.Bso, "\n")
    356 		for p := s.Text; p != nil; p = p.Link {
    357 			fmt.Fprintf(ctxt.Bso, "\t%#04x %v\n", uint(int(p.Pc)), p)
    358 		}
    359 		var c int
    360 		var j int
    361 		for i := 0; i < len(s.P); {
    362 			fmt.Fprintf(ctxt.Bso, "\t%#04x", uint(i))
    363 			for j = i; j < i+16 && j < len(s.P); j++ {
    364 				fmt.Fprintf(ctxt.Bso, " %02x", s.P[j])
    365 			}
    366 			for ; j < i+16; j++ {
    367 				fmt.Fprintf(ctxt.Bso, "   ")
    368 			}
    369 			fmt.Fprintf(ctxt.Bso, "  ")
    370 			for j = i; j < i+16 && j < len(s.P); j++ {
    371 				c = int(s.P[j])
    372 				if ' ' <= c && c <= 0x7e {
    373 					fmt.Fprintf(ctxt.Bso, "%c", c)
    374 				} else {
    375 					fmt.Fprintf(ctxt.Bso, ".")
    376 				}
    377 			}
    378 
    379 			fmt.Fprintf(ctxt.Bso, "\n")
    380 			i += 16
    381 		}
    382 
    383 		var r *Reloc
    384 		var name string
    385 		for i := 0; i < len(s.R); i++ {
    386 			r = &s.R[i]
    387 			name = ""
    388 			if r.Sym != nil {
    389 				name = r.Sym.Name
    390 			}
    391 			if ctxt.Arch.Thechar == '5' || ctxt.Arch.Thechar == '9' {
    392 				fmt.Fprintf(ctxt.Bso, "\trel %d+%d t=%d %s+%x\n", int(r.Off), r.Siz, r.Type, name, uint64(int64(r.Add)))
    393 			} else {
    394 				fmt.Fprintf(ctxt.Bso, "\trel %d+%d t=%d %s+%d\n", int(r.Off), r.Siz, r.Type, name, int64(r.Add))
    395 			}
    396 		}
    397 	}
    398 
    399 	Bputc(b, 0xfe)
    400 	wrint(b, int64(s.Type))
    401 	wrstring(b, s.Name)
    402 	wrint(b, int64(s.Version))
    403 	flags := int64(s.Dupok)
    404 	if s.Local {
    405 		flags |= 2
    406 	}
    407 	wrint(b, flags)
    408 	wrint(b, s.Size)
    409 	wrsym(b, s.Gotype)
    410 	wrdata(b, s.P)
    411 
    412 	wrint(b, int64(len(s.R)))
    413 	var r *Reloc
    414 	for i := 0; i < len(s.R); i++ {
    415 		r = &s.R[i]
    416 		wrint(b, int64(r.Off))
    417 		wrint(b, int64(r.Siz))
    418 		wrint(b, int64(r.Type))
    419 		wrint(b, r.Add)
    420 		wrint(b, 0) // Xadd, ignored
    421 		wrsym(b, r.Sym)
    422 		wrsym(b, nil) // Xsym, ignored
    423 	}
    424 
    425 	if s.Type == STEXT {
    426 		wrint(b, int64(s.Args))
    427 		wrint(b, int64(s.Locals))
    428 		wrint(b, int64(s.Nosplit))
    429 		wrint(b, int64(s.Leaf)|int64(s.Cfunc)<<1)
    430 		n := 0
    431 		for a := s.Autom; a != nil; a = a.Link {
    432 			n++
    433 		}
    434 		wrint(b, int64(n))
    435 		for a := s.Autom; a != nil; a = a.Link {
    436 			wrsym(b, a.Asym)
    437 			wrint(b, int64(a.Aoffset))
    438 			if a.Name == NAME_AUTO {
    439 				wrint(b, A_AUTO)
    440 			} else if a.Name == NAME_PARAM {
    441 				wrint(b, A_PARAM)
    442 			} else {
    443 				log.Fatalf("%s: invalid local variable type %d", s.Name, a.Name)
    444 			}
    445 			wrsym(b, a.Gotype)
    446 		}
    447 
    448 		pc := s.Pcln
    449 		wrdata(b, pc.Pcsp.P)
    450 		wrdata(b, pc.Pcfile.P)
    451 		wrdata(b, pc.Pcline.P)
    452 		wrint(b, int64(len(pc.Pcdata)))
    453 		for i := 0; i < len(pc.Pcdata); i++ {
    454 			wrdata(b, pc.Pcdata[i].P)
    455 		}
    456 		wrint(b, int64(len(pc.Funcdataoff)))
    457 		for i := 0; i < len(pc.Funcdataoff); i++ {
    458 			wrsym(b, pc.Funcdata[i])
    459 		}
    460 		for i := 0; i < len(pc.Funcdataoff); i++ {
    461 			wrint(b, pc.Funcdataoff[i])
    462 		}
    463 		wrint(b, int64(len(pc.File)))
    464 		for i := 0; i < len(pc.File); i++ {
    465 			wrpathsym(ctxt, b, pc.File[i])
    466 		}
    467 	}
    468 }
    469 
    470 // Reusable buffer to avoid allocations.
    471 // This buffer was responsible for 15% of gc's allocations.
    472 var varintbuf [10]uint8
    473 
    474 func wrint(b *Biobuf, sval int64) {
    475 	var v uint64
    476 	uv := (uint64(sval) << 1) ^ uint64(int64(sval>>63))
    477 	p := varintbuf[:]
    478 	for v = uv; v >= 0x80; v >>= 7 {
    479 		p[0] = uint8(v | 0x80)
    480 		p = p[1:]
    481 	}
    482 	p[0] = uint8(v)
    483 	p = p[1:]
    484 	b.Write(varintbuf[:len(varintbuf)-len(p)])
    485 }
    486 
    487 func wrstring(b *Biobuf, s string) {
    488 	wrint(b, int64(len(s)))
    489 	b.w.WriteString(s)
    490 }
    491 
    492 // wrpath writes a path just like a string, but on windows, it
    493 // translates '\\' to '/' in the process.
    494 func wrpath(ctxt *Link, b *Biobuf, p string) {
    495 	wrstring(b, filepath.ToSlash(p))
    496 }
    497 
    498 func wrdata(b *Biobuf, v []byte) {
    499 	wrint(b, int64(len(v)))
    500 	b.Write(v)
    501 }
    502 
    503 func wrpathsym(ctxt *Link, b *Biobuf, s *LSym) {
    504 	if s == nil {
    505 		wrint(b, 0)
    506 		wrint(b, 0)
    507 		return
    508 	}
    509 
    510 	wrpath(ctxt, b, s.Name)
    511 	wrint(b, int64(s.Version))
    512 }
    513 
    514 func wrsym(b *Biobuf, s *LSym) {
    515 	if s == nil {
    516 		wrint(b, 0)
    517 		wrint(b, 0)
    518 		return
    519 	}
    520 
    521 	wrstring(b, s.Name)
    522 	wrint(b, int64(s.Version))
    523 }
    524