...

Source file src/pkg/cmd/link/internal/ld/ar.go

     1	// Inferno utils/include/ar.h
     2	// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/include/ar.h
     3	//
     4	//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
     5	//	Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
     6	//	Portions Copyright © 1997-1999 Vita Nuova Limited
     7	//	Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
     8	//	Portions Copyright © 2004,2006 Bruce Ellis
     9	//	Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
    10	//	Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
    11	//	Portions Copyright © 2009 The Go Authors. All rights reserved.
    12	//
    13	// Permission is hereby granted, free of charge, to any person obtaining a copy
    14	// of this software and associated documentation files (the "Software"), to deal
    15	// in the Software without restriction, including without limitation the rights
    16	// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    17	// copies of the Software, and to permit persons to whom the Software is
    18	// furnished to do so, subject to the following conditions:
    19	//
    20	// The above copyright notice and this permission notice shall be included in
    21	// all copies or substantial portions of the Software.
    22	//
    23	// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    24	// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    25	// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
    26	// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    27	// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    28	// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    29	// THE SOFTWARE.
    30	
    31	package ld
    32	
    33	import (
    34		"cmd/internal/bio"
    35		"cmd/internal/objabi"
    36		"cmd/link/internal/sym"
    37		"encoding/binary"
    38		"fmt"
    39		"io"
    40		"os"
    41	)
    42	
    43	const (
    44		SARMAG  = 8
    45		SAR_HDR = 16 + 44
    46	)
    47	
    48	const (
    49		ARMAG = "!<arch>\n"
    50	)
    51	
    52	type ArHdr struct {
    53		name string
    54		date string
    55		uid  string
    56		gid  string
    57		mode string
    58		size string
    59		fmag string
    60	}
    61	
    62	// hostArchive reads an archive file holding host objects and links in
    63	// required objects. The general format is the same as a Go archive
    64	// file, but it has an armap listing symbols and the objects that
    65	// define them. This is used for the compiler support library
    66	// libgcc.a.
    67	func hostArchive(ctxt *Link, name string) {
    68		f, err := bio.Open(name)
    69		if err != nil {
    70			if os.IsNotExist(err) {
    71				// It's OK if we don't have a libgcc file at all.
    72				if ctxt.Debugvlog != 0 {
    73					ctxt.Logf("skipping libgcc file: %v\n", err)
    74				}
    75				return
    76			}
    77			Exitf("cannot open file %s: %v", name, err)
    78		}
    79		defer f.Close()
    80	
    81		var magbuf [len(ARMAG)]byte
    82		if _, err := io.ReadFull(f, magbuf[:]); err != nil {
    83			Exitf("file %s too short", name)
    84		}
    85	
    86		if string(magbuf[:]) != ARMAG {
    87			Exitf("%s is not an archive file", name)
    88		}
    89	
    90		var arhdr ArHdr
    91		l := nextar(f, f.Offset(), &arhdr)
    92		if l <= 0 {
    93			Exitf("%s missing armap", name)
    94		}
    95	
    96		var armap archiveMap
    97		if arhdr.name == "/" || arhdr.name == "/SYM64/" {
    98			armap = readArmap(name, f, arhdr)
    99		} else {
   100			Exitf("%s missing armap", name)
   101		}
   102	
   103		loaded := make(map[uint64]bool)
   104		any := true
   105		for any {
   106			var load []uint64
   107			for _, s := range ctxt.Syms.Allsym {
   108				for i := range s.R {
   109					r := &s.R[i] // Copying sym.Reloc has measurable impact on performance
   110					if r.Sym != nil && r.Sym.Type == sym.SXREF {
   111						if off := armap[r.Sym.Name]; off != 0 && !loaded[off] {
   112							load = append(load, off)
   113							loaded[off] = true
   114						}
   115					}
   116				}
   117			}
   118	
   119			for _, off := range load {
   120				l := nextar(f, int64(off), &arhdr)
   121				if l <= 0 {
   122					Exitf("%s missing archive entry at offset %d", name, off)
   123				}
   124				pname := fmt.Sprintf("%s(%s)", name, arhdr.name)
   125				l = atolwhex(arhdr.size)
   126	
   127				libgcc := sym.Library{Pkg: "libgcc"}
   128				h := ldobj(ctxt, f, &libgcc, l, pname, name)
   129				f.MustSeek(h.off, 0)
   130				h.ld(ctxt, f, h.pkg, h.length, h.pn)
   131			}
   132	
   133			any = len(load) > 0
   134		}
   135	}
   136	
   137	// archiveMap is an archive symbol map: a mapping from symbol name to
   138	// offset within the archive file.
   139	type archiveMap map[string]uint64
   140	
   141	// readArmap reads the archive symbol map.
   142	func readArmap(filename string, f *bio.Reader, arhdr ArHdr) archiveMap {
   143		is64 := arhdr.name == "/SYM64/"
   144		wordSize := 4
   145		if is64 {
   146			wordSize = 8
   147		}
   148	
   149		contents := make([]byte, atolwhex(arhdr.size))
   150		if _, err := io.ReadFull(f, contents); err != nil {
   151			Exitf("short read from %s", filename)
   152		}
   153	
   154		var c uint64
   155		if is64 {
   156			c = binary.BigEndian.Uint64(contents)
   157		} else {
   158			c = uint64(binary.BigEndian.Uint32(contents))
   159		}
   160		contents = contents[wordSize:]
   161	
   162		ret := make(archiveMap)
   163	
   164		names := contents[c*uint64(wordSize):]
   165		for i := uint64(0); i < c; i++ {
   166			n := 0
   167			for names[n] != 0 {
   168				n++
   169			}
   170			name := string(names[:n])
   171			names = names[n+1:]
   172	
   173			// For Mach-O and PE/386 files we strip a leading
   174			// underscore from the symbol name.
   175			if objabi.GOOS == "darwin" || (objabi.GOOS == "windows" && objabi.GOARCH == "386") {
   176				if name[0] == '_' && len(name) > 1 {
   177					name = name[1:]
   178				}
   179			}
   180	
   181			var off uint64
   182			if is64 {
   183				off = binary.BigEndian.Uint64(contents)
   184			} else {
   185				off = uint64(binary.BigEndian.Uint32(contents))
   186			}
   187			contents = contents[wordSize:]
   188	
   189			ret[name] = off
   190		}
   191	
   192		return ret
   193	}
   194	

View as plain text