mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
cmd/new5l etc: convert from C to Go
Using rsc.io/c2go rev fc8cbfa's run.ld script. Change-Id: I4d4d14fce96f8ce7a934bf8b9701b84fa9cf772d Reviewed-on: https://go-review.googlesource.com/6335 Reviewed-by: Rob Pike <r@golang.org>
This commit is contained in:
parent
30e36983f3
commit
1f9dbb60ef
38 changed files with 21892 additions and 0 deletions
51
src/cmd/internal/ld/ar.go
Normal file
51
src/cmd/internal/ld/ar.go
Normal file
|
|
@ -0,0 +1,51 @@
|
||||||
|
// Inferno utils/include/ar.h
|
||||||
|
// http://code.google.com/p/inferno-os/source/browse/utils/include/ar.h
|
||||||
|
//
|
||||||
|
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
|
||||||
|
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
|
||||||
|
// Portions Copyright © 1997-1999 Vita Nuova Limited
|
||||||
|
// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
|
||||||
|
// Portions Copyright © 2004,2006 Bruce Ellis
|
||||||
|
// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
|
||||||
|
// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
|
||||||
|
// Portions Copyright © 2009 The Go Authors. All rights reserved.
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
|
// in the Software without restriction, including without limitation the rights
|
||||||
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
// THE SOFTWARE.
|
||||||
|
|
||||||
|
package ld
|
||||||
|
|
||||||
|
const (
|
||||||
|
SARMAG = 8
|
||||||
|
SARNAME = 16
|
||||||
|
SAR_HDR = 16 + 44
|
||||||
|
)
|
||||||
|
|
||||||
|
var ARMAG string = "!<arch>\n"
|
||||||
|
|
||||||
|
var ARFMAG string = "`\n"
|
||||||
|
|
||||||
|
type ArHdr struct {
|
||||||
|
name string
|
||||||
|
date string
|
||||||
|
uid string
|
||||||
|
gid string
|
||||||
|
mode string
|
||||||
|
size string
|
||||||
|
fmag string
|
||||||
|
}
|
||||||
67
src/cmd/internal/ld/arch.go
Normal file
67
src/cmd/internal/ld/arch.go
Normal file
|
|
@ -0,0 +1,67 @@
|
||||||
|
// Copyright 2015 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package ld
|
||||||
|
|
||||||
|
import "encoding/binary"
|
||||||
|
|
||||||
|
var Linkarm = LinkArch{
|
||||||
|
ByteOrder: binary.LittleEndian,
|
||||||
|
Name: "arm",
|
||||||
|
Thechar: '5',
|
||||||
|
Endian: LittleEndian,
|
||||||
|
Minlc: 4,
|
||||||
|
Ptrsize: 4,
|
||||||
|
Regsize: 4,
|
||||||
|
}
|
||||||
|
|
||||||
|
var Linkamd64 = LinkArch{
|
||||||
|
ByteOrder: binary.LittleEndian,
|
||||||
|
Name: "amd64",
|
||||||
|
Thechar: '6',
|
||||||
|
Endian: LittleEndian,
|
||||||
|
Minlc: 1,
|
||||||
|
Ptrsize: 8,
|
||||||
|
Regsize: 8,
|
||||||
|
}
|
||||||
|
|
||||||
|
var Linkamd64p32 = LinkArch{
|
||||||
|
ByteOrder: binary.LittleEndian,
|
||||||
|
Name: "amd64p32",
|
||||||
|
Thechar: '6',
|
||||||
|
Endian: LittleEndian,
|
||||||
|
Minlc: 1,
|
||||||
|
Ptrsize: 4,
|
||||||
|
Regsize: 8,
|
||||||
|
}
|
||||||
|
|
||||||
|
var Link386 = LinkArch{
|
||||||
|
ByteOrder: binary.LittleEndian,
|
||||||
|
Name: "386",
|
||||||
|
Thechar: '8',
|
||||||
|
Endian: LittleEndian,
|
||||||
|
Minlc: 1,
|
||||||
|
Ptrsize: 4,
|
||||||
|
Regsize: 4,
|
||||||
|
}
|
||||||
|
|
||||||
|
var Linkppc64 = LinkArch{
|
||||||
|
ByteOrder: binary.BigEndian,
|
||||||
|
Name: "ppc64",
|
||||||
|
Thechar: '9',
|
||||||
|
Endian: BigEndian,
|
||||||
|
Minlc: 4,
|
||||||
|
Ptrsize: 8,
|
||||||
|
Regsize: 8,
|
||||||
|
}
|
||||||
|
|
||||||
|
var Linkppc64le = LinkArch{
|
||||||
|
ByteOrder: binary.LittleEndian,
|
||||||
|
Name: "ppc64le",
|
||||||
|
Thechar: '9',
|
||||||
|
Endian: LittleEndian,
|
||||||
|
Minlc: 4,
|
||||||
|
Ptrsize: 8,
|
||||||
|
Regsize: 8,
|
||||||
|
}
|
||||||
1798
src/cmd/internal/ld/data.go
Normal file
1798
src/cmd/internal/ld/data.go
Normal file
File diff suppressed because it is too large
Load diff
183
src/cmd/internal/ld/decodesym.go
Normal file
183
src/cmd/internal/ld/decodesym.go
Normal file
|
|
@ -0,0 +1,183 @@
|
||||||
|
// Copyright 2012 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package ld
|
||||||
|
|
||||||
|
import "cmd/internal/obj"
|
||||||
|
|
||||||
|
// Decoding the type.* symbols. This has to be in sync with
|
||||||
|
// ../../runtime/type.go, or more specifically, with what
|
||||||
|
// ../gc/reflect.c stuffs in these.
|
||||||
|
|
||||||
|
func decode_reloc(s *LSym, off int32) *Reloc {
|
||||||
|
var i int
|
||||||
|
|
||||||
|
for i = 0; i < len(s.R); i++ {
|
||||||
|
if s.R[i].Off == off {
|
||||||
|
return &s.R[i:][0]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func decode_reloc_sym(s *LSym, off int32) *LSym {
|
||||||
|
var r *Reloc
|
||||||
|
|
||||||
|
r = decode_reloc(s, off)
|
||||||
|
if r == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return r.Sym
|
||||||
|
}
|
||||||
|
|
||||||
|
func decode_inuxi(p []byte, sz int) uint64 {
|
||||||
|
switch sz {
|
||||||
|
case 2:
|
||||||
|
return uint64(Ctxt.Arch.ByteOrder.Uint16(p))
|
||||||
|
case 4:
|
||||||
|
return uint64(Ctxt.Arch.ByteOrder.Uint32(p))
|
||||||
|
case 8:
|
||||||
|
return Ctxt.Arch.ByteOrder.Uint64(p)
|
||||||
|
}
|
||||||
|
Diag("dwarf: decode inuxi %d", sz)
|
||||||
|
Errorexit()
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func commonsize() int {
|
||||||
|
return 8*Thearch.Ptrsize + 8
|
||||||
|
}
|
||||||
|
|
||||||
|
// Type.commonType.kind
|
||||||
|
func decodetype_kind(s *LSym) uint8 {
|
||||||
|
return uint8(s.P[1*Thearch.Ptrsize+7] & obj.KindMask) // 0x13 / 0x1f
|
||||||
|
}
|
||||||
|
|
||||||
|
// Type.commonType.kind
|
||||||
|
func decodetype_noptr(s *LSym) uint8 {
|
||||||
|
return uint8(s.P[1*Thearch.Ptrsize+7] & obj.KindNoPointers) // 0x13 / 0x1f
|
||||||
|
}
|
||||||
|
|
||||||
|
// Type.commonType.kind
|
||||||
|
func decodetype_usegcprog(s *LSym) uint8 {
|
||||||
|
return uint8(s.P[1*Thearch.Ptrsize+7] & obj.KindGCProg) // 0x13 / 0x1f
|
||||||
|
}
|
||||||
|
|
||||||
|
// Type.commonType.size
|
||||||
|
func decodetype_size(s *LSym) int64 {
|
||||||
|
return int64(decode_inuxi(s.P, Thearch.Ptrsize)) // 0x8 / 0x10
|
||||||
|
}
|
||||||
|
|
||||||
|
// Type.commonType.gc
|
||||||
|
func decodetype_gcprog(s *LSym) *LSym {
|
||||||
|
return decode_reloc_sym(s, 1*int32(Thearch.Ptrsize)+8+2*int32(Thearch.Ptrsize))
|
||||||
|
}
|
||||||
|
|
||||||
|
func decodetype_gcmask(s *LSym) []byte {
|
||||||
|
var mask *LSym
|
||||||
|
|
||||||
|
mask = decode_reloc_sym(s, 1*int32(Thearch.Ptrsize)+8+1*int32(Thearch.Ptrsize))
|
||||||
|
return mask.P
|
||||||
|
}
|
||||||
|
|
||||||
|
// Type.ArrayType.elem and Type.SliceType.Elem
|
||||||
|
func decodetype_arrayelem(s *LSym) *LSym {
|
||||||
|
return decode_reloc_sym(s, int32(commonsize())) // 0x1c / 0x30
|
||||||
|
}
|
||||||
|
|
||||||
|
func decodetype_arraylen(s *LSym) int64 {
|
||||||
|
return int64(decode_inuxi(s.P[commonsize()+2*Thearch.Ptrsize:], Thearch.Ptrsize))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Type.PtrType.elem
|
||||||
|
func decodetype_ptrelem(s *LSym) *LSym {
|
||||||
|
return decode_reloc_sym(s, int32(commonsize())) // 0x1c / 0x30
|
||||||
|
}
|
||||||
|
|
||||||
|
// Type.MapType.key, elem
|
||||||
|
func decodetype_mapkey(s *LSym) *LSym {
|
||||||
|
return decode_reloc_sym(s, int32(commonsize())) // 0x1c / 0x30
|
||||||
|
}
|
||||||
|
|
||||||
|
func decodetype_mapvalue(s *LSym) *LSym {
|
||||||
|
return decode_reloc_sym(s, int32(commonsize())+int32(Thearch.Ptrsize)) // 0x20 / 0x38
|
||||||
|
}
|
||||||
|
|
||||||
|
// Type.ChanType.elem
|
||||||
|
func decodetype_chanelem(s *LSym) *LSym {
|
||||||
|
return decode_reloc_sym(s, int32(commonsize())) // 0x1c / 0x30
|
||||||
|
}
|
||||||
|
|
||||||
|
// Type.FuncType.dotdotdot
|
||||||
|
func decodetype_funcdotdotdot(s *LSym) int {
|
||||||
|
return int(s.P[commonsize()])
|
||||||
|
}
|
||||||
|
|
||||||
|
// Type.FuncType.in.length
|
||||||
|
func decodetype_funcincount(s *LSym) int {
|
||||||
|
return int(decode_inuxi(s.P[commonsize()+2*Thearch.Ptrsize:], Thearch.Intsize))
|
||||||
|
}
|
||||||
|
|
||||||
|
func decodetype_funcoutcount(s *LSym) int {
|
||||||
|
return int(decode_inuxi(s.P[commonsize()+3*Thearch.Ptrsize+2*Thearch.Intsize:], Thearch.Intsize))
|
||||||
|
}
|
||||||
|
|
||||||
|
func decodetype_funcintype(s *LSym, i int) *LSym {
|
||||||
|
var r *Reloc
|
||||||
|
|
||||||
|
r = decode_reloc(s, int32(commonsize())+int32(Thearch.Ptrsize))
|
||||||
|
if r == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return decode_reloc_sym(r.Sym, int32(r.Add+int64(int32(i)*int32(Thearch.Ptrsize))))
|
||||||
|
}
|
||||||
|
|
||||||
|
func decodetype_funcouttype(s *LSym, i int) *LSym {
|
||||||
|
var r *Reloc
|
||||||
|
|
||||||
|
r = decode_reloc(s, int32(commonsize())+2*int32(Thearch.Ptrsize)+2*int32(Thearch.Intsize))
|
||||||
|
if r == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return decode_reloc_sym(r.Sym, int32(r.Add+int64(int32(i)*int32(Thearch.Ptrsize))))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Type.StructType.fields.Slice::length
|
||||||
|
func decodetype_structfieldcount(s *LSym) int {
|
||||||
|
return int(decode_inuxi(s.P[commonsize()+Thearch.Ptrsize:], Thearch.Intsize))
|
||||||
|
}
|
||||||
|
|
||||||
|
func structfieldsize() int {
|
||||||
|
return 5 * Thearch.Ptrsize
|
||||||
|
}
|
||||||
|
|
||||||
|
// Type.StructType.fields[]-> name, typ and offset.
|
||||||
|
func decodetype_structfieldname(s *LSym, i int) string {
|
||||||
|
var r *Reloc
|
||||||
|
|
||||||
|
// go.string."foo" 0x28 / 0x40
|
||||||
|
s = decode_reloc_sym(s, int32(commonsize())+int32(Thearch.Ptrsize)+2*int32(Thearch.Intsize)+int32(i)*int32(structfieldsize()))
|
||||||
|
|
||||||
|
if s == nil { // embedded structs have a nil name.
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
r = decode_reloc(s, 0) // s has a pointer to the string data at offset 0
|
||||||
|
if r == nil { // shouldn't happen.
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return cstring(r.Sym.P[r.Add:])
|
||||||
|
}
|
||||||
|
|
||||||
|
func decodetype_structfieldtype(s *LSym, i int) *LSym {
|
||||||
|
return decode_reloc_sym(s, int32(commonsize())+int32(Thearch.Ptrsize)+2*int32(Thearch.Intsize)+int32(i)*int32(structfieldsize())+2*int32(Thearch.Ptrsize))
|
||||||
|
}
|
||||||
|
|
||||||
|
func decodetype_structfieldoffs(s *LSym, i int) int64 {
|
||||||
|
return int64(decode_inuxi(s.P[commonsize()+Thearch.Ptrsize+2*Thearch.Intsize+i*structfieldsize()+4*Thearch.Ptrsize:], Thearch.Intsize))
|
||||||
|
}
|
||||||
|
|
||||||
|
// InterfaceTYpe.methods.length
|
||||||
|
func decodetype_ifacemethodcount(s *LSym) int64 {
|
||||||
|
return int64(decode_inuxi(s.P[commonsize()+Thearch.Ptrsize:], Thearch.Intsize))
|
||||||
|
}
|
||||||
2744
src/cmd/internal/ld/dwarf.go
Normal file
2744
src/cmd/internal/ld/dwarf.go
Normal file
File diff suppressed because it is too large
Load diff
500
src/cmd/internal/ld/dwarf_defs.go
Normal file
500
src/cmd/internal/ld/dwarf_defs.go
Normal file
|
|
@ -0,0 +1,500 @@
|
||||||
|
// Copyright 2010 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package ld
|
||||||
|
|
||||||
|
// TODO/NICETOHAVE:
|
||||||
|
// - eliminate DW_CLS_ if not used
|
||||||
|
// - package info in compilation units
|
||||||
|
// - assign global variables and types to their packages
|
||||||
|
// - gdb uses c syntax, meaning clumsy quoting is needed for go identifiers. eg
|
||||||
|
// ptype struct '[]uint8' and qualifiers need to be quoted away
|
||||||
|
// - lexical scoping is lost, so gdb gets confused as to which 'obj.i' you mean.
|
||||||
|
// - file:line info for variables
|
||||||
|
// - make strings a typedef so prettyprinters can see the underlying string type
|
||||||
|
//
|
||||||
|
// Copyright 2010 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Emit debug_abbrevs, debug_info and debug_line sections to current
|
||||||
|
* offset in cout.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add the dwarf section names to the ELF
|
||||||
|
* s[ection]h[eader]str[ing]tab. Prerequisite for
|
||||||
|
* dwarfaddelfheaders().
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add section headers pointing to the sections emitted in
|
||||||
|
* dwarfemitdebugsections.
|
||||||
|
*/
|
||||||
|
// Copyright 2010 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// Cut, pasted, tr-and-awk'ed from tables in
|
||||||
|
// http://dwarfstd.org/doc/Dwarf3.pdf
|
||||||
|
|
||||||
|
// Table 18
|
||||||
|
const (
|
||||||
|
DW_TAG_array_type = 0x01
|
||||||
|
DW_TAG_class_type = 0x02
|
||||||
|
DW_TAG_entry_point = 0x03
|
||||||
|
DW_TAG_enumeration_type = 0x04
|
||||||
|
DW_TAG_formal_parameter = 0x05
|
||||||
|
DW_TAG_imported_declaration = 0x08
|
||||||
|
DW_TAG_label = 0x0a
|
||||||
|
DW_TAG_lexical_block = 0x0b
|
||||||
|
DW_TAG_member = 0x0d
|
||||||
|
DW_TAG_pointer_type = 0x0f
|
||||||
|
DW_TAG_reference_type = 0x10
|
||||||
|
DW_TAG_compile_unit = 0x11
|
||||||
|
DW_TAG_string_type = 0x12
|
||||||
|
DW_TAG_structure_type = 0x13
|
||||||
|
DW_TAG_subroutine_type = 0x15
|
||||||
|
DW_TAG_typedef = 0x16
|
||||||
|
DW_TAG_union_type = 0x17
|
||||||
|
DW_TAG_unspecified_parameters = 0x18
|
||||||
|
DW_TAG_variant = 0x19
|
||||||
|
DW_TAG_common_block = 0x1a
|
||||||
|
DW_TAG_common_inclusion = 0x1b
|
||||||
|
DW_TAG_inheritance = 0x1c
|
||||||
|
DW_TAG_inlined_subroutine = 0x1d
|
||||||
|
DW_TAG_module = 0x1e
|
||||||
|
DW_TAG_ptr_to_member_type = 0x1f
|
||||||
|
DW_TAG_set_type = 0x20
|
||||||
|
DW_TAG_subrange_type = 0x21
|
||||||
|
DW_TAG_with_stmt = 0x22
|
||||||
|
DW_TAG_access_declaration = 0x23
|
||||||
|
DW_TAG_base_type = 0x24
|
||||||
|
DW_TAG_catch_block = 0x25
|
||||||
|
DW_TAG_const_type = 0x26
|
||||||
|
DW_TAG_constant = 0x27
|
||||||
|
DW_TAG_enumerator = 0x28
|
||||||
|
DW_TAG_file_type = 0x29
|
||||||
|
DW_TAG_friend = 0x2a
|
||||||
|
DW_TAG_namelist = 0x2b
|
||||||
|
DW_TAG_namelist_item = 0x2c
|
||||||
|
DW_TAG_packed_type = 0x2d
|
||||||
|
DW_TAG_subprogram = 0x2e
|
||||||
|
DW_TAG_template_type_parameter = 0x2f
|
||||||
|
DW_TAG_template_value_parameter = 0x30
|
||||||
|
DW_TAG_thrown_type = 0x31
|
||||||
|
DW_TAG_try_block = 0x32
|
||||||
|
DW_TAG_variant_part = 0x33
|
||||||
|
DW_TAG_variable = 0x34
|
||||||
|
DW_TAG_volatile_type = 0x35
|
||||||
|
DW_TAG_dwarf_procedure = 0x36
|
||||||
|
DW_TAG_restrict_type = 0x37
|
||||||
|
DW_TAG_interface_type = 0x38
|
||||||
|
DW_TAG_namespace = 0x39
|
||||||
|
DW_TAG_imported_module = 0x3a
|
||||||
|
DW_TAG_unspecified_type = 0x3b
|
||||||
|
DW_TAG_partial_unit = 0x3c
|
||||||
|
DW_TAG_imported_unit = 0x3d
|
||||||
|
DW_TAG_condition = 0x3f
|
||||||
|
DW_TAG_shared_type = 0x40
|
||||||
|
DW_TAG_type_unit = 0x41
|
||||||
|
DW_TAG_rvalue_reference_type = 0x42
|
||||||
|
DW_TAG_template_alias = 0x43
|
||||||
|
DW_TAG_lo_user = 0x4080
|
||||||
|
DW_TAG_hi_user = 0xffff
|
||||||
|
)
|
||||||
|
|
||||||
|
// Table 19
|
||||||
|
const (
|
||||||
|
DW_CHILDREN_no = 0x00
|
||||||
|
DW_CHILDREN_yes = 0x01
|
||||||
|
)
|
||||||
|
|
||||||
|
// Not from the spec, but logicaly belongs here
|
||||||
|
const (
|
||||||
|
DW_CLS_ADDRESS = 0x01 + iota
|
||||||
|
DW_CLS_BLOCK
|
||||||
|
DW_CLS_CONSTANT
|
||||||
|
DW_CLS_FLAG
|
||||||
|
DW_CLS_PTR
|
||||||
|
DW_CLS_REFERENCE
|
||||||
|
DW_CLS_ADDRLOC
|
||||||
|
DW_CLS_STRING
|
||||||
|
)
|
||||||
|
|
||||||
|
// Table 20
|
||||||
|
const (
|
||||||
|
DW_AT_sibling = 0x01
|
||||||
|
DW_AT_location = 0x02
|
||||||
|
DW_AT_name = 0x03
|
||||||
|
DW_AT_ordering = 0x09
|
||||||
|
DW_AT_byte_size = 0x0b
|
||||||
|
DW_AT_bit_offset = 0x0c
|
||||||
|
DW_AT_bit_size = 0x0d
|
||||||
|
DW_AT_stmt_list = 0x10
|
||||||
|
DW_AT_low_pc = 0x11
|
||||||
|
DW_AT_high_pc = 0x12
|
||||||
|
DW_AT_language = 0x13
|
||||||
|
DW_AT_discr = 0x15
|
||||||
|
DW_AT_discr_value = 0x16
|
||||||
|
DW_AT_visibility = 0x17
|
||||||
|
DW_AT_import = 0x18
|
||||||
|
DW_AT_string_length = 0x19
|
||||||
|
DW_AT_common_reference = 0x1a
|
||||||
|
DW_AT_comp_dir = 0x1b
|
||||||
|
DW_AT_const_value = 0x1c
|
||||||
|
DW_AT_containing_type = 0x1d
|
||||||
|
DW_AT_default_value = 0x1e
|
||||||
|
DW_AT_inline = 0x20
|
||||||
|
DW_AT_is_optional = 0x21
|
||||||
|
DW_AT_lower_bound = 0x22
|
||||||
|
DW_AT_producer = 0x25
|
||||||
|
DW_AT_prototyped = 0x27
|
||||||
|
DW_AT_return_addr = 0x2a
|
||||||
|
DW_AT_start_scope = 0x2c
|
||||||
|
DW_AT_bit_stride = 0x2e
|
||||||
|
DW_AT_upper_bound = 0x2f
|
||||||
|
DW_AT_abstract_origin = 0x31
|
||||||
|
DW_AT_accessibility = 0x32
|
||||||
|
DW_AT_address_class = 0x33
|
||||||
|
DW_AT_artificial = 0x34
|
||||||
|
DW_AT_base_types = 0x35
|
||||||
|
DW_AT_calling_convention = 0x36
|
||||||
|
DW_AT_count = 0x37
|
||||||
|
DW_AT_data_member_location = 0x38
|
||||||
|
DW_AT_decl_column = 0x39
|
||||||
|
DW_AT_decl_file = 0x3a
|
||||||
|
DW_AT_decl_line = 0x3b
|
||||||
|
DW_AT_declaration = 0x3c
|
||||||
|
DW_AT_discr_list = 0x3d
|
||||||
|
DW_AT_encoding = 0x3e
|
||||||
|
DW_AT_external = 0x3f
|
||||||
|
DW_AT_frame_base = 0x40
|
||||||
|
DW_AT_friend = 0x41
|
||||||
|
DW_AT_identifier_case = 0x42
|
||||||
|
DW_AT_macro_info = 0x43
|
||||||
|
DW_AT_namelist_item = 0x44
|
||||||
|
DW_AT_priority = 0x45
|
||||||
|
DW_AT_segment = 0x46
|
||||||
|
DW_AT_specification = 0x47
|
||||||
|
DW_AT_static_link = 0x48
|
||||||
|
DW_AT_type = 0x49
|
||||||
|
DW_AT_use_location = 0x4a
|
||||||
|
DW_AT_variable_parameter = 0x4b
|
||||||
|
DW_AT_virtuality = 0x4c
|
||||||
|
DW_AT_vtable_elem_location = 0x4d
|
||||||
|
DW_AT_allocated = 0x4e
|
||||||
|
DW_AT_associated = 0x4f
|
||||||
|
DW_AT_data_location = 0x50
|
||||||
|
DW_AT_byte_stride = 0x51
|
||||||
|
DW_AT_entry_pc = 0x52
|
||||||
|
DW_AT_use_UTF8 = 0x53
|
||||||
|
DW_AT_extension = 0x54
|
||||||
|
DW_AT_ranges = 0x55
|
||||||
|
DW_AT_trampoline = 0x56
|
||||||
|
DW_AT_call_column = 0x57
|
||||||
|
DW_AT_call_file = 0x58
|
||||||
|
DW_AT_call_line = 0x59
|
||||||
|
DW_AT_description = 0x5a
|
||||||
|
DW_AT_binary_scale = 0x5b
|
||||||
|
DW_AT_decimal_scale = 0x5c
|
||||||
|
DW_AT_small = 0x5d
|
||||||
|
DW_AT_decimal_sign = 0x5e
|
||||||
|
DW_AT_digit_count = 0x5f
|
||||||
|
DW_AT_picture_string = 0x60
|
||||||
|
DW_AT_mutable = 0x61
|
||||||
|
DW_AT_threads_scaled = 0x62
|
||||||
|
DW_AT_explicit = 0x63
|
||||||
|
DW_AT_object_pointer = 0x64
|
||||||
|
DW_AT_endianity = 0x65
|
||||||
|
DW_AT_elemental = 0x66
|
||||||
|
DW_AT_pure = 0x67
|
||||||
|
DW_AT_recursive = 0x68
|
||||||
|
DW_AT_lo_user = 0x2000
|
||||||
|
DW_AT_hi_user = 0x3fff
|
||||||
|
)
|
||||||
|
|
||||||
|
// Table 21
|
||||||
|
const (
|
||||||
|
DW_FORM_addr = 0x01
|
||||||
|
DW_FORM_block2 = 0x03
|
||||||
|
DW_FORM_block4 = 0x04
|
||||||
|
DW_FORM_data2 = 0x05
|
||||||
|
DW_FORM_data4 = 0x06
|
||||||
|
DW_FORM_data8 = 0x07
|
||||||
|
DW_FORM_string = 0x08
|
||||||
|
DW_FORM_block = 0x09
|
||||||
|
DW_FORM_block1 = 0x0a
|
||||||
|
DW_FORM_data1 = 0x0b
|
||||||
|
DW_FORM_flag = 0x0c
|
||||||
|
DW_FORM_sdata = 0x0d
|
||||||
|
DW_FORM_strp = 0x0e
|
||||||
|
DW_FORM_udata = 0x0f
|
||||||
|
DW_FORM_ref_addr = 0x10
|
||||||
|
DW_FORM_ref1 = 0x11
|
||||||
|
DW_FORM_ref2 = 0x12
|
||||||
|
DW_FORM_ref4 = 0x13
|
||||||
|
DW_FORM_ref8 = 0x14
|
||||||
|
DW_FORM_ref_udata = 0x15
|
||||||
|
DW_FORM_indirect = 0x16
|
||||||
|
)
|
||||||
|
|
||||||
|
// Table 24 (#operands, notes)
|
||||||
|
const (
|
||||||
|
DW_OP_addr = 0x03
|
||||||
|
DW_OP_deref = 0x06
|
||||||
|
DW_OP_const1u = 0x08
|
||||||
|
DW_OP_const1s = 0x09
|
||||||
|
DW_OP_const2u = 0x0a
|
||||||
|
DW_OP_const2s = 0x0b
|
||||||
|
DW_OP_const4u = 0x0c
|
||||||
|
DW_OP_const4s = 0x0d
|
||||||
|
DW_OP_const8u = 0x0e
|
||||||
|
DW_OP_const8s = 0x0f
|
||||||
|
DW_OP_constu = 0x10
|
||||||
|
DW_OP_consts = 0x11
|
||||||
|
DW_OP_dup = 0x12
|
||||||
|
DW_OP_drop = 0x13
|
||||||
|
DW_OP_over = 0x14
|
||||||
|
DW_OP_pick = 0x15
|
||||||
|
DW_OP_swap = 0x16
|
||||||
|
DW_OP_rot = 0x17
|
||||||
|
DW_OP_xderef = 0x18
|
||||||
|
DW_OP_abs = 0x19
|
||||||
|
DW_OP_and = 0x1a
|
||||||
|
DW_OP_div = 0x1b
|
||||||
|
DW_OP_minus = 0x1c
|
||||||
|
DW_OP_mod = 0x1d
|
||||||
|
DW_OP_mul = 0x1e
|
||||||
|
DW_OP_neg = 0x1f
|
||||||
|
DW_OP_not = 0x20
|
||||||
|
DW_OP_or = 0x21
|
||||||
|
DW_OP_plus = 0x22
|
||||||
|
DW_OP_plus_uconst = 0x23
|
||||||
|
DW_OP_shl = 0x24
|
||||||
|
DW_OP_shr = 0x25
|
||||||
|
DW_OP_shra = 0x26
|
||||||
|
DW_OP_xor = 0x27
|
||||||
|
DW_OP_skip = 0x2f
|
||||||
|
DW_OP_bra = 0x28
|
||||||
|
DW_OP_eq = 0x29
|
||||||
|
DW_OP_ge = 0x2a
|
||||||
|
DW_OP_gt = 0x2b
|
||||||
|
DW_OP_le = 0x2c
|
||||||
|
DW_OP_lt = 0x2d
|
||||||
|
DW_OP_ne = 0x2e
|
||||||
|
DW_OP_lit0 = 0x30
|
||||||
|
DW_OP_lit31 = 0x4f
|
||||||
|
DW_OP_reg0 = 0x50
|
||||||
|
DW_OP_reg31 = 0x6f
|
||||||
|
DW_OP_breg0 = 0x70
|
||||||
|
DW_OP_breg31 = 0x8f
|
||||||
|
DW_OP_regx = 0x90
|
||||||
|
DW_OP_fbreg = 0x91
|
||||||
|
DW_OP_bregx = 0x92
|
||||||
|
DW_OP_piece = 0x93
|
||||||
|
DW_OP_deref_size = 0x94
|
||||||
|
DW_OP_xderef_size = 0x95
|
||||||
|
DW_OP_nop = 0x96
|
||||||
|
DW_OP_push_object_address = 0x97
|
||||||
|
DW_OP_call2 = 0x98
|
||||||
|
DW_OP_call4 = 0x99
|
||||||
|
DW_OP_call_ref = 0x9a
|
||||||
|
DW_OP_form_tls_address = 0x9b
|
||||||
|
DW_OP_call_frame_cfa = 0x9c
|
||||||
|
DW_OP_bit_piece = 0x9d
|
||||||
|
DW_OP_lo_user = 0xe0
|
||||||
|
DW_OP_hi_user = 0xff
|
||||||
|
)
|
||||||
|
|
||||||
|
// Table 25
|
||||||
|
const (
|
||||||
|
DW_ATE_address = 0x01
|
||||||
|
DW_ATE_boolean = 0x02
|
||||||
|
DW_ATE_complex_float = 0x03
|
||||||
|
DW_ATE_float = 0x04
|
||||||
|
DW_ATE_signed = 0x05
|
||||||
|
DW_ATE_signed_char = 0x06
|
||||||
|
DW_ATE_unsigned = 0x07
|
||||||
|
DW_ATE_unsigned_char = 0x08
|
||||||
|
DW_ATE_imaginary_float = 0x09
|
||||||
|
DW_ATE_packed_decimal = 0x0a
|
||||||
|
DW_ATE_numeric_string = 0x0b
|
||||||
|
DW_ATE_edited = 0x0c
|
||||||
|
DW_ATE_signed_fixed = 0x0d
|
||||||
|
DW_ATE_unsigned_fixed = 0x0e
|
||||||
|
DW_ATE_decimal_float = 0x0f
|
||||||
|
DW_ATE_lo_user = 0x80
|
||||||
|
DW_ATE_hi_user = 0xff
|
||||||
|
)
|
||||||
|
|
||||||
|
// Table 26
|
||||||
|
const (
|
||||||
|
DW_DS_unsigned = 0x01
|
||||||
|
DW_DS_leading_overpunch = 0x02
|
||||||
|
DW_DS_trailing_overpunch = 0x03
|
||||||
|
DW_DS_leading_separate = 0x04
|
||||||
|
DW_DS_trailing_separate = 0x05
|
||||||
|
)
|
||||||
|
|
||||||
|
// Table 27
|
||||||
|
const (
|
||||||
|
DW_END_default = 0x00
|
||||||
|
DW_END_big = 0x01
|
||||||
|
DW_END_little = 0x02
|
||||||
|
DW_END_lo_user = 0x40
|
||||||
|
DW_END_hi_user = 0xff
|
||||||
|
)
|
||||||
|
|
||||||
|
// Table 28
|
||||||
|
const (
|
||||||
|
DW_ACCESS_public = 0x01
|
||||||
|
DW_ACCESS_protected = 0x02
|
||||||
|
DW_ACCESS_private = 0x03
|
||||||
|
)
|
||||||
|
|
||||||
|
// Table 29
|
||||||
|
const (
|
||||||
|
DW_VIS_local = 0x01
|
||||||
|
DW_VIS_exported = 0x02
|
||||||
|
DW_VIS_qualified = 0x03
|
||||||
|
)
|
||||||
|
|
||||||
|
// Table 30
|
||||||
|
const (
|
||||||
|
DW_VIRTUALITY_none = 0x00
|
||||||
|
DW_VIRTUALITY_virtual = 0x01
|
||||||
|
DW_VIRTUALITY_pure_virtual = 0x02
|
||||||
|
)
|
||||||
|
|
||||||
|
// Table 31
|
||||||
|
const (
|
||||||
|
DW_LANG_C89 = 0x0001
|
||||||
|
DW_LANG_C = 0x0002
|
||||||
|
DW_LANG_Ada83 = 0x0003
|
||||||
|
DW_LANG_C_plus_plus = 0x0004
|
||||||
|
DW_LANG_Cobol74 = 0x0005
|
||||||
|
DW_LANG_Cobol85 = 0x0006
|
||||||
|
DW_LANG_Fortran77 = 0x0007
|
||||||
|
DW_LANG_Fortran90 = 0x0008
|
||||||
|
DW_LANG_Pascal83 = 0x0009
|
||||||
|
DW_LANG_Modula2 = 0x000a
|
||||||
|
DW_LANG_Java = 0x000b
|
||||||
|
DW_LANG_C99 = 0x000c
|
||||||
|
DW_LANG_Ada95 = 0x000d
|
||||||
|
DW_LANG_Fortran95 = 0x000e
|
||||||
|
DW_LANG_PLI = 0x000f
|
||||||
|
DW_LANG_ObjC = 0x0010
|
||||||
|
DW_LANG_ObjC_plus_plus = 0x0011
|
||||||
|
DW_LANG_UPC = 0x0012
|
||||||
|
DW_LANG_D = 0x0013
|
||||||
|
DW_LANG_Python = 0x0014
|
||||||
|
DW_LANG_Go = 0x0016
|
||||||
|
DW_LANG_lo_user = 0x8000
|
||||||
|
DW_LANG_hi_user = 0xffff
|
||||||
|
)
|
||||||
|
|
||||||
|
// Table 32
|
||||||
|
const (
|
||||||
|
DW_ID_case_sensitive = 0x00
|
||||||
|
DW_ID_up_case = 0x01
|
||||||
|
DW_ID_down_case = 0x02
|
||||||
|
DW_ID_case_insensitive = 0x03
|
||||||
|
)
|
||||||
|
|
||||||
|
// Table 33
|
||||||
|
const (
|
||||||
|
DW_CC_normal = 0x01
|
||||||
|
DW_CC_program = 0x02
|
||||||
|
DW_CC_nocall = 0x03
|
||||||
|
DW_CC_lo_user = 0x40
|
||||||
|
DW_CC_hi_user = 0xff
|
||||||
|
)
|
||||||
|
|
||||||
|
// Table 34
|
||||||
|
const (
|
||||||
|
DW_INL_not_inlined = 0x00
|
||||||
|
DW_INL_inlined = 0x01
|
||||||
|
DW_INL_declared_not_inlined = 0x02
|
||||||
|
DW_INL_declared_inlined = 0x03
|
||||||
|
)
|
||||||
|
|
||||||
|
// Table 35
|
||||||
|
const (
|
||||||
|
DW_ORD_row_major = 0x00
|
||||||
|
DW_ORD_col_major = 0x01
|
||||||
|
)
|
||||||
|
|
||||||
|
// Table 36
|
||||||
|
const (
|
||||||
|
DW_DSC_label = 0x00
|
||||||
|
DW_DSC_range = 0x01
|
||||||
|
)
|
||||||
|
|
||||||
|
// Table 37
|
||||||
|
const (
|
||||||
|
DW_LNS_copy = 0x01
|
||||||
|
DW_LNS_advance_pc = 0x02
|
||||||
|
DW_LNS_advance_line = 0x03
|
||||||
|
DW_LNS_set_file = 0x04
|
||||||
|
DW_LNS_set_column = 0x05
|
||||||
|
DW_LNS_negate_stmt = 0x06
|
||||||
|
DW_LNS_set_basic_block = 0x07
|
||||||
|
DW_LNS_const_add_pc = 0x08
|
||||||
|
DW_LNS_fixed_advance_pc = 0x09
|
||||||
|
DW_LNS_set_prologue_end = 0x0a
|
||||||
|
DW_LNS_set_epilogue_begin = 0x0b
|
||||||
|
DW_LNS_set_isa = 0x0c
|
||||||
|
)
|
||||||
|
|
||||||
|
// Table 38
|
||||||
|
const (
|
||||||
|
DW_LNE_end_sequence = 0x01
|
||||||
|
DW_LNE_set_address = 0x02
|
||||||
|
DW_LNE_define_file = 0x03
|
||||||
|
DW_LNE_lo_user = 0x80
|
||||||
|
DW_LNE_hi_user = 0xff
|
||||||
|
)
|
||||||
|
|
||||||
|
// Table 39
|
||||||
|
const (
|
||||||
|
DW_MACINFO_define = 0x01
|
||||||
|
DW_MACINFO_undef = 0x02
|
||||||
|
DW_MACINFO_start_file = 0x03
|
||||||
|
DW_MACINFO_end_file = 0x04
|
||||||
|
DW_MACINFO_vendor_ext = 0xff
|
||||||
|
)
|
||||||
|
|
||||||
|
// Table 40.
|
||||||
|
const (
|
||||||
|
DW_CFA_nop = 0x00
|
||||||
|
DW_CFA_set_loc = 0x01
|
||||||
|
DW_CFA_advance_loc1 = 0x02
|
||||||
|
DW_CFA_advance_loc2 = 0x03
|
||||||
|
DW_CFA_advance_loc4 = 0x04
|
||||||
|
DW_CFA_offset_extended = 0x05
|
||||||
|
DW_CFA_restore_extended = 0x06
|
||||||
|
DW_CFA_undefined = 0x07
|
||||||
|
DW_CFA_same_value = 0x08
|
||||||
|
DW_CFA_register = 0x09
|
||||||
|
DW_CFA_remember_state = 0x0a
|
||||||
|
DW_CFA_restore_state = 0x0b
|
||||||
|
DW_CFA_def_cfa = 0x0c
|
||||||
|
DW_CFA_def_cfa_register = 0x0d
|
||||||
|
DW_CFA_def_cfa_offset = 0x0e
|
||||||
|
DW_CFA_def_cfa_expression = 0x0f
|
||||||
|
DW_CFA_expression = 0x10
|
||||||
|
DW_CFA_offset_extended_sf = 0x11
|
||||||
|
DW_CFA_def_cfa_sf = 0x12
|
||||||
|
DW_CFA_def_cfa_offset_sf = 0x13
|
||||||
|
DW_CFA_val_offset = 0x14
|
||||||
|
DW_CFA_val_offset_sf = 0x15
|
||||||
|
DW_CFA_val_expression = 0x16
|
||||||
|
DW_CFA_lo_user = 0x1c
|
||||||
|
DW_CFA_hi_user = 0x3f
|
||||||
|
DW_CFA_advance_loc = 0x1 << 6
|
||||||
|
DW_CFA_offset = 0x2 << 6
|
||||||
|
DW_CFA_restore = 0x3 << 6
|
||||||
|
)
|
||||||
2448
src/cmd/internal/ld/elf.go
Normal file
2448
src/cmd/internal/ld/elf.go
Normal file
File diff suppressed because it is too large
Load diff
60
src/cmd/internal/ld/fmt.go
Normal file
60
src/cmd/internal/ld/fmt.go
Normal file
|
|
@ -0,0 +1,60 @@
|
||||||
|
/*
|
||||||
|
* The authors of this software are Rob Pike and Ken Thompson.
|
||||||
|
* Copyright (c) 2002 by Lucent Technologies.
|
||||||
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
|
* purpose without fee is hereby granted, provided that this entire notice
|
||||||
|
* is included in all copies of any software which is or includes a copy
|
||||||
|
* or modification of this software and in all copies of the supporting
|
||||||
|
* documentation for such software.
|
||||||
|
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
|
||||||
|
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
|
||||||
|
* REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
|
||||||
|
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package ld
|
||||||
|
|
||||||
|
// (The comments in this file were copied from the manpage files rune.3,
|
||||||
|
// isalpharune.3, and runestrcat.3. Some formatting changes were also made
|
||||||
|
// to conform to Google style. /JRM 11/11/05)
|
||||||
|
|
||||||
|
type Fmt struct {
|
||||||
|
runes uint8
|
||||||
|
start interface{}
|
||||||
|
to interface{}
|
||||||
|
stop interface{}
|
||||||
|
flush func(*Fmt) int
|
||||||
|
farg interface{}
|
||||||
|
nfmt int
|
||||||
|
args []interface{}
|
||||||
|
r uint
|
||||||
|
width int
|
||||||
|
prec int
|
||||||
|
flags uint32
|
||||||
|
decimal string
|
||||||
|
thousands string
|
||||||
|
grouping string
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
FmtWidth = 1
|
||||||
|
FmtLeft = FmtWidth << 1
|
||||||
|
FmtPrec = FmtLeft << 1
|
||||||
|
FmtSharp = FmtPrec << 1
|
||||||
|
FmtSpace = FmtSharp << 1
|
||||||
|
FmtSign = FmtSpace << 1
|
||||||
|
FmtApost = FmtSign << 1
|
||||||
|
FmtZero = FmtApost << 1
|
||||||
|
FmtUnsigned = FmtZero << 1
|
||||||
|
FmtShort = FmtUnsigned << 1
|
||||||
|
FmtLong = FmtShort << 1
|
||||||
|
FmtVLong = FmtLong << 1
|
||||||
|
FmtComma = FmtVLong << 1
|
||||||
|
FmtByte = FmtComma << 1
|
||||||
|
FmtLDouble = FmtByte << 1
|
||||||
|
FmtFlag = FmtLDouble << 1
|
||||||
|
)
|
||||||
|
|
||||||
|
var fmtdoquote func(int) int
|
||||||
|
|
||||||
|
/* Edit .+1,/^$/ | cfn $PLAN9/src/lib9/fmt/?*.c | grep -v static |grep -v __ */
|
||||||
929
src/cmd/internal/ld/go.go
Normal file
929
src/cmd/internal/ld/go.go
Normal file
|
|
@ -0,0 +1,929 @@
|
||||||
|
// Copyright 2009 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package ld
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"cmd/internal/obj"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
"unicode/utf8"
|
||||||
|
)
|
||||||
|
|
||||||
|
// go-specific code shared across loaders (5l, 6l, 8l).
|
||||||
|
|
||||||
|
// replace all "". with pkg.
|
||||||
|
func expandpkg(t0 string, pkg string) string {
|
||||||
|
return strings.Replace(t0, `"".`, pkg+".", -1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copyright 2009 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// go-specific code shared across loaders (5l, 6l, 8l).
|
||||||
|
|
||||||
|
// accumulate all type information from .6 files.
|
||||||
|
// check for inconsistencies.
|
||||||
|
|
||||||
|
// TODO:
|
||||||
|
// generate debugging section in binary.
|
||||||
|
// once the dust settles, try to move some code to
|
||||||
|
// libmach, so that other linkers and ar can share.
|
||||||
|
|
||||||
|
/*
|
||||||
|
* package import data
|
||||||
|
*/
|
||||||
|
type Import struct {
|
||||||
|
hash *Import
|
||||||
|
prefix string
|
||||||
|
name string
|
||||||
|
def string
|
||||||
|
file string
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
NIHASH = 1024
|
||||||
|
)
|
||||||
|
|
||||||
|
var ihash [NIHASH]*Import
|
||||||
|
|
||||||
|
var nimport int
|
||||||
|
|
||||||
|
func hashstr(name string) int {
|
||||||
|
var h uint32
|
||||||
|
var cp string
|
||||||
|
|
||||||
|
h = 0
|
||||||
|
for cp = name; cp != ""; cp = cp[1:] {
|
||||||
|
h = h*1119 + uint32(cp[0])
|
||||||
|
}
|
||||||
|
h &= 0xffffff
|
||||||
|
return int(h)
|
||||||
|
}
|
||||||
|
|
||||||
|
func ilookup(name string) *Import {
|
||||||
|
var h int
|
||||||
|
var x *Import
|
||||||
|
|
||||||
|
h = hashstr(name) % NIHASH
|
||||||
|
for x = ihash[h]; x != nil; x = x.hash {
|
||||||
|
if x.name[0] == name[0] && x.name == name {
|
||||||
|
return x
|
||||||
|
}
|
||||||
|
}
|
||||||
|
x = new(Import)
|
||||||
|
x.name = name
|
||||||
|
x.hash = ihash[h]
|
||||||
|
ihash[h] = x
|
||||||
|
nimport++
|
||||||
|
return x
|
||||||
|
}
|
||||||
|
|
||||||
|
func ldpkg(f *Biobuf, pkg string, length int64, filename string, whence int) {
|
||||||
|
var bdata []byte
|
||||||
|
var data string
|
||||||
|
var p0, p1 int
|
||||||
|
var name string
|
||||||
|
|
||||||
|
if Debug['g'] != 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if int64(int(length)) != length {
|
||||||
|
fmt.Fprintf(os.Stderr, "%s: too much pkg data in %s\n", os.Args[0], filename)
|
||||||
|
if Debug['u'] != 0 {
|
||||||
|
Errorexit()
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
bdata = make([]byte, length)
|
||||||
|
if int64(Bread(f, bdata)) != length {
|
||||||
|
fmt.Fprintf(os.Stderr, "%s: short pkg read %s\n", os.Args[0], filename)
|
||||||
|
if Debug['u'] != 0 {
|
||||||
|
Errorexit()
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
data = string(bdata)
|
||||||
|
|
||||||
|
// first \n$$ marks beginning of exports - skip rest of line
|
||||||
|
p0 = strings.Index(data, "\n$$")
|
||||||
|
if p0 < 0 {
|
||||||
|
if Debug['u'] != 0 && whence != ArchiveObj {
|
||||||
|
fmt.Fprintf(os.Stderr, "%s: cannot find export data in %s\n", os.Args[0], filename)
|
||||||
|
Errorexit()
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
p0 += 3
|
||||||
|
for p0 < len(data) && data[0] != '\n' {
|
||||||
|
p0++
|
||||||
|
}
|
||||||
|
|
||||||
|
// second marks end of exports / beginning of local data
|
||||||
|
p1 = strings.Index(data[p0:], "\n$$")
|
||||||
|
if p1 < 0 {
|
||||||
|
fmt.Fprintf(os.Stderr, "%s: cannot find end of exports in %s\n", os.Args[0], filename)
|
||||||
|
if Debug['u'] != 0 {
|
||||||
|
Errorexit()
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
p1 += p0
|
||||||
|
|
||||||
|
for p0 < p1 && (data[p0] == ' ' || data[0] == '\t' || data[0] == '\n') {
|
||||||
|
p0++
|
||||||
|
}
|
||||||
|
if p0 < p1 {
|
||||||
|
if !strings.HasPrefix(data[p0:], "package ") {
|
||||||
|
fmt.Fprintf(os.Stderr, "%s: bad package section in %s - %.20s\n", os.Args[0], filename, data[p0:])
|
||||||
|
if Debug['u'] != 0 {
|
||||||
|
Errorexit()
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
p0 += 8
|
||||||
|
for p0 < p1 && (data[p0] == ' ' || data[p0] == '\t' || data[p0] == '\n') {
|
||||||
|
p0++
|
||||||
|
}
|
||||||
|
name = data[p0:]
|
||||||
|
for p0 < p1 && data[p0] != ' ' && data[p0] != '\t' && data[p0] != '\n' {
|
||||||
|
p0++
|
||||||
|
}
|
||||||
|
if Debug['u'] != 0 && whence != ArchiveObj && (p0+6 > p1 || !strings.HasPrefix(data[p0:], " safe\n")) {
|
||||||
|
fmt.Fprintf(os.Stderr, "%s: load of unsafe package %s\n", os.Args[0], filename)
|
||||||
|
nerrors++
|
||||||
|
Errorexit()
|
||||||
|
}
|
||||||
|
|
||||||
|
name = name[:p1-p0]
|
||||||
|
if p0 < p1 {
|
||||||
|
if data[p0] == '\n' {
|
||||||
|
p0++
|
||||||
|
} else {
|
||||||
|
p0++
|
||||||
|
for p0 < p1 && data[p0] != '\n' {
|
||||||
|
p0++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if pkg == "main" && name != "main" {
|
||||||
|
fmt.Fprintf(os.Stderr, "%s: %s: not package main (package %s)\n", os.Args[0], filename, name)
|
||||||
|
nerrors++
|
||||||
|
Errorexit()
|
||||||
|
}
|
||||||
|
|
||||||
|
loadpkgdata(filename, pkg, data[p0:p1])
|
||||||
|
}
|
||||||
|
|
||||||
|
// __.PKGDEF has no cgo section - those are in the C compiler-generated object files.
|
||||||
|
if whence == Pkgdef {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// look for cgo section
|
||||||
|
p0 = strings.Index(data[p1:], "\n$$ // cgo")
|
||||||
|
if p0 >= 0 {
|
||||||
|
p0 += p1
|
||||||
|
i := strings.IndexByte(data[p0+1:], '\n')
|
||||||
|
if i < 0 {
|
||||||
|
fmt.Fprintf(os.Stderr, "%s: found $$ // cgo but no newline in %s\n", os.Args[0], filename)
|
||||||
|
if Debug['u'] != 0 {
|
||||||
|
Errorexit()
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
p0 += 1 + i
|
||||||
|
|
||||||
|
p1 = strings.Index(data[p0:], "\n$$")
|
||||||
|
if p1 < 0 {
|
||||||
|
p1 = strings.Index(data[p0:], "\n!\n")
|
||||||
|
}
|
||||||
|
if p1 < 0 {
|
||||||
|
fmt.Fprintf(os.Stderr, "%s: cannot find end of // cgo section in %s\n", os.Args[0], filename)
|
||||||
|
if Debug['u'] != 0 {
|
||||||
|
Errorexit()
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
p1 += p0
|
||||||
|
|
||||||
|
loadcgo(filename, pkg, data[p0:p1])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func loadpkgdata(file string, pkg string, data string) {
|
||||||
|
var p string
|
||||||
|
var prefix string
|
||||||
|
var name string
|
||||||
|
var def string
|
||||||
|
var x *Import
|
||||||
|
|
||||||
|
file = file
|
||||||
|
p = data
|
||||||
|
for parsepkgdata(file, pkg, &p, &prefix, &name, &def) > 0 {
|
||||||
|
x = ilookup(name)
|
||||||
|
if x.prefix == "" {
|
||||||
|
x.prefix = prefix
|
||||||
|
x.def = def
|
||||||
|
x.file = file
|
||||||
|
} else if x.prefix != prefix {
|
||||||
|
fmt.Fprintf(os.Stderr, "%s: conflicting definitions for %s\n", os.Args[0], name)
|
||||||
|
fmt.Fprintf(os.Stderr, "%s:\t%s %s ...\n", x.file, x.prefix, name)
|
||||||
|
fmt.Fprintf(os.Stderr, "%s:\t%s %s ...\n", file, prefix, name)
|
||||||
|
nerrors++
|
||||||
|
} else if x.def != def {
|
||||||
|
fmt.Fprintf(os.Stderr, "%s: conflicting definitions for %s\n", os.Args[0], name)
|
||||||
|
fmt.Fprintf(os.Stderr, "%s:\t%s %s %s\n", x.file, x.prefix, name, x.def)
|
||||||
|
fmt.Fprintf(os.Stderr, "%s:\t%s %s %s\n", file, prefix, name, def)
|
||||||
|
nerrors++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func parsepkgdata(file string, pkg string, pp *string, prefixp *string, namep *string, defp *string) int {
|
||||||
|
var p string
|
||||||
|
var prefix string
|
||||||
|
var name string
|
||||||
|
var def string
|
||||||
|
var meth string
|
||||||
|
var inquote bool
|
||||||
|
|
||||||
|
// skip white space
|
||||||
|
p = *pp
|
||||||
|
|
||||||
|
loop:
|
||||||
|
for len(p) > 0 && (p[0] == ' ' || p[0] == '\t' || p[0] == '\n') {
|
||||||
|
p = p[1:]
|
||||||
|
}
|
||||||
|
if len(p) == 0 || strings.HasPrefix(p, "$$\n") {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// prefix: (var|type|func|const)
|
||||||
|
prefix = p
|
||||||
|
|
||||||
|
if len(p) < 7 {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
if strings.HasPrefix(p, "var ") {
|
||||||
|
p = p[4:]
|
||||||
|
} else if strings.HasPrefix(p, "type ") {
|
||||||
|
p = p[5:]
|
||||||
|
} else if strings.HasPrefix(p, "func ") {
|
||||||
|
p = p[5:]
|
||||||
|
} else if strings.HasPrefix(p, "const ") {
|
||||||
|
p = p[6:]
|
||||||
|
} else if strings.HasPrefix(p, "import ") {
|
||||||
|
p = p[7:]
|
||||||
|
for len(p) > 0 && p[0] != ' ' {
|
||||||
|
p = p[1:]
|
||||||
|
}
|
||||||
|
p = p[1:]
|
||||||
|
name := p
|
||||||
|
for len(p) > 0 && p[0] != '\n' {
|
||||||
|
p = p[1:]
|
||||||
|
}
|
||||||
|
if len(p) == 0 {
|
||||||
|
fmt.Fprintf(os.Stderr, "%s: %s: confused in import line\n", os.Args[0], file)
|
||||||
|
nerrors++
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
name = name[:len(name)-len(p)]
|
||||||
|
p = p[1:]
|
||||||
|
imported(pkg, name)
|
||||||
|
goto loop
|
||||||
|
} else {
|
||||||
|
fmt.Fprintf(os.Stderr, "%s: %s: confused in pkg data near <<%.40s>>\n", os.Args[0], file, prefix)
|
||||||
|
nerrors++
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|
||||||
|
prefix = prefix[:len(prefix)-len(p)-1]
|
||||||
|
|
||||||
|
// name: a.b followed by space
|
||||||
|
name = p
|
||||||
|
|
||||||
|
inquote = false
|
||||||
|
for len(p) > 0 {
|
||||||
|
if p[0] == ' ' && !inquote {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
if p[0] == '\\' {
|
||||||
|
p = p[1:]
|
||||||
|
} else if p[0] == '"' {
|
||||||
|
inquote = !inquote
|
||||||
|
}
|
||||||
|
|
||||||
|
p = p[1:]
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(p) == 0 {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
name = name[:len(name)-len(p)]
|
||||||
|
p = p[1:]
|
||||||
|
|
||||||
|
// def: free form to new line
|
||||||
|
def = p
|
||||||
|
|
||||||
|
for len(p) > 0 && p[0] != '\n' {
|
||||||
|
p = p[1:]
|
||||||
|
}
|
||||||
|
if len(p) == 0 {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
def = def[:len(def)-len(p)]
|
||||||
|
var defbuf *bytes.Buffer
|
||||||
|
p = p[1:]
|
||||||
|
|
||||||
|
// include methods on successive lines in def of named type
|
||||||
|
for parsemethod(&p, &meth) > 0 {
|
||||||
|
if defbuf == nil {
|
||||||
|
defbuf = new(bytes.Buffer)
|
||||||
|
defbuf.WriteString(def)
|
||||||
|
}
|
||||||
|
defbuf.WriteString("\n\t")
|
||||||
|
defbuf.WriteString(meth)
|
||||||
|
}
|
||||||
|
if defbuf != nil {
|
||||||
|
def = defbuf.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
name = expandpkg(name, pkg)
|
||||||
|
def = expandpkg(def, pkg)
|
||||||
|
|
||||||
|
// done
|
||||||
|
*pp = p
|
||||||
|
|
||||||
|
*prefixp = prefix
|
||||||
|
*namep = name
|
||||||
|
*defp = def
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
func parsemethod(pp *string, methp *string) int {
|
||||||
|
var p string
|
||||||
|
|
||||||
|
// skip white space
|
||||||
|
p = *pp
|
||||||
|
|
||||||
|
for len(p) > 0 && (p[0] == ' ' || p[0] == '\t') {
|
||||||
|
p = p[1:]
|
||||||
|
}
|
||||||
|
if len(p) == 0 {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// might be a comment about the method
|
||||||
|
if strings.HasPrefix(p, "//") {
|
||||||
|
goto useline
|
||||||
|
}
|
||||||
|
|
||||||
|
// if it says "func (", it's a method
|
||||||
|
if strings.HasPrefix(p, "func (") {
|
||||||
|
goto useline
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
|
||||||
|
// definition to end of line
|
||||||
|
useline:
|
||||||
|
*methp = p
|
||||||
|
|
||||||
|
for len(p) > 0 && p[0] != '\n' {
|
||||||
|
p = p[1:]
|
||||||
|
}
|
||||||
|
if len(p) == 0 {
|
||||||
|
fmt.Fprintf(os.Stderr, "%s: lost end of line in method definition\n", os.Args[0])
|
||||||
|
*pp = ""
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|
||||||
|
*methp = (*methp)[:len(*methp)-len(p)]
|
||||||
|
*pp = p[1:]
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
func loadcgo(file string, pkg string, p string) {
|
||||||
|
var next string
|
||||||
|
var p0 string
|
||||||
|
var q string
|
||||||
|
var f []string
|
||||||
|
var local string
|
||||||
|
var remote string
|
||||||
|
var lib string
|
||||||
|
var s *LSym
|
||||||
|
|
||||||
|
p0 = ""
|
||||||
|
for ; p != ""; p = next {
|
||||||
|
if i := strings.Index(p, "\n"); i >= 0 {
|
||||||
|
p, next = p[:i], p[i+1:]
|
||||||
|
} else {
|
||||||
|
next = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
p0 = p // save for error message
|
||||||
|
f = tokenize(p)
|
||||||
|
if len(f) == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if f[0] == "cgo_import_dynamic" {
|
||||||
|
if len(f) < 2 || len(f) > 4 {
|
||||||
|
goto err
|
||||||
|
}
|
||||||
|
|
||||||
|
local = f[1]
|
||||||
|
remote = local
|
||||||
|
if len(f) > 2 {
|
||||||
|
remote = f[2]
|
||||||
|
}
|
||||||
|
lib = ""
|
||||||
|
if len(f) > 3 {
|
||||||
|
lib = f[3]
|
||||||
|
}
|
||||||
|
|
||||||
|
if Debug['d'] != 0 {
|
||||||
|
fmt.Fprintf(os.Stderr, "%s: %s: cannot use dynamic imports with -d flag\n", os.Args[0], file)
|
||||||
|
nerrors++
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if local == "_" && remote == "_" {
|
||||||
|
// allow #pragma dynimport _ _ "foo.so"
|
||||||
|
// to force a link of foo.so.
|
||||||
|
havedynamic = 1
|
||||||
|
|
||||||
|
Thearch.Adddynlib(lib)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
local = expandpkg(local, pkg)
|
||||||
|
q = ""
|
||||||
|
if i := strings.Index(remote, "#"); i >= 0 {
|
||||||
|
remote, q = remote[:i], remote[i+1:]
|
||||||
|
}
|
||||||
|
s = Linklookup(Ctxt, local, 0)
|
||||||
|
if local != f[1] {
|
||||||
|
}
|
||||||
|
if s.Type == 0 || s.Type == SXREF || s.Type == SHOSTOBJ {
|
||||||
|
s.Dynimplib = lib
|
||||||
|
s.Extname = remote
|
||||||
|
s.Dynimpvers = q
|
||||||
|
if s.Type != SHOSTOBJ {
|
||||||
|
s.Type = SDYNIMPORT
|
||||||
|
}
|
||||||
|
havedynamic = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if f[0] == "cgo_import_static" {
|
||||||
|
if len(f) != 2 {
|
||||||
|
goto err
|
||||||
|
}
|
||||||
|
local = f[1]
|
||||||
|
s = Linklookup(Ctxt, local, 0)
|
||||||
|
s.Type = SHOSTOBJ
|
||||||
|
s.Size = 0
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if f[0] == "cgo_export_static" || f[0] == "cgo_export_dynamic" {
|
||||||
|
// TODO: Remove once we know Windows is okay.
|
||||||
|
if f[0] == "cgo_export_static" && HEADTYPE == Hwindows {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(f) < 2 || len(f) > 3 {
|
||||||
|
goto err
|
||||||
|
}
|
||||||
|
local = f[1]
|
||||||
|
if len(f) > 2 {
|
||||||
|
remote = f[2]
|
||||||
|
} else {
|
||||||
|
remote = local
|
||||||
|
}
|
||||||
|
local = expandpkg(local, pkg)
|
||||||
|
s = Linklookup(Ctxt, local, 0)
|
||||||
|
|
||||||
|
if Flag_shared != 0 && s == Linklookup(Ctxt, "main", 0) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// export overrides import, for openbsd/cgo.
|
||||||
|
// see issue 4878.
|
||||||
|
if s.Dynimplib != "" {
|
||||||
|
s.Dynimplib = ""
|
||||||
|
s.Extname = ""
|
||||||
|
s.Dynimpvers = ""
|
||||||
|
s.Type = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
if s.Cgoexport == 0 {
|
||||||
|
s.Extname = remote
|
||||||
|
dynexp = append(dynexp, s)
|
||||||
|
} else if s.Extname != remote {
|
||||||
|
fmt.Fprintf(os.Stderr, "%s: conflicting cgo_export directives: %s as %s and %s\n", os.Args[0], s.Name, s.Extname, remote)
|
||||||
|
nerrors++
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if f[0] == "cgo_export_static" {
|
||||||
|
s.Cgoexport |= CgoExportStatic
|
||||||
|
} else {
|
||||||
|
s.Cgoexport |= CgoExportDynamic
|
||||||
|
}
|
||||||
|
if local != f[1] {
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if f[0] == "cgo_dynamic_linker" {
|
||||||
|
if len(f) != 2 {
|
||||||
|
goto err
|
||||||
|
}
|
||||||
|
|
||||||
|
if Debug['I'] == 0 {
|
||||||
|
if interpreter != "" && interpreter != f[1] {
|
||||||
|
fmt.Fprintf(os.Stderr, "%s: conflict dynlinker: %s and %s\n", os.Args[0], interpreter, f[1])
|
||||||
|
nerrors++
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
interpreter = f[1]
|
||||||
|
}
|
||||||
|
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if f[0] == "cgo_ldflag" {
|
||||||
|
if len(f) != 2 {
|
||||||
|
goto err
|
||||||
|
}
|
||||||
|
ldflag = append(ldflag, f[1])
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
|
err:
|
||||||
|
fmt.Fprintf(os.Stderr, "%s: %s: invalid dynimport line: %s\n", os.Args[0], file, p0)
|
||||||
|
nerrors++
|
||||||
|
}
|
||||||
|
|
||||||
|
var markq *LSym
|
||||||
|
|
||||||
|
var emarkq *LSym
|
||||||
|
|
||||||
|
func mark1(s *LSym, parent *LSym) {
|
||||||
|
if s == nil || s.Reachable {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if strings.HasPrefix(s.Name, "go.weak.") {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
s.Reachable = true
|
||||||
|
s.Reachparent = parent
|
||||||
|
if markq == nil {
|
||||||
|
markq = s
|
||||||
|
} else {
|
||||||
|
emarkq.Queue = s
|
||||||
|
}
|
||||||
|
emarkq = s
|
||||||
|
}
|
||||||
|
|
||||||
|
func mark(s *LSym) {
|
||||||
|
mark1(s, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func markflood() {
|
||||||
|
var a *Auto
|
||||||
|
var s *LSym
|
||||||
|
var i int
|
||||||
|
|
||||||
|
for s = markq; s != nil; s = s.Queue {
|
||||||
|
if s.Type == STEXT {
|
||||||
|
if Debug['v'] > 1 {
|
||||||
|
fmt.Fprintf(&Bso, "marktext %s\n", s.Name)
|
||||||
|
}
|
||||||
|
for a = s.Autom; a != nil; a = a.Link {
|
||||||
|
mark1(a.Gotype, s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for i = 0; i < len(s.R); i++ {
|
||||||
|
mark1(s.R[i].Sym, s)
|
||||||
|
}
|
||||||
|
if s.Pcln != nil {
|
||||||
|
for i = 0; i < s.Pcln.Nfuncdata; i++ {
|
||||||
|
mark1(s.Pcln.Funcdata[i], s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mark1(s.Gotype, s)
|
||||||
|
mark1(s.Sub, s)
|
||||||
|
mark1(s.Outer, s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var markextra = []string{
|
||||||
|
"runtime.morestack",
|
||||||
|
"runtime.morestackx",
|
||||||
|
"runtime.morestack00",
|
||||||
|
"runtime.morestack10",
|
||||||
|
"runtime.morestack01",
|
||||||
|
"runtime.morestack11",
|
||||||
|
"runtime.morestack8",
|
||||||
|
"runtime.morestack16",
|
||||||
|
"runtime.morestack24",
|
||||||
|
"runtime.morestack32",
|
||||||
|
"runtime.morestack40",
|
||||||
|
"runtime.morestack48",
|
||||||
|
// on arm, lock in the div/mod helpers too
|
||||||
|
"_div",
|
||||||
|
"_divu",
|
||||||
|
"_mod",
|
||||||
|
"_modu",
|
||||||
|
}
|
||||||
|
|
||||||
|
func deadcode() {
|
||||||
|
var i int
|
||||||
|
var s *LSym
|
||||||
|
var last *LSym
|
||||||
|
var p *LSym
|
||||||
|
var fmt_ string
|
||||||
|
|
||||||
|
if Debug['v'] != 0 {
|
||||||
|
fmt.Fprintf(&Bso, "%5.2f deadcode\n", obj.Cputime())
|
||||||
|
}
|
||||||
|
|
||||||
|
mark(Linklookup(Ctxt, INITENTRY, 0))
|
||||||
|
for i = 0; i < len(markextra); i++ {
|
||||||
|
mark(Linklookup(Ctxt, markextra[i], 0))
|
||||||
|
}
|
||||||
|
|
||||||
|
for i = 0; i < len(dynexp); i++ {
|
||||||
|
mark(dynexp[i])
|
||||||
|
}
|
||||||
|
|
||||||
|
markflood()
|
||||||
|
|
||||||
|
// keep each beginning with 'typelink.' if the symbol it points at is being kept.
|
||||||
|
for s = Ctxt.Allsym; s != nil; s = s.Allsym {
|
||||||
|
if strings.HasPrefix(s.Name, "go.typelink.") {
|
||||||
|
s.Reachable = len(s.R) == 1 && s.R[0].Sym.Reachable
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove dead text but keep file information (z symbols).
|
||||||
|
last = nil
|
||||||
|
|
||||||
|
for s = Ctxt.Textp; s != nil; s = s.Next {
|
||||||
|
if !s.Reachable {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE: Removing s from old textp and adding to new, shorter textp.
|
||||||
|
if last == nil {
|
||||||
|
Ctxt.Textp = s
|
||||||
|
} else {
|
||||||
|
last.Next = s
|
||||||
|
}
|
||||||
|
last = s
|
||||||
|
}
|
||||||
|
|
||||||
|
if last == nil {
|
||||||
|
Ctxt.Textp = nil
|
||||||
|
} else {
|
||||||
|
last.Next = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
for s = Ctxt.Allsym; s != nil; s = s.Allsym {
|
||||||
|
if strings.HasPrefix(s.Name, "go.weak.") {
|
||||||
|
s.Special = 1 // do not lay out in data segment
|
||||||
|
s.Reachable = true
|
||||||
|
s.Hide = 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// record field tracking references
|
||||||
|
fmt_ = ""
|
||||||
|
|
||||||
|
for s = Ctxt.Allsym; s != nil; s = s.Allsym {
|
||||||
|
if strings.HasPrefix(s.Name, "go.track.") {
|
||||||
|
s.Special = 1 // do not lay out in data segment
|
||||||
|
s.Hide = 1
|
||||||
|
if s.Reachable {
|
||||||
|
fmt_ += fmt.Sprintf("%s", s.Name[9:])
|
||||||
|
for p = s.Reachparent; p != nil; p = p.Reachparent {
|
||||||
|
fmt_ += fmt.Sprintf("\t%s", p.Name)
|
||||||
|
}
|
||||||
|
fmt_ += fmt.Sprintf("\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
s.Type = SCONST
|
||||||
|
s.Value = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if tracksym == "" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
s = Linklookup(Ctxt, tracksym, 0)
|
||||||
|
if !s.Reachable {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
addstrdata(tracksym, fmt_)
|
||||||
|
}
|
||||||
|
|
||||||
|
func doweak() {
|
||||||
|
var s *LSym
|
||||||
|
var t *LSym
|
||||||
|
|
||||||
|
// resolve weak references only if
|
||||||
|
// target symbol will be in binary anyway.
|
||||||
|
for s = Ctxt.Allsym; s != nil; s = s.Allsym {
|
||||||
|
if strings.HasPrefix(s.Name, "go.weak.") {
|
||||||
|
t = Linkrlookup(Ctxt, s.Name[8:], int(s.Version))
|
||||||
|
if t != nil && t.Type != 0 && t.Reachable {
|
||||||
|
s.Value = t.Value
|
||||||
|
s.Type = t.Type
|
||||||
|
s.Outer = t
|
||||||
|
} else {
|
||||||
|
s.Type = SCONST
|
||||||
|
s.Value = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func addexport() {
|
||||||
|
var i int
|
||||||
|
|
||||||
|
if HEADTYPE == Hdarwin {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for i = 0; i < len(dynexp); i++ {
|
||||||
|
Thearch.Adddynsym(Ctxt, dynexp[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* %Z from gc, for quoting import paths */
|
||||||
|
func Zconv(s string, flag int) string {
|
||||||
|
// NOTE: Keep in sync with gc Zconv.
|
||||||
|
var n int
|
||||||
|
var fp string
|
||||||
|
for i := 0; i < len(s); i += n {
|
||||||
|
var r rune
|
||||||
|
r, n = utf8.DecodeRuneInString(s[i:])
|
||||||
|
switch r {
|
||||||
|
case utf8.RuneError:
|
||||||
|
if n == 1 {
|
||||||
|
fp += fmt.Sprintf("\\x%02x", s[i])
|
||||||
|
break
|
||||||
|
}
|
||||||
|
fallthrough
|
||||||
|
|
||||||
|
// fall through
|
||||||
|
default:
|
||||||
|
if r < ' ' {
|
||||||
|
fp += fmt.Sprintf("\\x%02x", r)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
fp += string(r)
|
||||||
|
|
||||||
|
case '\t':
|
||||||
|
fp += "\\t"
|
||||||
|
|
||||||
|
case '\n':
|
||||||
|
fp += "\\n"
|
||||||
|
|
||||||
|
case '"',
|
||||||
|
'\\':
|
||||||
|
fp += `\` + string(r)
|
||||||
|
|
||||||
|
case 0xFEFF: // BOM, basically disallowed in source code
|
||||||
|
fp += "\\uFEFF"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return fp
|
||||||
|
}
|
||||||
|
|
||||||
|
type Pkg struct {
|
||||||
|
mark uint8
|
||||||
|
checked uint8
|
||||||
|
next *Pkg
|
||||||
|
path_ string
|
||||||
|
impby []*Pkg
|
||||||
|
all *Pkg
|
||||||
|
}
|
||||||
|
|
||||||
|
var phash [1024]*Pkg
|
||||||
|
|
||||||
|
var pkgall *Pkg
|
||||||
|
|
||||||
|
func getpkg(path_ string) *Pkg {
|
||||||
|
var p *Pkg
|
||||||
|
var h int
|
||||||
|
|
||||||
|
h = hashstr(path_) % len(phash)
|
||||||
|
for p = phash[h]; p != nil; p = p.next {
|
||||||
|
if p.path_ == path_ {
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
}
|
||||||
|
p = new(Pkg)
|
||||||
|
p.path_ = path_
|
||||||
|
p.next = phash[h]
|
||||||
|
phash[h] = p
|
||||||
|
p.all = pkgall
|
||||||
|
pkgall = p
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
func imported(pkg string, import_ string) {
|
||||||
|
var p *Pkg
|
||||||
|
var i *Pkg
|
||||||
|
|
||||||
|
// everyone imports runtime, even runtime.
|
||||||
|
if import_ == "\"runtime\"" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
pkg = fmt.Sprintf("\"%v\"", Zconv(pkg, 0)) // turn pkg path into quoted form, freed below
|
||||||
|
p = getpkg(pkg)
|
||||||
|
i = getpkg(import_)
|
||||||
|
i.impby = append(i.impby, p)
|
||||||
|
}
|
||||||
|
|
||||||
|
func cycle(p *Pkg) *Pkg {
|
||||||
|
var i int
|
||||||
|
var bad *Pkg
|
||||||
|
|
||||||
|
if p.checked != 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if p.mark != 0 {
|
||||||
|
nerrors++
|
||||||
|
fmt.Printf("import cycle:\n")
|
||||||
|
fmt.Printf("\t%s\n", p.path_)
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
p.mark = 1
|
||||||
|
for i = 0; i < len(p.impby); i++ {
|
||||||
|
bad = cycle(p.impby[i])
|
||||||
|
if bad != nil {
|
||||||
|
p.mark = 0
|
||||||
|
p.checked = 1
|
||||||
|
fmt.Printf("\timports %s\n", p.path_)
|
||||||
|
if bad == p {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return bad
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
p.checked = 1
|
||||||
|
p.mark = 0
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func importcycles() {
|
||||||
|
var p *Pkg
|
||||||
|
|
||||||
|
for p = pkgall; p != nil; p = p.all {
|
||||||
|
cycle(p)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func setlinkmode(arg string) {
|
||||||
|
if arg == "internal" {
|
||||||
|
Linkmode = LinkInternal
|
||||||
|
} else if arg == "external" {
|
||||||
|
Linkmode = LinkExternal
|
||||||
|
} else if arg == "auto" {
|
||||||
|
Linkmode = LinkAuto
|
||||||
|
} else {
|
||||||
|
fmt.Fprintf(os.Stderr, "unknown link mode -linkmode %s\n", arg)
|
||||||
|
Errorexit()
|
||||||
|
}
|
||||||
|
}
|
||||||
123
src/cmd/internal/ld/ld.go
Normal file
123
src/cmd/internal/ld/ld.go
Normal file
|
|
@ -0,0 +1,123 @@
|
||||||
|
// Derived from Inferno utils/6l/obj.c and utils/6l/span.c
|
||||||
|
// http://code.google.com/p/inferno-os/source/browse/utils/6l/obj.c
|
||||||
|
// http://code.google.com/p/inferno-os/source/browse/utils/6l/span.c
|
||||||
|
//
|
||||||
|
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
|
||||||
|
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
|
||||||
|
// Portions Copyright © 1997-1999 Vita Nuova Limited
|
||||||
|
// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
|
||||||
|
// Portions Copyright © 2004,2006 Bruce Ellis
|
||||||
|
// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
|
||||||
|
// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
|
||||||
|
// Portions Copyright © 2009 The Go Authors. All rights reserved.
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
|
// in the Software without restriction, including without limitation the rights
|
||||||
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
// THE SOFTWARE.
|
||||||
|
|
||||||
|
package ld
|
||||||
|
|
||||||
|
import (
|
||||||
|
"cmd/internal/obj"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"path"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
func addlib(ctxt *Link, src string, obj string, pathname string) {
|
||||||
|
name := path.Clean(pathname)
|
||||||
|
|
||||||
|
// runtime.a -> runtime, runtime.6 -> runtime
|
||||||
|
pkg := name
|
||||||
|
if len(pkg) >= 2 && pkg[len(pkg)-2] == '.' {
|
||||||
|
pkg = pkg[:len(pkg)-2]
|
||||||
|
}
|
||||||
|
|
||||||
|
// already loaded?
|
||||||
|
for i := 0; i < len(ctxt.Library); i++ {
|
||||||
|
if ctxt.Library[i].Pkg == pkg {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var pname string
|
||||||
|
if (ctxt.Windows == 0 && strings.HasPrefix(name, "/")) || (ctxt.Windows != 0 && len(name) >= 2 && name[1] == ':') {
|
||||||
|
pname = name
|
||||||
|
} else {
|
||||||
|
// try dot, -L "libdir", and then goroot.
|
||||||
|
for _, dir := range ctxt.Libdir {
|
||||||
|
pname = dir + "/" + name
|
||||||
|
if _, err := os.Stat(pname); err == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pname = path.Clean(pname)
|
||||||
|
|
||||||
|
if ctxt.Debugvlog > 1 && ctxt.Bso != nil {
|
||||||
|
fmt.Fprintf(ctxt.Bso, "%5.2f addlib: %s %s pulls in %s\n", elapsed(), obj, src, pname)
|
||||||
|
}
|
||||||
|
|
||||||
|
addlibpath(ctxt, src, obj, pname, pkg)
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* add library to library list.
|
||||||
|
* srcref: src file referring to package
|
||||||
|
* objref: object file referring to package
|
||||||
|
* file: object file, e.g., /home/rsc/go/pkg/container/vector.a
|
||||||
|
* pkg: package import path, e.g. container/vector
|
||||||
|
*/
|
||||||
|
func addlibpath(ctxt *Link, srcref string, objref string, file string, pkg string) {
|
||||||
|
var i int
|
||||||
|
var l *Library
|
||||||
|
|
||||||
|
for i = 0; i < len(ctxt.Library); i++ {
|
||||||
|
if file == ctxt.Library[i].File {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ctxt.Debugvlog > 1 && ctxt.Bso != nil {
|
||||||
|
fmt.Fprintf(ctxt.Bso, "%5.2f addlibpath: srcref: %s objref: %s file: %s pkg: %s\n", obj.Cputime(), srcref, objref, file, pkg)
|
||||||
|
}
|
||||||
|
|
||||||
|
ctxt.Library = append(ctxt.Library, Library{})
|
||||||
|
l = &ctxt.Library[len(ctxt.Library)-1]
|
||||||
|
l.Objref = objref
|
||||||
|
l.Srcref = srcref
|
||||||
|
l.File = file
|
||||||
|
l.Pkg = pkg
|
||||||
|
}
|
||||||
|
|
||||||
|
var fnuxi8 [8]uint8
|
||||||
|
|
||||||
|
var fnuxi4 [4]uint8
|
||||||
|
|
||||||
|
var inuxi1 [1]uint8
|
||||||
|
|
||||||
|
var inuxi2 [2]uint8
|
||||||
|
|
||||||
|
var inuxi8 [8]uint8
|
||||||
|
|
||||||
|
func atolwhex(s string) int64 {
|
||||||
|
n, _ := strconv.ParseInt(s, 0, 64)
|
||||||
|
return n
|
||||||
|
}
|
||||||
1004
src/cmd/internal/ld/ldelf.go
Normal file
1004
src/cmd/internal/ld/ldelf.go
Normal file
File diff suppressed because it is too large
Load diff
919
src/cmd/internal/ld/ldmacho.go
Normal file
919
src/cmd/internal/ld/ldmacho.go
Normal file
|
|
@ -0,0 +1,919 @@
|
||||||
|
package ld
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/binary"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"sort"
|
||||||
|
)
|
||||||
|
|
||||||
|
/*
|
||||||
|
Derived from Plan 9 from User Space's src/libmach/elf.h, elf.c
|
||||||
|
http://code.swtch.com/plan9port/src/tip/src/libmach/
|
||||||
|
|
||||||
|
Copyright © 2004 Russ Cox.
|
||||||
|
Portions Copyright © 2008-2010 Google Inc.
|
||||||
|
Portions Copyright © 2010 The Go Authors.
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
const (
|
||||||
|
N_EXT = 0x01
|
||||||
|
N_TYPE = 0x1e
|
||||||
|
N_STAB = 0xe0
|
||||||
|
)
|
||||||
|
|
||||||
|
type LdMachoObj struct {
|
||||||
|
f *Biobuf
|
||||||
|
base int64
|
||||||
|
length int64
|
||||||
|
is64 bool
|
||||||
|
name string
|
||||||
|
e binary.ByteOrder
|
||||||
|
cputype uint
|
||||||
|
subcputype uint
|
||||||
|
filetype uint32
|
||||||
|
flags uint32
|
||||||
|
cmd []LdMachoCmd
|
||||||
|
ncmd uint
|
||||||
|
}
|
||||||
|
|
||||||
|
type LdMachoCmd struct {
|
||||||
|
type_ int
|
||||||
|
off uint32
|
||||||
|
size uint32
|
||||||
|
seg LdMachoSeg
|
||||||
|
sym LdMachoSymtab
|
||||||
|
dsym LdMachoDysymtab
|
||||||
|
}
|
||||||
|
|
||||||
|
type LdMachoSeg struct {
|
||||||
|
name string
|
||||||
|
vmaddr uint64
|
||||||
|
vmsize uint64
|
||||||
|
fileoff uint32
|
||||||
|
filesz uint32
|
||||||
|
maxprot uint32
|
||||||
|
initprot uint32
|
||||||
|
nsect uint32
|
||||||
|
flags uint32
|
||||||
|
sect []LdMachoSect
|
||||||
|
}
|
||||||
|
|
||||||
|
type LdMachoSect struct {
|
||||||
|
name string
|
||||||
|
segname string
|
||||||
|
addr uint64
|
||||||
|
size uint64
|
||||||
|
off uint32
|
||||||
|
align uint32
|
||||||
|
reloff uint32
|
||||||
|
nreloc uint32
|
||||||
|
flags uint32
|
||||||
|
res1 uint32
|
||||||
|
res2 uint32
|
||||||
|
sym *LSym
|
||||||
|
rel []LdMachoRel
|
||||||
|
}
|
||||||
|
|
||||||
|
type LdMachoRel struct {
|
||||||
|
addr uint32
|
||||||
|
symnum uint32
|
||||||
|
pcrel uint8
|
||||||
|
length uint8
|
||||||
|
extrn uint8
|
||||||
|
type_ uint8
|
||||||
|
scattered uint8
|
||||||
|
value uint32
|
||||||
|
}
|
||||||
|
|
||||||
|
type LdMachoSymtab struct {
|
||||||
|
symoff uint32
|
||||||
|
nsym uint32
|
||||||
|
stroff uint32
|
||||||
|
strsize uint32
|
||||||
|
str []byte
|
||||||
|
sym []LdMachoSym
|
||||||
|
}
|
||||||
|
|
||||||
|
type LdMachoSym struct {
|
||||||
|
name string
|
||||||
|
type_ uint8
|
||||||
|
sectnum uint8
|
||||||
|
desc uint16
|
||||||
|
kind int8
|
||||||
|
value uint64
|
||||||
|
sym *LSym
|
||||||
|
}
|
||||||
|
|
||||||
|
type LdMachoDysymtab struct {
|
||||||
|
ilocalsym uint32
|
||||||
|
nlocalsym uint32
|
||||||
|
iextdefsym uint32
|
||||||
|
nextdefsym uint32
|
||||||
|
iundefsym uint32
|
||||||
|
nundefsym uint32
|
||||||
|
tocoff uint32
|
||||||
|
ntoc uint32
|
||||||
|
modtaboff uint32
|
||||||
|
nmodtab uint32
|
||||||
|
extrefsymoff uint32
|
||||||
|
nextrefsyms uint32
|
||||||
|
indirectsymoff uint32
|
||||||
|
nindirectsyms uint32
|
||||||
|
extreloff uint32
|
||||||
|
nextrel uint32
|
||||||
|
locreloff uint32
|
||||||
|
nlocrel uint32
|
||||||
|
indir []uint32
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
LdMachoCpuVax = 1
|
||||||
|
LdMachoCpu68000 = 6
|
||||||
|
LdMachoCpu386 = 7
|
||||||
|
LdMachoCpuAmd64 = 0x1000007
|
||||||
|
LdMachoCpuMips = 8
|
||||||
|
LdMachoCpu98000 = 10
|
||||||
|
LdMachoCpuHppa = 11
|
||||||
|
LdMachoCpuArm = 12
|
||||||
|
LdMachoCpu88000 = 13
|
||||||
|
LdMachoCpuSparc = 14
|
||||||
|
LdMachoCpu860 = 15
|
||||||
|
LdMachoCpuAlpha = 16
|
||||||
|
LdMachoCpuPower = 18
|
||||||
|
LdMachoCmdSegment = 1
|
||||||
|
LdMachoCmdSymtab = 2
|
||||||
|
LdMachoCmdSymseg = 3
|
||||||
|
LdMachoCmdThread = 4
|
||||||
|
LdMachoCmdDysymtab = 11
|
||||||
|
LdMachoCmdSegment64 = 25
|
||||||
|
LdMachoFileObject = 1
|
||||||
|
LdMachoFileExecutable = 2
|
||||||
|
LdMachoFileFvmlib = 3
|
||||||
|
LdMachoFileCore = 4
|
||||||
|
LdMachoFilePreload = 5
|
||||||
|
)
|
||||||
|
|
||||||
|
func unpackcmd(p []byte, m *LdMachoObj, c *LdMachoCmd, type_ uint, sz uint) int {
|
||||||
|
var e4 func([]byte) uint32
|
||||||
|
var e8 func([]byte) uint64
|
||||||
|
var s *LdMachoSect
|
||||||
|
var i int
|
||||||
|
|
||||||
|
e4 = m.e.Uint32
|
||||||
|
e8 = m.e.Uint64
|
||||||
|
|
||||||
|
c.type_ = int(type_)
|
||||||
|
c.size = uint32(sz)
|
||||||
|
switch type_ {
|
||||||
|
default:
|
||||||
|
return -1
|
||||||
|
|
||||||
|
case LdMachoCmdSegment:
|
||||||
|
if sz < 56 {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
c.seg.name = cstring(p[8:24])
|
||||||
|
c.seg.vmaddr = uint64(e4(p[24:]))
|
||||||
|
c.seg.vmsize = uint64(e4(p[28:]))
|
||||||
|
c.seg.fileoff = e4(p[32:])
|
||||||
|
c.seg.filesz = e4(p[36:])
|
||||||
|
c.seg.maxprot = e4(p[40:])
|
||||||
|
c.seg.initprot = e4(p[44:])
|
||||||
|
c.seg.nsect = e4(p[48:])
|
||||||
|
c.seg.flags = e4(p[52:])
|
||||||
|
c.seg.sect = make([]LdMachoSect, c.seg.nsect)
|
||||||
|
if uint32(sz) < 56+c.seg.nsect*68 {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
p = p[56:]
|
||||||
|
for i = 0; uint32(i) < c.seg.nsect; i++ {
|
||||||
|
s = &c.seg.sect[i]
|
||||||
|
s.name = cstring(p[0:16])
|
||||||
|
s.segname = cstring(p[16:32])
|
||||||
|
s.addr = uint64(e4(p[32:]))
|
||||||
|
s.size = uint64(e4(p[36:]))
|
||||||
|
s.off = e4(p[40:])
|
||||||
|
s.align = e4(p[44:])
|
||||||
|
s.reloff = e4(p[48:])
|
||||||
|
s.nreloc = e4(p[52:])
|
||||||
|
s.flags = e4(p[56:])
|
||||||
|
s.res1 = e4(p[60:])
|
||||||
|
s.res2 = e4(p[64:])
|
||||||
|
p = p[68:]
|
||||||
|
}
|
||||||
|
|
||||||
|
case LdMachoCmdSegment64:
|
||||||
|
if sz < 72 {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
c.seg.name = cstring(p[8:24])
|
||||||
|
c.seg.vmaddr = e8(p[24:])
|
||||||
|
c.seg.vmsize = e8(p[32:])
|
||||||
|
c.seg.fileoff = uint32(e8(p[40:]))
|
||||||
|
c.seg.filesz = uint32(e8(p[48:]))
|
||||||
|
c.seg.maxprot = e4(p[56:])
|
||||||
|
c.seg.initprot = e4(p[60:])
|
||||||
|
c.seg.nsect = e4(p[64:])
|
||||||
|
c.seg.flags = e4(p[68:])
|
||||||
|
c.seg.sect = make([]LdMachoSect, c.seg.nsect)
|
||||||
|
if uint32(sz) < 72+c.seg.nsect*80 {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
p = p[72:]
|
||||||
|
for i = 0; uint32(i) < c.seg.nsect; i++ {
|
||||||
|
s = &c.seg.sect[i]
|
||||||
|
s.name = cstring(p[0:16])
|
||||||
|
s.segname = cstring(p[16:32])
|
||||||
|
s.addr = e8(p[32:])
|
||||||
|
s.size = e8(p[40:])
|
||||||
|
s.off = e4(p[48:])
|
||||||
|
s.align = e4(p[52:])
|
||||||
|
s.reloff = e4(p[56:])
|
||||||
|
s.nreloc = e4(p[60:])
|
||||||
|
s.flags = e4(p[64:])
|
||||||
|
s.res1 = e4(p[68:])
|
||||||
|
s.res2 = e4(p[72:])
|
||||||
|
|
||||||
|
// p+76 is reserved
|
||||||
|
p = p[80:]
|
||||||
|
}
|
||||||
|
|
||||||
|
case LdMachoCmdSymtab:
|
||||||
|
if sz < 24 {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
c.sym.symoff = e4(p[8:])
|
||||||
|
c.sym.nsym = e4(p[12:])
|
||||||
|
c.sym.stroff = e4(p[16:])
|
||||||
|
c.sym.strsize = e4(p[20:])
|
||||||
|
|
||||||
|
case LdMachoCmdDysymtab:
|
||||||
|
if sz < 80 {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
c.dsym.ilocalsym = e4(p[8:])
|
||||||
|
c.dsym.nlocalsym = e4(p[12:])
|
||||||
|
c.dsym.iextdefsym = e4(p[16:])
|
||||||
|
c.dsym.nextdefsym = e4(p[20:])
|
||||||
|
c.dsym.iundefsym = e4(p[24:])
|
||||||
|
c.dsym.nundefsym = e4(p[28:])
|
||||||
|
c.dsym.tocoff = e4(p[32:])
|
||||||
|
c.dsym.ntoc = e4(p[36:])
|
||||||
|
c.dsym.modtaboff = e4(p[40:])
|
||||||
|
c.dsym.nmodtab = e4(p[44:])
|
||||||
|
c.dsym.extrefsymoff = e4(p[48:])
|
||||||
|
c.dsym.nextrefsyms = e4(p[52:])
|
||||||
|
c.dsym.indirectsymoff = e4(p[56:])
|
||||||
|
c.dsym.nindirectsyms = e4(p[60:])
|
||||||
|
c.dsym.extreloff = e4(p[64:])
|
||||||
|
c.dsym.nextrel = e4(p[68:])
|
||||||
|
c.dsym.locreloff = e4(p[72:])
|
||||||
|
c.dsym.nlocrel = e4(p[76:])
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func macholoadrel(m *LdMachoObj, sect *LdMachoSect) int {
|
||||||
|
var rel []LdMachoRel
|
||||||
|
var r *LdMachoRel
|
||||||
|
var buf []byte
|
||||||
|
var p []byte
|
||||||
|
var i int
|
||||||
|
var n int
|
||||||
|
var v uint32
|
||||||
|
|
||||||
|
if sect.rel != nil || sect.nreloc == 0 {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
rel = make([]LdMachoRel, sect.nreloc)
|
||||||
|
n = int(sect.nreloc * 8)
|
||||||
|
buf = make([]byte, n)
|
||||||
|
if Bseek(m.f, m.base+int64(sect.reloff), 0) < 0 || Bread(m.f, buf) != n {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
for i = 0; uint32(i) < sect.nreloc; i++ {
|
||||||
|
r = &rel[i]
|
||||||
|
p = buf[i*8:]
|
||||||
|
r.addr = m.e.Uint32(p)
|
||||||
|
|
||||||
|
// TODO(rsc): Wrong interpretation for big-endian bitfields?
|
||||||
|
if r.addr&0x80000000 != 0 {
|
||||||
|
// scatterbrained relocation
|
||||||
|
r.scattered = 1
|
||||||
|
|
||||||
|
v = r.addr >> 24
|
||||||
|
r.addr &= 0xFFFFFF
|
||||||
|
r.type_ = uint8(v & 0xF)
|
||||||
|
v >>= 4
|
||||||
|
r.length = 1 << (v & 3)
|
||||||
|
v >>= 2
|
||||||
|
r.pcrel = uint8(v & 1)
|
||||||
|
r.value = m.e.Uint32(p[4:])
|
||||||
|
} else {
|
||||||
|
v = m.e.Uint32(p[4:])
|
||||||
|
r.symnum = v & 0xFFFFFF
|
||||||
|
v >>= 24
|
||||||
|
r.pcrel = uint8(v & 1)
|
||||||
|
v >>= 1
|
||||||
|
r.length = 1 << (v & 3)
|
||||||
|
v >>= 2
|
||||||
|
r.extrn = uint8(v & 1)
|
||||||
|
v >>= 1
|
||||||
|
r.type_ = uint8(v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sect.rel = rel
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func macholoaddsym(m *LdMachoObj, d *LdMachoDysymtab) int {
|
||||||
|
var p []byte
|
||||||
|
var i int
|
||||||
|
var n int
|
||||||
|
|
||||||
|
n = int(d.nindirectsyms)
|
||||||
|
|
||||||
|
p = make([]byte, n*4)
|
||||||
|
if Bseek(m.f, m.base+int64(d.indirectsymoff), 0) < 0 || Bread(m.f, p) != len(p) {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|
||||||
|
d.indir = make([]uint32, n)
|
||||||
|
for i = 0; i < n; i++ {
|
||||||
|
d.indir[i] = m.e.Uint32(p[4*i:])
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func macholoadsym(m *LdMachoObj, symtab *LdMachoSymtab) int {
|
||||||
|
var strbuf []byte
|
||||||
|
var symbuf []byte
|
||||||
|
var p []byte
|
||||||
|
var i int
|
||||||
|
var n int
|
||||||
|
var symsize int
|
||||||
|
var sym []LdMachoSym
|
||||||
|
var s *LdMachoSym
|
||||||
|
var v uint32
|
||||||
|
|
||||||
|
if symtab.sym != nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
strbuf = make([]byte, symtab.strsize)
|
||||||
|
if Bseek(m.f, m.base+int64(symtab.stroff), 0) < 0 || Bread(m.f, strbuf) != len(strbuf) {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|
||||||
|
symsize = 12
|
||||||
|
if m.is64 {
|
||||||
|
symsize = 16
|
||||||
|
}
|
||||||
|
n = int(symtab.nsym * uint32(symsize))
|
||||||
|
symbuf = make([]byte, n)
|
||||||
|
if Bseek(m.f, m.base+int64(symtab.symoff), 0) < 0 || Bread(m.f, symbuf) != len(symbuf) {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
sym = make([]LdMachoSym, symtab.nsym)
|
||||||
|
p = symbuf
|
||||||
|
for i = 0; uint32(i) < symtab.nsym; i++ {
|
||||||
|
s = &sym[i]
|
||||||
|
v = m.e.Uint32(p)
|
||||||
|
if v >= symtab.strsize {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
s.name = cstring(strbuf[v:])
|
||||||
|
s.type_ = uint8(p[4])
|
||||||
|
s.sectnum = uint8(p[5])
|
||||||
|
s.desc = m.e.Uint16(p[6:])
|
||||||
|
if m.is64 {
|
||||||
|
s.value = m.e.Uint64(p[8:])
|
||||||
|
} else {
|
||||||
|
s.value = uint64(m.e.Uint32(p[8:]))
|
||||||
|
}
|
||||||
|
p = p[symsize:]
|
||||||
|
}
|
||||||
|
|
||||||
|
symtab.str = strbuf
|
||||||
|
symtab.sym = sym
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func ldmacho(f *Biobuf, pkg string, length int64, pn string) {
|
||||||
|
var err error
|
||||||
|
var i int
|
||||||
|
var j int
|
||||||
|
var is64 bool
|
||||||
|
var secaddr uint64
|
||||||
|
var hdr [7 * 4]uint8
|
||||||
|
var cmdp []byte
|
||||||
|
var tmp [4]uint8
|
||||||
|
var dat []byte
|
||||||
|
var ncmd uint32
|
||||||
|
var cmdsz uint32
|
||||||
|
var ty uint32
|
||||||
|
var sz uint32
|
||||||
|
var off uint32
|
||||||
|
var m *LdMachoObj
|
||||||
|
var e binary.ByteOrder
|
||||||
|
var base int64
|
||||||
|
var sect *LdMachoSect
|
||||||
|
var rel *LdMachoRel
|
||||||
|
var rpi int
|
||||||
|
var s *LSym
|
||||||
|
var s1 *LSym
|
||||||
|
var outer *LSym
|
||||||
|
var c *LdMachoCmd
|
||||||
|
var symtab *LdMachoSymtab
|
||||||
|
var dsymtab *LdMachoDysymtab
|
||||||
|
var sym *LdMachoSym
|
||||||
|
var r []Reloc
|
||||||
|
var rp *Reloc
|
||||||
|
var name string
|
||||||
|
|
||||||
|
Ctxt.Version++
|
||||||
|
base = Boffset(f)
|
||||||
|
if Bread(f, hdr[:]) != len(hdr) {
|
||||||
|
goto bad
|
||||||
|
}
|
||||||
|
|
||||||
|
if binary.BigEndian.Uint32(hdr[:])&^1 == 0xFEEDFACE {
|
||||||
|
e = binary.BigEndian
|
||||||
|
} else if binary.LittleEndian.Uint32(hdr[:])&^1 == 0xFEEDFACE {
|
||||||
|
e = binary.LittleEndian
|
||||||
|
} else {
|
||||||
|
err = fmt.Errorf("bad magic - not mach-o file")
|
||||||
|
goto bad
|
||||||
|
}
|
||||||
|
|
||||||
|
is64 = e.Uint32(hdr[:]) == 0xFEEDFACF
|
||||||
|
ncmd = e.Uint32([]byte(hdr[4*4:]))
|
||||||
|
cmdsz = e.Uint32([]byte(hdr[5*4:]))
|
||||||
|
if ncmd > 0x10000 || cmdsz >= 0x01000000 {
|
||||||
|
err = fmt.Errorf("implausible mach-o header ncmd=%d cmdsz=%d", ncmd, cmdsz)
|
||||||
|
goto bad
|
||||||
|
}
|
||||||
|
|
||||||
|
if is64 {
|
||||||
|
Bread(f, tmp[:4]) // skip reserved word in header
|
||||||
|
}
|
||||||
|
|
||||||
|
m = new(LdMachoObj)
|
||||||
|
|
||||||
|
m.f = f
|
||||||
|
m.e = e
|
||||||
|
m.cputype = uint(e.Uint32([]byte(hdr[1*4:])))
|
||||||
|
m.subcputype = uint(e.Uint32([]byte(hdr[2*4:])))
|
||||||
|
m.filetype = e.Uint32([]byte(hdr[3*4:]))
|
||||||
|
m.ncmd = uint(ncmd)
|
||||||
|
m.flags = e.Uint32([]byte(hdr[6*4:]))
|
||||||
|
m.is64 = is64
|
||||||
|
m.base = base
|
||||||
|
m.length = length
|
||||||
|
m.name = pn
|
||||||
|
|
||||||
|
switch Thearch.Thechar {
|
||||||
|
default:
|
||||||
|
Diag("%s: mach-o %s unimplemented", pn, Thestring)
|
||||||
|
return
|
||||||
|
|
||||||
|
case '6':
|
||||||
|
if e != binary.LittleEndian || m.cputype != LdMachoCpuAmd64 {
|
||||||
|
Diag("%s: mach-o object but not amd64", pn)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
case '8':
|
||||||
|
if e != binary.LittleEndian || m.cputype != LdMachoCpu386 {
|
||||||
|
Diag("%s: mach-o object but not 386", pn)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m.cmd = make([]LdMachoCmd, ncmd)
|
||||||
|
off = uint32(len(hdr))
|
||||||
|
cmdp = make([]byte, cmdsz)
|
||||||
|
if Bread(f, cmdp) != len(cmdp) {
|
||||||
|
err = fmt.Errorf("reading cmds: %v", err)
|
||||||
|
goto bad
|
||||||
|
}
|
||||||
|
|
||||||
|
// read and parse load commands
|
||||||
|
c = nil
|
||||||
|
|
||||||
|
symtab = nil
|
||||||
|
dsymtab = nil
|
||||||
|
|
||||||
|
for i = 0; uint32(i) < ncmd; i++ {
|
||||||
|
ty = e.Uint32(cmdp)
|
||||||
|
sz = e.Uint32(cmdp[4:])
|
||||||
|
m.cmd[i].off = off
|
||||||
|
unpackcmd(cmdp, m, &m.cmd[i], uint(ty), uint(sz))
|
||||||
|
cmdp = cmdp[sz:]
|
||||||
|
off += sz
|
||||||
|
if ty == LdMachoCmdSymtab {
|
||||||
|
if symtab != nil {
|
||||||
|
err = fmt.Errorf("multiple symbol tables")
|
||||||
|
goto bad
|
||||||
|
}
|
||||||
|
|
||||||
|
symtab = &m.cmd[i].sym
|
||||||
|
macholoadsym(m, symtab)
|
||||||
|
}
|
||||||
|
|
||||||
|
if ty == LdMachoCmdDysymtab {
|
||||||
|
dsymtab = &m.cmd[i].dsym
|
||||||
|
macholoaddsym(m, dsymtab)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is64 && ty == LdMachoCmdSegment64) || (!is64 && ty == LdMachoCmdSegment) {
|
||||||
|
if c != nil {
|
||||||
|
err = fmt.Errorf("multiple load commands")
|
||||||
|
goto bad
|
||||||
|
}
|
||||||
|
|
||||||
|
c = &m.cmd[i]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// load text and data segments into memory.
|
||||||
|
// they are not as small as the load commands, but we'll need
|
||||||
|
// the memory anyway for the symbol images, so we might
|
||||||
|
// as well use one large chunk.
|
||||||
|
if c == nil {
|
||||||
|
err = fmt.Errorf("no load command")
|
||||||
|
goto bad
|
||||||
|
}
|
||||||
|
|
||||||
|
if symtab == nil {
|
||||||
|
// our work is done here - no symbols means nothing can refer to this file
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if int64(c.seg.fileoff+c.seg.filesz) >= length {
|
||||||
|
err = fmt.Errorf("load segment out of range")
|
||||||
|
goto bad
|
||||||
|
}
|
||||||
|
|
||||||
|
dat = make([]byte, c.seg.filesz)
|
||||||
|
if Bseek(f, m.base+int64(c.seg.fileoff), 0) < 0 || Bread(f, dat) != len(dat) {
|
||||||
|
err = fmt.Errorf("cannot load object data: %v", err)
|
||||||
|
goto bad
|
||||||
|
}
|
||||||
|
|
||||||
|
for i = 0; uint32(i) < c.seg.nsect; i++ {
|
||||||
|
sect = &c.seg.sect[i]
|
||||||
|
if sect.segname != "__TEXT" && sect.segname != "__DATA" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if sect.name == "__eh_frame" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
name = fmt.Sprintf("%s(%s/%s)", pkg, sect.segname, sect.name)
|
||||||
|
s = Linklookup(Ctxt, name, Ctxt.Version)
|
||||||
|
if s.Type != 0 {
|
||||||
|
err = fmt.Errorf("duplicate %s/%s", sect.segname, sect.name)
|
||||||
|
goto bad
|
||||||
|
}
|
||||||
|
|
||||||
|
if sect.flags&0xff == 1 { // S_ZEROFILL
|
||||||
|
s.P = make([]byte, sect.size)
|
||||||
|
} else {
|
||||||
|
s.P = dat[sect.addr-c.seg.vmaddr:][:sect.size]
|
||||||
|
}
|
||||||
|
s.Size = int64(len(s.P))
|
||||||
|
|
||||||
|
if sect.segname == "__TEXT" {
|
||||||
|
if sect.name == "__text" {
|
||||||
|
s.Type = STEXT
|
||||||
|
} else {
|
||||||
|
s.Type = SRODATA
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if sect.name == "__bss" {
|
||||||
|
s.Type = SNOPTRBSS
|
||||||
|
s.P = s.P[:0]
|
||||||
|
} else {
|
||||||
|
s.Type = SNOPTRDATA
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sect.sym = s
|
||||||
|
}
|
||||||
|
|
||||||
|
// enter sub-symbols into symbol table.
|
||||||
|
// have to guess sizes from next symbol.
|
||||||
|
for i = 0; uint32(i) < symtab.nsym; i++ {
|
||||||
|
var v int
|
||||||
|
sym = &symtab.sym[i]
|
||||||
|
if sym.type_&N_STAB != 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: check sym->type against outer->type.
|
||||||
|
name = sym.name
|
||||||
|
|
||||||
|
if name[0] == '_' && name[1] != '\x00' {
|
||||||
|
name = name[1:]
|
||||||
|
}
|
||||||
|
v = 0
|
||||||
|
if sym.type_&N_EXT == 0 {
|
||||||
|
v = Ctxt.Version
|
||||||
|
}
|
||||||
|
s = Linklookup(Ctxt, name, v)
|
||||||
|
if sym.type_&N_EXT == 0 {
|
||||||
|
s.Dupok = 1
|
||||||
|
}
|
||||||
|
sym.sym = s
|
||||||
|
if sym.sectnum == 0 { // undefined
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if uint32(sym.sectnum) > c.seg.nsect {
|
||||||
|
err = fmt.Errorf("reference to invalid section %d", sym.sectnum)
|
||||||
|
goto bad
|
||||||
|
}
|
||||||
|
|
||||||
|
sect = &c.seg.sect[sym.sectnum-1]
|
||||||
|
outer = sect.sym
|
||||||
|
if outer == nil {
|
||||||
|
err = fmt.Errorf("reference to invalid section %s/%s", sect.segname, sect.name)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if s.Outer != nil {
|
||||||
|
if s.Dupok != 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
Diag("%s: duplicate symbol reference: %s in both %s and %s", pn, s.Name, s.Outer.Name, sect.sym.Name)
|
||||||
|
Errorexit()
|
||||||
|
}
|
||||||
|
|
||||||
|
s.Type = outer.Type | SSUB
|
||||||
|
s.Sub = outer.Sub
|
||||||
|
outer.Sub = s
|
||||||
|
s.Outer = outer
|
||||||
|
s.Value = int64(sym.value - sect.addr)
|
||||||
|
if s.Cgoexport&CgoExportDynamic == 0 {
|
||||||
|
s.Dynimplib = "" // satisfy dynimport
|
||||||
|
}
|
||||||
|
if outer.Type == STEXT {
|
||||||
|
if s.External != 0 && s.Dupok == 0 {
|
||||||
|
Diag("%s: duplicate definition of %s", pn, s.Name)
|
||||||
|
}
|
||||||
|
s.External = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
sym.sym = s
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sort outer lists by address, adding to textp.
|
||||||
|
// This keeps textp in increasing address order.
|
||||||
|
for i = 0; uint32(i) < c.seg.nsect; i++ {
|
||||||
|
sect = &c.seg.sect[i]
|
||||||
|
s = sect.sym
|
||||||
|
if s == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if s.Sub != nil {
|
||||||
|
s.Sub = listsort(s.Sub, valuecmp, listsubp)
|
||||||
|
|
||||||
|
// assign sizes, now that we know symbols in sorted order.
|
||||||
|
for s1 = s.Sub; s1 != nil; s1 = s1.Sub {
|
||||||
|
if s1.Sub != nil {
|
||||||
|
s1.Size = s1.Sub.Value - s1.Value
|
||||||
|
} else {
|
||||||
|
s1.Size = s.Value + s.Size - s1.Value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if s.Type == STEXT {
|
||||||
|
if s.Onlist != 0 {
|
||||||
|
log.Fatalf("symbol %s listed multiple times", s.Name)
|
||||||
|
}
|
||||||
|
s.Onlist = 1
|
||||||
|
if Ctxt.Etextp != nil {
|
||||||
|
Ctxt.Etextp.Next = s
|
||||||
|
} else {
|
||||||
|
Ctxt.Textp = s
|
||||||
|
}
|
||||||
|
Ctxt.Etextp = s
|
||||||
|
for s1 = s.Sub; s1 != nil; s1 = s1.Sub {
|
||||||
|
if s1.Onlist != 0 {
|
||||||
|
log.Fatalf("symbol %s listed multiple times", s1.Name)
|
||||||
|
}
|
||||||
|
s1.Onlist = 1
|
||||||
|
Ctxt.Etextp.Next = s1
|
||||||
|
Ctxt.Etextp = s1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// load relocations
|
||||||
|
for i = 0; uint32(i) < c.seg.nsect; i++ {
|
||||||
|
sect = &c.seg.sect[i]
|
||||||
|
s = sect.sym
|
||||||
|
if s == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
macholoadrel(m, sect)
|
||||||
|
if sect.rel == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
r = make([]Reloc, sect.nreloc)
|
||||||
|
rpi = 0
|
||||||
|
for j = 0; uint32(j) < sect.nreloc; j++ {
|
||||||
|
rp = &r[rpi]
|
||||||
|
rel = §.rel[j]
|
||||||
|
if rel.scattered != 0 {
|
||||||
|
var k int
|
||||||
|
var ks *LdMachoSect
|
||||||
|
|
||||||
|
if Thearch.Thechar != '8' {
|
||||||
|
// mach-o only uses scattered relocation on 32-bit platforms
|
||||||
|
Diag("unexpected scattered relocation")
|
||||||
|
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// on 386, rewrite scattered 4/1 relocation and some
|
||||||
|
// scattered 2/1 relocation into the pseudo-pc-relative
|
||||||
|
// reference that it is.
|
||||||
|
// assume that the second in the pair is in this section
|
||||||
|
// and use that as the pc-relative base.
|
||||||
|
if uint32(j+1) >= sect.nreloc {
|
||||||
|
err = fmt.Errorf("unsupported scattered relocation %d", int(rel.type_))
|
||||||
|
goto bad
|
||||||
|
}
|
||||||
|
|
||||||
|
if sect.rel[j+1].scattered == 0 || sect.rel[j+1].type_ != 1 || (rel.type_ != 4 && rel.type_ != 2) || uint64(sect.rel[j+1].value) < sect.addr || uint64(sect.rel[j+1].value) >= sect.addr+sect.size {
|
||||||
|
err = fmt.Errorf("unsupported scattered relocation %d/%d", int(rel.type_), int(sect.rel[j+1].type_))
|
||||||
|
goto bad
|
||||||
|
}
|
||||||
|
|
||||||
|
rp.Siz = rel.length
|
||||||
|
rp.Off = int32(rel.addr)
|
||||||
|
|
||||||
|
// NOTE(rsc): I haven't worked out why (really when)
|
||||||
|
// we should ignore the addend on a
|
||||||
|
// scattered relocation, but it seems that the
|
||||||
|
// common case is we ignore it.
|
||||||
|
// It's likely that this is not strictly correct
|
||||||
|
// and that the math should look something
|
||||||
|
// like the non-scattered case below.
|
||||||
|
rp.Add = 0
|
||||||
|
|
||||||
|
// want to make it pc-relative aka relative to rp->off+4
|
||||||
|
// but the scatter asks for relative to off = sect->rel[j+1].value - sect->addr.
|
||||||
|
// adjust rp->add accordingly.
|
||||||
|
rp.Type = R_PCREL
|
||||||
|
|
||||||
|
rp.Add += int64(uint64(int64(rp.Off)+4) - (uint64(sect.rel[j+1].value) - sect.addr))
|
||||||
|
|
||||||
|
// now consider the desired symbol.
|
||||||
|
// find the section where it lives.
|
||||||
|
for k = 0; uint32(k) < c.seg.nsect; k++ {
|
||||||
|
ks = &c.seg.sect[k]
|
||||||
|
if ks.addr <= uint64(rel.value) && uint64(rel.value) < ks.addr+ks.size {
|
||||||
|
goto foundk
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
err = fmt.Errorf("unsupported scattered relocation: invalid address %#x", rel.addr)
|
||||||
|
goto bad
|
||||||
|
|
||||||
|
foundk:
|
||||||
|
if ks.sym != nil {
|
||||||
|
rp.Sym = ks.sym
|
||||||
|
rp.Add += int64(uint64(rel.value) - ks.addr)
|
||||||
|
} else if ks.segname == "__IMPORT" && ks.name == "__pointers" {
|
||||||
|
// handle reference to __IMPORT/__pointers.
|
||||||
|
// how much worse can this get?
|
||||||
|
// why are we supporting 386 on the mac anyway?
|
||||||
|
rp.Type = 512 + MACHO_FAKE_GOTPCREL
|
||||||
|
|
||||||
|
// figure out which pointer this is a reference to.
|
||||||
|
k = int(uint64(ks.res1) + (uint64(rel.value)-ks.addr)/4)
|
||||||
|
|
||||||
|
// load indirect table for __pointers
|
||||||
|
// fetch symbol number
|
||||||
|
if dsymtab == nil || k < 0 || uint32(k) >= dsymtab.nindirectsyms || dsymtab.indir == nil {
|
||||||
|
err = fmt.Errorf("invalid scattered relocation: indirect symbol reference out of range")
|
||||||
|
goto bad
|
||||||
|
}
|
||||||
|
|
||||||
|
k = int(dsymtab.indir[k])
|
||||||
|
if k < 0 || uint32(k) >= symtab.nsym {
|
||||||
|
err = fmt.Errorf("invalid scattered relocation: symbol reference out of range")
|
||||||
|
goto bad
|
||||||
|
}
|
||||||
|
|
||||||
|
rp.Sym = symtab.sym[k].sym
|
||||||
|
} else {
|
||||||
|
err = fmt.Errorf("unsupported scattered relocation: reference to %s/%s", ks.segname, ks.name)
|
||||||
|
goto bad
|
||||||
|
}
|
||||||
|
|
||||||
|
rpi++
|
||||||
|
|
||||||
|
// skip #1 of 2 rel; continue skips #2 of 2.
|
||||||
|
j++
|
||||||
|
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
rp.Siz = rel.length
|
||||||
|
rp.Type = 512 + (int32(rel.type_) << 1) + int32(rel.pcrel)
|
||||||
|
rp.Off = int32(rel.addr)
|
||||||
|
|
||||||
|
// Handle X86_64_RELOC_SIGNED referencing a section (rel->extrn == 0).
|
||||||
|
if Thearch.Thechar == '6' && rel.extrn == 0 && rel.type_ == 1 {
|
||||||
|
// Calculate the addend as the offset into the section.
|
||||||
|
//
|
||||||
|
// The rip-relative offset stored in the object file is encoded
|
||||||
|
// as follows:
|
||||||
|
//
|
||||||
|
// movsd 0x00000360(%rip),%xmm0
|
||||||
|
//
|
||||||
|
// To get the absolute address of the value this rip-relative address is pointing
|
||||||
|
// to, we must add the address of the next instruction to it. This is done by
|
||||||
|
// taking the address of the relocation and adding 4 to it (since the rip-relative
|
||||||
|
// offset can at most be 32 bits long). To calculate the offset into the section the
|
||||||
|
// relocation is referencing, we subtract the vaddr of the start of the referenced
|
||||||
|
// section found in the original object file.
|
||||||
|
//
|
||||||
|
// [For future reference, see Darwin's /usr/include/mach-o/x86_64/reloc.h]
|
||||||
|
secaddr = c.seg.sect[rel.symnum-1].addr
|
||||||
|
|
||||||
|
rp.Add = int64(uint64(int64(int32(e.Uint32(s.P[rp.Off:])))+int64(rp.Off)+4) - secaddr)
|
||||||
|
} else {
|
||||||
|
rp.Add = int64(int32(e.Uint32(s.P[rp.Off:])))
|
||||||
|
}
|
||||||
|
|
||||||
|
// For i386 Mach-O PC-relative, the addend is written such that
|
||||||
|
// it *is* the PC being subtracted. Use that to make
|
||||||
|
// it match our version of PC-relative.
|
||||||
|
if rel.pcrel != 0 && Thearch.Thechar == '8' {
|
||||||
|
rp.Add += int64(rp.Off) + int64(rp.Siz)
|
||||||
|
}
|
||||||
|
if rel.extrn == 0 {
|
||||||
|
if rel.symnum < 1 || rel.symnum > c.seg.nsect {
|
||||||
|
err = fmt.Errorf("invalid relocation: section reference out of range %d vs %d", rel.symnum, c.seg.nsect)
|
||||||
|
goto bad
|
||||||
|
}
|
||||||
|
|
||||||
|
rp.Sym = c.seg.sect[rel.symnum-1].sym
|
||||||
|
if rp.Sym == nil {
|
||||||
|
err = fmt.Errorf("invalid relocation: %s", c.seg.sect[rel.symnum-1].name)
|
||||||
|
goto bad
|
||||||
|
}
|
||||||
|
|
||||||
|
// References to symbols in other sections
|
||||||
|
// include that information in the addend.
|
||||||
|
// We only care about the delta from the
|
||||||
|
// section base.
|
||||||
|
if Thearch.Thechar == '8' {
|
||||||
|
rp.Add -= int64(c.seg.sect[rel.symnum-1].addr)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if rel.symnum >= symtab.nsym {
|
||||||
|
err = fmt.Errorf("invalid relocation: symbol reference out of range")
|
||||||
|
goto bad
|
||||||
|
}
|
||||||
|
|
||||||
|
rp.Sym = symtab.sym[rel.symnum].sym
|
||||||
|
}
|
||||||
|
|
||||||
|
rpi++
|
||||||
|
}
|
||||||
|
|
||||||
|
sort.Sort(rbyoff(r[:rpi]))
|
||||||
|
s.R = r
|
||||||
|
s.R = s.R[:rpi]
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
|
bad:
|
||||||
|
Diag("%s: malformed mach-o file: %v", pn, err)
|
||||||
|
}
|
||||||
550
src/cmd/internal/ld/ldpe.go
Normal file
550
src/cmd/internal/ld/ldpe.go
Normal file
|
|
@ -0,0 +1,550 @@
|
||||||
|
// Copyright 2010 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package ld
|
||||||
|
|
||||||
|
import (
|
||||||
|
"cmd/internal/obj"
|
||||||
|
"encoding/binary"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"sort"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
IMAGE_SYM_UNDEFINED = 0
|
||||||
|
IMAGE_SYM_ABSOLUTE = -1
|
||||||
|
IMAGE_SYM_DEBUG = -2
|
||||||
|
IMAGE_SYM_TYPE_NULL = 0
|
||||||
|
IMAGE_SYM_TYPE_VOID = 1
|
||||||
|
IMAGE_SYM_TYPE_CHAR = 2
|
||||||
|
IMAGE_SYM_TYPE_SHORT = 3
|
||||||
|
IMAGE_SYM_TYPE_INT = 4
|
||||||
|
IMAGE_SYM_TYPE_LONG = 5
|
||||||
|
IMAGE_SYM_TYPE_FLOAT = 6
|
||||||
|
IMAGE_SYM_TYPE_DOUBLE = 7
|
||||||
|
IMAGE_SYM_TYPE_STRUCT = 8
|
||||||
|
IMAGE_SYM_TYPE_UNION = 9
|
||||||
|
IMAGE_SYM_TYPE_ENUM = 10
|
||||||
|
IMAGE_SYM_TYPE_MOE = 11
|
||||||
|
IMAGE_SYM_TYPE_BYTE = 12
|
||||||
|
IMAGE_SYM_TYPE_WORD = 13
|
||||||
|
IMAGE_SYM_TYPE_UINT = 14
|
||||||
|
IMAGE_SYM_TYPE_DWORD = 15
|
||||||
|
IMAGE_SYM_TYPE_PCODE = 32768
|
||||||
|
IMAGE_SYM_DTYPE_NULL = 0
|
||||||
|
IMAGE_SYM_DTYPE_POINTER = 0x10
|
||||||
|
IMAGE_SYM_DTYPE_FUNCTION = 0x20
|
||||||
|
IMAGE_SYM_DTYPE_ARRAY = 0x30
|
||||||
|
IMAGE_SYM_CLASS_END_OF_FUNCTION = -1
|
||||||
|
IMAGE_SYM_CLASS_NULL = 0
|
||||||
|
IMAGE_SYM_CLASS_AUTOMATIC = 1
|
||||||
|
IMAGE_SYM_CLASS_EXTERNAL = 2
|
||||||
|
IMAGE_SYM_CLASS_STATIC = 3
|
||||||
|
IMAGE_SYM_CLASS_REGISTER = 4
|
||||||
|
IMAGE_SYM_CLASS_EXTERNAL_DEF = 5
|
||||||
|
IMAGE_SYM_CLASS_LABEL = 6
|
||||||
|
IMAGE_SYM_CLASS_UNDEFINED_LABEL = 7
|
||||||
|
IMAGE_SYM_CLASS_MEMBER_OF_STRUCT = 8
|
||||||
|
IMAGE_SYM_CLASS_ARGUMENT = 9
|
||||||
|
IMAGE_SYM_CLASS_STRUCT_TAG = 10
|
||||||
|
IMAGE_SYM_CLASS_MEMBER_OF_UNION = 11
|
||||||
|
IMAGE_SYM_CLASS_UNION_TAG = 12
|
||||||
|
IMAGE_SYM_CLASS_TYPE_DEFINITION = 13
|
||||||
|
IMAGE_SYM_CLASS_UNDEFINED_STATIC = 14
|
||||||
|
IMAGE_SYM_CLASS_ENUM_TAG = 15
|
||||||
|
IMAGE_SYM_CLASS_MEMBER_OF_ENUM = 16
|
||||||
|
IMAGE_SYM_CLASS_REGISTER_PARAM = 17
|
||||||
|
IMAGE_SYM_CLASS_BIT_FIELD = 18
|
||||||
|
IMAGE_SYM_CLASS_FAR_EXTERNAL = 68
|
||||||
|
IMAGE_SYM_CLASS_BLOCK = 100
|
||||||
|
IMAGE_SYM_CLASS_FUNCTION = 101
|
||||||
|
IMAGE_SYM_CLASS_END_OF_STRUCT = 102
|
||||||
|
IMAGE_SYM_CLASS_FILE = 103
|
||||||
|
IMAGE_SYM_CLASS_SECTION = 104
|
||||||
|
IMAGE_SYM_CLASS_WEAK_EXTERNAL = 105
|
||||||
|
IMAGE_SYM_CLASS_CLR_TOKEN = 107
|
||||||
|
IMAGE_REL_I386_ABSOLUTE = 0x0000
|
||||||
|
IMAGE_REL_I386_DIR16 = 0x0001
|
||||||
|
IMAGE_REL_I386_REL16 = 0x0002
|
||||||
|
IMAGE_REL_I386_DIR32 = 0x0006
|
||||||
|
IMAGE_REL_I386_DIR32NB = 0x0007
|
||||||
|
IMAGE_REL_I386_SEG12 = 0x0009
|
||||||
|
IMAGE_REL_I386_SECTION = 0x000A
|
||||||
|
IMAGE_REL_I386_SECREL = 0x000B
|
||||||
|
IMAGE_REL_I386_TOKEN = 0x000C
|
||||||
|
IMAGE_REL_I386_SECREL7 = 0x000D
|
||||||
|
IMAGE_REL_I386_REL32 = 0x0014
|
||||||
|
IMAGE_REL_AMD64_ABSOLUTE = 0x0000
|
||||||
|
IMAGE_REL_AMD64_ADDR64 = 0x0001
|
||||||
|
IMAGE_REL_AMD64_ADDR32 = 0x0002
|
||||||
|
IMAGE_REL_AMD64_ADDR32NB = 0x0003
|
||||||
|
IMAGE_REL_AMD64_REL32 = 0x0004
|
||||||
|
IMAGE_REL_AMD64_REL32_1 = 0x0005
|
||||||
|
IMAGE_REL_AMD64_REL32_2 = 0x0006
|
||||||
|
IMAGE_REL_AMD64_REL32_3 = 0x0007
|
||||||
|
IMAGE_REL_AMD64_REL32_4 = 0x0008
|
||||||
|
IMAGE_REL_AMD64_REL32_5 = 0x0009
|
||||||
|
IMAGE_REL_AMD64_SECTION = 0x000A
|
||||||
|
IMAGE_REL_AMD64_SECREL = 0x000B
|
||||||
|
IMAGE_REL_AMD64_SECREL7 = 0x000C
|
||||||
|
IMAGE_REL_AMD64_TOKEN = 0x000D
|
||||||
|
IMAGE_REL_AMD64_SREL32 = 0x000E
|
||||||
|
IMAGE_REL_AMD64_PAIR = 0x000F
|
||||||
|
IMAGE_REL_AMD64_SSPAN32 = 0x0010
|
||||||
|
)
|
||||||
|
|
||||||
|
type PeSym struct {
|
||||||
|
name string
|
||||||
|
value uint32
|
||||||
|
sectnum uint16
|
||||||
|
type_ uint16
|
||||||
|
sclass uint8
|
||||||
|
aux uint8
|
||||||
|
sym *LSym
|
||||||
|
}
|
||||||
|
|
||||||
|
type PeSect struct {
|
||||||
|
name string
|
||||||
|
base []byte
|
||||||
|
size uint64
|
||||||
|
sym *LSym
|
||||||
|
sh IMAGE_SECTION_HEADER
|
||||||
|
}
|
||||||
|
|
||||||
|
type PeObj struct {
|
||||||
|
f *Biobuf
|
||||||
|
name string
|
||||||
|
base uint32
|
||||||
|
sect []PeSect
|
||||||
|
nsect uint
|
||||||
|
pesym []PeSym
|
||||||
|
npesym uint
|
||||||
|
fh IMAGE_FILE_HEADER
|
||||||
|
snames []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
func ldpe(f *Biobuf, pkg string, length int64, pn string) {
|
||||||
|
var err error
|
||||||
|
var name string
|
||||||
|
var base int32
|
||||||
|
var l uint32
|
||||||
|
var i int
|
||||||
|
var j int
|
||||||
|
var numaux int
|
||||||
|
var peobj *PeObj
|
||||||
|
var sect *PeSect
|
||||||
|
var rsect *PeSect
|
||||||
|
var symbuf [18]uint8
|
||||||
|
var s *LSym
|
||||||
|
var r []Reloc
|
||||||
|
var rp *Reloc
|
||||||
|
var sym *PeSym
|
||||||
|
|
||||||
|
if Debug['v'] != 0 {
|
||||||
|
fmt.Fprintf(&Bso, "%5.2f ldpe %s\n", obj.Cputime(), pn)
|
||||||
|
}
|
||||||
|
|
||||||
|
sect = nil
|
||||||
|
Ctxt.Version++
|
||||||
|
base = int32(Boffset(f))
|
||||||
|
|
||||||
|
peobj = new(PeObj)
|
||||||
|
peobj.f = f
|
||||||
|
peobj.base = uint32(base)
|
||||||
|
peobj.name = pn
|
||||||
|
|
||||||
|
// read header
|
||||||
|
if err = binary.Read(f, binary.LittleEndian, &peobj.fh); err != nil {
|
||||||
|
goto bad
|
||||||
|
}
|
||||||
|
|
||||||
|
// load section list
|
||||||
|
peobj.sect = make([]PeSect, peobj.fh.NumberOfSections)
|
||||||
|
|
||||||
|
peobj.nsect = uint(peobj.fh.NumberOfSections)
|
||||||
|
for i = 0; i < int(peobj.fh.NumberOfSections); i++ {
|
||||||
|
if err = binary.Read(f, binary.LittleEndian, &peobj.sect[i].sh); err != nil {
|
||||||
|
goto bad
|
||||||
|
}
|
||||||
|
peobj.sect[i].size = uint64(peobj.sect[i].sh.SizeOfRawData)
|
||||||
|
peobj.sect[i].name = cstring(peobj.sect[i].sh.Name[:])
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO return error if found .cormeta
|
||||||
|
|
||||||
|
// load string table
|
||||||
|
Bseek(f, int64(base)+int64(peobj.fh.PointerToSymbolTable)+int64(len(symbuf))*int64(peobj.fh.NumberOfSymbols), 0)
|
||||||
|
|
||||||
|
if Bread(f, symbuf[:4]) != 4 {
|
||||||
|
goto bad
|
||||||
|
}
|
||||||
|
l = Le32(symbuf[:])
|
||||||
|
peobj.snames = make([]byte, l)
|
||||||
|
Bseek(f, int64(base)+int64(peobj.fh.PointerToSymbolTable)+int64(len(symbuf))*int64(peobj.fh.NumberOfSymbols), 0)
|
||||||
|
if Bread(f, peobj.snames) != len(peobj.snames) {
|
||||||
|
goto bad
|
||||||
|
}
|
||||||
|
|
||||||
|
// rewrite section names if they start with /
|
||||||
|
for i = 0; i < int(peobj.fh.NumberOfSections); i++ {
|
||||||
|
if peobj.sect[i].name == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if peobj.sect[i].name[0] != '/' {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
l = uint32(obj.Atoi(peobj.sect[i].name[1:]))
|
||||||
|
peobj.sect[i].name = cstring(peobj.snames[l:])
|
||||||
|
}
|
||||||
|
|
||||||
|
// read symbols
|
||||||
|
peobj.pesym = make([]PeSym, peobj.fh.NumberOfSymbols)
|
||||||
|
|
||||||
|
peobj.npesym = uint(peobj.fh.NumberOfSymbols)
|
||||||
|
Bseek(f, int64(base)+int64(peobj.fh.PointerToSymbolTable), 0)
|
||||||
|
for i = 0; uint32(i) < peobj.fh.NumberOfSymbols; i += numaux + 1 {
|
||||||
|
Bseek(f, int64(base)+int64(peobj.fh.PointerToSymbolTable)+int64(len(symbuf))*int64(i), 0)
|
||||||
|
if Bread(f, symbuf[:]) != len(symbuf) {
|
||||||
|
goto bad
|
||||||
|
}
|
||||||
|
|
||||||
|
if (symbuf[0] == 0) && (symbuf[1] == 0) && (symbuf[2] == 0) && (symbuf[3] == 0) {
|
||||||
|
l = Le32(symbuf[4:])
|
||||||
|
peobj.pesym[i].name = cstring(peobj.snames[l:]) // sym name length <= 8
|
||||||
|
} else {
|
||||||
|
peobj.pesym[i].name = cstring(symbuf[:8])
|
||||||
|
}
|
||||||
|
|
||||||
|
peobj.pesym[i].value = Le32(symbuf[8:])
|
||||||
|
peobj.pesym[i].sectnum = Le16(symbuf[12:])
|
||||||
|
peobj.pesym[i].sclass = symbuf[16]
|
||||||
|
peobj.pesym[i].aux = symbuf[17]
|
||||||
|
peobj.pesym[i].type_ = Le16(symbuf[14:])
|
||||||
|
numaux = int(peobj.pesym[i].aux)
|
||||||
|
if numaux < 0 {
|
||||||
|
numaux = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// create symbols for mapped sections
|
||||||
|
for i = 0; uint(i) < peobj.nsect; i++ {
|
||||||
|
sect = &peobj.sect[i]
|
||||||
|
if sect.sh.Characteristics&IMAGE_SCN_MEM_DISCARDABLE != 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if sect.sh.Characteristics&(IMAGE_SCN_CNT_CODE|IMAGE_SCN_CNT_INITIALIZED_DATA|IMAGE_SCN_CNT_UNINITIALIZED_DATA) == 0 {
|
||||||
|
// This has been seen for .idata sections, which we
|
||||||
|
// want to ignore. See issues 5106 and 5273.
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if pemap(peobj, sect) < 0 {
|
||||||
|
goto bad
|
||||||
|
}
|
||||||
|
|
||||||
|
name = fmt.Sprintf("%s(%s)", pkg, sect.name)
|
||||||
|
s = Linklookup(Ctxt, name, Ctxt.Version)
|
||||||
|
|
||||||
|
switch sect.sh.Characteristics & (IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE) {
|
||||||
|
case IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ: //.rdata
|
||||||
|
s.Type = SRODATA
|
||||||
|
|
||||||
|
case IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE: //.bss
|
||||||
|
s.Type = SNOPTRBSS
|
||||||
|
|
||||||
|
case IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE: //.data
|
||||||
|
s.Type = SNOPTRDATA
|
||||||
|
|
||||||
|
case IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ: //.text
|
||||||
|
s.Type = STEXT
|
||||||
|
|
||||||
|
default:
|
||||||
|
err = fmt.Errorf("unexpected flags %#06x for PE section %s", sect.sh.Characteristics, sect.name)
|
||||||
|
goto bad
|
||||||
|
}
|
||||||
|
|
||||||
|
s.P = sect.base
|
||||||
|
s.P = s.P[:sect.size]
|
||||||
|
s.Size = int64(sect.size)
|
||||||
|
sect.sym = s
|
||||||
|
if sect.name == ".rsrc" {
|
||||||
|
setpersrc(sect.sym)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// load relocations
|
||||||
|
for i = 0; uint(i) < peobj.nsect; i++ {
|
||||||
|
rsect = &peobj.sect[i]
|
||||||
|
if rsect.sym == nil || rsect.sh.NumberOfRelocations == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if rsect.sh.Characteristics&IMAGE_SCN_MEM_DISCARDABLE != 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if sect.sh.Characteristics&(IMAGE_SCN_CNT_CODE|IMAGE_SCN_CNT_INITIALIZED_DATA|IMAGE_SCN_CNT_UNINITIALIZED_DATA) == 0 {
|
||||||
|
// This has been seen for .idata sections, which we
|
||||||
|
// want to ignore. See issues 5106 and 5273.
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
r = make([]Reloc, rsect.sh.NumberOfRelocations)
|
||||||
|
Bseek(f, int64(peobj.base)+int64(rsect.sh.PointerToRelocations), 0)
|
||||||
|
for j = 0; j < int(rsect.sh.NumberOfRelocations); j++ {
|
||||||
|
rp = &r[j]
|
||||||
|
if Bread(f, symbuf[:10]) != 10 {
|
||||||
|
goto bad
|
||||||
|
}
|
||||||
|
var rva uint32
|
||||||
|
var symindex uint32
|
||||||
|
var type_ uint16
|
||||||
|
rva = Le32(symbuf[0:])
|
||||||
|
symindex = Le32(symbuf[4:])
|
||||||
|
type_ = Le16(symbuf[8:])
|
||||||
|
if err = readpesym(peobj, int(symindex), &sym); err != nil {
|
||||||
|
goto bad
|
||||||
|
}
|
||||||
|
if sym.sym == nil {
|
||||||
|
err = fmt.Errorf("reloc of invalid sym %s idx=%d type=%d", sym.name, symindex, sym.type_)
|
||||||
|
goto bad
|
||||||
|
}
|
||||||
|
|
||||||
|
rp.Sym = sym.sym
|
||||||
|
rp.Siz = 4
|
||||||
|
rp.Off = int32(rva)
|
||||||
|
switch type_ {
|
||||||
|
default:
|
||||||
|
Diag("%s: unknown relocation type %d;", pn, type_)
|
||||||
|
fallthrough
|
||||||
|
|
||||||
|
case IMAGE_REL_I386_REL32,
|
||||||
|
IMAGE_REL_AMD64_REL32,
|
||||||
|
IMAGE_REL_AMD64_ADDR32, // R_X86_64_PC32
|
||||||
|
IMAGE_REL_AMD64_ADDR32NB:
|
||||||
|
rp.Type = R_PCREL
|
||||||
|
|
||||||
|
rp.Add = int64(int32(Le32(rsect.base[rp.Off:])))
|
||||||
|
|
||||||
|
case IMAGE_REL_I386_DIR32NB,
|
||||||
|
IMAGE_REL_I386_DIR32:
|
||||||
|
rp.Type = R_ADDR
|
||||||
|
|
||||||
|
// load addend from image
|
||||||
|
rp.Add = int64(int32(Le32(rsect.base[rp.Off:])))
|
||||||
|
|
||||||
|
case IMAGE_REL_AMD64_ADDR64: // R_X86_64_64
|
||||||
|
rp.Siz = 8
|
||||||
|
|
||||||
|
rp.Type = R_ADDR
|
||||||
|
|
||||||
|
// load addend from image
|
||||||
|
rp.Add = int64(Le64(rsect.base[rp.Off:]))
|
||||||
|
}
|
||||||
|
|
||||||
|
// ld -r could generate multiple section symbols for the
|
||||||
|
// same section but with different values, we have to take
|
||||||
|
// that into account
|
||||||
|
if issect(&peobj.pesym[symindex]) {
|
||||||
|
rp.Add += int64(peobj.pesym[symindex].value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sort.Sort(rbyoff(r[:rsect.sh.NumberOfRelocations]))
|
||||||
|
|
||||||
|
s = rsect.sym
|
||||||
|
s.R = r
|
||||||
|
s.R = s.R[:rsect.sh.NumberOfRelocations]
|
||||||
|
}
|
||||||
|
|
||||||
|
// enter sub-symbols into symbol table.
|
||||||
|
for i = 0; uint(i) < peobj.npesym; i++ {
|
||||||
|
if peobj.pesym[i].name == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if issect(&peobj.pesym[i]) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if uint(peobj.pesym[i].sectnum) > peobj.nsect {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if peobj.pesym[i].sectnum > 0 {
|
||||||
|
sect = &peobj.sect[peobj.pesym[i].sectnum-1]
|
||||||
|
if sect.sym == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = readpesym(peobj, i, &sym); err != nil {
|
||||||
|
goto bad
|
||||||
|
}
|
||||||
|
|
||||||
|
s = sym.sym
|
||||||
|
if sym.sectnum == 0 { // extern
|
||||||
|
if s.Type == SDYNIMPORT {
|
||||||
|
s.Plt = -2 // flag for dynimport in PE object files.
|
||||||
|
}
|
||||||
|
if s.Type == SXREF && sym.value > 0 { // global data
|
||||||
|
s.Type = SNOPTRDATA
|
||||||
|
s.Size = int64(sym.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
continue
|
||||||
|
} else if sym.sectnum > 0 && uint(sym.sectnum) <= peobj.nsect {
|
||||||
|
sect = &peobj.sect[sym.sectnum-1]
|
||||||
|
if sect.sym == nil {
|
||||||
|
Diag("%s: %s sym == 0!", pn, s.Name)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Diag("%s: %s sectnum < 0!", pn, s.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
if sect == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if s.Outer != nil {
|
||||||
|
if s.Dupok != 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
Diag("%s: duplicate symbol reference: %s in both %s and %s", pn, s.Name, s.Outer.Name, sect.sym.Name)
|
||||||
|
Errorexit()
|
||||||
|
}
|
||||||
|
|
||||||
|
s.Sub = sect.sym.Sub
|
||||||
|
sect.sym.Sub = s
|
||||||
|
s.Type = sect.sym.Type | SSUB
|
||||||
|
s.Value = int64(sym.value)
|
||||||
|
s.Size = 4
|
||||||
|
s.Outer = sect.sym
|
||||||
|
if sect.sym.Type == STEXT {
|
||||||
|
if s.External != 0 && s.Dupok == 0 {
|
||||||
|
Diag("%s: duplicate definition of %s", pn, s.Name)
|
||||||
|
}
|
||||||
|
s.External = 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sort outer lists by address, adding to textp.
|
||||||
|
// This keeps textp in increasing address order.
|
||||||
|
for i = 0; uint(i) < peobj.nsect; i++ {
|
||||||
|
s = peobj.sect[i].sym
|
||||||
|
if s == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if s.Sub != nil {
|
||||||
|
s.Sub = listsort(s.Sub, valuecmp, listsubp)
|
||||||
|
}
|
||||||
|
if s.Type == STEXT {
|
||||||
|
if s.Onlist != 0 {
|
||||||
|
log.Fatalf("symbol %s listed multiple times", s.Name)
|
||||||
|
}
|
||||||
|
s.Onlist = 1
|
||||||
|
if Ctxt.Etextp != nil {
|
||||||
|
Ctxt.Etextp.Next = s
|
||||||
|
} else {
|
||||||
|
Ctxt.Textp = s
|
||||||
|
}
|
||||||
|
Ctxt.Etextp = s
|
||||||
|
for s = s.Sub; s != nil; s = s.Sub {
|
||||||
|
if s.Onlist != 0 {
|
||||||
|
log.Fatalf("symbol %s listed multiple times", s.Name)
|
||||||
|
}
|
||||||
|
s.Onlist = 1
|
||||||
|
Ctxt.Etextp.Next = s
|
||||||
|
Ctxt.Etextp = s
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
|
bad:
|
||||||
|
Diag("%s: malformed pe file: %v", pn, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func pemap(peobj *PeObj, sect *PeSect) int {
|
||||||
|
if sect.base != nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
sect.base = make([]byte, sect.sh.SizeOfRawData)
|
||||||
|
if sect.sh.PointerToRawData == 0 { // .bss doesn't have data in object file
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
if Bseek(peobj.f, int64(peobj.base)+int64(sect.sh.PointerToRawData), 0) < 0 || Bread(peobj.f, sect.base) != len(sect.base) {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func issect(s *PeSym) bool {
|
||||||
|
return s.sclass == IMAGE_SYM_CLASS_STATIC && s.type_ == 0 && s.name[0] == '.'
|
||||||
|
}
|
||||||
|
|
||||||
|
func readpesym(peobj *PeObj, i int, y **PeSym) (err error) {
|
||||||
|
var s *LSym
|
||||||
|
var sym *PeSym
|
||||||
|
var name string
|
||||||
|
|
||||||
|
if uint(i) >= peobj.npesym || i < 0 {
|
||||||
|
err = fmt.Errorf("invalid pe symbol index")
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
sym = &peobj.pesym[i]
|
||||||
|
*y = sym
|
||||||
|
|
||||||
|
if issect(sym) {
|
||||||
|
name = peobj.sect[sym.sectnum-1].sym.Name
|
||||||
|
} else {
|
||||||
|
name = sym.name
|
||||||
|
if strings.HasPrefix(name, "__imp_") {
|
||||||
|
name = name[6:] // __imp_Name => Name
|
||||||
|
}
|
||||||
|
if Thearch.Thechar == '8' && name[0] == '_' {
|
||||||
|
name = name[1:] // _Name => Name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove last @XXX
|
||||||
|
if i := strings.LastIndex(name, "@"); i >= 0 {
|
||||||
|
name = name[:i]
|
||||||
|
}
|
||||||
|
|
||||||
|
switch sym.type_ {
|
||||||
|
default:
|
||||||
|
err = fmt.Errorf("%s: invalid symbol type %d", sym.name, sym.type_)
|
||||||
|
return err
|
||||||
|
|
||||||
|
case IMAGE_SYM_DTYPE_FUNCTION,
|
||||||
|
IMAGE_SYM_DTYPE_NULL:
|
||||||
|
switch sym.sclass {
|
||||||
|
case IMAGE_SYM_CLASS_EXTERNAL: //global
|
||||||
|
s = Linklookup(Ctxt, name, 0)
|
||||||
|
|
||||||
|
case IMAGE_SYM_CLASS_NULL,
|
||||||
|
IMAGE_SYM_CLASS_STATIC,
|
||||||
|
IMAGE_SYM_CLASS_LABEL:
|
||||||
|
s = Linklookup(Ctxt, name, Ctxt.Version)
|
||||||
|
s.Dupok = 1
|
||||||
|
|
||||||
|
default:
|
||||||
|
err = fmt.Errorf("%s: invalid symbol binding %d", sym.name, sym.sclass)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if s != nil && s.Type == 0 && (sym.sclass != IMAGE_SYM_CLASS_STATIC || sym.value != 0) {
|
||||||
|
s.Type = SXREF
|
||||||
|
}
|
||||||
|
if strings.HasPrefix(sym.name, "__imp_") {
|
||||||
|
s.Got = -2 // flag for __imp_
|
||||||
|
}
|
||||||
|
sym.sym = s
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
1751
src/cmd/internal/ld/lib.go
Normal file
1751
src/cmd/internal/ld/lib.go
Normal file
File diff suppressed because it is too large
Load diff
299
src/cmd/internal/ld/link.go
Normal file
299
src/cmd/internal/ld/link.go
Normal file
|
|
@ -0,0 +1,299 @@
|
||||||
|
// Derived from Inferno utils/6l/l.h and related files.
|
||||||
|
// http://code.google.com/p/inferno-os/source/browse/utils/6l/l.h
|
||||||
|
//
|
||||||
|
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
|
||||||
|
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
|
||||||
|
// Portions Copyright © 1997-1999 Vita Nuova Limited
|
||||||
|
// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
|
||||||
|
// Portions Copyright © 2004,2006 Bruce Ellis
|
||||||
|
// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
|
||||||
|
// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
|
||||||
|
// Portions Copyright © 2009 The Go Authors. All rights reserved.
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
|
// in the Software without restriction, including without limitation the rights
|
||||||
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
// THE SOFTWARE.
|
||||||
|
|
||||||
|
package ld
|
||||||
|
|
||||||
|
import "encoding/binary"
|
||||||
|
|
||||||
|
type LSym struct {
|
||||||
|
Name string
|
||||||
|
Extname string
|
||||||
|
Type int16
|
||||||
|
Version int16
|
||||||
|
Dupok uint8
|
||||||
|
Cfunc uint8
|
||||||
|
External uint8
|
||||||
|
Nosplit uint8
|
||||||
|
Reachable bool
|
||||||
|
Cgoexport uint8
|
||||||
|
Special uint8
|
||||||
|
Stkcheck uint8
|
||||||
|
Hide uint8
|
||||||
|
Leaf uint8
|
||||||
|
Localentry uint8
|
||||||
|
Onlist uint8
|
||||||
|
Dynid int32
|
||||||
|
Sig int32
|
||||||
|
Plt int32
|
||||||
|
Got int32
|
||||||
|
Align int32
|
||||||
|
Elfsym int32
|
||||||
|
Args int32
|
||||||
|
Locals int32
|
||||||
|
Value int64
|
||||||
|
Size int64
|
||||||
|
Hash *LSym
|
||||||
|
Allsym *LSym
|
||||||
|
Next *LSym
|
||||||
|
Sub *LSym
|
||||||
|
Outer *LSym
|
||||||
|
Gotype *LSym
|
||||||
|
Reachparent *LSym
|
||||||
|
Queue *LSym
|
||||||
|
File string
|
||||||
|
Dynimplib string
|
||||||
|
Dynimpvers string
|
||||||
|
Sect interface{}
|
||||||
|
Autom *Auto
|
||||||
|
Pcln *Pcln
|
||||||
|
P []byte
|
||||||
|
R []Reloc
|
||||||
|
}
|
||||||
|
|
||||||
|
type Reloc struct {
|
||||||
|
Off int32
|
||||||
|
Siz uint8
|
||||||
|
Done uint8
|
||||||
|
Type int32
|
||||||
|
Variant int32
|
||||||
|
Add int64
|
||||||
|
Xadd int64
|
||||||
|
Sym *LSym
|
||||||
|
Xsym *LSym
|
||||||
|
}
|
||||||
|
|
||||||
|
type Auto struct {
|
||||||
|
Asym *LSym
|
||||||
|
Link *Auto
|
||||||
|
Aoffset int32
|
||||||
|
Name int16
|
||||||
|
Gotype *LSym
|
||||||
|
}
|
||||||
|
|
||||||
|
type Link struct {
|
||||||
|
Thechar int32
|
||||||
|
Thestring string
|
||||||
|
Goarm int32
|
||||||
|
Headtype int
|
||||||
|
Arch *LinkArch
|
||||||
|
Debugasm int32
|
||||||
|
Debugvlog int32
|
||||||
|
Bso *Biobuf
|
||||||
|
Windows int32
|
||||||
|
Goroot string
|
||||||
|
Hash map[symVer]*LSym
|
||||||
|
Allsym *LSym
|
||||||
|
Nsymbol int32
|
||||||
|
Tlsg *LSym
|
||||||
|
Libdir []string
|
||||||
|
Library []Library
|
||||||
|
Tlsoffset int
|
||||||
|
Diag func(string, ...interface{})
|
||||||
|
Cursym *LSym
|
||||||
|
Version int
|
||||||
|
Textp *LSym
|
||||||
|
Etextp *LSym
|
||||||
|
Nhistfile int32
|
||||||
|
Filesyms *LSym
|
||||||
|
}
|
||||||
|
|
||||||
|
type LinkArch struct {
|
||||||
|
ByteOrder binary.ByteOrder
|
||||||
|
Name string
|
||||||
|
Thechar int
|
||||||
|
Endian int32
|
||||||
|
Minlc int
|
||||||
|
Ptrsize int
|
||||||
|
Regsize int
|
||||||
|
}
|
||||||
|
|
||||||
|
type Library struct {
|
||||||
|
Objref string
|
||||||
|
Srcref string
|
||||||
|
File string
|
||||||
|
Pkg string
|
||||||
|
}
|
||||||
|
|
||||||
|
type Pcln struct {
|
||||||
|
Pcsp Pcdata
|
||||||
|
Pcfile Pcdata
|
||||||
|
Pcline Pcdata
|
||||||
|
Pcdata []Pcdata
|
||||||
|
Npcdata int
|
||||||
|
Funcdata []*LSym
|
||||||
|
Funcdataoff []int64
|
||||||
|
Nfuncdata int
|
||||||
|
File []*LSym
|
||||||
|
Nfile int
|
||||||
|
Mfile int
|
||||||
|
Lastfile *LSym
|
||||||
|
Lastindex int
|
||||||
|
}
|
||||||
|
|
||||||
|
type Pcdata struct {
|
||||||
|
P []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
type Pciter struct {
|
||||||
|
d Pcdata
|
||||||
|
p []byte
|
||||||
|
pc uint32
|
||||||
|
nextpc uint32
|
||||||
|
pcscale uint32
|
||||||
|
value int32
|
||||||
|
start int
|
||||||
|
done int
|
||||||
|
}
|
||||||
|
|
||||||
|
// LSym.type
|
||||||
|
const (
|
||||||
|
Sxxx = iota
|
||||||
|
STEXT
|
||||||
|
SELFRXSECT
|
||||||
|
STYPE
|
||||||
|
SSTRING
|
||||||
|
SGOSTRING
|
||||||
|
SGOFUNC
|
||||||
|
SRODATA
|
||||||
|
SFUNCTAB
|
||||||
|
STYPELINK
|
||||||
|
SSYMTAB
|
||||||
|
SPCLNTAB
|
||||||
|
SELFROSECT
|
||||||
|
SMACHOPLT
|
||||||
|
SELFSECT
|
||||||
|
SMACHO
|
||||||
|
SMACHOGOT
|
||||||
|
SWINDOWS
|
||||||
|
SELFGOT
|
||||||
|
SNOPTRDATA
|
||||||
|
SINITARR
|
||||||
|
SDATA
|
||||||
|
SBSS
|
||||||
|
SNOPTRBSS
|
||||||
|
STLSBSS
|
||||||
|
SXREF
|
||||||
|
SMACHOSYMSTR
|
||||||
|
SMACHOSYMTAB
|
||||||
|
SMACHOINDIRECTPLT
|
||||||
|
SMACHOINDIRECTGOT
|
||||||
|
SFILE
|
||||||
|
SFILEPATH
|
||||||
|
SCONST
|
||||||
|
SDYNIMPORT
|
||||||
|
SHOSTOBJ
|
||||||
|
SSUB = 1 << 8
|
||||||
|
SMASK = SSUB - 1
|
||||||
|
SHIDDEN = 1 << 9
|
||||||
|
)
|
||||||
|
|
||||||
|
// Reloc.type
|
||||||
|
const (
|
||||||
|
R_ADDR = 1 + iota
|
||||||
|
R_ADDRPOWER
|
||||||
|
R_SIZE
|
||||||
|
R_CALL
|
||||||
|
R_CALLARM
|
||||||
|
R_CALLIND
|
||||||
|
R_CALLPOWER
|
||||||
|
R_CONST
|
||||||
|
R_PCREL
|
||||||
|
R_TLS
|
||||||
|
R_TLS_LE
|
||||||
|
R_TLS_IE
|
||||||
|
R_GOTOFF
|
||||||
|
R_PLT0
|
||||||
|
R_PLT1
|
||||||
|
R_PLT2
|
||||||
|
R_USEFIELD
|
||||||
|
R_POWER_TOC
|
||||||
|
)
|
||||||
|
|
||||||
|
// Reloc.variant
|
||||||
|
const (
|
||||||
|
RV_NONE = iota
|
||||||
|
RV_POWER_LO
|
||||||
|
RV_POWER_HI
|
||||||
|
RV_POWER_HA
|
||||||
|
RV_POWER_DS
|
||||||
|
RV_CHECK_OVERFLOW = 1 << 8
|
||||||
|
RV_TYPE_MASK = RV_CHECK_OVERFLOW - 1
|
||||||
|
)
|
||||||
|
|
||||||
|
// Auto.name
|
||||||
|
const (
|
||||||
|
A_AUTO = 1 + iota
|
||||||
|
A_PARAM
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
LINKHASH = 100003
|
||||||
|
)
|
||||||
|
|
||||||
|
// Pcdata iterator.
|
||||||
|
// for(pciterinit(ctxt, &it, &pcd); !it.done; pciternext(&it)) { it.value holds in [it.pc, it.nextpc) }
|
||||||
|
|
||||||
|
// symbol version, incremented each time a file is loaded.
|
||||||
|
// version==1 is reserved for savehist.
|
||||||
|
const (
|
||||||
|
HistVersion = 1
|
||||||
|
)
|
||||||
|
|
||||||
|
// Link holds the context for writing object code from a compiler
|
||||||
|
// to be linker input or for reading that input into the linker.
|
||||||
|
|
||||||
|
const (
|
||||||
|
LittleEndian = 0x04030201
|
||||||
|
BigEndian = 0x01020304
|
||||||
|
)
|
||||||
|
|
||||||
|
// LinkArch is the definition of a single architecture.
|
||||||
|
|
||||||
|
/* executable header types */
|
||||||
|
const (
|
||||||
|
Hunknown = 0 + iota
|
||||||
|
Hdarwin
|
||||||
|
Hdragonfly
|
||||||
|
Helf
|
||||||
|
Hfreebsd
|
||||||
|
Hlinux
|
||||||
|
Hnacl
|
||||||
|
Hnetbsd
|
||||||
|
Hopenbsd
|
||||||
|
Hplan9
|
||||||
|
Hsolaris
|
||||||
|
Hwindows
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
LinkAuto = 0 + iota
|
||||||
|
LinkInternal
|
||||||
|
LinkExternal
|
||||||
|
)
|
||||||
892
src/cmd/internal/ld/macho.go
Normal file
892
src/cmd/internal/ld/macho.go
Normal file
|
|
@ -0,0 +1,892 @@
|
||||||
|
// Copyright 2009 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package ld
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sort"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type MachoHdr struct {
|
||||||
|
cpu uint32
|
||||||
|
subcpu uint32
|
||||||
|
}
|
||||||
|
|
||||||
|
type MachoSect struct {
|
||||||
|
name string
|
||||||
|
segname string
|
||||||
|
addr uint64
|
||||||
|
size uint64
|
||||||
|
off uint32
|
||||||
|
align uint32
|
||||||
|
reloc uint32
|
||||||
|
nreloc uint32
|
||||||
|
flag uint32
|
||||||
|
res1 uint32
|
||||||
|
res2 uint32
|
||||||
|
}
|
||||||
|
|
||||||
|
type MachoSeg struct {
|
||||||
|
name string
|
||||||
|
vsize uint64
|
||||||
|
vaddr uint64
|
||||||
|
fileoffset uint64
|
||||||
|
filesize uint64
|
||||||
|
prot1 uint32
|
||||||
|
prot2 uint32
|
||||||
|
nsect uint32
|
||||||
|
msect uint32
|
||||||
|
sect []MachoSect
|
||||||
|
flag uint32
|
||||||
|
}
|
||||||
|
|
||||||
|
type MachoLoad struct {
|
||||||
|
type_ uint32
|
||||||
|
data []uint32
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Total amount of space to reserve at the start of the file
|
||||||
|
* for Header, PHeaders, and SHeaders.
|
||||||
|
* May waste some.
|
||||||
|
*/
|
||||||
|
const (
|
||||||
|
INITIAL_MACHO_HEADR = 4 * 1024
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
MACHO_CPU_AMD64 = 1<<24 | 7
|
||||||
|
MACHO_CPU_386 = 7
|
||||||
|
MACHO_SUBCPU_X86 = 3
|
||||||
|
MACHO_CPU_ARM = 12
|
||||||
|
MACHO_SUBCPU_ARM = 0
|
||||||
|
MACHO_SUBCPU_ARMV7 = 9
|
||||||
|
MACHO32SYMSIZE = 12
|
||||||
|
MACHO64SYMSIZE = 16
|
||||||
|
MACHO_X86_64_RELOC_UNSIGNED = 0
|
||||||
|
MACHO_X86_64_RELOC_SIGNED = 1
|
||||||
|
MACHO_X86_64_RELOC_BRANCH = 2
|
||||||
|
MACHO_X86_64_RELOC_GOT_LOAD = 3
|
||||||
|
MACHO_X86_64_RELOC_GOT = 4
|
||||||
|
MACHO_X86_64_RELOC_SUBTRACTOR = 5
|
||||||
|
MACHO_X86_64_RELOC_SIGNED_1 = 6
|
||||||
|
MACHO_X86_64_RELOC_SIGNED_2 = 7
|
||||||
|
MACHO_X86_64_RELOC_SIGNED_4 = 8
|
||||||
|
MACHO_ARM_RELOC_VANILLA = 0
|
||||||
|
MACHO_ARM_RELOC_BR24 = 5
|
||||||
|
MACHO_GENERIC_RELOC_VANILLA = 0
|
||||||
|
MACHO_FAKE_GOTPCREL = 100
|
||||||
|
)
|
||||||
|
|
||||||
|
// Copyright 2009 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// Mach-O file writing
|
||||||
|
// http://developer.apple.com/mac/library/DOCUMENTATION/DeveloperTools/Conceptual/MachORuntime/Reference/reference.html
|
||||||
|
|
||||||
|
var macho64 bool
|
||||||
|
|
||||||
|
var machohdr MachoHdr
|
||||||
|
|
||||||
|
var load []MachoLoad
|
||||||
|
|
||||||
|
var seg [16]MachoSeg
|
||||||
|
|
||||||
|
var nload int
|
||||||
|
|
||||||
|
var mload int
|
||||||
|
|
||||||
|
var nseg int
|
||||||
|
|
||||||
|
var ndebug int
|
||||||
|
|
||||||
|
var nsect int
|
||||||
|
|
||||||
|
const (
|
||||||
|
SymKindLocal = 0 + iota
|
||||||
|
SymKindExtdef
|
||||||
|
SymKindUndef
|
||||||
|
NumSymKind
|
||||||
|
)
|
||||||
|
|
||||||
|
var nkind [NumSymKind]int
|
||||||
|
|
||||||
|
var sortsym []*LSym
|
||||||
|
|
||||||
|
var nsortsym int
|
||||||
|
|
||||||
|
// Amount of space left for adding load commands
|
||||||
|
// that refer to dynamic libraries. Because these have
|
||||||
|
// to go in the Mach-O header, we can't just pick a
|
||||||
|
// "big enough" header size. The initial header is
|
||||||
|
// one page, the non-dynamic library stuff takes
|
||||||
|
// up about 1300 bytes; we overestimate that as 2k.
|
||||||
|
var load_budget int = INITIAL_MACHO_HEADR - 2*1024
|
||||||
|
|
||||||
|
func Machoinit() {
|
||||||
|
switch Thearch.Thechar {
|
||||||
|
// 64-bit architectures
|
||||||
|
case '6',
|
||||||
|
'9':
|
||||||
|
macho64 = true
|
||||||
|
|
||||||
|
// 32-bit architectures
|
||||||
|
default:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func getMachoHdr() *MachoHdr {
|
||||||
|
return &machohdr
|
||||||
|
}
|
||||||
|
|
||||||
|
func newMachoLoad(type_ uint32, ndata uint32) *MachoLoad {
|
||||||
|
if macho64 && (ndata&1 != 0) {
|
||||||
|
ndata++
|
||||||
|
}
|
||||||
|
|
||||||
|
load = append(load, MachoLoad{})
|
||||||
|
l := &load[len(load)-1]
|
||||||
|
l.type_ = type_
|
||||||
|
l.data = make([]uint32, ndata)
|
||||||
|
return l
|
||||||
|
}
|
||||||
|
|
||||||
|
func newMachoSeg(name string, msect int) *MachoSeg {
|
||||||
|
var s *MachoSeg
|
||||||
|
|
||||||
|
if nseg >= len(seg) {
|
||||||
|
Diag("too many segs")
|
||||||
|
Errorexit()
|
||||||
|
}
|
||||||
|
|
||||||
|
s = &seg[nseg]
|
||||||
|
nseg++
|
||||||
|
s.name = name
|
||||||
|
s.msect = uint32(msect)
|
||||||
|
s.sect = make([]MachoSect, msect)
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
func newMachoSect(seg *MachoSeg, name string, segname string) *MachoSect {
|
||||||
|
var s *MachoSect
|
||||||
|
|
||||||
|
if seg.nsect >= seg.msect {
|
||||||
|
Diag("too many sects in segment %s", seg.name)
|
||||||
|
Errorexit()
|
||||||
|
}
|
||||||
|
|
||||||
|
s = &seg.sect[seg.nsect]
|
||||||
|
seg.nsect++
|
||||||
|
s.name = name
|
||||||
|
s.segname = segname
|
||||||
|
nsect++
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generic linking code.
|
||||||
|
|
||||||
|
var dylib []string
|
||||||
|
|
||||||
|
var ndylib int
|
||||||
|
|
||||||
|
var linkoff int64
|
||||||
|
|
||||||
|
func machowrite() int {
|
||||||
|
var o1 int64
|
||||||
|
var loadsize int
|
||||||
|
var i int
|
||||||
|
var j int
|
||||||
|
var s *MachoSeg
|
||||||
|
var t *MachoSect
|
||||||
|
var l *MachoLoad
|
||||||
|
|
||||||
|
o1 = Cpos()
|
||||||
|
|
||||||
|
loadsize = 4 * 4 * ndebug
|
||||||
|
for i = 0; i < len(load); i++ {
|
||||||
|
loadsize += 4 * (len(load[i].data) + 2)
|
||||||
|
}
|
||||||
|
if macho64 {
|
||||||
|
loadsize += 18 * 4 * nseg
|
||||||
|
loadsize += 20 * 4 * nsect
|
||||||
|
} else {
|
||||||
|
loadsize += 14 * 4 * nseg
|
||||||
|
loadsize += 17 * 4 * nsect
|
||||||
|
}
|
||||||
|
|
||||||
|
if macho64 {
|
||||||
|
Thearch.Lput(0xfeedfacf)
|
||||||
|
} else {
|
||||||
|
Thearch.Lput(0xfeedface)
|
||||||
|
}
|
||||||
|
Thearch.Lput(machohdr.cpu)
|
||||||
|
Thearch.Lput(machohdr.subcpu)
|
||||||
|
if Linkmode == LinkExternal {
|
||||||
|
Thearch.Lput(1) /* file type - mach object */
|
||||||
|
} else {
|
||||||
|
Thearch.Lput(2) /* file type - mach executable */
|
||||||
|
}
|
||||||
|
Thearch.Lput(uint32(len(load)) + uint32(nseg) + uint32(ndebug))
|
||||||
|
Thearch.Lput(uint32(loadsize))
|
||||||
|
Thearch.Lput(1) /* flags - no undefines */
|
||||||
|
if macho64 {
|
||||||
|
Thearch.Lput(0) /* reserved */
|
||||||
|
}
|
||||||
|
|
||||||
|
for i = 0; i < nseg; i++ {
|
||||||
|
s = &seg[i]
|
||||||
|
if macho64 {
|
||||||
|
Thearch.Lput(25) /* segment 64 */
|
||||||
|
Thearch.Lput(72 + 80*s.nsect)
|
||||||
|
strnput(s.name, 16)
|
||||||
|
Thearch.Vput(s.vaddr)
|
||||||
|
Thearch.Vput(s.vsize)
|
||||||
|
Thearch.Vput(s.fileoffset)
|
||||||
|
Thearch.Vput(s.filesize)
|
||||||
|
Thearch.Lput(s.prot1)
|
||||||
|
Thearch.Lput(s.prot2)
|
||||||
|
Thearch.Lput(s.nsect)
|
||||||
|
Thearch.Lput(s.flag)
|
||||||
|
} else {
|
||||||
|
Thearch.Lput(1) /* segment 32 */
|
||||||
|
Thearch.Lput(56 + 68*s.nsect)
|
||||||
|
strnput(s.name, 16)
|
||||||
|
Thearch.Lput(uint32(s.vaddr))
|
||||||
|
Thearch.Lput(uint32(s.vsize))
|
||||||
|
Thearch.Lput(uint32(s.fileoffset))
|
||||||
|
Thearch.Lput(uint32(s.filesize))
|
||||||
|
Thearch.Lput(s.prot1)
|
||||||
|
Thearch.Lput(s.prot2)
|
||||||
|
Thearch.Lput(s.nsect)
|
||||||
|
Thearch.Lput(s.flag)
|
||||||
|
}
|
||||||
|
|
||||||
|
for j = 0; uint32(j) < s.nsect; j++ {
|
||||||
|
t = &s.sect[j]
|
||||||
|
if macho64 {
|
||||||
|
strnput(t.name, 16)
|
||||||
|
strnput(t.segname, 16)
|
||||||
|
Thearch.Vput(t.addr)
|
||||||
|
Thearch.Vput(t.size)
|
||||||
|
Thearch.Lput(t.off)
|
||||||
|
Thearch.Lput(t.align)
|
||||||
|
Thearch.Lput(t.reloc)
|
||||||
|
Thearch.Lput(t.nreloc)
|
||||||
|
Thearch.Lput(t.flag)
|
||||||
|
Thearch.Lput(t.res1) /* reserved */
|
||||||
|
Thearch.Lput(t.res2) /* reserved */
|
||||||
|
Thearch.Lput(0) /* reserved */
|
||||||
|
} else {
|
||||||
|
strnput(t.name, 16)
|
||||||
|
strnput(t.segname, 16)
|
||||||
|
Thearch.Lput(uint32(t.addr))
|
||||||
|
Thearch.Lput(uint32(t.size))
|
||||||
|
Thearch.Lput(t.off)
|
||||||
|
Thearch.Lput(t.align)
|
||||||
|
Thearch.Lput(t.reloc)
|
||||||
|
Thearch.Lput(t.nreloc)
|
||||||
|
Thearch.Lput(t.flag)
|
||||||
|
Thearch.Lput(t.res1) /* reserved */
|
||||||
|
Thearch.Lput(t.res2) /* reserved */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for i = 0; i < len(load); i++ {
|
||||||
|
l = &load[i]
|
||||||
|
Thearch.Lput(l.type_)
|
||||||
|
Thearch.Lput(4 * (uint32(len(l.data)) + 2))
|
||||||
|
for j = 0; j < len(l.data); j++ {
|
||||||
|
Thearch.Lput(l.data[j])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return int(Cpos() - o1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func domacho() {
|
||||||
|
var s *LSym
|
||||||
|
|
||||||
|
if Debug['d'] != 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// empirically, string table must begin with " \x00".
|
||||||
|
s = Linklookup(Ctxt, ".machosymstr", 0)
|
||||||
|
|
||||||
|
s.Type = SMACHOSYMSTR
|
||||||
|
s.Reachable = true
|
||||||
|
Adduint8(Ctxt, s, ' ')
|
||||||
|
Adduint8(Ctxt, s, '\x00')
|
||||||
|
|
||||||
|
s = Linklookup(Ctxt, ".machosymtab", 0)
|
||||||
|
s.Type = SMACHOSYMTAB
|
||||||
|
s.Reachable = true
|
||||||
|
|
||||||
|
if Linkmode != LinkExternal {
|
||||||
|
s = Linklookup(Ctxt, ".plt", 0) // will be __symbol_stub
|
||||||
|
s.Type = SMACHOPLT
|
||||||
|
s.Reachable = true
|
||||||
|
|
||||||
|
s = Linklookup(Ctxt, ".got", 0) // will be __nl_symbol_ptr
|
||||||
|
s.Type = SMACHOGOT
|
||||||
|
s.Reachable = true
|
||||||
|
s.Align = 4
|
||||||
|
|
||||||
|
s = Linklookup(Ctxt, ".linkedit.plt", 0) // indirect table for .plt
|
||||||
|
s.Type = SMACHOINDIRECTPLT
|
||||||
|
s.Reachable = true
|
||||||
|
|
||||||
|
s = Linklookup(Ctxt, ".linkedit.got", 0) // indirect table for .got
|
||||||
|
s.Type = SMACHOINDIRECTGOT
|
||||||
|
s.Reachable = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Machoadddynlib(lib string) {
|
||||||
|
// Will need to store the library name rounded up
|
||||||
|
// and 24 bytes of header metadata. If not enough
|
||||||
|
// space, grab another page of initial space at the
|
||||||
|
// beginning of the output file.
|
||||||
|
load_budget -= (len(lib)+7)/8*8 + 24
|
||||||
|
|
||||||
|
if load_budget < 0 {
|
||||||
|
HEADR += 4096
|
||||||
|
INITTEXT += 4096
|
||||||
|
load_budget += 4096
|
||||||
|
}
|
||||||
|
|
||||||
|
dylib = append(dylib, lib)
|
||||||
|
}
|
||||||
|
|
||||||
|
func machoshbits(mseg *MachoSeg, sect *Section, segname string) {
|
||||||
|
var msect *MachoSect
|
||||||
|
var buf string
|
||||||
|
|
||||||
|
buf = "__" + strings.Replace(sect.Name[1:], ".", "_", -1)
|
||||||
|
|
||||||
|
msect = newMachoSect(mseg, buf, segname)
|
||||||
|
if sect.Rellen > 0 {
|
||||||
|
msect.reloc = uint32(sect.Reloff)
|
||||||
|
msect.nreloc = uint32(sect.Rellen / 8)
|
||||||
|
}
|
||||||
|
|
||||||
|
for 1<<msect.align < sect.Align {
|
||||||
|
msect.align++
|
||||||
|
}
|
||||||
|
msect.addr = sect.Vaddr
|
||||||
|
msect.size = sect.Length
|
||||||
|
|
||||||
|
if sect.Vaddr < sect.Seg.Vaddr+sect.Seg.Filelen {
|
||||||
|
// data in file
|
||||||
|
if sect.Length > sect.Seg.Vaddr+sect.Seg.Filelen-sect.Vaddr {
|
||||||
|
Diag("macho cannot represent section %s crossing data and bss", sect.Name)
|
||||||
|
}
|
||||||
|
msect.off = uint32(sect.Seg.Fileoff + sect.Vaddr - sect.Seg.Vaddr)
|
||||||
|
} else {
|
||||||
|
// zero fill
|
||||||
|
msect.off = 0
|
||||||
|
|
||||||
|
msect.flag |= 1
|
||||||
|
}
|
||||||
|
|
||||||
|
if sect.Rwx&1 != 0 {
|
||||||
|
msect.flag |= 0x400 /* has instructions */
|
||||||
|
}
|
||||||
|
|
||||||
|
if sect.Name == ".plt" {
|
||||||
|
msect.name = "__symbol_stub1"
|
||||||
|
msect.flag = 0x80000408 /* only instructions, code, symbol stubs */
|
||||||
|
msect.res1 = 0 //nkind[SymKindLocal];
|
||||||
|
msect.res2 = 6
|
||||||
|
}
|
||||||
|
|
||||||
|
if sect.Name == ".got" {
|
||||||
|
msect.name = "__nl_symbol_ptr"
|
||||||
|
msect.flag = 6 /* section with nonlazy symbol pointers */
|
||||||
|
msect.res1 = uint32(Linklookup(Ctxt, ".linkedit.plt", 0).Size / 4) /* offset into indirect symbol table */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Asmbmacho() {
|
||||||
|
var v int64
|
||||||
|
var w int64
|
||||||
|
var va int64
|
||||||
|
var a int
|
||||||
|
var i int
|
||||||
|
var mh *MachoHdr
|
||||||
|
var ms *MachoSeg
|
||||||
|
var ml *MachoLoad
|
||||||
|
var sect *Section
|
||||||
|
|
||||||
|
/* apple MACH */
|
||||||
|
va = INITTEXT - int64(HEADR)
|
||||||
|
|
||||||
|
mh = getMachoHdr()
|
||||||
|
switch Thearch.Thechar {
|
||||||
|
default:
|
||||||
|
Diag("unknown mach architecture")
|
||||||
|
Errorexit()
|
||||||
|
fallthrough
|
||||||
|
|
||||||
|
case '5':
|
||||||
|
mh.cpu = MACHO_CPU_ARM
|
||||||
|
mh.subcpu = MACHO_SUBCPU_ARMV7
|
||||||
|
|
||||||
|
case '6':
|
||||||
|
mh.cpu = MACHO_CPU_AMD64
|
||||||
|
mh.subcpu = MACHO_SUBCPU_X86
|
||||||
|
|
||||||
|
case '8':
|
||||||
|
mh.cpu = MACHO_CPU_386
|
||||||
|
mh.subcpu = MACHO_SUBCPU_X86
|
||||||
|
}
|
||||||
|
|
||||||
|
ms = nil
|
||||||
|
if Linkmode == LinkExternal {
|
||||||
|
/* segment for entire file */
|
||||||
|
ms = newMachoSeg("", 40)
|
||||||
|
|
||||||
|
ms.fileoffset = Segtext.Fileoff
|
||||||
|
ms.filesize = Segdata.Fileoff + Segdata.Filelen - Segtext.Fileoff
|
||||||
|
}
|
||||||
|
|
||||||
|
/* segment for zero page */
|
||||||
|
if Linkmode != LinkExternal {
|
||||||
|
ms = newMachoSeg("__PAGEZERO", 0)
|
||||||
|
ms.vsize = uint64(va)
|
||||||
|
}
|
||||||
|
|
||||||
|
/* text */
|
||||||
|
v = Rnd(int64(uint64(HEADR)+Segtext.Length), int64(INITRND))
|
||||||
|
|
||||||
|
if Linkmode != LinkExternal {
|
||||||
|
ms = newMachoSeg("__TEXT", 20)
|
||||||
|
ms.vaddr = uint64(va)
|
||||||
|
ms.vsize = uint64(v)
|
||||||
|
ms.fileoffset = 0
|
||||||
|
ms.filesize = uint64(v)
|
||||||
|
ms.prot1 = 7
|
||||||
|
ms.prot2 = 5
|
||||||
|
}
|
||||||
|
|
||||||
|
for sect = Segtext.Sect; sect != nil; sect = sect.Next {
|
||||||
|
machoshbits(ms, sect, "__TEXT")
|
||||||
|
}
|
||||||
|
|
||||||
|
/* data */
|
||||||
|
if Linkmode != LinkExternal {
|
||||||
|
w = int64(Segdata.Length)
|
||||||
|
ms = newMachoSeg("__DATA", 20)
|
||||||
|
ms.vaddr = uint64(va) + uint64(v)
|
||||||
|
ms.vsize = uint64(w)
|
||||||
|
ms.fileoffset = uint64(v)
|
||||||
|
ms.filesize = Segdata.Filelen
|
||||||
|
ms.prot1 = 3
|
||||||
|
ms.prot2 = 3
|
||||||
|
}
|
||||||
|
|
||||||
|
for sect = Segdata.Sect; sect != nil; sect = sect.Next {
|
||||||
|
machoshbits(ms, sect, "__DATA")
|
||||||
|
}
|
||||||
|
|
||||||
|
if Linkmode != LinkExternal {
|
||||||
|
switch Thearch.Thechar {
|
||||||
|
default:
|
||||||
|
Diag("unknown macho architecture")
|
||||||
|
Errorexit()
|
||||||
|
fallthrough
|
||||||
|
|
||||||
|
case '5':
|
||||||
|
ml = newMachoLoad(5, 17+2) /* unix thread */
|
||||||
|
ml.data[0] = 1 /* thread type */
|
||||||
|
ml.data[1] = 17 /* word count */
|
||||||
|
ml.data[2+15] = uint32(Entryvalue()) /* start pc */
|
||||||
|
|
||||||
|
case '6':
|
||||||
|
ml = newMachoLoad(5, 42+2) /* unix thread */
|
||||||
|
ml.data[0] = 4 /* thread type */
|
||||||
|
ml.data[1] = 42 /* word count */
|
||||||
|
ml.data[2+32] = uint32(Entryvalue()) /* start pc */
|
||||||
|
ml.data[2+32+1] = uint32(Entryvalue() >> 16 >> 16) // hide >>32 for 8l
|
||||||
|
|
||||||
|
case '8':
|
||||||
|
ml = newMachoLoad(5, 16+2) /* unix thread */
|
||||||
|
ml.data[0] = 1 /* thread type */
|
||||||
|
ml.data[1] = 16 /* word count */
|
||||||
|
ml.data[2+10] = uint32(Entryvalue()) /* start pc */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if Debug['d'] == 0 {
|
||||||
|
var s1 *LSym
|
||||||
|
var s2 *LSym
|
||||||
|
var s3 *LSym
|
||||||
|
var s4 *LSym
|
||||||
|
|
||||||
|
// must match domacholink below
|
||||||
|
s1 = Linklookup(Ctxt, ".machosymtab", 0)
|
||||||
|
|
||||||
|
s2 = Linklookup(Ctxt, ".linkedit.plt", 0)
|
||||||
|
s3 = Linklookup(Ctxt, ".linkedit.got", 0)
|
||||||
|
s4 = Linklookup(Ctxt, ".machosymstr", 0)
|
||||||
|
|
||||||
|
if Linkmode != LinkExternal {
|
||||||
|
ms = newMachoSeg("__LINKEDIT", 0)
|
||||||
|
ms.vaddr = uint64(va) + uint64(v) + uint64(Rnd(int64(Segdata.Length), int64(INITRND)))
|
||||||
|
ms.vsize = uint64(s1.Size) + uint64(s2.Size) + uint64(s3.Size) + uint64(s4.Size)
|
||||||
|
ms.fileoffset = uint64(linkoff)
|
||||||
|
ms.filesize = ms.vsize
|
||||||
|
ms.prot1 = 7
|
||||||
|
ms.prot2 = 3
|
||||||
|
}
|
||||||
|
|
||||||
|
ml = newMachoLoad(2, 4) /* LC_SYMTAB */
|
||||||
|
ml.data[0] = uint32(linkoff) /* symoff */
|
||||||
|
ml.data[1] = uint32(nsortsym) /* nsyms */
|
||||||
|
ml.data[2] = uint32(linkoff + s1.Size + s2.Size + s3.Size) /* stroff */
|
||||||
|
ml.data[3] = uint32(s4.Size) /* strsize */
|
||||||
|
|
||||||
|
machodysymtab()
|
||||||
|
|
||||||
|
if Linkmode != LinkExternal {
|
||||||
|
ml = newMachoLoad(14, 6) /* LC_LOAD_DYLINKER */
|
||||||
|
ml.data[0] = 12 /* offset to string */
|
||||||
|
stringtouint32(ml.data[1:], "/usr/lib/dyld")
|
||||||
|
|
||||||
|
for i = 0; i < len(dylib); i++ {
|
||||||
|
ml = newMachoLoad(12, 4+(uint32(len(dylib[i]))+1+7)/8*2) /* LC_LOAD_DYLIB */
|
||||||
|
ml.data[0] = 24 /* offset of string from beginning of load */
|
||||||
|
ml.data[1] = 0 /* time stamp */
|
||||||
|
ml.data[2] = 0 /* version */
|
||||||
|
ml.data[3] = 0 /* compatibility version */
|
||||||
|
stringtouint32(ml.data[4:], dylib[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: dwarf headers go in ms too
|
||||||
|
if Debug['s'] == 0 && Linkmode != LinkExternal {
|
||||||
|
dwarfaddmachoheaders()
|
||||||
|
}
|
||||||
|
|
||||||
|
a = machowrite()
|
||||||
|
if int32(a) > HEADR {
|
||||||
|
Diag("HEADR too small: %d > %d", a, HEADR)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func symkind(s *LSym) int {
|
||||||
|
if s.Type == SDYNIMPORT {
|
||||||
|
return SymKindUndef
|
||||||
|
}
|
||||||
|
if s.Cgoexport != 0 {
|
||||||
|
return SymKindExtdef
|
||||||
|
}
|
||||||
|
return SymKindLocal
|
||||||
|
}
|
||||||
|
|
||||||
|
func addsym(s *LSym, name string, type_ int, addr int64, size int64, ver int, gotype *LSym) {
|
||||||
|
if s == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
switch type_ {
|
||||||
|
default:
|
||||||
|
return
|
||||||
|
|
||||||
|
case 'D',
|
||||||
|
'B',
|
||||||
|
'T':
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
if sortsym != nil {
|
||||||
|
sortsym[nsortsym] = s
|
||||||
|
nkind[symkind(s)]++
|
||||||
|
}
|
||||||
|
|
||||||
|
nsortsym++
|
||||||
|
}
|
||||||
|
|
||||||
|
type machoscmp []*LSym
|
||||||
|
|
||||||
|
func (x machoscmp) Len() int {
|
||||||
|
return len(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x machoscmp) Swap(i, j int) {
|
||||||
|
x[i], x[j] = x[j], x[i]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x machoscmp) Less(i, j int) bool {
|
||||||
|
var s1 *LSym
|
||||||
|
var s2 *LSym
|
||||||
|
var k1 int
|
||||||
|
var k2 int
|
||||||
|
|
||||||
|
s1 = x[i]
|
||||||
|
s2 = x[j]
|
||||||
|
|
||||||
|
k1 = symkind(s1)
|
||||||
|
k2 = symkind(s2)
|
||||||
|
if k1 != k2 {
|
||||||
|
return k1-k2 < 0
|
||||||
|
}
|
||||||
|
|
||||||
|
return stringsCompare(s1.Extname, s2.Extname) < 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func machogenasmsym(put func(*LSym, string, int, int64, int64, int, *LSym)) {
|
||||||
|
var s *LSym
|
||||||
|
|
||||||
|
genasmsym(put)
|
||||||
|
for s = Ctxt.Allsym; s != nil; s = s.Allsym {
|
||||||
|
if s.Type == SDYNIMPORT || s.Type == SHOSTOBJ {
|
||||||
|
if s.Reachable {
|
||||||
|
put(s, "", 'D', 0, 0, 0, nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func machosymorder() {
|
||||||
|
var i int
|
||||||
|
|
||||||
|
// On Mac OS X Mountain Lion, we must sort exported symbols
|
||||||
|
// So we sort them here and pre-allocate dynid for them
|
||||||
|
// See http://golang.org/issue/4029
|
||||||
|
for i = 0; i < len(dynexp); i++ {
|
||||||
|
dynexp[i].Reachable = true
|
||||||
|
}
|
||||||
|
machogenasmsym(addsym)
|
||||||
|
sortsym = make([]*LSym, nsortsym)
|
||||||
|
nsortsym = 0
|
||||||
|
machogenasmsym(addsym)
|
||||||
|
sort.Sort(machoscmp(sortsym[:nsortsym]))
|
||||||
|
for i = 0; i < nsortsym; i++ {
|
||||||
|
sortsym[i].Dynid = int32(i)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func machosymtab() {
|
||||||
|
var i int
|
||||||
|
var symtab *LSym
|
||||||
|
var symstr *LSym
|
||||||
|
var s *LSym
|
||||||
|
var o *LSym
|
||||||
|
var p string
|
||||||
|
|
||||||
|
symtab = Linklookup(Ctxt, ".machosymtab", 0)
|
||||||
|
symstr = Linklookup(Ctxt, ".machosymstr", 0)
|
||||||
|
|
||||||
|
for i = 0; i < nsortsym; i++ {
|
||||||
|
s = sortsym[i]
|
||||||
|
Adduint32(Ctxt, symtab, uint32(symstr.Size))
|
||||||
|
|
||||||
|
// Only add _ to C symbols. Go symbols have dot in the name.
|
||||||
|
if !strings.Contains(s.Extname, ".") {
|
||||||
|
Adduint8(Ctxt, symstr, '_')
|
||||||
|
}
|
||||||
|
|
||||||
|
// replace "·" as ".", because DTrace cannot handle it.
|
||||||
|
if !strings.Contains(s.Extname, "·") {
|
||||||
|
Addstring(symstr, s.Extname)
|
||||||
|
} else {
|
||||||
|
for p = s.Extname; p != ""; p = p[1:] {
|
||||||
|
if uint8(p[0]) == 0xc2 && uint8((p[1:])[0]) == 0xb7 {
|
||||||
|
Adduint8(Ctxt, symstr, '.')
|
||||||
|
p = p[1:]
|
||||||
|
} else {
|
||||||
|
Adduint8(Ctxt, symstr, uint8(p[0]))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Adduint8(Ctxt, symstr, '\x00')
|
||||||
|
}
|
||||||
|
|
||||||
|
if s.Type == SDYNIMPORT || s.Type == SHOSTOBJ {
|
||||||
|
Adduint8(Ctxt, symtab, 0x01) // type N_EXT, external symbol
|
||||||
|
Adduint8(Ctxt, symtab, 0) // no section
|
||||||
|
Adduint16(Ctxt, symtab, 0) // desc
|
||||||
|
adduintxx(Ctxt, symtab, 0, Thearch.Ptrsize) // no value
|
||||||
|
} else {
|
||||||
|
if s.Cgoexport != 0 {
|
||||||
|
Adduint8(Ctxt, symtab, 0x0f)
|
||||||
|
} else {
|
||||||
|
Adduint8(Ctxt, symtab, 0x0e)
|
||||||
|
}
|
||||||
|
o = s
|
||||||
|
for o.Outer != nil {
|
||||||
|
o = o.Outer
|
||||||
|
}
|
||||||
|
if o.Sect == nil {
|
||||||
|
Diag("missing section for %s", s.Name)
|
||||||
|
Adduint8(Ctxt, symtab, 0)
|
||||||
|
} else {
|
||||||
|
Adduint8(Ctxt, symtab, uint8((o.Sect.(*Section)).Extnum))
|
||||||
|
}
|
||||||
|
Adduint16(Ctxt, symtab, 0) // desc
|
||||||
|
adduintxx(Ctxt, symtab, uint64(Symaddr(s)), Thearch.Ptrsize)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func machodysymtab() {
|
||||||
|
var n int
|
||||||
|
var ml *MachoLoad
|
||||||
|
var s1 *LSym
|
||||||
|
var s2 *LSym
|
||||||
|
var s3 *LSym
|
||||||
|
|
||||||
|
ml = newMachoLoad(11, 18) /* LC_DYSYMTAB */
|
||||||
|
|
||||||
|
n = 0
|
||||||
|
ml.data[0] = uint32(n) /* ilocalsym */
|
||||||
|
ml.data[1] = uint32(nkind[SymKindLocal]) /* nlocalsym */
|
||||||
|
n += nkind[SymKindLocal]
|
||||||
|
|
||||||
|
ml.data[2] = uint32(n) /* iextdefsym */
|
||||||
|
ml.data[3] = uint32(nkind[SymKindExtdef]) /* nextdefsym */
|
||||||
|
n += nkind[SymKindExtdef]
|
||||||
|
|
||||||
|
ml.data[4] = uint32(n) /* iundefsym */
|
||||||
|
ml.data[5] = uint32(nkind[SymKindUndef]) /* nundefsym */
|
||||||
|
|
||||||
|
ml.data[6] = 0 /* tocoffset */
|
||||||
|
ml.data[7] = 0 /* ntoc */
|
||||||
|
ml.data[8] = 0 /* modtaboff */
|
||||||
|
ml.data[9] = 0 /* nmodtab */
|
||||||
|
ml.data[10] = 0 /* extrefsymoff */
|
||||||
|
ml.data[11] = 0 /* nextrefsyms */
|
||||||
|
|
||||||
|
// must match domacholink below
|
||||||
|
s1 = Linklookup(Ctxt, ".machosymtab", 0)
|
||||||
|
|
||||||
|
s2 = Linklookup(Ctxt, ".linkedit.plt", 0)
|
||||||
|
s3 = Linklookup(Ctxt, ".linkedit.got", 0)
|
||||||
|
ml.data[12] = uint32(linkoff + s1.Size) /* indirectsymoff */
|
||||||
|
ml.data[13] = uint32((s2.Size + s3.Size) / 4) /* nindirectsyms */
|
||||||
|
|
||||||
|
ml.data[14] = 0 /* extreloff */
|
||||||
|
ml.data[15] = 0 /* nextrel */
|
||||||
|
ml.data[16] = 0 /* locreloff */
|
||||||
|
ml.data[17] = 0 /* nlocrel */
|
||||||
|
}
|
||||||
|
|
||||||
|
func Domacholink() int64 {
|
||||||
|
var size int
|
||||||
|
var s1 *LSym
|
||||||
|
var s2 *LSym
|
||||||
|
var s3 *LSym
|
||||||
|
var s4 *LSym
|
||||||
|
|
||||||
|
machosymtab()
|
||||||
|
|
||||||
|
// write data that will be linkedit section
|
||||||
|
s1 = Linklookup(Ctxt, ".machosymtab", 0)
|
||||||
|
|
||||||
|
s2 = Linklookup(Ctxt, ".linkedit.plt", 0)
|
||||||
|
s3 = Linklookup(Ctxt, ".linkedit.got", 0)
|
||||||
|
s4 = Linklookup(Ctxt, ".machosymstr", 0)
|
||||||
|
|
||||||
|
// Force the linkedit section to end on a 16-byte
|
||||||
|
// boundary. This allows pure (non-cgo) Go binaries
|
||||||
|
// to be code signed correctly.
|
||||||
|
//
|
||||||
|
// Apple's codesign_allocate (a helper utility for
|
||||||
|
// the codesign utility) can do this fine itself if
|
||||||
|
// it is run on a dynamic Mach-O binary. However,
|
||||||
|
// when it is run on a pure (non-cgo) Go binary, where
|
||||||
|
// the linkedit section is mostly empty, it fails to
|
||||||
|
// account for the extra padding that it itself adds
|
||||||
|
// when adding the LC_CODE_SIGNATURE load command
|
||||||
|
// (which must be aligned on a 16-byte boundary).
|
||||||
|
//
|
||||||
|
// By forcing the linkedit section to end on a 16-byte
|
||||||
|
// boundary, codesign_allocate will not need to apply
|
||||||
|
// any alignment padding itself, working around the
|
||||||
|
// issue.
|
||||||
|
for s4.Size%16 != 0 {
|
||||||
|
Adduint8(Ctxt, s4, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
size = int(s1.Size + s2.Size + s3.Size + s4.Size)
|
||||||
|
|
||||||
|
if size > 0 {
|
||||||
|
linkoff = Rnd(int64(uint64(HEADR)+Segtext.Length), int64(INITRND)) + Rnd(int64(Segdata.Filelen), int64(INITRND)) + Rnd(int64(Segdwarf.Filelen), int64(INITRND))
|
||||||
|
Cseek(linkoff)
|
||||||
|
|
||||||
|
Cwrite(s1.P[:s1.Size])
|
||||||
|
Cwrite(s2.P[:s2.Size])
|
||||||
|
Cwrite(s3.P[:s3.Size])
|
||||||
|
Cwrite(s4.P[:s4.Size])
|
||||||
|
}
|
||||||
|
|
||||||
|
return Rnd(int64(size), int64(INITRND))
|
||||||
|
}
|
||||||
|
|
||||||
|
func machorelocsect(sect *Section, first *LSym) {
|
||||||
|
var sym *LSym
|
||||||
|
var eaddr int32
|
||||||
|
var ri int
|
||||||
|
var r *Reloc
|
||||||
|
|
||||||
|
// If main section has no bits, nothing to relocate.
|
||||||
|
if sect.Vaddr >= sect.Seg.Vaddr+sect.Seg.Filelen {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
sect.Reloff = uint64(Cpos())
|
||||||
|
for sym = first; sym != nil; sym = sym.Next {
|
||||||
|
if !sym.Reachable {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if uint64(sym.Value) >= sect.Vaddr {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
eaddr = int32(sect.Vaddr + sect.Length)
|
||||||
|
for ; sym != nil; sym = sym.Next {
|
||||||
|
if !sym.Reachable {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if sym.Value >= int64(eaddr) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
Ctxt.Cursym = sym
|
||||||
|
|
||||||
|
for ri = 0; ri < len(sym.R); ri++ {
|
||||||
|
r = &sym.R[ri]
|
||||||
|
if r.Done != 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if Thearch.Machoreloc1(r, int64(uint64(sym.Value+int64(r.Off))-sect.Vaddr)) < 0 {
|
||||||
|
Diag("unsupported obj reloc %d/%d to %s", r.Type, r.Siz, r.Sym.Name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sect.Rellen = uint64(Cpos()) - sect.Reloff
|
||||||
|
}
|
||||||
|
|
||||||
|
func Machoemitreloc() {
|
||||||
|
var sect *Section
|
||||||
|
|
||||||
|
for Cpos()&7 != 0 {
|
||||||
|
Cput(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
machorelocsect(Segtext.Sect, Ctxt.Textp)
|
||||||
|
for sect = Segtext.Sect.Next; sect != nil; sect = sect.Next {
|
||||||
|
machorelocsect(sect, datap)
|
||||||
|
}
|
||||||
|
for sect = Segdata.Sect; sect != nil; sect = sect.Next {
|
||||||
|
machorelocsect(sect, datap)
|
||||||
|
}
|
||||||
|
}
|
||||||
366
src/cmd/internal/ld/objfile.go
Normal file
366
src/cmd/internal/ld/objfile.go
Normal file
|
|
@ -0,0 +1,366 @@
|
||||||
|
// Copyright 2013 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package ld
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
var startmagic string = "\x00\x00go13ld"
|
||||||
|
|
||||||
|
var endmagic string = "\xff\xffgo13ld"
|
||||||
|
|
||||||
|
func ldobjfile(ctxt *Link, f *Biobuf, pkg string, length int64, pn string) {
|
||||||
|
var c int
|
||||||
|
var buf [8]uint8
|
||||||
|
var start int64
|
||||||
|
var lib string
|
||||||
|
|
||||||
|
start = Boffset(f)
|
||||||
|
ctxt.Version++
|
||||||
|
buf = [8]uint8{}
|
||||||
|
Bread(f, buf[:])
|
||||||
|
if string(buf[:]) != startmagic {
|
||||||
|
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])
|
||||||
|
}
|
||||||
|
c = Bgetc(f)
|
||||||
|
if c != 1 {
|
||||||
|
log.Fatalf("%s: invalid file version number %d", pn, c)
|
||||||
|
}
|
||||||
|
|
||||||
|
for {
|
||||||
|
lib = rdstring(f)
|
||||||
|
if lib == "" {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
addlib(ctxt, pkg, pn, lib)
|
||||||
|
}
|
||||||
|
|
||||||
|
for {
|
||||||
|
c = Bgetc(f)
|
||||||
|
Bungetc(f)
|
||||||
|
if c == 0xff {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
readsym(ctxt, f, pkg, pn)
|
||||||
|
}
|
||||||
|
|
||||||
|
buf = [8]uint8{}
|
||||||
|
Bread(f, buf[:])
|
||||||
|
if string(buf[:]) != endmagic {
|
||||||
|
log.Fatalf("%s: invalid file end", pn)
|
||||||
|
}
|
||||||
|
|
||||||
|
if Boffset(f) != start+length {
|
||||||
|
log.Fatalf("%s: unexpected end at %d, want %d", pn, int64(Boffset(f)), int64(start+length))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var readsym_ndup int
|
||||||
|
|
||||||
|
func readsym(ctxt *Link, f *Biobuf, pkg string, pn string) {
|
||||||
|
var i int
|
||||||
|
var j int
|
||||||
|
var c int
|
||||||
|
var t int
|
||||||
|
var v int
|
||||||
|
var n int
|
||||||
|
var nreloc int
|
||||||
|
var size int
|
||||||
|
var dupok int
|
||||||
|
var name string
|
||||||
|
var data []byte
|
||||||
|
var r *Reloc
|
||||||
|
var s *LSym
|
||||||
|
var dup *LSym
|
||||||
|
var typ *LSym
|
||||||
|
var pc *Pcln
|
||||||
|
var a *Auto
|
||||||
|
|
||||||
|
if Bgetc(f) != 0xfe {
|
||||||
|
log.Fatalf("readsym out of sync")
|
||||||
|
}
|
||||||
|
t = int(rdint(f))
|
||||||
|
name = expandpkg(rdstring(f), pkg)
|
||||||
|
v = int(rdint(f))
|
||||||
|
if v != 0 && v != 1 {
|
||||||
|
log.Fatalf("invalid symbol version %d", v)
|
||||||
|
}
|
||||||
|
dupok = int(rdint(f))
|
||||||
|
dupok &= 1
|
||||||
|
size = int(rdint(f))
|
||||||
|
typ = rdsym(ctxt, f, pkg)
|
||||||
|
rddata(f, &data)
|
||||||
|
nreloc = int(rdint(f))
|
||||||
|
|
||||||
|
if v != 0 {
|
||||||
|
v = ctxt.Version
|
||||||
|
}
|
||||||
|
s = Linklookup(ctxt, name, v)
|
||||||
|
dup = nil
|
||||||
|
if s.Type != 0 && s.Type != SXREF {
|
||||||
|
if (t == SDATA || t == SBSS || t == SNOPTRBSS) && len(data) == 0 && nreloc == 0 {
|
||||||
|
if s.Size < int64(size) {
|
||||||
|
s.Size = int64(size)
|
||||||
|
}
|
||||||
|
if typ != nil && s.Gotype == nil {
|
||||||
|
s.Gotype = typ
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (s.Type == SDATA || s.Type == SBSS || s.Type == SNOPTRBSS) && len(s.P) == 0 && len(s.R) == 0 {
|
||||||
|
goto overwrite
|
||||||
|
}
|
||||||
|
if s.Type != SBSS && s.Type != SNOPTRBSS && dupok == 0 && s.Dupok == 0 {
|
||||||
|
log.Fatalf("duplicate symbol %s (types %d and %d) in %s and %s", s.Name, s.Type, t, s.File, pn)
|
||||||
|
}
|
||||||
|
if len(s.P) > 0 {
|
||||||
|
dup = s
|
||||||
|
s = linknewsym(ctxt, ".dup", readsym_ndup)
|
||||||
|
readsym_ndup++ // scratch
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
overwrite:
|
||||||
|
s.File = pkg
|
||||||
|
s.Dupok = uint8(dupok)
|
||||||
|
if t == SXREF {
|
||||||
|
log.Fatalf("bad sxref")
|
||||||
|
}
|
||||||
|
if t == 0 {
|
||||||
|
log.Fatalf("missing type for %s in %s", name, pn)
|
||||||
|
}
|
||||||
|
if t == SBSS && (s.Type == SRODATA || s.Type == SNOPTRBSS) {
|
||||||
|
t = int(s.Type)
|
||||||
|
}
|
||||||
|
s.Type = int16(t)
|
||||||
|
if s.Size < int64(size) {
|
||||||
|
s.Size = int64(size)
|
||||||
|
}
|
||||||
|
if typ != nil { // if bss sym defined multiple times, take type from any one def
|
||||||
|
s.Gotype = typ
|
||||||
|
}
|
||||||
|
if dup != nil && typ != nil {
|
||||||
|
dup.Gotype = typ
|
||||||
|
}
|
||||||
|
s.P = data
|
||||||
|
s.P = s.P[:len(data)]
|
||||||
|
if nreloc > 0 {
|
||||||
|
s.R = make([]Reloc, nreloc)
|
||||||
|
s.R = s.R[:nreloc]
|
||||||
|
for i = 0; i < nreloc; i++ {
|
||||||
|
r = &s.R[i]
|
||||||
|
r.Off = int32(rdint(f))
|
||||||
|
r.Siz = uint8(rdint(f))
|
||||||
|
r.Type = int32(rdint(f))
|
||||||
|
r.Add = rdint(f)
|
||||||
|
r.Xadd = rdint(f)
|
||||||
|
r.Sym = rdsym(ctxt, f, pkg)
|
||||||
|
r.Xsym = rdsym(ctxt, f, pkg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(s.P) > 0 && dup != nil && len(dup.P) > 0 && strings.HasPrefix(s.Name, "gclocals·") {
|
||||||
|
// content-addressed garbage collection liveness bitmap symbol.
|
||||||
|
// double check for hash collisions.
|
||||||
|
if !bytes.Equal(s.P, dup.P) {
|
||||||
|
log.Fatalf("dupok hash collision for %s in %s and %s", s.Name, s.File, pn)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if s.Type == STEXT {
|
||||||
|
s.Args = int32(rdint(f))
|
||||||
|
s.Locals = int32(rdint(f))
|
||||||
|
s.Nosplit = uint8(rdint(f))
|
||||||
|
v = int(rdint(f))
|
||||||
|
s.Leaf = uint8(v & 1)
|
||||||
|
s.Cfunc = uint8(v & 2)
|
||||||
|
n = int(rdint(f))
|
||||||
|
for i = 0; i < n; i++ {
|
||||||
|
a = new(Auto)
|
||||||
|
a.Asym = rdsym(ctxt, f, pkg)
|
||||||
|
a.Aoffset = int32(rdint(f))
|
||||||
|
a.Name = int16(rdint(f))
|
||||||
|
a.Gotype = rdsym(ctxt, f, pkg)
|
||||||
|
a.Link = s.Autom
|
||||||
|
s.Autom = a
|
||||||
|
}
|
||||||
|
|
||||||
|
s.Pcln = new(Pcln)
|
||||||
|
pc = s.Pcln
|
||||||
|
rddata(f, &pc.Pcsp.P)
|
||||||
|
rddata(f, &pc.Pcfile.P)
|
||||||
|
rddata(f, &pc.Pcline.P)
|
||||||
|
n = int(rdint(f))
|
||||||
|
pc.Pcdata = make([]Pcdata, n)
|
||||||
|
pc.Npcdata = n
|
||||||
|
for i = 0; i < n; i++ {
|
||||||
|
rddata(f, &pc.Pcdata[i].P)
|
||||||
|
}
|
||||||
|
n = int(rdint(f))
|
||||||
|
pc.Funcdata = make([]*LSym, n)
|
||||||
|
pc.Funcdataoff = make([]int64, n)
|
||||||
|
pc.Nfuncdata = n
|
||||||
|
for i = 0; i < n; i++ {
|
||||||
|
pc.Funcdata[i] = rdsym(ctxt, f, pkg)
|
||||||
|
}
|
||||||
|
for i = 0; i < n; i++ {
|
||||||
|
pc.Funcdataoff[i] = rdint(f)
|
||||||
|
}
|
||||||
|
n = int(rdint(f))
|
||||||
|
pc.File = make([]*LSym, n)
|
||||||
|
pc.Nfile = n
|
||||||
|
for i = 0; i < n; i++ {
|
||||||
|
pc.File[i] = rdsym(ctxt, f, pkg)
|
||||||
|
}
|
||||||
|
|
||||||
|
if dup == nil {
|
||||||
|
if s.Onlist != 0 {
|
||||||
|
log.Fatalf("symbol %s listed multiple times", s.Name)
|
||||||
|
}
|
||||||
|
s.Onlist = 1
|
||||||
|
if ctxt.Etextp != nil {
|
||||||
|
ctxt.Etextp.Next = s
|
||||||
|
} else {
|
||||||
|
ctxt.Textp = s
|
||||||
|
}
|
||||||
|
ctxt.Etextp = s
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ctxt.Debugasm != 0 {
|
||||||
|
fmt.Fprintf(ctxt.Bso, "%s ", s.Name)
|
||||||
|
if s.Version != 0 {
|
||||||
|
fmt.Fprintf(ctxt.Bso, "v=%d ", s.Version)
|
||||||
|
}
|
||||||
|
if s.Type != 0 {
|
||||||
|
fmt.Fprintf(ctxt.Bso, "t=%d ", s.Type)
|
||||||
|
}
|
||||||
|
if s.Dupok != 0 {
|
||||||
|
fmt.Fprintf(ctxt.Bso, "dupok ")
|
||||||
|
}
|
||||||
|
if s.Cfunc != 0 {
|
||||||
|
fmt.Fprintf(ctxt.Bso, "cfunc ")
|
||||||
|
}
|
||||||
|
if s.Nosplit != 0 {
|
||||||
|
fmt.Fprintf(ctxt.Bso, "nosplit ")
|
||||||
|
}
|
||||||
|
fmt.Fprintf(ctxt.Bso, "size=%d value=%d", int64(s.Size), int64(s.Value))
|
||||||
|
if s.Type == STEXT {
|
||||||
|
fmt.Fprintf(ctxt.Bso, " args=%#x locals=%#x", uint64(s.Args), uint64(s.Locals))
|
||||||
|
}
|
||||||
|
fmt.Fprintf(ctxt.Bso, "\n")
|
||||||
|
for i = 0; i < len(s.P); {
|
||||||
|
fmt.Fprintf(ctxt.Bso, "\t%#04x", uint(i))
|
||||||
|
for j = i; j < i+16 && j < len(s.P); j++ {
|
||||||
|
fmt.Fprintf(ctxt.Bso, " %02x", s.P[j])
|
||||||
|
}
|
||||||
|
for ; j < i+16; j++ {
|
||||||
|
fmt.Fprintf(ctxt.Bso, " ")
|
||||||
|
}
|
||||||
|
fmt.Fprintf(ctxt.Bso, " ")
|
||||||
|
for j = i; j < i+16 && j < len(s.P); j++ {
|
||||||
|
c = int(s.P[j])
|
||||||
|
if ' ' <= c && c <= 0x7e {
|
||||||
|
fmt.Fprintf(ctxt.Bso, "%c", c)
|
||||||
|
} else {
|
||||||
|
fmt.Fprintf(ctxt.Bso, ".")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Fprintf(ctxt.Bso, "\n")
|
||||||
|
i += 16
|
||||||
|
}
|
||||||
|
|
||||||
|
for i = 0; i < len(s.R); i++ {
|
||||||
|
r = &s.R[i]
|
||||||
|
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))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func rdint(f *Biobuf) int64 {
|
||||||
|
var c int
|
||||||
|
var uv uint64
|
||||||
|
var shift int
|
||||||
|
|
||||||
|
uv = 0
|
||||||
|
for shift = 0; ; shift += 7 {
|
||||||
|
if shift >= 64 {
|
||||||
|
log.Fatalf("corrupt input")
|
||||||
|
}
|
||||||
|
c = Bgetc(f)
|
||||||
|
uv |= uint64(c&0x7F) << uint(shift)
|
||||||
|
if c&0x80 == 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return int64(uv>>1) ^ (int64(uint64(uv)<<63) >> 63)
|
||||||
|
}
|
||||||
|
|
||||||
|
func rdstring(f *Biobuf) string {
|
||||||
|
n := rdint(f)
|
||||||
|
p := make([]byte, n)
|
||||||
|
Bread(f, p)
|
||||||
|
return string(p)
|
||||||
|
}
|
||||||
|
|
||||||
|
func rddata(f *Biobuf, pp *[]byte) {
|
||||||
|
n := rdint(f)
|
||||||
|
*pp = make([]byte, n)
|
||||||
|
Bread(f, *pp)
|
||||||
|
}
|
||||||
|
|
||||||
|
var symbuf []byte
|
||||||
|
|
||||||
|
func rdsym(ctxt *Link, f *Biobuf, pkg string) *LSym {
|
||||||
|
var n int
|
||||||
|
var v int
|
||||||
|
var p string
|
||||||
|
var s *LSym
|
||||||
|
|
||||||
|
n = int(rdint(f))
|
||||||
|
if n == 0 {
|
||||||
|
rdint(f)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(symbuf) < n {
|
||||||
|
symbuf = make([]byte, n)
|
||||||
|
}
|
||||||
|
Bread(f, symbuf[:n])
|
||||||
|
p = string(symbuf[:n])
|
||||||
|
v = int(rdint(f))
|
||||||
|
if v != 0 {
|
||||||
|
v = ctxt.Version
|
||||||
|
}
|
||||||
|
s = Linklookup(ctxt, expandpkg(p, pkg), v)
|
||||||
|
|
||||||
|
if v == 0 && s.Name[0] == '$' && s.Type == 0 {
|
||||||
|
if strings.HasPrefix(s.Name, "$f32.") {
|
||||||
|
var i32 int32
|
||||||
|
x, _ := strconv.ParseUint(s.Name[5:], 16, 32)
|
||||||
|
i32 = int32(x)
|
||||||
|
s.Type = SRODATA
|
||||||
|
Adduint32(ctxt, s, uint32(i32))
|
||||||
|
s.Reachable = false
|
||||||
|
} else if strings.HasPrefix(s.Name, "$f64.") || strings.HasPrefix(s.Name, "$i64.") {
|
||||||
|
var i64 int64
|
||||||
|
x, _ := strconv.ParseUint(s.Name[5:], 16, 64)
|
||||||
|
i64 = int64(x)
|
||||||
|
s.Type = SRODATA
|
||||||
|
Adduint64(ctxt, s, uint64(i64))
|
||||||
|
s.Reachable = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return s
|
||||||
|
}
|
||||||
487
src/cmd/internal/ld/pcln.go
Normal file
487
src/cmd/internal/ld/pcln.go
Normal file
|
|
@ -0,0 +1,487 @@
|
||||||
|
// Copyright 2013 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package ld
|
||||||
|
|
||||||
|
import (
|
||||||
|
"cmd/internal/obj"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
)
|
||||||
|
|
||||||
|
// funcpctab writes to dst a pc-value table mapping the code in func to the values
|
||||||
|
// returned by valfunc parameterized by arg. The invocation of valfunc to update the
|
||||||
|
// current value is, for each p,
|
||||||
|
//
|
||||||
|
// val = valfunc(func, val, p, 0, arg);
|
||||||
|
// record val as value at p->pc;
|
||||||
|
// val = valfunc(func, val, p, 1, arg);
|
||||||
|
//
|
||||||
|
// where func is the function, val is the current value, p is the instruction being
|
||||||
|
// considered, and arg can be used to further parameterize valfunc.
|
||||||
|
|
||||||
|
// pctofileline computes either the file number (arg == 0)
|
||||||
|
// or the line number (arg == 1) to use at p.
|
||||||
|
// Because p->lineno applies to p, phase == 0 (before p)
|
||||||
|
// takes care of the update.
|
||||||
|
|
||||||
|
// pctospadj computes the sp adjustment in effect.
|
||||||
|
// It is oldval plus any adjustment made by p itself.
|
||||||
|
// The adjustment by p takes effect only after p, so we
|
||||||
|
// apply the change during phase == 1.
|
||||||
|
|
||||||
|
// pctopcdata computes the pcdata value in effect at p.
|
||||||
|
// A PCDATA instruction sets the value in effect at future
|
||||||
|
// non-PCDATA instructions.
|
||||||
|
// Since PCDATA instructions have no width in the final code,
|
||||||
|
// it does not matter which phase we use for the update.
|
||||||
|
|
||||||
|
// iteration over encoded pcdata tables.
|
||||||
|
|
||||||
|
func getvarint(pp *[]byte) uint32 {
|
||||||
|
var p []byte
|
||||||
|
var shift int
|
||||||
|
var v uint32
|
||||||
|
|
||||||
|
v = 0
|
||||||
|
p = *pp
|
||||||
|
for shift = 0; ; shift += 7 {
|
||||||
|
v |= uint32(p[0]&0x7F) << uint(shift)
|
||||||
|
tmp4 := p
|
||||||
|
p = p[1:]
|
||||||
|
if tmp4[0]&0x80 == 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*pp = p
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
|
func pciternext(it *Pciter) {
|
||||||
|
var v uint32
|
||||||
|
var dv int32
|
||||||
|
|
||||||
|
it.pc = it.nextpc
|
||||||
|
if it.done != 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if -cap(it.p) >= -cap(it.d.P[len(it.d.P):]) {
|
||||||
|
it.done = 1
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// value delta
|
||||||
|
v = getvarint(&it.p)
|
||||||
|
|
||||||
|
if v == 0 && it.start == 0 {
|
||||||
|
it.done = 1
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
it.start = 0
|
||||||
|
dv = int32(v>>1) ^ (int32(v<<31) >> 31)
|
||||||
|
it.value += dv
|
||||||
|
|
||||||
|
// pc delta
|
||||||
|
v = getvarint(&it.p)
|
||||||
|
|
||||||
|
it.nextpc = it.pc + v*it.pcscale
|
||||||
|
}
|
||||||
|
|
||||||
|
func pciterinit(ctxt *Link, it *Pciter, d *Pcdata) {
|
||||||
|
it.d = *d
|
||||||
|
it.p = it.d.P
|
||||||
|
it.pc = 0
|
||||||
|
it.nextpc = 0
|
||||||
|
it.value = -1
|
||||||
|
it.start = 1
|
||||||
|
it.done = 0
|
||||||
|
it.pcscale = uint32(ctxt.Arch.Minlc)
|
||||||
|
pciternext(it)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copyright 2013 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
func addvarint(d *Pcdata, val uint32) {
|
||||||
|
var n int32
|
||||||
|
var v uint32
|
||||||
|
var p []byte
|
||||||
|
|
||||||
|
n = 0
|
||||||
|
for v = val; v >= 0x80; v >>= 7 {
|
||||||
|
n++
|
||||||
|
}
|
||||||
|
n++
|
||||||
|
|
||||||
|
old := len(d.P)
|
||||||
|
for cap(d.P) < len(d.P)+int(n) {
|
||||||
|
d.P = append(d.P[:cap(d.P)], 0)
|
||||||
|
}
|
||||||
|
d.P = d.P[:old+int(n)]
|
||||||
|
|
||||||
|
p = d.P[old:]
|
||||||
|
for v = val; v >= 0x80; v >>= 7 {
|
||||||
|
p[0] = byte(v | 0x80)
|
||||||
|
p = p[1:]
|
||||||
|
}
|
||||||
|
p[0] = byte(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
func addpctab(ftab *LSym, off int32, d *Pcdata) int32 {
|
||||||
|
var start int32
|
||||||
|
|
||||||
|
start = int32(len(ftab.P))
|
||||||
|
Symgrow(Ctxt, ftab, int64(start)+int64(len(d.P)))
|
||||||
|
copy(ftab.P[start:], d.P)
|
||||||
|
|
||||||
|
return int32(setuint32(Ctxt, ftab, int64(off), uint32(start)))
|
||||||
|
}
|
||||||
|
|
||||||
|
func ftabaddstring(ftab *LSym, s string) int32 {
|
||||||
|
var n int32
|
||||||
|
var start int32
|
||||||
|
|
||||||
|
n = int32(len(s)) + 1
|
||||||
|
start = int32(len(ftab.P))
|
||||||
|
Symgrow(Ctxt, ftab, int64(start)+int64(n)+1)
|
||||||
|
copy(ftab.P[start:], s)
|
||||||
|
return start
|
||||||
|
}
|
||||||
|
|
||||||
|
func renumberfiles(ctxt *Link, files []*LSym, d *Pcdata) {
|
||||||
|
var i int
|
||||||
|
var f *LSym
|
||||||
|
var out Pcdata
|
||||||
|
var it Pciter
|
||||||
|
var v uint32
|
||||||
|
var oldval int32
|
||||||
|
var newval int32
|
||||||
|
var val int32
|
||||||
|
var dv int32
|
||||||
|
|
||||||
|
// Give files numbers.
|
||||||
|
for i = 0; i < len(files); i++ {
|
||||||
|
f = files[i]
|
||||||
|
if f.Type != SFILEPATH {
|
||||||
|
ctxt.Nhistfile++
|
||||||
|
f.Value = int64(ctxt.Nhistfile)
|
||||||
|
f.Type = SFILEPATH
|
||||||
|
f.Next = ctxt.Filesyms
|
||||||
|
ctxt.Filesyms = f
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
newval = -1
|
||||||
|
out = Pcdata{}
|
||||||
|
|
||||||
|
for pciterinit(ctxt, &it, d); it.done == 0; pciternext(&it) {
|
||||||
|
// value delta
|
||||||
|
oldval = it.value
|
||||||
|
|
||||||
|
if oldval == -1 {
|
||||||
|
val = -1
|
||||||
|
} else {
|
||||||
|
if oldval < 0 || oldval >= int32(len(files)) {
|
||||||
|
log.Fatalf("bad pcdata %d", oldval)
|
||||||
|
}
|
||||||
|
val = int32(files[oldval].Value)
|
||||||
|
}
|
||||||
|
|
||||||
|
dv = val - newval
|
||||||
|
newval = val
|
||||||
|
v = (uint32(dv) << 1) ^ uint32(int32(dv>>31))
|
||||||
|
addvarint(&out, v)
|
||||||
|
|
||||||
|
// pc delta
|
||||||
|
addvarint(&out, (it.nextpc-it.pc)/it.pcscale)
|
||||||
|
}
|
||||||
|
|
||||||
|
// terminating value delta
|
||||||
|
addvarint(&out, 0)
|
||||||
|
|
||||||
|
*d = out
|
||||||
|
}
|
||||||
|
|
||||||
|
func container(s *LSym) int {
|
||||||
|
// We want to generate func table entries only for the "lowest level" symbols,
|
||||||
|
// not containers of subsymbols.
|
||||||
|
if s != nil && s.Sub != nil {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// pclntab initializes the pclntab symbol with
|
||||||
|
// runtime function and file name information.
|
||||||
|
|
||||||
|
var pclntab_zpcln Pcln
|
||||||
|
|
||||||
|
func pclntab() {
|
||||||
|
var i int32
|
||||||
|
var nfunc int32
|
||||||
|
var start int32
|
||||||
|
var funcstart int32
|
||||||
|
var ftab *LSym
|
||||||
|
var s *LSym
|
||||||
|
var last *LSym
|
||||||
|
var off int32
|
||||||
|
var end int32
|
||||||
|
var frameptrsize int32
|
||||||
|
var funcdata_bytes int64
|
||||||
|
var pcln *Pcln
|
||||||
|
var it Pciter
|
||||||
|
|
||||||
|
funcdata_bytes = 0
|
||||||
|
ftab = Linklookup(Ctxt, "runtime.pclntab", 0)
|
||||||
|
ftab.Type = SPCLNTAB
|
||||||
|
ftab.Reachable = true
|
||||||
|
|
||||||
|
// See golang.org/s/go12symtab for the format. Briefly:
|
||||||
|
// 8-byte header
|
||||||
|
// nfunc [thearch.ptrsize bytes]
|
||||||
|
// function table, alternating PC and offset to func struct [each entry thearch.ptrsize bytes]
|
||||||
|
// end PC [thearch.ptrsize bytes]
|
||||||
|
// offset to file table [4 bytes]
|
||||||
|
nfunc = 0
|
||||||
|
|
||||||
|
for Ctxt.Cursym = Ctxt.Textp; Ctxt.Cursym != nil; Ctxt.Cursym = Ctxt.Cursym.Next {
|
||||||
|
if container(Ctxt.Cursym) == 0 {
|
||||||
|
nfunc++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Symgrow(Ctxt, ftab, 8+int64(Thearch.Ptrsize)+int64(nfunc)*2*int64(Thearch.Ptrsize)+int64(Thearch.Ptrsize)+4)
|
||||||
|
setuint32(Ctxt, ftab, 0, 0xfffffffb)
|
||||||
|
setuint8(Ctxt, ftab, 6, uint8(Thearch.Minlc))
|
||||||
|
setuint8(Ctxt, ftab, 7, uint8(Thearch.Ptrsize))
|
||||||
|
setuintxx(Ctxt, ftab, 8, uint64(nfunc), int64(Thearch.Ptrsize))
|
||||||
|
|
||||||
|
nfunc = 0
|
||||||
|
last = nil
|
||||||
|
for Ctxt.Cursym = Ctxt.Textp; Ctxt.Cursym != nil; Ctxt.Cursym = Ctxt.Cursym.Next {
|
||||||
|
last = Ctxt.Cursym
|
||||||
|
if container(Ctxt.Cursym) != 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
pcln = Ctxt.Cursym.Pcln
|
||||||
|
if pcln == nil {
|
||||||
|
pcln = &pclntab_zpcln
|
||||||
|
}
|
||||||
|
|
||||||
|
funcstart = int32(len(ftab.P))
|
||||||
|
funcstart += int32(-len(ftab.P)) & (int32(Thearch.Ptrsize) - 1)
|
||||||
|
|
||||||
|
setaddr(Ctxt, ftab, 8+int64(Thearch.Ptrsize)+int64(nfunc)*2*int64(Thearch.Ptrsize), Ctxt.Cursym)
|
||||||
|
setuintxx(Ctxt, ftab, 8+int64(Thearch.Ptrsize)+int64(nfunc)*2*int64(Thearch.Ptrsize)+int64(Thearch.Ptrsize), uint64(funcstart), int64(Thearch.Ptrsize))
|
||||||
|
|
||||||
|
// fixed size of struct, checked below
|
||||||
|
off = funcstart
|
||||||
|
|
||||||
|
end = funcstart + int32(Thearch.Ptrsize) + 3*4 + 5*4 + int32(pcln.Npcdata)*4 + int32(pcln.Nfuncdata)*int32(Thearch.Ptrsize)
|
||||||
|
if pcln.Nfuncdata > 0 && (end&int32(Thearch.Ptrsize-1) != 0) {
|
||||||
|
end += 4
|
||||||
|
}
|
||||||
|
Symgrow(Ctxt, ftab, int64(end))
|
||||||
|
|
||||||
|
// entry uintptr
|
||||||
|
off = int32(setaddr(Ctxt, ftab, int64(off), Ctxt.Cursym))
|
||||||
|
|
||||||
|
// name int32
|
||||||
|
off = int32(setuint32(Ctxt, ftab, int64(off), uint32(ftabaddstring(ftab, Ctxt.Cursym.Name))))
|
||||||
|
|
||||||
|
// args int32
|
||||||
|
// TODO: Move into funcinfo.
|
||||||
|
off = int32(setuint32(Ctxt, ftab, int64(off), uint32(Ctxt.Cursym.Args)))
|
||||||
|
|
||||||
|
// frame int32
|
||||||
|
// TODO: Remove entirely. The pcsp table is more precise.
|
||||||
|
// This is only used by a fallback case during stack walking
|
||||||
|
// when a called function doesn't have argument information.
|
||||||
|
// We need to make sure everything has argument information
|
||||||
|
// and then remove this.
|
||||||
|
frameptrsize = int32(Thearch.Ptrsize)
|
||||||
|
|
||||||
|
if Ctxt.Cursym.Leaf != 0 {
|
||||||
|
frameptrsize = 0
|
||||||
|
}
|
||||||
|
off = int32(setuint32(Ctxt, ftab, int64(off), uint32(Ctxt.Cursym.Locals)+uint32(frameptrsize)))
|
||||||
|
|
||||||
|
if pcln != &pclntab_zpcln {
|
||||||
|
renumberfiles(Ctxt, pcln.File, &pcln.Pcfile)
|
||||||
|
if false {
|
||||||
|
// Sanity check the new numbering
|
||||||
|
for pciterinit(Ctxt, &it, &pcln.Pcfile); it.done == 0; pciternext(&it) {
|
||||||
|
if it.value < 1 || it.value > Ctxt.Nhistfile {
|
||||||
|
Diag("bad file number in pcfile: %d not in range [1, %d]\n", it.value, Ctxt.Nhistfile)
|
||||||
|
Errorexit()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// pcdata
|
||||||
|
off = addpctab(ftab, off, &pcln.Pcsp)
|
||||||
|
|
||||||
|
off = addpctab(ftab, off, &pcln.Pcfile)
|
||||||
|
off = addpctab(ftab, off, &pcln.Pcline)
|
||||||
|
off = int32(setuint32(Ctxt, ftab, int64(off), uint32(pcln.Npcdata)))
|
||||||
|
off = int32(setuint32(Ctxt, ftab, int64(off), uint32(pcln.Nfuncdata)))
|
||||||
|
for i = 0; i < int32(pcln.Npcdata); i++ {
|
||||||
|
off = addpctab(ftab, off, &pcln.Pcdata[i])
|
||||||
|
}
|
||||||
|
|
||||||
|
// funcdata, must be pointer-aligned and we're only int32-aligned.
|
||||||
|
// Missing funcdata will be 0 (nil pointer).
|
||||||
|
if pcln.Nfuncdata > 0 {
|
||||||
|
if off&int32(Thearch.Ptrsize-1) != 0 {
|
||||||
|
off += 4
|
||||||
|
}
|
||||||
|
for i = 0; i < int32(pcln.Nfuncdata); i++ {
|
||||||
|
if pcln.Funcdata[i] == nil {
|
||||||
|
setuintxx(Ctxt, ftab, int64(off)+int64(Thearch.Ptrsize)*int64(i), uint64(pcln.Funcdataoff[i]), int64(Thearch.Ptrsize))
|
||||||
|
} else {
|
||||||
|
// TODO: Dedup.
|
||||||
|
funcdata_bytes += pcln.Funcdata[i].Size
|
||||||
|
|
||||||
|
setaddrplus(Ctxt, ftab, int64(off)+int64(Thearch.Ptrsize)*int64(i), pcln.Funcdata[i], pcln.Funcdataoff[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
off += int32(pcln.Nfuncdata) * int32(Thearch.Ptrsize)
|
||||||
|
}
|
||||||
|
|
||||||
|
if off != end {
|
||||||
|
Diag("bad math in functab: funcstart=%d off=%d but end=%d (npcdata=%d nfuncdata=%d ptrsize=%d)", funcstart, off, end, pcln.Npcdata, pcln.Nfuncdata, Thearch.Ptrsize)
|
||||||
|
Errorexit()
|
||||||
|
}
|
||||||
|
|
||||||
|
nfunc++
|
||||||
|
}
|
||||||
|
|
||||||
|
// Final entry of table is just end pc.
|
||||||
|
setaddrplus(Ctxt, ftab, 8+int64(Thearch.Ptrsize)+int64(nfunc)*2*int64(Thearch.Ptrsize), last, last.Size)
|
||||||
|
|
||||||
|
// Start file table.
|
||||||
|
start = int32(len(ftab.P))
|
||||||
|
|
||||||
|
start += int32(-len(ftab.P)) & (int32(Thearch.Ptrsize) - 1)
|
||||||
|
setuint32(Ctxt, ftab, 8+int64(Thearch.Ptrsize)+int64(nfunc)*2*int64(Thearch.Ptrsize)+int64(Thearch.Ptrsize), uint32(start))
|
||||||
|
|
||||||
|
Symgrow(Ctxt, ftab, int64(start)+(int64(Ctxt.Nhistfile)+1)*4)
|
||||||
|
setuint32(Ctxt, ftab, int64(start), uint32(Ctxt.Nhistfile))
|
||||||
|
for s = Ctxt.Filesyms; s != nil; s = s.Next {
|
||||||
|
setuint32(Ctxt, ftab, int64(start)+s.Value*4, uint32(ftabaddstring(ftab, s.Name)))
|
||||||
|
}
|
||||||
|
|
||||||
|
ftab.Size = int64(len(ftab.P))
|
||||||
|
|
||||||
|
if Debug['v'] != 0 {
|
||||||
|
fmt.Fprintf(&Bso, "%5.2f pclntab=%d bytes, funcdata total %d bytes\n", obj.Cputime(), int64(ftab.Size), int64(funcdata_bytes))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
BUCKETSIZE = 256 * MINFUNC
|
||||||
|
SUBBUCKETS = 16
|
||||||
|
SUBBUCKETSIZE = BUCKETSIZE / SUBBUCKETS
|
||||||
|
NOIDX = 0x7fffffff
|
||||||
|
)
|
||||||
|
|
||||||
|
// findfunctab generates a lookup table to quickly find the containing
|
||||||
|
// function for a pc. See src/runtime/symtab.go:findfunc for details.
|
||||||
|
func findfunctab() {
|
||||||
|
var t *LSym
|
||||||
|
var s *LSym
|
||||||
|
var e *LSym
|
||||||
|
var idx int32
|
||||||
|
var i int32
|
||||||
|
var j int32
|
||||||
|
var nbuckets int32
|
||||||
|
var n int32
|
||||||
|
var base int32
|
||||||
|
var min int64
|
||||||
|
var max int64
|
||||||
|
var p int64
|
||||||
|
var q int64
|
||||||
|
var indexes []int32
|
||||||
|
|
||||||
|
t = Linklookup(Ctxt, "runtime.findfunctab", 0)
|
||||||
|
t.Type = SRODATA
|
||||||
|
t.Reachable = true
|
||||||
|
|
||||||
|
// find min and max address
|
||||||
|
min = Ctxt.Textp.Value
|
||||||
|
|
||||||
|
max = 0
|
||||||
|
for s = Ctxt.Textp; s != nil; s = s.Next {
|
||||||
|
max = s.Value + s.Size
|
||||||
|
}
|
||||||
|
|
||||||
|
// for each subbucket, compute the minimum of all symbol indexes
|
||||||
|
// that map to that subbucket.
|
||||||
|
n = int32((max - min + SUBBUCKETSIZE - 1) / SUBBUCKETSIZE)
|
||||||
|
|
||||||
|
indexes = make([]int32, n)
|
||||||
|
for i = 0; i < n; i++ {
|
||||||
|
indexes[i] = NOIDX
|
||||||
|
}
|
||||||
|
idx = 0
|
||||||
|
for s = Ctxt.Textp; s != nil; s = s.Next {
|
||||||
|
if container(s) != 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
p = s.Value
|
||||||
|
e = s.Next
|
||||||
|
for container(e) != 0 {
|
||||||
|
e = e.Next
|
||||||
|
}
|
||||||
|
if e != nil {
|
||||||
|
q = e.Value
|
||||||
|
} else {
|
||||||
|
q = max
|
||||||
|
}
|
||||||
|
|
||||||
|
//print("%d: [%lld %lld] %s\n", idx, p, q, s->name);
|
||||||
|
for ; p < q; p += SUBBUCKETSIZE {
|
||||||
|
i = int32((p - min) / SUBBUCKETSIZE)
|
||||||
|
if indexes[i] > idx {
|
||||||
|
indexes[i] = idx
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
i = int32((q - 1 - min) / SUBBUCKETSIZE)
|
||||||
|
if indexes[i] > idx {
|
||||||
|
indexes[i] = idx
|
||||||
|
}
|
||||||
|
idx++
|
||||||
|
}
|
||||||
|
|
||||||
|
// allocate table
|
||||||
|
nbuckets = int32((max - min + BUCKETSIZE - 1) / BUCKETSIZE)
|
||||||
|
|
||||||
|
Symgrow(Ctxt, t, 4*int64(nbuckets)+int64(n))
|
||||||
|
|
||||||
|
// fill in table
|
||||||
|
for i = 0; i < nbuckets; i++ {
|
||||||
|
base = indexes[i*SUBBUCKETS]
|
||||||
|
if base == NOIDX {
|
||||||
|
Diag("hole in findfunctab")
|
||||||
|
}
|
||||||
|
setuint32(Ctxt, t, int64(i)*(4+SUBBUCKETS), uint32(base))
|
||||||
|
for j = 0; j < SUBBUCKETS && i*SUBBUCKETS+j < n; j++ {
|
||||||
|
idx = indexes[i*SUBBUCKETS+j]
|
||||||
|
if idx == NOIDX {
|
||||||
|
Diag("hole in findfunctab")
|
||||||
|
}
|
||||||
|
if idx-base >= 256 {
|
||||||
|
Diag("too many functions in a findfunc bucket! %d/%d %d %d", i, nbuckets, j, idx-base)
|
||||||
|
}
|
||||||
|
|
||||||
|
setuint8(Ctxt, t, int64(i)*(4+SUBBUCKETS)+4+int64(j), uint8(idx-base))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
1060
src/cmd/internal/ld/pe.go
Normal file
1060
src/cmd/internal/ld/pe.go
Normal file
File diff suppressed because it is too large
Load diff
224
src/cmd/internal/ld/pobj.go
Normal file
224
src/cmd/internal/ld/pobj.go
Normal file
|
|
@ -0,0 +1,224 @@
|
||||||
|
// Inferno utils/6l/obj.c
|
||||||
|
// http://code.google.com/p/inferno-os/source/browse/utils/6l/obj.c
|
||||||
|
//
|
||||||
|
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
|
||||||
|
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
|
||||||
|
// Portions Copyright © 1997-1999 Vita Nuova Limited
|
||||||
|
// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
|
||||||
|
// Portions Copyright © 2004,2006 Bruce Ellis
|
||||||
|
// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
|
||||||
|
// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
|
||||||
|
// Portions Copyright © 2009 The Go Authors. All rights reserved.
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
|
// in the Software without restriction, including without limitation the rights
|
||||||
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
// THE SOFTWARE.
|
||||||
|
|
||||||
|
package ld
|
||||||
|
|
||||||
|
import (
|
||||||
|
"cmd/internal/obj"
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Reading object files.
|
||||||
|
|
||||||
|
var noname string = "<none>"
|
||||||
|
|
||||||
|
var paramspace string = "FP"
|
||||||
|
|
||||||
|
func Ldmain() {
|
||||||
|
Ctxt = linknew(Thelinkarch)
|
||||||
|
Ctxt.Thechar = int32(Thearch.Thechar)
|
||||||
|
Ctxt.Thestring = Thestring
|
||||||
|
Ctxt.Diag = Diag
|
||||||
|
Ctxt.Bso = &Bso
|
||||||
|
|
||||||
|
Bso = *Binitw(os.Stdout)
|
||||||
|
Debug = [128]int{}
|
||||||
|
nerrors = 0
|
||||||
|
outfile = ""
|
||||||
|
HEADTYPE = -1
|
||||||
|
INITTEXT = -1
|
||||||
|
INITDAT = -1
|
||||||
|
INITRND = -1
|
||||||
|
INITENTRY = ""
|
||||||
|
Linkmode = LinkAuto
|
||||||
|
|
||||||
|
// For testing behavior of go command when tools crash.
|
||||||
|
// Undocumented, not in standard flag parser to avoid
|
||||||
|
// exposing in usage message.
|
||||||
|
for _, arg := range os.Args {
|
||||||
|
if arg == "-crash_for_testing" {
|
||||||
|
*(*int)(nil) = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if Thearch.Thechar == '5' && Ctxt.Goarm == 5 {
|
||||||
|
Debug['F'] = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
obj.Flagcount("1", "use alternate profiling code", &Debug['1'])
|
||||||
|
if Thearch.Thechar == '6' {
|
||||||
|
obj.Flagcount("8", "assume 64-bit addresses", &Debug['8'])
|
||||||
|
}
|
||||||
|
obj.Flagfn1("B", "info: define ELF NT_GNU_BUILD_ID note", addbuildinfo)
|
||||||
|
obj.Flagcount("C", "check Go calls to C code", &Debug['C'])
|
||||||
|
obj.Flagint64("D", "addr: data address", &INITDAT)
|
||||||
|
obj.Flagstr("E", "sym: entry symbol", &INITENTRY)
|
||||||
|
if Thearch.Thechar == '5' {
|
||||||
|
obj.Flagcount("G", "debug pseudo-ops", &Debug['G'])
|
||||||
|
}
|
||||||
|
obj.Flagfn1("I", "interp: set ELF interp", setinterp)
|
||||||
|
obj.Flagfn1("L", "dir: add dir to library path", Lflag)
|
||||||
|
obj.Flagfn1("H", "head: header type", setheadtype)
|
||||||
|
obj.Flagcount("K", "add stack underflow checks", &Debug['K'])
|
||||||
|
if Thearch.Thechar == '5' {
|
||||||
|
obj.Flagcount("M", "disable software div/mod", &Debug['M'])
|
||||||
|
}
|
||||||
|
obj.Flagcount("O", "print pc-line tables", &Debug['O'])
|
||||||
|
obj.Flagcount("Q", "debug byte-register code gen", &Debug['Q'])
|
||||||
|
if Thearch.Thechar == '5' {
|
||||||
|
obj.Flagcount("P", "debug code generation", &Debug['P'])
|
||||||
|
}
|
||||||
|
obj.Flagint32("R", "rnd: address rounding", &INITRND)
|
||||||
|
obj.Flagcount("nil", "check type signatures", &Debug['S'])
|
||||||
|
obj.Flagint64("T", "addr: text address", &INITTEXT)
|
||||||
|
obj.Flagfn0("V", "print version and exit", doversion)
|
||||||
|
obj.Flagcount("W", "disassemble input", &Debug['W'])
|
||||||
|
obj.Flagfn1("X", "name value: define string data", addstrdata1)
|
||||||
|
obj.Flagcount("Z", "clear stack frame on entry", &Debug['Z'])
|
||||||
|
obj.Flagcount("a", "disassemble output", &Debug['a'])
|
||||||
|
obj.Flagcount("c", "dump call graph", &Debug['c'])
|
||||||
|
obj.Flagcount("d", "disable dynamic executable", &Debug['d'])
|
||||||
|
obj.Flagstr("extld", "ld: linker to run in external mode", &extld)
|
||||||
|
obj.Flagstr("extldflags", "ldflags: flags for external linker", &extldflags)
|
||||||
|
obj.Flagcount("f", "ignore version mismatch", &Debug['f'])
|
||||||
|
obj.Flagcount("g", "disable go package data checks", &Debug['g'])
|
||||||
|
obj.Flagstr("installsuffix", "suffix: pkg directory suffix", &flag_installsuffix)
|
||||||
|
obj.Flagstr("k", "sym: set field tracking symbol", &tracksym)
|
||||||
|
obj.Flagfn1("linkmode", "mode: set link mode (internal, external, auto)", setlinkmode)
|
||||||
|
obj.Flagcount("n", "dump symbol table", &Debug['n'])
|
||||||
|
obj.Flagstr("o", "outfile: set output file", &outfile)
|
||||||
|
obj.Flagstr("r", "dir1:dir2:...: set ELF dynamic linker search path", &rpath)
|
||||||
|
obj.Flagcount("race", "enable race detector", &flag_race)
|
||||||
|
obj.Flagcount("s", "disable symbol table", &Debug['s'])
|
||||||
|
if Thearch.Thechar == '5' || Thearch.Thechar == '6' {
|
||||||
|
obj.Flagcount("shared", "generate shared object (implies -linkmode external)", &Flag_shared)
|
||||||
|
}
|
||||||
|
obj.Flagstr("tmpdir", "dir: leave temporary files in this directory", &tmpdir)
|
||||||
|
obj.Flagcount("u", "reject unsafe packages", &Debug['u'])
|
||||||
|
obj.Flagcount("v", "print link trace", &Debug['v'])
|
||||||
|
obj.Flagcount("w", "disable DWARF generation", &Debug['w'])
|
||||||
|
|
||||||
|
// Clumsy hack to preserve old behavior of -X taking two arguments.
|
||||||
|
for i := 0; i < len(os.Args); i++ {
|
||||||
|
arg := os.Args[i]
|
||||||
|
if (arg == "--X" || arg == "-X") && i+2 < len(os.Args) {
|
||||||
|
os.Args[i+2] = "-X=VALUE:" + os.Args[i+2]
|
||||||
|
i += 2
|
||||||
|
} else if (strings.HasPrefix(arg, "--X=") || strings.HasPrefix(arg, "-X=")) && i+1 < len(os.Args) {
|
||||||
|
os.Args[i+1] = "-X=VALUE:" + os.Args[i+1]
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
obj.Flagstr("cpuprofile", "file: write cpu profile to file", &cpuprofile)
|
||||||
|
obj.Flagstr("memprofile", "file: write memory profile to file", &memprofile)
|
||||||
|
obj.Flagparse(usage)
|
||||||
|
startProfile()
|
||||||
|
Ctxt.Bso = &Bso
|
||||||
|
Ctxt.Debugvlog = int32(Debug['v'])
|
||||||
|
|
||||||
|
if flag.NArg() != 1 {
|
||||||
|
usage()
|
||||||
|
}
|
||||||
|
|
||||||
|
if outfile == "" {
|
||||||
|
if HEADTYPE == Hwindows {
|
||||||
|
outfile = fmt.Sprintf("%c.out.exe", Thearch.Thechar)
|
||||||
|
} else {
|
||||||
|
outfile = fmt.Sprintf("%c.out", Thearch.Thechar)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
libinit() // creates outfile
|
||||||
|
|
||||||
|
if HEADTYPE == -1 {
|
||||||
|
HEADTYPE = int32(headtype(goos))
|
||||||
|
}
|
||||||
|
Ctxt.Headtype = int(HEADTYPE)
|
||||||
|
if headstring == "" {
|
||||||
|
headstring = Headstr(int(HEADTYPE))
|
||||||
|
}
|
||||||
|
|
||||||
|
Thearch.Archinit()
|
||||||
|
|
||||||
|
if Debug['v'] != 0 {
|
||||||
|
fmt.Fprintf(&Bso, "HEADER = -H%d -T0x%x -D0x%x -R0x%x\n", HEADTYPE, uint64(INITTEXT), uint64(INITDAT), uint32(INITRND))
|
||||||
|
}
|
||||||
|
Bflush(&Bso)
|
||||||
|
|
||||||
|
addlibpath(Ctxt, "command line", "command line", flag.Arg(0), "main")
|
||||||
|
loadlib()
|
||||||
|
|
||||||
|
if Thearch.Thechar == '5' {
|
||||||
|
// mark some functions that are only referenced after linker code editing
|
||||||
|
if Debug['F'] != 0 {
|
||||||
|
mark(Linkrlookup(Ctxt, "_sfloat", 0))
|
||||||
|
}
|
||||||
|
mark(Linklookup(Ctxt, "runtime.read_tls_fallback", 0))
|
||||||
|
}
|
||||||
|
|
||||||
|
checkgo()
|
||||||
|
deadcode()
|
||||||
|
callgraph()
|
||||||
|
paramspace = "SP" /* (FP) now (SP) on output */
|
||||||
|
|
||||||
|
doelf()
|
||||||
|
if HEADTYPE == Hdarwin {
|
||||||
|
domacho()
|
||||||
|
}
|
||||||
|
dostkcheck()
|
||||||
|
if HEADTYPE == Hwindows {
|
||||||
|
dope()
|
||||||
|
}
|
||||||
|
addexport()
|
||||||
|
Thearch.Gentext() // trampolines, call stubs, etc.
|
||||||
|
textaddress()
|
||||||
|
pclntab()
|
||||||
|
findfunctab()
|
||||||
|
symtab()
|
||||||
|
dodata()
|
||||||
|
address()
|
||||||
|
doweak()
|
||||||
|
reloc()
|
||||||
|
Thearch.Asmb()
|
||||||
|
undef()
|
||||||
|
hostlink()
|
||||||
|
if Debug['v'] != 0 {
|
||||||
|
fmt.Fprintf(&Bso, "%5.2f cpu time\n", obj.Cputime())
|
||||||
|
fmt.Fprintf(&Bso, "%d symbols\n", Ctxt.Nsymbol)
|
||||||
|
fmt.Fprintf(&Bso, "%d liveness data\n", liveness)
|
||||||
|
}
|
||||||
|
|
||||||
|
Bflush(&Bso)
|
||||||
|
|
||||||
|
Errorexit()
|
||||||
|
}
|
||||||
238
src/cmd/internal/ld/sym.go
Normal file
238
src/cmd/internal/ld/sym.go
Normal file
|
|
@ -0,0 +1,238 @@
|
||||||
|
// Derived from Inferno utils/6l/obj.c and utils/6l/span.c
|
||||||
|
// http://code.google.com/p/inferno-os/source/browse/utils/6l/obj.c
|
||||||
|
// http://code.google.com/p/inferno-os/source/browse/utils/6l/span.c
|
||||||
|
//
|
||||||
|
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
|
||||||
|
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
|
||||||
|
// Portions Copyright © 1997-1999 Vita Nuova Limited
|
||||||
|
// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
|
||||||
|
// Portions Copyright © 2004,2006 Bruce Ellis
|
||||||
|
// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
|
||||||
|
// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
|
||||||
|
// Portions Copyright © 2009 The Go Authors. All rights reserved.
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
|
// in the Software without restriction, including without limitation the rights
|
||||||
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
// THE SOFTWARE.
|
||||||
|
|
||||||
|
package ld
|
||||||
|
|
||||||
|
import (
|
||||||
|
"cmd/internal/obj"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
)
|
||||||
|
|
||||||
|
func yy_isalpha(c int) bool {
|
||||||
|
return 'A' <= c && c <= 'Z' || 'a' <= c && c <= 'z'
|
||||||
|
}
|
||||||
|
|
||||||
|
var headers = []struct {
|
||||||
|
name string
|
||||||
|
val int
|
||||||
|
}{
|
||||||
|
{"darwin", Hdarwin},
|
||||||
|
{"dragonfly", Hdragonfly},
|
||||||
|
{"elf", Helf},
|
||||||
|
{"freebsd", Hfreebsd},
|
||||||
|
{"linux", Hlinux},
|
||||||
|
{"android", Hlinux}, // must be after "linux" entry or else headstr(Hlinux) == "android"
|
||||||
|
{"nacl", Hnacl},
|
||||||
|
{"netbsd", Hnetbsd},
|
||||||
|
{"openbsd", Hopenbsd},
|
||||||
|
{"plan9", Hplan9},
|
||||||
|
{"solaris", Hsolaris},
|
||||||
|
{"windows", Hwindows},
|
||||||
|
{"windowsgui", Hwindows},
|
||||||
|
}
|
||||||
|
|
||||||
|
func linknew(arch *LinkArch) *Link {
|
||||||
|
var ctxt *Link
|
||||||
|
var p string
|
||||||
|
var buf string
|
||||||
|
|
||||||
|
ctxt = new(Link)
|
||||||
|
ctxt.Hash = make(map[symVer]*LSym)
|
||||||
|
ctxt.Arch = arch
|
||||||
|
ctxt.Version = HistVersion
|
||||||
|
ctxt.Goroot = obj.Getgoroot()
|
||||||
|
|
||||||
|
p = obj.Getgoarch()
|
||||||
|
if p != arch.Name {
|
||||||
|
log.Fatalf("invalid goarch %s (want %s)", p, arch.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
buf, _ = os.Getwd()
|
||||||
|
if buf == "" {
|
||||||
|
buf = "/???"
|
||||||
|
}
|
||||||
|
buf = filepath.ToSlash(buf)
|
||||||
|
|
||||||
|
ctxt.Headtype = headtype(obj.Getgoos())
|
||||||
|
if ctxt.Headtype < 0 {
|
||||||
|
log.Fatalf("unknown goos %s", obj.Getgoos())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Record thread-local storage offset.
|
||||||
|
// TODO(rsc): Move tlsoffset back into the linker.
|
||||||
|
switch ctxt.Headtype {
|
||||||
|
default:
|
||||||
|
log.Fatalf("unknown thread-local storage offset for %s", Headstr(ctxt.Headtype))
|
||||||
|
|
||||||
|
case Hplan9,
|
||||||
|
Hwindows:
|
||||||
|
break
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ELF uses TLS offset negative from FS.
|
||||||
|
* Translate 0(FS) and 8(FS) into -16(FS) and -8(FS).
|
||||||
|
* Known to low-level assembly in package runtime and runtime/cgo.
|
||||||
|
*/
|
||||||
|
case Hlinux,
|
||||||
|
Hfreebsd,
|
||||||
|
Hnetbsd,
|
||||||
|
Hopenbsd,
|
||||||
|
Hdragonfly,
|
||||||
|
Hsolaris:
|
||||||
|
ctxt.Tlsoffset = -2 * ctxt.Arch.Ptrsize
|
||||||
|
|
||||||
|
case Hnacl:
|
||||||
|
switch ctxt.Arch.Thechar {
|
||||||
|
default:
|
||||||
|
log.Fatalf("unknown thread-local storage offset for nacl/%s", ctxt.Arch.Name)
|
||||||
|
|
||||||
|
case '5':
|
||||||
|
ctxt.Tlsoffset = 0
|
||||||
|
|
||||||
|
case '6':
|
||||||
|
ctxt.Tlsoffset = 0
|
||||||
|
|
||||||
|
case '8':
|
||||||
|
ctxt.Tlsoffset = -8
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* OS X system constants - offset from 0(GS) to our TLS.
|
||||||
|
* Explained in ../../runtime/cgo/gcc_darwin_*.c.
|
||||||
|
*/
|
||||||
|
case Hdarwin:
|
||||||
|
switch ctxt.Arch.Thechar {
|
||||||
|
default:
|
||||||
|
log.Fatalf("unknown thread-local storage offset for darwin/%s", ctxt.Arch.Name)
|
||||||
|
|
||||||
|
case '6':
|
||||||
|
ctxt.Tlsoffset = 0x8a0
|
||||||
|
|
||||||
|
case '8':
|
||||||
|
ctxt.Tlsoffset = 0x468
|
||||||
|
|
||||||
|
case '5':
|
||||||
|
ctxt.Tlsoffset = 0 // dummy value, not needed
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// On arm, record goarm.
|
||||||
|
if ctxt.Arch.Thechar == '5' {
|
||||||
|
p = obj.Getgoarm()
|
||||||
|
if p != "" {
|
||||||
|
ctxt.Goarm = int32(obj.Atoi(p))
|
||||||
|
} else {
|
||||||
|
ctxt.Goarm = 6
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ctxt
|
||||||
|
}
|
||||||
|
|
||||||
|
func linknewsym(ctxt *Link, symb string, v int) *LSym {
|
||||||
|
var s *LSym
|
||||||
|
|
||||||
|
s = new(LSym)
|
||||||
|
*s = LSym{}
|
||||||
|
|
||||||
|
s.Dynid = -1
|
||||||
|
s.Plt = -1
|
||||||
|
s.Got = -1
|
||||||
|
s.Name = symb
|
||||||
|
s.Type = 0
|
||||||
|
s.Version = int16(v)
|
||||||
|
s.Value = 0
|
||||||
|
s.Sig = 0
|
||||||
|
s.Size = 0
|
||||||
|
ctxt.Nsymbol++
|
||||||
|
|
||||||
|
s.Allsym = ctxt.Allsym
|
||||||
|
ctxt.Allsym = s
|
||||||
|
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
type symVer struct {
|
||||||
|
sym string
|
||||||
|
ver int
|
||||||
|
}
|
||||||
|
|
||||||
|
func _lookup(ctxt *Link, symb string, v int, creat int) *LSym {
|
||||||
|
s := ctxt.Hash[symVer{symb, v}]
|
||||||
|
if s != nil {
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
if creat == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
s = linknewsym(ctxt, symb, v)
|
||||||
|
s.Extname = s.Name
|
||||||
|
ctxt.Hash[symVer{symb, v}] = s
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
func Linklookup(ctxt *Link, name string, v int) *LSym {
|
||||||
|
return _lookup(ctxt, name, v, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// read-only lookup
|
||||||
|
func Linkrlookup(ctxt *Link, name string, v int) *LSym {
|
||||||
|
return _lookup(ctxt, name, v, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
var headstr_buf string
|
||||||
|
|
||||||
|
func Headstr(v int) string {
|
||||||
|
var i int
|
||||||
|
|
||||||
|
for i = 0; i < len(headers); i++ {
|
||||||
|
if v == headers[i].val {
|
||||||
|
return headers[i].name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
headstr_buf = fmt.Sprintf("%d", v)
|
||||||
|
return headstr_buf
|
||||||
|
}
|
||||||
|
|
||||||
|
func headtype(name string) int {
|
||||||
|
var i int
|
||||||
|
|
||||||
|
for i = 0; i < len(headers); i++ {
|
||||||
|
if name == headers[i].name {
|
||||||
|
return headers[i].val
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1
|
||||||
|
}
|
||||||
440
src/cmd/internal/ld/symtab.go
Normal file
440
src/cmd/internal/ld/symtab.go
Normal file
|
|
@ -0,0 +1,440 @@
|
||||||
|
// Inferno utils/6l/span.c
|
||||||
|
// http://code.google.com/p/inferno-os/source/browse/utils/6l/span.c
|
||||||
|
//
|
||||||
|
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
|
||||||
|
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
|
||||||
|
// Portions Copyright © 1997-1999 Vita Nuova Limited
|
||||||
|
// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
|
||||||
|
// Portions Copyright © 2004,2006 Bruce Ellis
|
||||||
|
// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
|
||||||
|
// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
|
||||||
|
// Portions Copyright © 2009 The Go Authors. All rights reserved.
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
|
// in the Software without restriction, including without limitation the rights
|
||||||
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
// THE SOFTWARE.
|
||||||
|
|
||||||
|
package ld
|
||||||
|
|
||||||
|
import "strings"
|
||||||
|
|
||||||
|
// Symbol table.
|
||||||
|
|
||||||
|
var maxelfstr int
|
||||||
|
|
||||||
|
func putelfstr(s string) int {
|
||||||
|
var off int
|
||||||
|
var n int
|
||||||
|
|
||||||
|
if len(Elfstrdat) == 0 && s != "" {
|
||||||
|
// first entry must be empty string
|
||||||
|
putelfstr("")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rewrite · to . for ASCII-only tools like DTrace (sigh)
|
||||||
|
s = strings.Replace(s, "·", ".", -1)
|
||||||
|
|
||||||
|
n = len(s) + 1
|
||||||
|
for len(Elfstrdat)+n > cap(Elfstrdat) {
|
||||||
|
Elfstrdat = append(Elfstrdat[:cap(Elfstrdat)], 0)[:len(Elfstrdat)]
|
||||||
|
}
|
||||||
|
|
||||||
|
off = len(Elfstrdat)
|
||||||
|
Elfstrdat = Elfstrdat[:off+n]
|
||||||
|
copy(Elfstrdat[off:], s)
|
||||||
|
|
||||||
|
return off
|
||||||
|
}
|
||||||
|
|
||||||
|
func putelfsyment(off int, addr int64, size int64, info int, shndx int, other int) {
|
||||||
|
switch Thearch.Thechar {
|
||||||
|
case '6',
|
||||||
|
'9':
|
||||||
|
Thearch.Lput(uint32(off))
|
||||||
|
Cput(uint8(info))
|
||||||
|
Cput(uint8(other))
|
||||||
|
Thearch.Wput(uint16(shndx))
|
||||||
|
Thearch.Vput(uint64(addr))
|
||||||
|
Thearch.Vput(uint64(size))
|
||||||
|
Symsize += ELF64SYMSIZE
|
||||||
|
|
||||||
|
default:
|
||||||
|
Thearch.Lput(uint32(off))
|
||||||
|
Thearch.Lput(uint32(addr))
|
||||||
|
Thearch.Lput(uint32(size))
|
||||||
|
Cput(uint8(info))
|
||||||
|
Cput(uint8(other))
|
||||||
|
Thearch.Wput(uint16(shndx))
|
||||||
|
Symsize += ELF32SYMSIZE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var numelfsym int = 1 // 0 is reserved
|
||||||
|
|
||||||
|
var elfbind int
|
||||||
|
|
||||||
|
func putelfsym(x *LSym, s string, t int, addr int64, size int64, ver int, go_ *LSym) {
|
||||||
|
var bind int
|
||||||
|
var type_ int
|
||||||
|
var off int
|
||||||
|
var other int
|
||||||
|
var xo *LSym
|
||||||
|
|
||||||
|
switch t {
|
||||||
|
default:
|
||||||
|
return
|
||||||
|
|
||||||
|
case 'T':
|
||||||
|
type_ = STT_FUNC
|
||||||
|
|
||||||
|
case 'D':
|
||||||
|
type_ = STT_OBJECT
|
||||||
|
|
||||||
|
case 'B':
|
||||||
|
type_ = STT_OBJECT
|
||||||
|
}
|
||||||
|
|
||||||
|
xo = x
|
||||||
|
for xo.Outer != nil {
|
||||||
|
xo = xo.Outer
|
||||||
|
}
|
||||||
|
if xo.Sect == nil {
|
||||||
|
Ctxt.Cursym = x
|
||||||
|
Diag("missing section in putelfsym")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (xo.Sect.(*Section)).Elfsect == nil {
|
||||||
|
Ctxt.Cursym = x
|
||||||
|
Diag("missing ELF section in putelfsym")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// One pass for each binding: STB_LOCAL, STB_GLOBAL,
|
||||||
|
// maybe one day STB_WEAK.
|
||||||
|
bind = STB_GLOBAL
|
||||||
|
|
||||||
|
if ver != 0 || (x.Type&SHIDDEN != 0) {
|
||||||
|
bind = STB_LOCAL
|
||||||
|
}
|
||||||
|
|
||||||
|
// In external linking mode, we have to invoke gcc with -rdynamic
|
||||||
|
// to get the exported symbols put into the dynamic symbol table.
|
||||||
|
// To avoid filling the dynamic table with lots of unnecessary symbols,
|
||||||
|
// mark all Go symbols local (not global) in the final executable.
|
||||||
|
if Linkmode == LinkExternal && x.Cgoexport&CgoExportStatic == 0 {
|
||||||
|
bind = STB_LOCAL
|
||||||
|
}
|
||||||
|
|
||||||
|
if bind != elfbind {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
off = putelfstr(s)
|
||||||
|
if Linkmode == LinkExternal {
|
||||||
|
addr -= int64((xo.Sect.(*Section)).Vaddr)
|
||||||
|
}
|
||||||
|
other = 2
|
||||||
|
if x.Type&SHIDDEN != 0 {
|
||||||
|
other = 0
|
||||||
|
}
|
||||||
|
putelfsyment(off, addr, size, bind<<4|type_&0xf, ((xo.Sect.(*Section)).Elfsect.(*ElfShdr)).shnum, other)
|
||||||
|
x.Elfsym = int32(numelfsym)
|
||||||
|
numelfsym++
|
||||||
|
}
|
||||||
|
|
||||||
|
func putelfsectionsym(s *LSym, shndx int) {
|
||||||
|
putelfsyment(0, 0, 0, STB_LOCAL<<4|STT_SECTION, shndx, 0)
|
||||||
|
s.Elfsym = int32(numelfsym)
|
||||||
|
numelfsym++
|
||||||
|
}
|
||||||
|
|
||||||
|
func putelfsymshndx(sympos int64, shndx int) {
|
||||||
|
var here int64
|
||||||
|
|
||||||
|
here = Cpos()
|
||||||
|
switch Thearch.Thechar {
|
||||||
|
case '6':
|
||||||
|
Cseek(sympos + 6)
|
||||||
|
|
||||||
|
default:
|
||||||
|
Cseek(sympos + 14)
|
||||||
|
}
|
||||||
|
|
||||||
|
Thearch.Wput(uint16(shndx))
|
||||||
|
Cseek(here)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Asmelfsym() {
|
||||||
|
var s *LSym
|
||||||
|
var name string
|
||||||
|
|
||||||
|
// the first symbol entry is reserved
|
||||||
|
putelfsyment(0, 0, 0, STB_LOCAL<<4|STT_NOTYPE, 0, 0)
|
||||||
|
|
||||||
|
dwarfaddelfsectionsyms()
|
||||||
|
|
||||||
|
elfbind = STB_LOCAL
|
||||||
|
genasmsym(putelfsym)
|
||||||
|
|
||||||
|
if Linkmode == LinkExternal && HEADTYPE != Hopenbsd {
|
||||||
|
s = Linklookup(Ctxt, "runtime.tlsg", 0)
|
||||||
|
if s.Sect == nil {
|
||||||
|
Ctxt.Cursym = nil
|
||||||
|
Diag("missing section for %s", s.Name)
|
||||||
|
Errorexit()
|
||||||
|
}
|
||||||
|
|
||||||
|
if goos == "android" {
|
||||||
|
// Android emulates runtime.tlsg as a regular variable.
|
||||||
|
putelfsyment(putelfstr(s.Name), 0, s.Size, STB_LOCAL<<4|STT_OBJECT, ((s.Sect.(*Section)).Elfsect.(*ElfShdr)).shnum, 0)
|
||||||
|
} else {
|
||||||
|
putelfsyment(putelfstr(s.Name), 0, s.Size, STB_LOCAL<<4|STT_TLS, ((s.Sect.(*Section)).Elfsect.(*ElfShdr)).shnum, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
s.Elfsym = int32(numelfsym)
|
||||||
|
numelfsym++
|
||||||
|
}
|
||||||
|
|
||||||
|
elfbind = STB_GLOBAL
|
||||||
|
elfglobalsymndx = numelfsym
|
||||||
|
genasmsym(putelfsym)
|
||||||
|
|
||||||
|
for s = Ctxt.Allsym; s != nil; s = s.Allsym {
|
||||||
|
if s.Type != SHOSTOBJ && (s.Type != SDYNIMPORT || !s.Reachable) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if s.Type == SDYNIMPORT {
|
||||||
|
name = s.Extname
|
||||||
|
} else {
|
||||||
|
name = s.Name
|
||||||
|
}
|
||||||
|
putelfsyment(putelfstr(name), 0, 0, STB_GLOBAL<<4|STT_NOTYPE, 0, 0)
|
||||||
|
s.Elfsym = int32(numelfsym)
|
||||||
|
numelfsym++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func putplan9sym(x *LSym, s string, t int, addr int64, size int64, ver int, go_ *LSym) {
|
||||||
|
var i int
|
||||||
|
var l int
|
||||||
|
|
||||||
|
switch t {
|
||||||
|
case 'T',
|
||||||
|
'L',
|
||||||
|
'D',
|
||||||
|
'B':
|
||||||
|
if ver != 0 {
|
||||||
|
t += 'a' - 'A'
|
||||||
|
}
|
||||||
|
fallthrough
|
||||||
|
|
||||||
|
case 'a',
|
||||||
|
'p',
|
||||||
|
'f',
|
||||||
|
'z',
|
||||||
|
'Z',
|
||||||
|
'm':
|
||||||
|
l = 4
|
||||||
|
if HEADTYPE == Hplan9 && Thearch.Thechar == '6' && Debug['8'] == 0 {
|
||||||
|
Lputb(uint32(addr >> 32))
|
||||||
|
l = 8
|
||||||
|
}
|
||||||
|
|
||||||
|
Lputb(uint32(addr))
|
||||||
|
Cput(uint8(t + 0x80)) /* 0x80 is variable length */
|
||||||
|
|
||||||
|
if t == 'z' || t == 'Z' {
|
||||||
|
Cput(uint8(s[0]))
|
||||||
|
for i = 1; s[i] != 0 || s[i+1] != 0; i += 2 {
|
||||||
|
Cput(uint8(s[i]))
|
||||||
|
Cput(uint8(s[i+1]))
|
||||||
|
}
|
||||||
|
|
||||||
|
Cput(0)
|
||||||
|
Cput(0)
|
||||||
|
i++
|
||||||
|
} else {
|
||||||
|
/* skip the '<' in filenames */
|
||||||
|
if t == 'f' {
|
||||||
|
s = s[1:]
|
||||||
|
}
|
||||||
|
for i = 0; i < len(s); i++ {
|
||||||
|
Cput(uint8(s[i]))
|
||||||
|
}
|
||||||
|
Cput(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
Symsize += int32(l) + 1 + int32(i) + 1
|
||||||
|
|
||||||
|
default:
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Asmplan9sym() {
|
||||||
|
genasmsym(putplan9sym)
|
||||||
|
}
|
||||||
|
|
||||||
|
var symt *LSym
|
||||||
|
|
||||||
|
func Wputl(w uint16) {
|
||||||
|
Cput(uint8(w))
|
||||||
|
Cput(uint8(w >> 8))
|
||||||
|
}
|
||||||
|
|
||||||
|
func Wputb(w uint16) {
|
||||||
|
Cput(uint8(w >> 8))
|
||||||
|
Cput(uint8(w))
|
||||||
|
}
|
||||||
|
|
||||||
|
func Lputb(l uint32) {
|
||||||
|
Cput(uint8(l >> 24))
|
||||||
|
Cput(uint8(l >> 16))
|
||||||
|
Cput(uint8(l >> 8))
|
||||||
|
Cput(uint8(l))
|
||||||
|
}
|
||||||
|
|
||||||
|
func Lputl(l uint32) {
|
||||||
|
Cput(uint8(l))
|
||||||
|
Cput(uint8(l >> 8))
|
||||||
|
Cput(uint8(l >> 16))
|
||||||
|
Cput(uint8(l >> 24))
|
||||||
|
}
|
||||||
|
|
||||||
|
func Vputb(v uint64) {
|
||||||
|
Lputb(uint32(v >> 32))
|
||||||
|
Lputb(uint32(v))
|
||||||
|
}
|
||||||
|
|
||||||
|
func Vputl(v uint64) {
|
||||||
|
Lputl(uint32(v))
|
||||||
|
Lputl(uint32(v >> 32))
|
||||||
|
}
|
||||||
|
|
||||||
|
func symtab() {
|
||||||
|
var s *LSym
|
||||||
|
var symtype *LSym
|
||||||
|
var symtypelink *LSym
|
||||||
|
var symgostring *LSym
|
||||||
|
var symgofunc *LSym
|
||||||
|
|
||||||
|
dosymtype()
|
||||||
|
|
||||||
|
// Define these so that they'll get put into the symbol table.
|
||||||
|
// data.c:/^address will provide the actual values.
|
||||||
|
xdefine("runtime.text", STEXT, 0)
|
||||||
|
|
||||||
|
xdefine("runtime.etext", STEXT, 0)
|
||||||
|
xdefine("runtime.typelink", SRODATA, 0)
|
||||||
|
xdefine("runtime.etypelink", SRODATA, 0)
|
||||||
|
xdefine("runtime.rodata", SRODATA, 0)
|
||||||
|
xdefine("runtime.erodata", SRODATA, 0)
|
||||||
|
xdefine("runtime.noptrdata", SNOPTRDATA, 0)
|
||||||
|
xdefine("runtime.enoptrdata", SNOPTRDATA, 0)
|
||||||
|
xdefine("runtime.data", SDATA, 0)
|
||||||
|
xdefine("runtime.edata", SDATA, 0)
|
||||||
|
xdefine("runtime.bss", SBSS, 0)
|
||||||
|
xdefine("runtime.ebss", SBSS, 0)
|
||||||
|
xdefine("runtime.noptrbss", SNOPTRBSS, 0)
|
||||||
|
xdefine("runtime.enoptrbss", SNOPTRBSS, 0)
|
||||||
|
xdefine("runtime.end", SBSS, 0)
|
||||||
|
xdefine("runtime.epclntab", SRODATA, 0)
|
||||||
|
xdefine("runtime.esymtab", SRODATA, 0)
|
||||||
|
|
||||||
|
// garbage collection symbols
|
||||||
|
s = Linklookup(Ctxt, "runtime.gcdata", 0)
|
||||||
|
|
||||||
|
s.Type = SRODATA
|
||||||
|
s.Size = 0
|
||||||
|
s.Reachable = true
|
||||||
|
xdefine("runtime.egcdata", SRODATA, 0)
|
||||||
|
|
||||||
|
s = Linklookup(Ctxt, "runtime.gcbss", 0)
|
||||||
|
s.Type = SRODATA
|
||||||
|
s.Size = 0
|
||||||
|
s.Reachable = true
|
||||||
|
xdefine("runtime.egcbss", SRODATA, 0)
|
||||||
|
|
||||||
|
// pseudo-symbols to mark locations of type, string, and go string data.
|
||||||
|
s = Linklookup(Ctxt, "type.*", 0)
|
||||||
|
|
||||||
|
s.Type = STYPE
|
||||||
|
s.Size = 0
|
||||||
|
s.Reachable = true
|
||||||
|
symtype = s
|
||||||
|
|
||||||
|
s = Linklookup(Ctxt, "go.string.*", 0)
|
||||||
|
s.Type = SGOSTRING
|
||||||
|
s.Size = 0
|
||||||
|
s.Reachable = true
|
||||||
|
symgostring = s
|
||||||
|
|
||||||
|
s = Linklookup(Ctxt, "go.func.*", 0)
|
||||||
|
s.Type = SGOFUNC
|
||||||
|
s.Size = 0
|
||||||
|
s.Reachable = true
|
||||||
|
symgofunc = s
|
||||||
|
|
||||||
|
symtypelink = Linklookup(Ctxt, "runtime.typelink", 0)
|
||||||
|
|
||||||
|
symt = Linklookup(Ctxt, "runtime.symtab", 0)
|
||||||
|
symt.Type = SSYMTAB
|
||||||
|
symt.Size = 0
|
||||||
|
symt.Reachable = true
|
||||||
|
|
||||||
|
// assign specific types so that they sort together.
|
||||||
|
// within a type they sort by size, so the .* symbols
|
||||||
|
// just defined above will be first.
|
||||||
|
// hide the specific symbols.
|
||||||
|
for s = Ctxt.Allsym; s != nil; s = s.Allsym {
|
||||||
|
if !s.Reachable || s.Special != 0 || s.Type != SRODATA {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if strings.HasPrefix(s.Name, "type.") {
|
||||||
|
s.Type = STYPE
|
||||||
|
s.Hide = 1
|
||||||
|
s.Outer = symtype
|
||||||
|
}
|
||||||
|
|
||||||
|
if strings.HasPrefix(s.Name, "go.typelink.") {
|
||||||
|
s.Type = STYPELINK
|
||||||
|
s.Hide = 1
|
||||||
|
s.Outer = symtypelink
|
||||||
|
}
|
||||||
|
|
||||||
|
if strings.HasPrefix(s.Name, "go.string.") {
|
||||||
|
s.Type = SGOSTRING
|
||||||
|
s.Hide = 1
|
||||||
|
s.Outer = symgostring
|
||||||
|
}
|
||||||
|
|
||||||
|
if strings.HasPrefix(s.Name, "go.func.") {
|
||||||
|
s.Type = SGOFUNC
|
||||||
|
s.Hide = 1
|
||||||
|
s.Outer = symgofunc
|
||||||
|
}
|
||||||
|
|
||||||
|
if strings.HasPrefix(s.Name, "gcargs.") || strings.HasPrefix(s.Name, "gclocals.") || strings.HasPrefix(s.Name, "gclocals·") {
|
||||||
|
s.Type = SGOFUNC
|
||||||
|
s.Hide = 1
|
||||||
|
s.Outer = symgofunc
|
||||||
|
s.Align = 4
|
||||||
|
liveness += (s.Size + int64(s.Align) - 1) &^ (int64(s.Align) - 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
133
src/cmd/internal/ld/textflag.go
Normal file
133
src/cmd/internal/ld/textflag.go
Normal file
|
|
@ -0,0 +1,133 @@
|
||||||
|
// Copyright 2013 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package ld
|
||||||
|
|
||||||
|
// Writing and reading of Go object files.
|
||||||
|
//
|
||||||
|
// Originally, Go object files were Plan 9 object files, but no longer.
|
||||||
|
// Now they are more like standard object files, in that each symbol is defined
|
||||||
|
// by an associated memory image (bytes) and a list of relocations to apply
|
||||||
|
// during linking. We do not (yet?) use a standard file format, however.
|
||||||
|
// For now, the format is chosen to be as simple as possible to read and write.
|
||||||
|
// It may change for reasons of efficiency, or we may even switch to a
|
||||||
|
// standard file format if there are compelling benefits to doing so.
|
||||||
|
// See golang.org/s/go13linker for more background.
|
||||||
|
//
|
||||||
|
// The file format is:
|
||||||
|
//
|
||||||
|
// - magic header: "\x00\x00go13ld"
|
||||||
|
// - byte 1 - version number
|
||||||
|
// - sequence of strings giving dependencies (imported packages)
|
||||||
|
// - empty string (marks end of sequence)
|
||||||
|
// - sequence of defined symbols
|
||||||
|
// - byte 0xff (marks end of sequence)
|
||||||
|
// - magic footer: "\xff\xffgo13ld"
|
||||||
|
//
|
||||||
|
// All integers are stored in a zigzag varint format.
|
||||||
|
// See golang.org/s/go12symtab for a definition.
|
||||||
|
//
|
||||||
|
// Data blocks and strings are both stored as an integer
|
||||||
|
// followed by that many bytes.
|
||||||
|
//
|
||||||
|
// A symbol reference is a string name followed by a version.
|
||||||
|
// An empty name corresponds to a nil LSym* pointer.
|
||||||
|
//
|
||||||
|
// Each symbol is laid out as the following fields (taken from LSym*):
|
||||||
|
//
|
||||||
|
// - byte 0xfe (sanity check for synchronization)
|
||||||
|
// - type [int]
|
||||||
|
// - name [string]
|
||||||
|
// - version [int]
|
||||||
|
// - flags [int]
|
||||||
|
// 1 dupok
|
||||||
|
// - size [int]
|
||||||
|
// - gotype [symbol reference]
|
||||||
|
// - p [data block]
|
||||||
|
// - nr [int]
|
||||||
|
// - r [nr relocations, sorted by off]
|
||||||
|
//
|
||||||
|
// If type == STEXT, there are a few more fields:
|
||||||
|
//
|
||||||
|
// - args [int]
|
||||||
|
// - locals [int]
|
||||||
|
// - nosplit [int]
|
||||||
|
// - flags [int]
|
||||||
|
// 1 leaf
|
||||||
|
// 2 C function
|
||||||
|
// - nlocal [int]
|
||||||
|
// - local [nlocal automatics]
|
||||||
|
// - pcln [pcln table]
|
||||||
|
//
|
||||||
|
// Each relocation has the encoding:
|
||||||
|
//
|
||||||
|
// - off [int]
|
||||||
|
// - siz [int]
|
||||||
|
// - type [int]
|
||||||
|
// - add [int]
|
||||||
|
// - xadd [int]
|
||||||
|
// - sym [symbol reference]
|
||||||
|
// - xsym [symbol reference]
|
||||||
|
//
|
||||||
|
// Each local has the encoding:
|
||||||
|
//
|
||||||
|
// - asym [symbol reference]
|
||||||
|
// - offset [int]
|
||||||
|
// - type [int]
|
||||||
|
// - gotype [symbol reference]
|
||||||
|
//
|
||||||
|
// The pcln table has the encoding:
|
||||||
|
//
|
||||||
|
// - pcsp [data block]
|
||||||
|
// - pcfile [data block]
|
||||||
|
// - pcline [data block]
|
||||||
|
// - npcdata [int]
|
||||||
|
// - pcdata [npcdata data blocks]
|
||||||
|
// - nfuncdata [int]
|
||||||
|
// - funcdata [nfuncdata symbol references]
|
||||||
|
// - funcdatasym [nfuncdata ints]
|
||||||
|
// - nfile [int]
|
||||||
|
// - file [nfile symbol references]
|
||||||
|
//
|
||||||
|
// The file layout and meaning of type integers are architecture-independent.
|
||||||
|
//
|
||||||
|
// TODO(rsc): The file format is good for a first pass but needs work.
|
||||||
|
// - There are SymID in the object file that should really just be strings.
|
||||||
|
// - The actual symbol memory images are interlaced with the symbol
|
||||||
|
// metadata. They should be separated, to reduce the I/O required to
|
||||||
|
// load just the metadata.
|
||||||
|
// - The symbol references should be shortened, either with a symbol
|
||||||
|
// table or by using a simple backward index to an earlier mentioned symbol.
|
||||||
|
|
||||||
|
// Copyright 2013 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// This file defines flags attached to various functions
|
||||||
|
// and data objects. The compilers, assemblers, and linker must
|
||||||
|
// all agree on these values.
|
||||||
|
|
||||||
|
// Don't profile the marked routine. This flag is deprecated.
|
||||||
|
|
||||||
|
// It is ok for the linker to get multiple of these symbols. It will
|
||||||
|
// pick one of the duplicates to use.
|
||||||
|
|
||||||
|
// Don't insert stack check preamble.
|
||||||
|
|
||||||
|
// Put this data in a read-only section.
|
||||||
|
|
||||||
|
// This data contains no pointers.
|
||||||
|
|
||||||
|
// This is a wrapper function and should not count as disabling 'recover'.
|
||||||
|
|
||||||
|
// This function uses its incoming context register.
|
||||||
|
const (
|
||||||
|
NOPROF = 1
|
||||||
|
DUPOK = 2
|
||||||
|
NOSPLIT = 4
|
||||||
|
RODATA = 8
|
||||||
|
NOPTR = 16
|
||||||
|
WRAPPER = 32
|
||||||
|
NEEDCTXT = 64
|
||||||
|
)
|
||||||
369
src/cmd/internal/ld/util.go
Normal file
369
src/cmd/internal/ld/util.go
Normal file
|
|
@ -0,0 +1,369 @@
|
||||||
|
// Copyright 2015 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package ld
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"bytes"
|
||||||
|
"encoding/binary"
|
||||||
|
"io"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"runtime/pprof"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func cstring(x []byte) string {
|
||||||
|
i := bytes.IndexByte(x, '\x00')
|
||||||
|
if i >= 0 {
|
||||||
|
x = x[:i]
|
||||||
|
}
|
||||||
|
return string(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func plan9quote(s string) string {
|
||||||
|
if s == "" {
|
||||||
|
goto needquote
|
||||||
|
}
|
||||||
|
for i := 0; i < len(s); i++ {
|
||||||
|
if s[i] <= ' ' || s[i] == '\'' {
|
||||||
|
goto needquote
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return s
|
||||||
|
|
||||||
|
needquote:
|
||||||
|
return "'" + strings.Replace(s, "'", "''", -1) + "'"
|
||||||
|
}
|
||||||
|
|
||||||
|
func tokenize(s string) []string {
|
||||||
|
var f []string
|
||||||
|
for {
|
||||||
|
s = strings.TrimLeft(s, " \t\r\n")
|
||||||
|
if s == "" {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
quote := false
|
||||||
|
i := 0
|
||||||
|
for ; i < len(s); i++ {
|
||||||
|
if s[i] == '\'' {
|
||||||
|
if quote && i+1 < len(s) && s[i+1] == '\'' {
|
||||||
|
i++
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
quote = !quote
|
||||||
|
}
|
||||||
|
if !quote && (s[i] == ' ' || s[i] == '\t' || s[i] == '\r' || s[i] == '\n') {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
next := s[:i]
|
||||||
|
s = s[i:]
|
||||||
|
if strings.Contains(next, "'") {
|
||||||
|
var buf []byte
|
||||||
|
quote := false
|
||||||
|
for i := 0; i < len(next); i++ {
|
||||||
|
if next[i] == '\'' {
|
||||||
|
if quote && i+1 < len(next) && next[i+1] == '\'' {
|
||||||
|
i++
|
||||||
|
buf = append(buf, '\'')
|
||||||
|
}
|
||||||
|
quote = !quote
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
buf = append(buf, next[i])
|
||||||
|
}
|
||||||
|
next = string(buf)
|
||||||
|
}
|
||||||
|
f = append(f, next)
|
||||||
|
}
|
||||||
|
return f
|
||||||
|
}
|
||||||
|
|
||||||
|
func cutStringAtNUL(s string) string {
|
||||||
|
if i := strings.Index(s, "\x00"); i >= 0 {
|
||||||
|
s = s[:i]
|
||||||
|
}
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
type Biobuf struct {
|
||||||
|
unget [2]int
|
||||||
|
numUnget int
|
||||||
|
f *os.File
|
||||||
|
r *bufio.Reader
|
||||||
|
w *bufio.Writer
|
||||||
|
linelen int
|
||||||
|
}
|
||||||
|
|
||||||
|
func Bopenw(name string) (*Biobuf, error) {
|
||||||
|
f, err := os.Create(name)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &Biobuf{f: f, w: bufio.NewWriter(f)}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func Bopenr(name string) (*Biobuf, error) {
|
||||||
|
f, err := os.Open(name)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &Biobuf{f: f, r: bufio.NewReader(f)}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func Binitw(w *os.File) *Biobuf {
|
||||||
|
return &Biobuf{w: bufio.NewWriter(w), f: w}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *Biobuf) Write(p []byte) (int, error) {
|
||||||
|
return b.w.Write(p)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Bwritestring(b *Biobuf, p string) (int, error) {
|
||||||
|
return b.w.WriteString(p)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Bseek(b *Biobuf, offset int64, whence int) int64 {
|
||||||
|
if b.w != nil {
|
||||||
|
if err := b.w.Flush(); err != nil {
|
||||||
|
log.Fatalf("writing output: %v", err)
|
||||||
|
}
|
||||||
|
} else if b.r != nil {
|
||||||
|
if whence == 1 {
|
||||||
|
offset -= int64(b.r.Buffered())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
off, err := b.f.Seek(offset, whence)
|
||||||
|
if err != nil {
|
||||||
|
log.Panicf("seeking in output [%d %d %p]: %v", offset, whence, b.f, err)
|
||||||
|
}
|
||||||
|
if b.r != nil {
|
||||||
|
b.r.Reset(b.f)
|
||||||
|
}
|
||||||
|
return off
|
||||||
|
}
|
||||||
|
|
||||||
|
func Boffset(b *Biobuf) int64 {
|
||||||
|
if b.w != nil {
|
||||||
|
if err := b.w.Flush(); err != nil {
|
||||||
|
log.Fatalf("writing output: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
off, err := b.f.Seek(0, 1)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("seeking in output [0, 1]: %v", err)
|
||||||
|
}
|
||||||
|
if b.r != nil {
|
||||||
|
off -= int64(b.r.Buffered())
|
||||||
|
}
|
||||||
|
return off
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *Biobuf) Flush() error {
|
||||||
|
return b.w.Flush()
|
||||||
|
}
|
||||||
|
|
||||||
|
func Bwrite(b *Biobuf, p []byte) (int, error) {
|
||||||
|
return b.w.Write(p)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Bputc(b *Biobuf, c byte) {
|
||||||
|
b.w.WriteByte(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
const Beof = -1
|
||||||
|
|
||||||
|
func Bread(b *Biobuf, p []byte) int {
|
||||||
|
if b.numUnget > 0 {
|
||||||
|
Bseek(b, -int64(b.numUnget), 1)
|
||||||
|
b.numUnget = 0
|
||||||
|
}
|
||||||
|
n, err := io.ReadFull(b.r, p)
|
||||||
|
if n == 0 {
|
||||||
|
if err != nil && err != io.EOF {
|
||||||
|
n = -1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return n
|
||||||
|
}
|
||||||
|
|
||||||
|
func Bgetc(b *Biobuf) int {
|
||||||
|
if b.numUnget > 0 {
|
||||||
|
b.numUnget--
|
||||||
|
return int(b.unget[b.numUnget])
|
||||||
|
}
|
||||||
|
c, err := b.r.ReadByte()
|
||||||
|
r := int(c)
|
||||||
|
if err != nil {
|
||||||
|
r = -1
|
||||||
|
}
|
||||||
|
b.unget[1] = b.unget[0]
|
||||||
|
b.unget[0] = r
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
func Bgetrune(b *Biobuf) int {
|
||||||
|
if b.numUnget > 0 {
|
||||||
|
Bseek(b, -int64(b.numUnget), 1)
|
||||||
|
b.numUnget = 0
|
||||||
|
}
|
||||||
|
r, _, err := b.r.ReadRune()
|
||||||
|
if err != nil {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
return int(r)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Bungetrune(b *Biobuf) {
|
||||||
|
b.r.UnreadRune()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *Biobuf) Read(p []byte) (int, error) {
|
||||||
|
return b.r.Read(p)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Brdline(b *Biobuf, delim int) string {
|
||||||
|
if b.numUnget > 0 {
|
||||||
|
Bseek(b, -int64(b.numUnget), 1)
|
||||||
|
b.numUnget = 0
|
||||||
|
}
|
||||||
|
s, err := b.r.ReadBytes(byte(delim))
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("reading input: %v", err)
|
||||||
|
}
|
||||||
|
b.linelen = len(s)
|
||||||
|
return string(s)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Brdstr(b *Biobuf, delim int, cut int) string {
|
||||||
|
if b.numUnget > 0 {
|
||||||
|
Bseek(b, -int64(b.numUnget), 1)
|
||||||
|
b.numUnget = 0
|
||||||
|
}
|
||||||
|
s, err := b.r.ReadString(byte(delim))
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("reading input: %v", err)
|
||||||
|
}
|
||||||
|
if len(s) > 0 && cut > 0 {
|
||||||
|
s = s[:len(s)-1]
|
||||||
|
}
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
func Access(name string, mode int) int {
|
||||||
|
if mode != 0 {
|
||||||
|
panic("bad access")
|
||||||
|
}
|
||||||
|
_, err := os.Stat(name)
|
||||||
|
if err != nil {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func Blinelen(b *Biobuf) int {
|
||||||
|
return b.linelen
|
||||||
|
}
|
||||||
|
|
||||||
|
func Bungetc(b *Biobuf) {
|
||||||
|
b.numUnget++
|
||||||
|
}
|
||||||
|
|
||||||
|
func Bflush(b *Biobuf) error {
|
||||||
|
return b.w.Flush()
|
||||||
|
}
|
||||||
|
|
||||||
|
func Bterm(b *Biobuf) error {
|
||||||
|
var err error
|
||||||
|
if b.w != nil {
|
||||||
|
err = b.w.Flush()
|
||||||
|
}
|
||||||
|
err1 := b.f.Close()
|
||||||
|
if err == nil {
|
||||||
|
err = err1
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// strings.Compare, introduced in Go 1.5.
|
||||||
|
func stringsCompare(a, b string) int {
|
||||||
|
if a == b {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
if a < b {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
return +1
|
||||||
|
}
|
||||||
|
|
||||||
|
var atExitFuncs []func()
|
||||||
|
|
||||||
|
func AtExit(f func()) {
|
||||||
|
atExitFuncs = append(atExitFuncs, f)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Exit(code int) {
|
||||||
|
for i := len(atExitFuncs) - 1; i >= 0; i-- {
|
||||||
|
f := atExitFuncs[i]
|
||||||
|
atExitFuncs = atExitFuncs[:i]
|
||||||
|
f()
|
||||||
|
}
|
||||||
|
os.Exit(code)
|
||||||
|
}
|
||||||
|
|
||||||
|
var cpuprofile string
|
||||||
|
var memprofile string
|
||||||
|
|
||||||
|
func startProfile() {
|
||||||
|
if cpuprofile != "" {
|
||||||
|
f, err := os.Create(cpuprofile)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("%v", err)
|
||||||
|
}
|
||||||
|
if err := pprof.StartCPUProfile(f); err != nil {
|
||||||
|
log.Fatalf("%v", err)
|
||||||
|
}
|
||||||
|
AtExit(pprof.StopCPUProfile)
|
||||||
|
}
|
||||||
|
if memprofile != "" {
|
||||||
|
f, err := os.Create(memprofile)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("%v", err)
|
||||||
|
}
|
||||||
|
AtExit(func() {
|
||||||
|
if err := pprof.WriteHeapProfile(f); err != nil {
|
||||||
|
log.Fatalf("%v", err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func artrim(x []byte) string {
|
||||||
|
i := 0
|
||||||
|
j := len(x)
|
||||||
|
for i < len(x) && x[i] == ' ' {
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
for j > i && x[j-1] == ' ' {
|
||||||
|
j--
|
||||||
|
}
|
||||||
|
return string(x[i:j])
|
||||||
|
}
|
||||||
|
|
||||||
|
func stringtouint32(x []uint32, s string) {
|
||||||
|
for i := 0; len(s) > 0; i++ {
|
||||||
|
var buf [4]byte
|
||||||
|
s = s[copy(buf[:], s):]
|
||||||
|
x[i] = binary.LittleEndian.Uint32(buf[:])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var start = time.Now()
|
||||||
|
|
||||||
|
func elapsed() float64 {
|
||||||
|
return time.Since(start).Seconds()
|
||||||
|
}
|
||||||
1
src/cmd/internal/ld/z.go
Normal file
1
src/cmd/internal/ld/z.go
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
package ld
|
||||||
777
src/cmd/new5l/asm.go
Normal file
777
src/cmd/new5l/asm.go
Normal file
|
|
@ -0,0 +1,777 @@
|
||||||
|
// Inferno utils/5l/asm.c
|
||||||
|
// http://code.google.com/p/inferno-os/source/browse/utils/5l/asm.c
|
||||||
|
//
|
||||||
|
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
|
||||||
|
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
|
||||||
|
// Portions Copyright © 1997-1999 Vita Nuova Limited
|
||||||
|
// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
|
||||||
|
// Portions Copyright © 2004,2006 Bruce Ellis
|
||||||
|
// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
|
||||||
|
// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
|
||||||
|
// Portions Copyright © 2009 The Go Authors. All rights reserved.
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
|
// in the Software without restriction, including without limitation the rights
|
||||||
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
// THE SOFTWARE.
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"cmd/internal/obj"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
)
|
||||||
|
import "cmd/internal/ld"
|
||||||
|
|
||||||
|
func needlib(name string) int {
|
||||||
|
var p string
|
||||||
|
var s *ld.LSym
|
||||||
|
|
||||||
|
if name[0] == '\x00' {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
/* reuse hash code in symbol table */
|
||||||
|
p = fmt.Sprintf(".dynlib.%s", name)
|
||||||
|
|
||||||
|
s = ld.Linklookup(ld.Ctxt, p, 0)
|
||||||
|
|
||||||
|
if s.Type == 0 {
|
||||||
|
s.Type = 100 // avoid SDATA, etc.
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func gentext() {
|
||||||
|
}
|
||||||
|
|
||||||
|
// Preserve highest 8 bits of a, and do addition to lower 24-bit
|
||||||
|
// of a and b; used to adjust ARM branch intruction's target
|
||||||
|
func braddoff(a int32, b int32) int32 {
|
||||||
|
return int32((uint32(a))&0xff000000 | 0x00ffffff&uint32(a+b))
|
||||||
|
}
|
||||||
|
|
||||||
|
func adddynrela(rel *ld.LSym, s *ld.LSym, r *ld.Reloc) {
|
||||||
|
ld.Addaddrplus(ld.Ctxt, rel, s, int64(r.Off))
|
||||||
|
ld.Adduint32(ld.Ctxt, rel, ld.R_ARM_RELATIVE)
|
||||||
|
}
|
||||||
|
|
||||||
|
func adddynrel(s *ld.LSym, r *ld.Reloc) {
|
||||||
|
var targ *ld.LSym
|
||||||
|
var rel *ld.LSym
|
||||||
|
|
||||||
|
targ = r.Sym
|
||||||
|
ld.Ctxt.Cursym = s
|
||||||
|
|
||||||
|
switch r.Type {
|
||||||
|
default:
|
||||||
|
if r.Type >= 256 {
|
||||||
|
ld.Diag("unexpected relocation type %d", r.Type)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle relocations found in ELF object files.
|
||||||
|
case 256 + ld.R_ARM_PLT32:
|
||||||
|
r.Type = ld.R_CALLARM
|
||||||
|
|
||||||
|
if targ.Type == ld.SDYNIMPORT {
|
||||||
|
addpltsym(ld.Ctxt, targ)
|
||||||
|
r.Sym = ld.Linklookup(ld.Ctxt, ".plt", 0)
|
||||||
|
r.Add = int64(braddoff(int32(r.Add), targ.Plt/4))
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
|
case 256 + ld.R_ARM_THM_PC22: // R_ARM_THM_CALL
|
||||||
|
ld.Diag("R_ARM_THM_CALL, are you using -marm?")
|
||||||
|
|
||||||
|
ld.Errorexit()
|
||||||
|
return
|
||||||
|
|
||||||
|
case 256 + ld.R_ARM_GOT32: // R_ARM_GOT_BREL
|
||||||
|
if targ.Type != ld.SDYNIMPORT {
|
||||||
|
addgotsyminternal(ld.Ctxt, targ)
|
||||||
|
} else {
|
||||||
|
addgotsym(ld.Ctxt, targ)
|
||||||
|
}
|
||||||
|
|
||||||
|
r.Type = ld.R_CONST // write r->add during relocsym
|
||||||
|
r.Sym = nil
|
||||||
|
r.Add += int64(targ.Got)
|
||||||
|
return
|
||||||
|
|
||||||
|
case 256 + ld.R_ARM_GOT_PREL: // GOT(nil) + A - nil
|
||||||
|
if targ.Type != ld.SDYNIMPORT {
|
||||||
|
addgotsyminternal(ld.Ctxt, targ)
|
||||||
|
} else {
|
||||||
|
addgotsym(ld.Ctxt, targ)
|
||||||
|
}
|
||||||
|
|
||||||
|
r.Type = ld.R_PCREL
|
||||||
|
r.Sym = ld.Linklookup(ld.Ctxt, ".got", 0)
|
||||||
|
r.Add += int64(targ.Got) + 4
|
||||||
|
return
|
||||||
|
|
||||||
|
case 256 + ld.R_ARM_GOTOFF: // R_ARM_GOTOFF32
|
||||||
|
r.Type = ld.R_GOTOFF
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
|
case 256 + ld.R_ARM_GOTPC: // R_ARM_BASE_PREL
|
||||||
|
r.Type = ld.R_PCREL
|
||||||
|
|
||||||
|
r.Sym = ld.Linklookup(ld.Ctxt, ".got", 0)
|
||||||
|
r.Add += 4
|
||||||
|
return
|
||||||
|
|
||||||
|
case 256 + ld.R_ARM_CALL:
|
||||||
|
r.Type = ld.R_CALLARM
|
||||||
|
if targ.Type == ld.SDYNIMPORT {
|
||||||
|
addpltsym(ld.Ctxt, targ)
|
||||||
|
r.Sym = ld.Linklookup(ld.Ctxt, ".plt", 0)
|
||||||
|
r.Add = int64(braddoff(int32(r.Add), targ.Plt/4))
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
|
case 256 + ld.R_ARM_REL32: // R_ARM_REL32
|
||||||
|
r.Type = ld.R_PCREL
|
||||||
|
|
||||||
|
r.Add += 4
|
||||||
|
return
|
||||||
|
|
||||||
|
case 256 + ld.R_ARM_ABS32:
|
||||||
|
if targ.Type == ld.SDYNIMPORT {
|
||||||
|
ld.Diag("unexpected R_ARM_ABS32 relocation for dynamic symbol %s", targ.Name)
|
||||||
|
}
|
||||||
|
r.Type = ld.R_ADDR
|
||||||
|
return
|
||||||
|
|
||||||
|
// we can just ignore this, because we are targeting ARM V5+ anyway
|
||||||
|
case 256 + ld.R_ARM_V4BX:
|
||||||
|
if r.Sym != nil {
|
||||||
|
// R_ARM_V4BX is ABS relocation, so this symbol is a dummy symbol, ignore it
|
||||||
|
r.Sym.Type = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
r.Sym = nil
|
||||||
|
return
|
||||||
|
|
||||||
|
case 256 + ld.R_ARM_PC24,
|
||||||
|
256 + ld.R_ARM_JUMP24:
|
||||||
|
r.Type = ld.R_CALLARM
|
||||||
|
if targ.Type == ld.SDYNIMPORT {
|
||||||
|
addpltsym(ld.Ctxt, targ)
|
||||||
|
r.Sym = ld.Linklookup(ld.Ctxt, ".plt", 0)
|
||||||
|
r.Add = int64(braddoff(int32(r.Add), targ.Plt/4))
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle references to ELF symbols from our own object files.
|
||||||
|
if targ.Type != ld.SDYNIMPORT {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
switch r.Type {
|
||||||
|
case ld.R_CALLARM:
|
||||||
|
addpltsym(ld.Ctxt, targ)
|
||||||
|
r.Sym = ld.Linklookup(ld.Ctxt, ".plt", 0)
|
||||||
|
r.Add = int64(targ.Plt)
|
||||||
|
return
|
||||||
|
|
||||||
|
case ld.R_ADDR:
|
||||||
|
if s.Type != ld.SDATA {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if ld.Iself {
|
||||||
|
adddynsym(ld.Ctxt, targ)
|
||||||
|
rel = ld.Linklookup(ld.Ctxt, ".rel", 0)
|
||||||
|
ld.Addaddrplus(ld.Ctxt, rel, s, int64(r.Off))
|
||||||
|
ld.Adduint32(ld.Ctxt, rel, ld.ELF32_R_INFO(uint32(targ.Dynid), ld.R_ARM_GLOB_DAT)) // we need a nil + A dynmic reloc
|
||||||
|
r.Type = ld.R_CONST // write r->add during relocsym
|
||||||
|
r.Sym = nil
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ld.Ctxt.Cursym = s
|
||||||
|
ld.Diag("unsupported relocation for dynamic symbol %s (type=%d stype=%d)", targ.Name, r.Type, targ.Type)
|
||||||
|
}
|
||||||
|
|
||||||
|
func elfreloc1(r *ld.Reloc, sectoff int64) int {
|
||||||
|
var elfsym int32
|
||||||
|
|
||||||
|
ld.Thearch.Lput(uint32(sectoff))
|
||||||
|
|
||||||
|
elfsym = r.Xsym.Elfsym
|
||||||
|
switch r.Type {
|
||||||
|
default:
|
||||||
|
return -1
|
||||||
|
|
||||||
|
case ld.R_ADDR:
|
||||||
|
if r.Siz == 4 {
|
||||||
|
ld.Thearch.Lput(ld.R_ARM_ABS32 | uint32(elfsym)<<8)
|
||||||
|
} else {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|
||||||
|
case ld.R_PCREL:
|
||||||
|
if r.Siz == 4 {
|
||||||
|
ld.Thearch.Lput(ld.R_ARM_REL32 | uint32(elfsym)<<8)
|
||||||
|
} else {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|
||||||
|
case ld.R_CALLARM:
|
||||||
|
if r.Siz == 4 {
|
||||||
|
if r.Add&0xff000000 == 0xeb000000 { // BL
|
||||||
|
ld.Thearch.Lput(ld.R_ARM_CALL | uint32(elfsym)<<8)
|
||||||
|
} else {
|
||||||
|
ld.Thearch.Lput(ld.R_ARM_JUMP24 | uint32(elfsym)<<8)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|
||||||
|
case ld.R_TLS:
|
||||||
|
if r.Siz == 4 {
|
||||||
|
if ld.Flag_shared != 0 {
|
||||||
|
ld.Thearch.Lput(ld.R_ARM_TLS_IE32 | uint32(elfsym)<<8)
|
||||||
|
} else {
|
||||||
|
ld.Thearch.Lput(ld.R_ARM_TLS_LE32 | uint32(elfsym)<<8)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func elfsetupplt() {
|
||||||
|
var plt *ld.LSym
|
||||||
|
var got *ld.LSym
|
||||||
|
|
||||||
|
plt = ld.Linklookup(ld.Ctxt, ".plt", 0)
|
||||||
|
got = ld.Linklookup(ld.Ctxt, ".got.plt", 0)
|
||||||
|
if plt.Size == 0 {
|
||||||
|
// str lr, [sp, #-4]!
|
||||||
|
ld.Adduint32(ld.Ctxt, plt, 0xe52de004)
|
||||||
|
|
||||||
|
// ldr lr, [pc, #4]
|
||||||
|
ld.Adduint32(ld.Ctxt, plt, 0xe59fe004)
|
||||||
|
|
||||||
|
// add lr, pc, lr
|
||||||
|
ld.Adduint32(ld.Ctxt, plt, 0xe08fe00e)
|
||||||
|
|
||||||
|
// ldr pc, [lr, #8]!
|
||||||
|
ld.Adduint32(ld.Ctxt, plt, 0xe5bef008)
|
||||||
|
|
||||||
|
// .word &GLOBAL_OFFSET_TABLE[0] - .
|
||||||
|
ld.Addpcrelplus(ld.Ctxt, plt, got, 4)
|
||||||
|
|
||||||
|
// the first .plt entry requires 3 .plt.got entries
|
||||||
|
ld.Adduint32(ld.Ctxt, got, 0)
|
||||||
|
|
||||||
|
ld.Adduint32(ld.Ctxt, got, 0)
|
||||||
|
ld.Adduint32(ld.Ctxt, got, 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func machoreloc1(r *ld.Reloc, sectoff int64) int {
|
||||||
|
var v uint32
|
||||||
|
var rs *ld.LSym
|
||||||
|
|
||||||
|
rs = r.Xsym
|
||||||
|
|
||||||
|
if rs.Type == ld.SHOSTOBJ || r.Type == ld.R_CALLARM {
|
||||||
|
if rs.Dynid < 0 {
|
||||||
|
ld.Diag("reloc %d to non-macho symbol %s type=%d", r.Type, rs.Name, rs.Type)
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|
||||||
|
v = uint32(rs.Dynid)
|
||||||
|
v |= 1 << 27 // external relocation
|
||||||
|
} else {
|
||||||
|
v = uint32((rs.Sect.(*ld.Section)).Extnum)
|
||||||
|
if v == 0 {
|
||||||
|
ld.Diag("reloc %d to symbol %s in non-macho section %s type=%d", r.Type, rs.Name, (rs.Sect.(*ld.Section)).Name, rs.Type)
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch r.Type {
|
||||||
|
default:
|
||||||
|
return -1
|
||||||
|
|
||||||
|
case ld.R_ADDR:
|
||||||
|
v |= ld.MACHO_GENERIC_RELOC_VANILLA << 28
|
||||||
|
|
||||||
|
case ld.R_CALLARM:
|
||||||
|
v |= 1 << 24 // pc-relative bit
|
||||||
|
v |= ld.MACHO_ARM_RELOC_BR24 << 28
|
||||||
|
}
|
||||||
|
|
||||||
|
switch r.Siz {
|
||||||
|
default:
|
||||||
|
return -1
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
v |= 0 << 25
|
||||||
|
|
||||||
|
case 2:
|
||||||
|
v |= 1 << 25
|
||||||
|
|
||||||
|
case 4:
|
||||||
|
v |= 2 << 25
|
||||||
|
|
||||||
|
case 8:
|
||||||
|
v |= 3 << 25
|
||||||
|
}
|
||||||
|
|
||||||
|
ld.Thearch.Lput(uint32(sectoff))
|
||||||
|
ld.Thearch.Lput(v)
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func archreloc(r *ld.Reloc, s *ld.LSym, val *int64) int {
|
||||||
|
var rs *ld.LSym
|
||||||
|
|
||||||
|
if ld.Linkmode == ld.LinkExternal {
|
||||||
|
switch r.Type {
|
||||||
|
case ld.R_CALLARM:
|
||||||
|
r.Done = 0
|
||||||
|
|
||||||
|
// set up addend for eventual relocation via outer symbol.
|
||||||
|
rs = r.Sym
|
||||||
|
|
||||||
|
r.Xadd = r.Add
|
||||||
|
if r.Xadd&0x800000 != 0 {
|
||||||
|
r.Xadd |= ^0xffffff
|
||||||
|
}
|
||||||
|
r.Xadd *= 4
|
||||||
|
for rs.Outer != nil {
|
||||||
|
r.Xadd += ld.Symaddr(rs) - ld.Symaddr(rs.Outer)
|
||||||
|
rs = rs.Outer
|
||||||
|
}
|
||||||
|
|
||||||
|
if rs.Type != ld.SHOSTOBJ && rs.Sect == nil {
|
||||||
|
ld.Diag("missing section for %s", rs.Name)
|
||||||
|
}
|
||||||
|
r.Xsym = rs
|
||||||
|
|
||||||
|
// ld64 for arm seems to want the symbol table to contain offset
|
||||||
|
// into the section rather than pseudo virtual address that contains
|
||||||
|
// the section load address.
|
||||||
|
// we need to compensate that by removing the instruction's address
|
||||||
|
// from addend.
|
||||||
|
if ld.HEADTYPE == ld.Hdarwin {
|
||||||
|
r.Xadd -= ld.Symaddr(s) + int64(r.Off)
|
||||||
|
}
|
||||||
|
|
||||||
|
*val = int64(braddoff(int32(0xff000000&uint32(r.Add)), int32(0xffffff&uint32(r.Xadd/4))))
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|
||||||
|
switch r.Type {
|
||||||
|
case ld.R_CONST:
|
||||||
|
*val = r.Add
|
||||||
|
return 0
|
||||||
|
|
||||||
|
case ld.R_GOTOFF:
|
||||||
|
*val = ld.Symaddr(r.Sym) + r.Add - ld.Symaddr(ld.Linklookup(ld.Ctxt, ".got", 0))
|
||||||
|
return 0
|
||||||
|
|
||||||
|
// The following three arch specific relocations are only for generation of
|
||||||
|
// Linux/ARM ELF's PLT entry (3 assembler instruction)
|
||||||
|
case ld.R_PLT0: // add ip, pc, #0xXX00000
|
||||||
|
if ld.Symaddr(ld.Linklookup(ld.Ctxt, ".got.plt", 0)) < ld.Symaddr(ld.Linklookup(ld.Ctxt, ".plt", 0)) {
|
||||||
|
ld.Diag(".got.plt should be placed after .plt section.")
|
||||||
|
}
|
||||||
|
*val = 0xe28fc600 + (0xff & (int64(uint32(ld.Symaddr(r.Sym)-(ld.Symaddr(ld.Linklookup(ld.Ctxt, ".plt", 0))+int64(r.Off))+r.Add)) >> 20))
|
||||||
|
return 0
|
||||||
|
|
||||||
|
case ld.R_PLT1: // add ip, ip, #0xYY000
|
||||||
|
*val = 0xe28cca00 + (0xff & (int64(uint32(ld.Symaddr(r.Sym)-(ld.Symaddr(ld.Linklookup(ld.Ctxt, ".plt", 0))+int64(r.Off))+r.Add+4)) >> 12))
|
||||||
|
|
||||||
|
return 0
|
||||||
|
|
||||||
|
case ld.R_PLT2: // ldr pc, [ip, #0xZZZ]!
|
||||||
|
*val = 0xe5bcf000 + (0xfff & int64(uint32(ld.Symaddr(r.Sym)-(ld.Symaddr(ld.Linklookup(ld.Ctxt, ".plt", 0))+int64(r.Off))+r.Add+8)))
|
||||||
|
|
||||||
|
return 0
|
||||||
|
|
||||||
|
case ld.R_CALLARM: // bl XXXXXX or b YYYYYY
|
||||||
|
*val = int64(braddoff(int32(0xff000000&uint32(r.Add)), int32(0xffffff&uint32((ld.Symaddr(r.Sym)+int64((uint32(r.Add))*4)-(s.Value+int64(r.Off)))/4))))
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|
||||||
|
func archrelocvariant(r *ld.Reloc, s *ld.LSym, t int64) int64 {
|
||||||
|
log.Fatalf("unexpected relocation variant")
|
||||||
|
return t
|
||||||
|
}
|
||||||
|
|
||||||
|
func addpltreloc(ctxt *ld.Link, plt *ld.LSym, got *ld.LSym, sym *ld.LSym, typ int) *ld.Reloc {
|
||||||
|
var r *ld.Reloc
|
||||||
|
|
||||||
|
r = ld.Addrel(plt)
|
||||||
|
r.Sym = got
|
||||||
|
r.Off = int32(plt.Size)
|
||||||
|
r.Siz = 4
|
||||||
|
r.Type = int32(typ)
|
||||||
|
r.Add = int64(sym.Got) - 8
|
||||||
|
|
||||||
|
plt.Reachable = true
|
||||||
|
plt.Size += 4
|
||||||
|
ld.Symgrow(ctxt, plt, plt.Size)
|
||||||
|
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
func addpltsym(ctxt *ld.Link, s *ld.LSym) {
|
||||||
|
var plt *ld.LSym
|
||||||
|
var got *ld.LSym
|
||||||
|
var rel *ld.LSym
|
||||||
|
|
||||||
|
if s.Plt >= 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
adddynsym(ctxt, s)
|
||||||
|
|
||||||
|
if ld.Iself {
|
||||||
|
plt = ld.Linklookup(ctxt, ".plt", 0)
|
||||||
|
got = ld.Linklookup(ctxt, ".got.plt", 0)
|
||||||
|
rel = ld.Linklookup(ctxt, ".rel.plt", 0)
|
||||||
|
if plt.Size == 0 {
|
||||||
|
elfsetupplt()
|
||||||
|
}
|
||||||
|
|
||||||
|
// .got entry
|
||||||
|
s.Got = int32(got.Size)
|
||||||
|
|
||||||
|
// In theory, all GOT should point to the first PLT entry,
|
||||||
|
// Linux/ARM's dynamic linker will do that for us, but FreeBSD/ARM's
|
||||||
|
// dynamic linker won't, so we'd better do it ourselves.
|
||||||
|
ld.Addaddrplus(ctxt, got, plt, 0)
|
||||||
|
|
||||||
|
// .plt entry, this depends on the .got entry
|
||||||
|
s.Plt = int32(plt.Size)
|
||||||
|
|
||||||
|
addpltreloc(ctxt, plt, got, s, ld.R_PLT0) // add lr, pc, #0xXX00000
|
||||||
|
addpltreloc(ctxt, plt, got, s, ld.R_PLT1) // add lr, lr, #0xYY000
|
||||||
|
addpltreloc(ctxt, plt, got, s, ld.R_PLT2) // ldr pc, [lr, #0xZZZ]!
|
||||||
|
|
||||||
|
// rel
|
||||||
|
ld.Addaddrplus(ctxt, rel, got, int64(s.Got))
|
||||||
|
|
||||||
|
ld.Adduint32(ctxt, rel, ld.ELF32_R_INFO(uint32(s.Dynid), ld.R_ARM_JUMP_SLOT))
|
||||||
|
} else {
|
||||||
|
ld.Diag("addpltsym: unsupported binary format")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func addgotsyminternal(ctxt *ld.Link, s *ld.LSym) {
|
||||||
|
var got *ld.LSym
|
||||||
|
|
||||||
|
if s.Got >= 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
got = ld.Linklookup(ctxt, ".got", 0)
|
||||||
|
s.Got = int32(got.Size)
|
||||||
|
|
||||||
|
ld.Addaddrplus(ctxt, got, s, 0)
|
||||||
|
|
||||||
|
if ld.Iself {
|
||||||
|
} else {
|
||||||
|
ld.Diag("addgotsyminternal: unsupported binary format")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func addgotsym(ctxt *ld.Link, s *ld.LSym) {
|
||||||
|
var got *ld.LSym
|
||||||
|
var rel *ld.LSym
|
||||||
|
|
||||||
|
if s.Got >= 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
adddynsym(ctxt, s)
|
||||||
|
got = ld.Linklookup(ctxt, ".got", 0)
|
||||||
|
s.Got = int32(got.Size)
|
||||||
|
ld.Adduint32(ctxt, got, 0)
|
||||||
|
|
||||||
|
if ld.Iself {
|
||||||
|
rel = ld.Linklookup(ctxt, ".rel", 0)
|
||||||
|
ld.Addaddrplus(ctxt, rel, got, int64(s.Got))
|
||||||
|
ld.Adduint32(ctxt, rel, ld.ELF32_R_INFO(uint32(s.Dynid), ld.R_ARM_GLOB_DAT))
|
||||||
|
} else {
|
||||||
|
ld.Diag("addgotsym: unsupported binary format")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func adddynsym(ctxt *ld.Link, s *ld.LSym) {
|
||||||
|
var d *ld.LSym
|
||||||
|
var t int
|
||||||
|
var name string
|
||||||
|
|
||||||
|
if s.Dynid >= 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if ld.Iself {
|
||||||
|
s.Dynid = int32(ld.Nelfsym)
|
||||||
|
ld.Nelfsym++
|
||||||
|
|
||||||
|
d = ld.Linklookup(ctxt, ".dynsym", 0)
|
||||||
|
|
||||||
|
/* name */
|
||||||
|
name = s.Extname
|
||||||
|
|
||||||
|
ld.Adduint32(ctxt, d, uint32(ld.Addstring(ld.Linklookup(ctxt, ".dynstr", 0), name)))
|
||||||
|
|
||||||
|
/* value */
|
||||||
|
if s.Type == ld.SDYNIMPORT {
|
||||||
|
ld.Adduint32(ctxt, d, 0)
|
||||||
|
} else {
|
||||||
|
ld.Addaddr(ctxt, d, s)
|
||||||
|
}
|
||||||
|
|
||||||
|
/* size */
|
||||||
|
ld.Adduint32(ctxt, d, 0)
|
||||||
|
|
||||||
|
/* type */
|
||||||
|
t = ld.STB_GLOBAL << 4
|
||||||
|
|
||||||
|
if (s.Cgoexport&ld.CgoExportDynamic != 0) && s.Type&ld.SMASK == ld.STEXT {
|
||||||
|
t |= ld.STT_FUNC
|
||||||
|
} else {
|
||||||
|
t |= ld.STT_OBJECT
|
||||||
|
}
|
||||||
|
ld.Adduint8(ctxt, d, uint8(t))
|
||||||
|
ld.Adduint8(ctxt, d, 0)
|
||||||
|
|
||||||
|
/* shndx */
|
||||||
|
if s.Type == ld.SDYNIMPORT {
|
||||||
|
ld.Adduint16(ctxt, d, ld.SHN_UNDEF)
|
||||||
|
} else {
|
||||||
|
ld.Adduint16(ctxt, d, 1)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ld.Diag("adddynsym: unsupported binary format")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func adddynlib(lib string) {
|
||||||
|
var s *ld.LSym
|
||||||
|
|
||||||
|
if needlib(lib) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if ld.Iself {
|
||||||
|
s = ld.Linklookup(ld.Ctxt, ".dynstr", 0)
|
||||||
|
if s.Size == 0 {
|
||||||
|
ld.Addstring(s, "")
|
||||||
|
}
|
||||||
|
ld.Elfwritedynent(ld.Linklookup(ld.Ctxt, ".dynamic", 0), ld.DT_NEEDED, uint64(ld.Addstring(s, lib)))
|
||||||
|
} else if ld.HEADTYPE == ld.Hdarwin {
|
||||||
|
ld.Machoadddynlib(lib)
|
||||||
|
} else {
|
||||||
|
ld.Diag("adddynlib: unsupported binary format")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func asmb() {
|
||||||
|
var symo uint32
|
||||||
|
var dwarfoff uint32
|
||||||
|
var machlink uint32
|
||||||
|
var sect *ld.Section
|
||||||
|
var sym *ld.LSym
|
||||||
|
var i int
|
||||||
|
|
||||||
|
if ld.Debug['v'] != 0 {
|
||||||
|
fmt.Fprintf(&ld.Bso, "%5.2f asmb\n", obj.Cputime())
|
||||||
|
}
|
||||||
|
ld.Bflush(&ld.Bso)
|
||||||
|
|
||||||
|
if ld.Iself {
|
||||||
|
ld.Asmbelfsetup()
|
||||||
|
}
|
||||||
|
|
||||||
|
sect = ld.Segtext.Sect
|
||||||
|
ld.Cseek(int64(sect.Vaddr - ld.Segtext.Vaddr + ld.Segtext.Fileoff))
|
||||||
|
ld.Codeblk(int64(sect.Vaddr), int64(sect.Length))
|
||||||
|
for sect = sect.Next; sect != nil; sect = sect.Next {
|
||||||
|
ld.Cseek(int64(sect.Vaddr - ld.Segtext.Vaddr + ld.Segtext.Fileoff))
|
||||||
|
ld.Datblk(int64(sect.Vaddr), int64(sect.Length))
|
||||||
|
}
|
||||||
|
|
||||||
|
if ld.Segrodata.Filelen > 0 {
|
||||||
|
if ld.Debug['v'] != 0 {
|
||||||
|
fmt.Fprintf(&ld.Bso, "%5.2f rodatblk\n", obj.Cputime())
|
||||||
|
}
|
||||||
|
ld.Bflush(&ld.Bso)
|
||||||
|
|
||||||
|
ld.Cseek(int64(ld.Segrodata.Fileoff))
|
||||||
|
ld.Datblk(int64(ld.Segrodata.Vaddr), int64(ld.Segrodata.Filelen))
|
||||||
|
}
|
||||||
|
|
||||||
|
if ld.Debug['v'] != 0 {
|
||||||
|
fmt.Fprintf(&ld.Bso, "%5.2f datblk\n", obj.Cputime())
|
||||||
|
}
|
||||||
|
ld.Bflush(&ld.Bso)
|
||||||
|
|
||||||
|
ld.Cseek(int64(ld.Segdata.Fileoff))
|
||||||
|
ld.Datblk(int64(ld.Segdata.Vaddr), int64(ld.Segdata.Filelen))
|
||||||
|
|
||||||
|
machlink = 0
|
||||||
|
if ld.HEADTYPE == ld.Hdarwin {
|
||||||
|
if ld.Debug['v'] != 0 {
|
||||||
|
fmt.Fprintf(&ld.Bso, "%5.2f dwarf\n", obj.Cputime())
|
||||||
|
}
|
||||||
|
|
||||||
|
if ld.Debug['w'] == 0 {
|
||||||
|
dwarfoff = uint32(ld.Rnd(int64(uint64(ld.HEADR)+ld.Segtext.Length), int64(ld.INITRND)) + ld.Rnd(int64(ld.Segdata.Filelen), int64(ld.INITRND)))
|
||||||
|
ld.Cseek(int64(dwarfoff))
|
||||||
|
|
||||||
|
ld.Segdwarf.Fileoff = uint64(ld.Cpos())
|
||||||
|
ld.Dwarfemitdebugsections()
|
||||||
|
ld.Segdwarf.Filelen = uint64(ld.Cpos()) - ld.Segdwarf.Fileoff
|
||||||
|
}
|
||||||
|
|
||||||
|
machlink = uint32(ld.Domacholink())
|
||||||
|
}
|
||||||
|
|
||||||
|
/* output symbol table */
|
||||||
|
ld.Symsize = 0
|
||||||
|
|
||||||
|
ld.Lcsize = 0
|
||||||
|
symo = 0
|
||||||
|
if ld.Debug['s'] == 0 {
|
||||||
|
// TODO: rationalize
|
||||||
|
if ld.Debug['v'] != 0 {
|
||||||
|
fmt.Fprintf(&ld.Bso, "%5.2f sym\n", obj.Cputime())
|
||||||
|
}
|
||||||
|
ld.Bflush(&ld.Bso)
|
||||||
|
switch ld.HEADTYPE {
|
||||||
|
default:
|
||||||
|
if ld.Iself {
|
||||||
|
symo = uint32(ld.Segdata.Fileoff + ld.Segdata.Filelen)
|
||||||
|
symo = uint32(ld.Rnd(int64(symo), int64(ld.INITRND)))
|
||||||
|
}
|
||||||
|
|
||||||
|
case ld.Hplan9:
|
||||||
|
symo = uint32(ld.Segdata.Fileoff + ld.Segdata.Filelen)
|
||||||
|
|
||||||
|
case ld.Hdarwin:
|
||||||
|
symo = uint32(ld.Rnd(int64(uint64(ld.HEADR)+ld.Segtext.Filelen), int64(ld.INITRND)) + ld.Rnd(int64(ld.Segdata.Filelen), int64(ld.INITRND)) + int64(machlink))
|
||||||
|
}
|
||||||
|
|
||||||
|
ld.Cseek(int64(symo))
|
||||||
|
switch ld.HEADTYPE {
|
||||||
|
default:
|
||||||
|
if ld.Iself {
|
||||||
|
if ld.Debug['v'] != 0 {
|
||||||
|
fmt.Fprintf(&ld.Bso, "%5.2f elfsym\n", obj.Cputime())
|
||||||
|
}
|
||||||
|
ld.Asmelfsym()
|
||||||
|
ld.Cflush()
|
||||||
|
ld.Cwrite(ld.Elfstrdat)
|
||||||
|
|
||||||
|
if ld.Debug['v'] != 0 {
|
||||||
|
fmt.Fprintf(&ld.Bso, "%5.2f dwarf\n", obj.Cputime())
|
||||||
|
}
|
||||||
|
ld.Dwarfemitdebugsections()
|
||||||
|
|
||||||
|
if ld.Linkmode == ld.LinkExternal {
|
||||||
|
ld.Elfemitreloc()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
case ld.Hplan9:
|
||||||
|
ld.Asmplan9sym()
|
||||||
|
ld.Cflush()
|
||||||
|
|
||||||
|
sym = ld.Linklookup(ld.Ctxt, "pclntab", 0)
|
||||||
|
if sym != nil {
|
||||||
|
ld.Lcsize = int32(len(sym.P))
|
||||||
|
for i = 0; int32(i) < ld.Lcsize; i++ {
|
||||||
|
ld.Cput(uint8(sym.P[i]))
|
||||||
|
}
|
||||||
|
|
||||||
|
ld.Cflush()
|
||||||
|
}
|
||||||
|
|
||||||
|
case ld.Hdarwin:
|
||||||
|
if ld.Linkmode == ld.LinkExternal {
|
||||||
|
ld.Machoemitreloc()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ld.Ctxt.Cursym = nil
|
||||||
|
if ld.Debug['v'] != 0 {
|
||||||
|
fmt.Fprintf(&ld.Bso, "%5.2f header\n", obj.Cputime())
|
||||||
|
}
|
||||||
|
ld.Bflush(&ld.Bso)
|
||||||
|
ld.Cseek(0)
|
||||||
|
switch ld.HEADTYPE {
|
||||||
|
default:
|
||||||
|
case ld.Hplan9: /* plan 9 */
|
||||||
|
ld.Thearch.Lput(0x647) /* magic */
|
||||||
|
ld.Thearch.Lput(uint32(ld.Segtext.Filelen)) /* sizes */
|
||||||
|
ld.Thearch.Lput(uint32(ld.Segdata.Filelen))
|
||||||
|
ld.Thearch.Lput(uint32(ld.Segdata.Length - ld.Segdata.Filelen))
|
||||||
|
ld.Thearch.Lput(uint32(ld.Symsize)) /* nsyms */
|
||||||
|
ld.Thearch.Lput(uint32(ld.Entryvalue())) /* va of entry */
|
||||||
|
ld.Thearch.Lput(0)
|
||||||
|
ld.Thearch.Lput(uint32(ld.Lcsize))
|
||||||
|
|
||||||
|
case ld.Hlinux,
|
||||||
|
ld.Hfreebsd,
|
||||||
|
ld.Hnetbsd,
|
||||||
|
ld.Hopenbsd,
|
||||||
|
ld.Hnacl:
|
||||||
|
ld.Asmbelf(int64(symo))
|
||||||
|
|
||||||
|
case ld.Hdarwin:
|
||||||
|
ld.Asmbmacho()
|
||||||
|
}
|
||||||
|
|
||||||
|
ld.Cflush()
|
||||||
|
if ld.Debug['c'] != 0 {
|
||||||
|
fmt.Printf("textsize=%d\n", ld.Segtext.Filelen)
|
||||||
|
fmt.Printf("datsize=%d\n", ld.Segdata.Filelen)
|
||||||
|
fmt.Printf("bsssize=%d\n", ld.Segdata.Length-ld.Segdata.Filelen)
|
||||||
|
fmt.Printf("symsize=%d\n", ld.Symsize)
|
||||||
|
fmt.Printf("lcsize=%d\n", ld.Lcsize)
|
||||||
|
fmt.Printf("total=%d\n", ld.Segtext.Filelen+ld.Segdata.Length+uint64(ld.Symsize)+uint64(ld.Lcsize))
|
||||||
|
}
|
||||||
|
}
|
||||||
78
src/cmd/new5l/l.go
Normal file
78
src/cmd/new5l/l.go
Normal file
|
|
@ -0,0 +1,78 @@
|
||||||
|
// Inferno utils/5l/asm.c
|
||||||
|
// http://code.google.com/p/inferno-os/source/browse/utils/5l/asm.c
|
||||||
|
//
|
||||||
|
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
|
||||||
|
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
|
||||||
|
// Portions Copyright © 1997-1999 Vita Nuova Limited
|
||||||
|
// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
|
||||||
|
// Portions Copyright © 2004,2006 Bruce Ellis
|
||||||
|
// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
|
||||||
|
// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
|
||||||
|
// Portions Copyright © 2009 The Go Authors. All rights reserved.
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
|
// in the Software without restriction, including without limitation the rights
|
||||||
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
// THE SOFTWARE.
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
// Writing object files.
|
||||||
|
|
||||||
|
// Inferno utils/5l/l.h
|
||||||
|
// http://code.google.com/p/inferno-os/source/browse/utils/5l/l.h
|
||||||
|
//
|
||||||
|
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
|
||||||
|
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
|
||||||
|
// Portions Copyright © 1997-1999 Vita Nuova Limited
|
||||||
|
// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
|
||||||
|
// Portions Copyright © 2004,2006 Bruce Ellis
|
||||||
|
// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
|
||||||
|
// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
|
||||||
|
// Portions Copyright © 2009 The Go Authors. All rights reserved.
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
|
// in the Software without restriction, including without limitation the rights
|
||||||
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
// THE SOFTWARE.
|
||||||
|
|
||||||
|
const (
|
||||||
|
thechar = '5'
|
||||||
|
PtrSize = 4
|
||||||
|
IntSize = 4
|
||||||
|
RegSize = 4
|
||||||
|
MaxAlign = 8
|
||||||
|
FuncAlign = 4
|
||||||
|
MINLC = 4
|
||||||
|
)
|
||||||
|
|
||||||
|
/* Used by ../ld/dwarf.c */
|
||||||
|
const (
|
||||||
|
DWARFREGSP = 13
|
||||||
|
)
|
||||||
182
src/cmd/new5l/obj.go
Normal file
182
src/cmd/new5l/obj.go
Normal file
|
|
@ -0,0 +1,182 @@
|
||||||
|
// Inferno utils/5l/obj.c
|
||||||
|
// http://code.google.com/p/inferno-os/source/browse/utils/5l/obj.c
|
||||||
|
//
|
||||||
|
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
|
||||||
|
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
|
||||||
|
// Portions Copyright © 1997-1999 Vita Nuova Limited
|
||||||
|
// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
|
||||||
|
// Portions Copyright © 2004,2006 Bruce Ellis
|
||||||
|
// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
|
||||||
|
// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
|
||||||
|
// Portions Copyright © 2009 The Go Authors. All rights reserved.
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
|
// in the Software without restriction, including without limitation the rights
|
||||||
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
// THE SOFTWARE.
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"cmd/internal/obj"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
)
|
||||||
|
import "cmd/internal/ld"
|
||||||
|
|
||||||
|
// Reading object files.
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
linkarchinit()
|
||||||
|
ld.Ldmain()
|
||||||
|
}
|
||||||
|
|
||||||
|
func linkarchinit() {
|
||||||
|
ld.Thestring = "arm"
|
||||||
|
ld.Thelinkarch = &ld.Linkarm
|
||||||
|
|
||||||
|
ld.Thearch.Thechar = thechar
|
||||||
|
ld.Thearch.Ptrsize = ld.Thelinkarch.Ptrsize
|
||||||
|
ld.Thearch.Intsize = ld.Thelinkarch.Ptrsize
|
||||||
|
ld.Thearch.Regsize = ld.Thelinkarch.Regsize
|
||||||
|
ld.Thearch.Funcalign = FuncAlign
|
||||||
|
ld.Thearch.Maxalign = MaxAlign
|
||||||
|
ld.Thearch.Minlc = MINLC
|
||||||
|
ld.Thearch.Dwarfregsp = DWARFREGSP
|
||||||
|
|
||||||
|
ld.Thearch.Adddynlib = adddynlib
|
||||||
|
ld.Thearch.Adddynrel = adddynrel
|
||||||
|
ld.Thearch.Adddynsym = adddynsym
|
||||||
|
ld.Thearch.Archinit = archinit
|
||||||
|
ld.Thearch.Archreloc = archreloc
|
||||||
|
ld.Thearch.Archrelocvariant = archrelocvariant
|
||||||
|
ld.Thearch.Asmb = asmb
|
||||||
|
ld.Thearch.Elfreloc1 = elfreloc1
|
||||||
|
ld.Thearch.Elfsetupplt = elfsetupplt
|
||||||
|
ld.Thearch.Gentext = gentext
|
||||||
|
ld.Thearch.Machoreloc1 = machoreloc1
|
||||||
|
ld.Thearch.Lput = ld.Lputl
|
||||||
|
ld.Thearch.Wput = ld.Wputl
|
||||||
|
ld.Thearch.Vput = ld.Vputl
|
||||||
|
|
||||||
|
ld.Thearch.Linuxdynld = "/lib/ld-linux.so.3" // 2 for OABI, 3 for EABI
|
||||||
|
ld.Thearch.Freebsddynld = "/usr/libexec/ld-elf.so.1"
|
||||||
|
ld.Thearch.Openbsddynld = "XXX"
|
||||||
|
ld.Thearch.Netbsddynld = "/libexec/ld.elf_so"
|
||||||
|
ld.Thearch.Dragonflydynld = "XXX"
|
||||||
|
ld.Thearch.Solarisdynld = "XXX"
|
||||||
|
}
|
||||||
|
|
||||||
|
func archinit() {
|
||||||
|
var s *ld.LSym
|
||||||
|
|
||||||
|
// getgoextlinkenabled is based on GO_EXTLINK_ENABLED when
|
||||||
|
// Go was built; see ../../make.bash.
|
||||||
|
if ld.Linkmode == ld.LinkAuto && obj.Getgoextlinkenabled() == "0" {
|
||||||
|
ld.Linkmode = ld.LinkInternal
|
||||||
|
}
|
||||||
|
|
||||||
|
switch ld.HEADTYPE {
|
||||||
|
default:
|
||||||
|
if ld.Linkmode == ld.LinkAuto {
|
||||||
|
ld.Linkmode = ld.LinkInternal
|
||||||
|
}
|
||||||
|
if ld.Linkmode == ld.LinkExternal && obj.Getgoextlinkenabled() != "1" {
|
||||||
|
log.Fatalf("cannot use -linkmode=external with -H %s", ld.Headstr(int(ld.HEADTYPE)))
|
||||||
|
}
|
||||||
|
|
||||||
|
case ld.Hlinux,
|
||||||
|
ld.Hfreebsd,
|
||||||
|
ld.Hnacl,
|
||||||
|
ld.Hdarwin:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
switch ld.HEADTYPE {
|
||||||
|
default:
|
||||||
|
ld.Diag("unknown -H option")
|
||||||
|
ld.Errorexit()
|
||||||
|
fallthrough
|
||||||
|
|
||||||
|
case ld.Hplan9: /* plan 9 */
|
||||||
|
ld.HEADR = 32
|
||||||
|
|
||||||
|
if ld.INITTEXT == -1 {
|
||||||
|
ld.INITTEXT = 4128
|
||||||
|
}
|
||||||
|
if ld.INITDAT == -1 {
|
||||||
|
ld.INITDAT = 0
|
||||||
|
}
|
||||||
|
if ld.INITRND == -1 {
|
||||||
|
ld.INITRND = 4096
|
||||||
|
}
|
||||||
|
|
||||||
|
case ld.Hlinux, /* arm elf */
|
||||||
|
ld.Hfreebsd,
|
||||||
|
ld.Hnetbsd:
|
||||||
|
ld.Debug['d'] = 0
|
||||||
|
// with dynamic linking
|
||||||
|
ld.Elfinit()
|
||||||
|
ld.HEADR = ld.ELFRESERVE
|
||||||
|
if ld.INITTEXT == -1 {
|
||||||
|
ld.INITTEXT = 0x10000 + int64(ld.HEADR)
|
||||||
|
}
|
||||||
|
if ld.INITDAT == -1 {
|
||||||
|
ld.INITDAT = 0
|
||||||
|
}
|
||||||
|
if ld.INITRND == -1 {
|
||||||
|
ld.INITRND = 4096
|
||||||
|
}
|
||||||
|
|
||||||
|
case ld.Hnacl:
|
||||||
|
ld.Elfinit()
|
||||||
|
ld.HEADR = 0x10000
|
||||||
|
ld.Funcalign = 16
|
||||||
|
if ld.INITTEXT == -1 {
|
||||||
|
ld.INITTEXT = 0x20000
|
||||||
|
}
|
||||||
|
if ld.INITDAT == -1 {
|
||||||
|
ld.INITDAT = 0
|
||||||
|
}
|
||||||
|
if ld.INITRND == -1 {
|
||||||
|
ld.INITRND = 0x10000
|
||||||
|
}
|
||||||
|
|
||||||
|
case ld.Hdarwin: /* apple MACH */
|
||||||
|
ld.Debug['w'] = 1 // disable DWARF generataion
|
||||||
|
ld.Machoinit()
|
||||||
|
ld.HEADR = ld.INITIAL_MACHO_HEADR
|
||||||
|
if ld.INITTEXT == -1 {
|
||||||
|
ld.INITTEXT = 4096 + int64(ld.HEADR)
|
||||||
|
}
|
||||||
|
if ld.INITDAT == -1 {
|
||||||
|
ld.INITDAT = 0
|
||||||
|
}
|
||||||
|
if ld.INITRND == -1 {
|
||||||
|
ld.INITRND = 4096
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ld.INITDAT != 0 && ld.INITRND != 0 {
|
||||||
|
fmt.Printf("warning: -D0x%x is ignored because of -R0x%x\n", uint64(ld.INITDAT), uint32(ld.INITRND))
|
||||||
|
}
|
||||||
|
|
||||||
|
// embed goarm to runtime.goarm
|
||||||
|
s = ld.Linklookup(ld.Ctxt, "runtime.goarm", 0)
|
||||||
|
|
||||||
|
s.Type = ld.SRODATA
|
||||||
|
ld.Adduint8(ld.Ctxt, s, uint8(ld.Ctxt.Goarm))
|
||||||
|
}
|
||||||
829
src/cmd/new6l/asm.go
Normal file
829
src/cmd/new6l/asm.go
Normal file
|
|
@ -0,0 +1,829 @@
|
||||||
|
// Inferno utils/6l/asm.c
|
||||||
|
// http://code.google.com/p/inferno-os/source/browse/utils/6l/asm.c
|
||||||
|
//
|
||||||
|
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
|
||||||
|
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
|
||||||
|
// Portions Copyright © 1997-1999 Vita Nuova Limited
|
||||||
|
// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
|
||||||
|
// Portions Copyright © 2004,2006 Bruce Ellis
|
||||||
|
// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
|
||||||
|
// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
|
||||||
|
// Portions Copyright © 2009 The Go Authors. All rights reserved.
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
|
// in the Software without restriction, including without limitation the rights
|
||||||
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
// THE SOFTWARE.
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"cmd/internal/obj"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
)
|
||||||
|
import "cmd/internal/ld"
|
||||||
|
|
||||||
|
func PADDR(x uint32) uint32 {
|
||||||
|
return x &^ 0x80000000
|
||||||
|
}
|
||||||
|
|
||||||
|
var zeroes string
|
||||||
|
|
||||||
|
func needlib(name string) int {
|
||||||
|
var p string
|
||||||
|
var s *ld.LSym
|
||||||
|
|
||||||
|
if name[0] == '\x00' {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
/* reuse hash code in symbol table */
|
||||||
|
p = fmt.Sprintf(".elfload.%s", name)
|
||||||
|
|
||||||
|
s = ld.Linklookup(ld.Ctxt, p, 0)
|
||||||
|
|
||||||
|
if s.Type == 0 {
|
||||||
|
s.Type = 100 // avoid SDATA, etc.
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func gentext() {
|
||||||
|
}
|
||||||
|
|
||||||
|
func adddynrela(rela *ld.LSym, s *ld.LSym, r *ld.Reloc) {
|
||||||
|
ld.Addaddrplus(ld.Ctxt, rela, s, int64(r.Off))
|
||||||
|
ld.Adduint64(ld.Ctxt, rela, ld.R_X86_64_RELATIVE)
|
||||||
|
ld.Addaddrplus(ld.Ctxt, rela, r.Sym, r.Add) // Addend
|
||||||
|
}
|
||||||
|
|
||||||
|
func adddynrel(s *ld.LSym, r *ld.Reloc) {
|
||||||
|
var targ *ld.LSym
|
||||||
|
var rela *ld.LSym
|
||||||
|
var got *ld.LSym
|
||||||
|
|
||||||
|
targ = r.Sym
|
||||||
|
ld.Ctxt.Cursym = s
|
||||||
|
|
||||||
|
switch r.Type {
|
||||||
|
default:
|
||||||
|
if r.Type >= 256 {
|
||||||
|
ld.Diag("unexpected relocation type %d", r.Type)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle relocations found in ELF object files.
|
||||||
|
case 256 + ld.R_X86_64_PC32:
|
||||||
|
if targ.Type == ld.SDYNIMPORT {
|
||||||
|
ld.Diag("unexpected R_X86_64_PC32 relocation for dynamic symbol %s", targ.Name)
|
||||||
|
}
|
||||||
|
if targ.Type == 0 || targ.Type == ld.SXREF {
|
||||||
|
ld.Diag("unknown symbol %s in pcrel", targ.Name)
|
||||||
|
}
|
||||||
|
r.Type = ld.R_PCREL
|
||||||
|
r.Add += 4
|
||||||
|
return
|
||||||
|
|
||||||
|
case 256 + ld.R_X86_64_PLT32:
|
||||||
|
r.Type = ld.R_PCREL
|
||||||
|
r.Add += 4
|
||||||
|
if targ.Type == ld.SDYNIMPORT {
|
||||||
|
addpltsym(targ)
|
||||||
|
r.Sym = ld.Linklookup(ld.Ctxt, ".plt", 0)
|
||||||
|
r.Add += int64(targ.Plt)
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
|
case 256 + ld.R_X86_64_GOTPCREL:
|
||||||
|
if targ.Type != ld.SDYNIMPORT {
|
||||||
|
// have symbol
|
||||||
|
if r.Off >= 2 && s.P[r.Off-2] == 0x8b {
|
||||||
|
// turn MOVQ of GOT entry into LEAQ of symbol itself
|
||||||
|
s.P[r.Off-2] = 0x8d
|
||||||
|
|
||||||
|
r.Type = ld.R_PCREL
|
||||||
|
r.Add += 4
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// fall back to using GOT and hope for the best (CMOV*)
|
||||||
|
// TODO: just needs relocation, no need to put in .dynsym
|
||||||
|
addgotsym(targ)
|
||||||
|
|
||||||
|
r.Type = ld.R_PCREL
|
||||||
|
r.Sym = ld.Linklookup(ld.Ctxt, ".got", 0)
|
||||||
|
r.Add += 4
|
||||||
|
r.Add += int64(targ.Got)
|
||||||
|
return
|
||||||
|
|
||||||
|
case 256 + ld.R_X86_64_64:
|
||||||
|
if targ.Type == ld.SDYNIMPORT {
|
||||||
|
ld.Diag("unexpected R_X86_64_64 relocation for dynamic symbol %s", targ.Name)
|
||||||
|
}
|
||||||
|
r.Type = ld.R_ADDR
|
||||||
|
return
|
||||||
|
|
||||||
|
// TODO: What is the difference between all these?
|
||||||
|
// Handle relocations found in Mach-O object files.
|
||||||
|
case 512 + ld.MACHO_X86_64_RELOC_UNSIGNED*2 + 0,
|
||||||
|
512 + ld.MACHO_X86_64_RELOC_SIGNED*2 + 0,
|
||||||
|
512 + ld.MACHO_X86_64_RELOC_BRANCH*2 + 0:
|
||||||
|
r.Type = ld.R_ADDR
|
||||||
|
|
||||||
|
if targ.Type == ld.SDYNIMPORT {
|
||||||
|
ld.Diag("unexpected reloc for dynamic symbol %s", targ.Name)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
|
||||||
|
case 512 + ld.MACHO_X86_64_RELOC_BRANCH*2 + 1:
|
||||||
|
if targ.Type == ld.SDYNIMPORT {
|
||||||
|
addpltsym(targ)
|
||||||
|
r.Sym = ld.Linklookup(ld.Ctxt, ".plt", 0)
|
||||||
|
r.Add = int64(targ.Plt)
|
||||||
|
r.Type = ld.R_PCREL
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fallthrough
|
||||||
|
|
||||||
|
// fall through
|
||||||
|
case 512 + ld.MACHO_X86_64_RELOC_UNSIGNED*2 + 1,
|
||||||
|
512 + ld.MACHO_X86_64_RELOC_SIGNED*2 + 1,
|
||||||
|
512 + ld.MACHO_X86_64_RELOC_SIGNED_1*2 + 1,
|
||||||
|
512 + ld.MACHO_X86_64_RELOC_SIGNED_2*2 + 1,
|
||||||
|
512 + ld.MACHO_X86_64_RELOC_SIGNED_4*2 + 1:
|
||||||
|
r.Type = ld.R_PCREL
|
||||||
|
|
||||||
|
if targ.Type == ld.SDYNIMPORT {
|
||||||
|
ld.Diag("unexpected pc-relative reloc for dynamic symbol %s", targ.Name)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
|
||||||
|
case 512 + ld.MACHO_X86_64_RELOC_GOT_LOAD*2 + 1:
|
||||||
|
if targ.Type != ld.SDYNIMPORT {
|
||||||
|
// have symbol
|
||||||
|
// turn MOVQ of GOT entry into LEAQ of symbol itself
|
||||||
|
if r.Off < 2 || s.P[r.Off-2] != 0x8b {
|
||||||
|
ld.Diag("unexpected GOT_LOAD reloc for non-dynamic symbol %s", targ.Name)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
s.P[r.Off-2] = 0x8d
|
||||||
|
r.Type = ld.R_PCREL
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fallthrough
|
||||||
|
|
||||||
|
// fall through
|
||||||
|
case 512 + ld.MACHO_X86_64_RELOC_GOT*2 + 1:
|
||||||
|
if targ.Type != ld.SDYNIMPORT {
|
||||||
|
ld.Diag("unexpected GOT reloc for non-dynamic symbol %s", targ.Name)
|
||||||
|
}
|
||||||
|
addgotsym(targ)
|
||||||
|
r.Type = ld.R_PCREL
|
||||||
|
r.Sym = ld.Linklookup(ld.Ctxt, ".got", 0)
|
||||||
|
r.Add += int64(targ.Got)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle references to ELF symbols from our own object files.
|
||||||
|
if targ.Type != ld.SDYNIMPORT {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
switch r.Type {
|
||||||
|
case ld.R_CALL,
|
||||||
|
ld.R_PCREL:
|
||||||
|
addpltsym(targ)
|
||||||
|
r.Sym = ld.Linklookup(ld.Ctxt, ".plt", 0)
|
||||||
|
r.Add = int64(targ.Plt)
|
||||||
|
return
|
||||||
|
|
||||||
|
case ld.R_ADDR:
|
||||||
|
if s.Type == ld.STEXT && ld.Iself {
|
||||||
|
// The code is asking for the address of an external
|
||||||
|
// function. We provide it with the address of the
|
||||||
|
// correspondent GOT symbol.
|
||||||
|
addgotsym(targ)
|
||||||
|
|
||||||
|
r.Sym = ld.Linklookup(ld.Ctxt, ".got", 0)
|
||||||
|
r.Add += int64(targ.Got)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if s.Type != ld.SDATA {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if ld.Iself {
|
||||||
|
adddynsym(ld.Ctxt, targ)
|
||||||
|
rela = ld.Linklookup(ld.Ctxt, ".rela", 0)
|
||||||
|
ld.Addaddrplus(ld.Ctxt, rela, s, int64(r.Off))
|
||||||
|
if r.Siz == 8 {
|
||||||
|
ld.Adduint64(ld.Ctxt, rela, ld.ELF64_R_INFO(uint32(targ.Dynid), ld.R_X86_64_64))
|
||||||
|
} else {
|
||||||
|
ld.Adduint64(ld.Ctxt, rela, ld.ELF64_R_INFO(uint32(targ.Dynid), ld.R_X86_64_32))
|
||||||
|
}
|
||||||
|
ld.Adduint64(ld.Ctxt, rela, uint64(r.Add))
|
||||||
|
r.Type = 256 // ignore during relocsym
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if ld.HEADTYPE == ld.Hdarwin && s.Size == int64(ld.Thearch.Ptrsize) && r.Off == 0 {
|
||||||
|
// Mach-O relocations are a royal pain to lay out.
|
||||||
|
// They use a compact stateful bytecode representation
|
||||||
|
// that is too much bother to deal with.
|
||||||
|
// Instead, interpret the C declaration
|
||||||
|
// void *_Cvar_stderr = &stderr;
|
||||||
|
// as making _Cvar_stderr the name of a GOT entry
|
||||||
|
// for stderr. This is separate from the usual GOT entry,
|
||||||
|
// just in case the C code assigns to the variable,
|
||||||
|
// and of course it only works for single pointers,
|
||||||
|
// but we only need to support cgo and that's all it needs.
|
||||||
|
adddynsym(ld.Ctxt, targ)
|
||||||
|
|
||||||
|
got = ld.Linklookup(ld.Ctxt, ".got", 0)
|
||||||
|
s.Type = got.Type | ld.SSUB
|
||||||
|
s.Outer = got
|
||||||
|
s.Sub = got.Sub
|
||||||
|
got.Sub = s
|
||||||
|
s.Value = got.Size
|
||||||
|
ld.Adduint64(ld.Ctxt, got, 0)
|
||||||
|
ld.Adduint32(ld.Ctxt, ld.Linklookup(ld.Ctxt, ".linkedit.got", 0), uint32(targ.Dynid))
|
||||||
|
r.Type = 256 // ignore during relocsym
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ld.Ctxt.Cursym = s
|
||||||
|
ld.Diag("unsupported relocation for dynamic symbol %s (type=%d stype=%d)", targ.Name, r.Type, targ.Type)
|
||||||
|
}
|
||||||
|
|
||||||
|
func elfreloc1(r *ld.Reloc, sectoff int64) int {
|
||||||
|
var elfsym int32
|
||||||
|
|
||||||
|
ld.Thearch.Vput(uint64(sectoff))
|
||||||
|
|
||||||
|
elfsym = r.Xsym.Elfsym
|
||||||
|
switch r.Type {
|
||||||
|
default:
|
||||||
|
return -1
|
||||||
|
|
||||||
|
case ld.R_ADDR:
|
||||||
|
if r.Siz == 4 {
|
||||||
|
ld.Thearch.Vput(ld.R_X86_64_32 | uint64(elfsym)<<32)
|
||||||
|
} else if r.Siz == 8 {
|
||||||
|
ld.Thearch.Vput(ld.R_X86_64_64 | uint64(elfsym)<<32)
|
||||||
|
} else {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|
||||||
|
case ld.R_TLS_LE:
|
||||||
|
if r.Siz == 4 {
|
||||||
|
ld.Thearch.Vput(ld.R_X86_64_TPOFF32 | uint64(elfsym)<<32)
|
||||||
|
} else {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|
||||||
|
case ld.R_CALL:
|
||||||
|
if r.Siz == 4 {
|
||||||
|
if r.Xsym.Type == ld.SDYNIMPORT {
|
||||||
|
ld.Thearch.Vput(ld.R_X86_64_GOTPCREL | uint64(elfsym)<<32)
|
||||||
|
} else {
|
||||||
|
ld.Thearch.Vput(ld.R_X86_64_PC32 | uint64(elfsym)<<32)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|
||||||
|
case ld.R_PCREL:
|
||||||
|
if r.Siz == 4 {
|
||||||
|
ld.Thearch.Vput(ld.R_X86_64_PC32 | uint64(elfsym)<<32)
|
||||||
|
} else {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|
||||||
|
case ld.R_TLS:
|
||||||
|
if r.Siz == 4 {
|
||||||
|
if ld.Flag_shared != 0 {
|
||||||
|
ld.Thearch.Vput(ld.R_X86_64_GOTTPOFF | uint64(elfsym)<<32)
|
||||||
|
} else {
|
||||||
|
ld.Thearch.Vput(ld.R_X86_64_TPOFF32 | uint64(elfsym)<<32)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ld.Thearch.Vput(uint64(r.Xadd))
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func machoreloc1(r *ld.Reloc, sectoff int64) int {
|
||||||
|
var v uint32
|
||||||
|
var rs *ld.LSym
|
||||||
|
|
||||||
|
rs = r.Xsym
|
||||||
|
|
||||||
|
if rs.Type == ld.SHOSTOBJ || r.Type == ld.R_PCREL {
|
||||||
|
if rs.Dynid < 0 {
|
||||||
|
ld.Diag("reloc %d to non-macho symbol %s type=%d", r.Type, rs.Name, rs.Type)
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|
||||||
|
v = uint32(rs.Dynid)
|
||||||
|
v |= 1 << 27 // external relocation
|
||||||
|
} else {
|
||||||
|
v = uint32((rs.Sect.(*ld.Section)).Extnum)
|
||||||
|
if v == 0 {
|
||||||
|
ld.Diag("reloc %d to symbol %s in non-macho section %s type=%d", r.Type, rs.Name, (rs.Sect.(*ld.Section)).Name, rs.Type)
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch r.Type {
|
||||||
|
default:
|
||||||
|
return -1
|
||||||
|
|
||||||
|
case ld.R_ADDR:
|
||||||
|
v |= ld.MACHO_X86_64_RELOC_UNSIGNED << 28
|
||||||
|
|
||||||
|
case ld.R_CALL:
|
||||||
|
v |= 1 << 24 // pc-relative bit
|
||||||
|
v |= ld.MACHO_X86_64_RELOC_BRANCH << 28
|
||||||
|
|
||||||
|
// NOTE: Only works with 'external' relocation. Forced above.
|
||||||
|
case ld.R_PCREL:
|
||||||
|
v |= 1 << 24 // pc-relative bit
|
||||||
|
v |= ld.MACHO_X86_64_RELOC_SIGNED << 28
|
||||||
|
}
|
||||||
|
|
||||||
|
switch r.Siz {
|
||||||
|
default:
|
||||||
|
return -1
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
v |= 0 << 25
|
||||||
|
|
||||||
|
case 2:
|
||||||
|
v |= 1 << 25
|
||||||
|
|
||||||
|
case 4:
|
||||||
|
v |= 2 << 25
|
||||||
|
|
||||||
|
case 8:
|
||||||
|
v |= 3 << 25
|
||||||
|
}
|
||||||
|
|
||||||
|
ld.Thearch.Lput(uint32(sectoff))
|
||||||
|
ld.Thearch.Lput(v)
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func archreloc(r *ld.Reloc, s *ld.LSym, val *int64) int {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|
||||||
|
func archrelocvariant(r *ld.Reloc, s *ld.LSym, t int64) int64 {
|
||||||
|
log.Fatalf("unexpected relocation variant")
|
||||||
|
return t
|
||||||
|
}
|
||||||
|
|
||||||
|
func elfsetupplt() {
|
||||||
|
var plt *ld.LSym
|
||||||
|
var got *ld.LSym
|
||||||
|
|
||||||
|
plt = ld.Linklookup(ld.Ctxt, ".plt", 0)
|
||||||
|
got = ld.Linklookup(ld.Ctxt, ".got.plt", 0)
|
||||||
|
if plt.Size == 0 {
|
||||||
|
// pushq got+8(IP)
|
||||||
|
ld.Adduint8(ld.Ctxt, plt, 0xff)
|
||||||
|
|
||||||
|
ld.Adduint8(ld.Ctxt, plt, 0x35)
|
||||||
|
ld.Addpcrelplus(ld.Ctxt, plt, got, 8)
|
||||||
|
|
||||||
|
// jmpq got+16(IP)
|
||||||
|
ld.Adduint8(ld.Ctxt, plt, 0xff)
|
||||||
|
|
||||||
|
ld.Adduint8(ld.Ctxt, plt, 0x25)
|
||||||
|
ld.Addpcrelplus(ld.Ctxt, plt, got, 16)
|
||||||
|
|
||||||
|
// nopl 0(AX)
|
||||||
|
ld.Adduint32(ld.Ctxt, plt, 0x00401f0f)
|
||||||
|
|
||||||
|
// assume got->size == 0 too
|
||||||
|
ld.Addaddrplus(ld.Ctxt, got, ld.Linklookup(ld.Ctxt, ".dynamic", 0), 0)
|
||||||
|
|
||||||
|
ld.Adduint64(ld.Ctxt, got, 0)
|
||||||
|
ld.Adduint64(ld.Ctxt, got, 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func addpltsym(s *ld.LSym) {
|
||||||
|
if s.Plt >= 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
adddynsym(ld.Ctxt, s)
|
||||||
|
|
||||||
|
if ld.Iself {
|
||||||
|
var plt *ld.LSym
|
||||||
|
var got *ld.LSym
|
||||||
|
var rela *ld.LSym
|
||||||
|
|
||||||
|
plt = ld.Linklookup(ld.Ctxt, ".plt", 0)
|
||||||
|
got = ld.Linklookup(ld.Ctxt, ".got.plt", 0)
|
||||||
|
rela = ld.Linklookup(ld.Ctxt, ".rela.plt", 0)
|
||||||
|
if plt.Size == 0 {
|
||||||
|
elfsetupplt()
|
||||||
|
}
|
||||||
|
|
||||||
|
// jmpq *got+size(IP)
|
||||||
|
ld.Adduint8(ld.Ctxt, plt, 0xff)
|
||||||
|
|
||||||
|
ld.Adduint8(ld.Ctxt, plt, 0x25)
|
||||||
|
ld.Addpcrelplus(ld.Ctxt, plt, got, got.Size)
|
||||||
|
|
||||||
|
// add to got: pointer to current pos in plt
|
||||||
|
ld.Addaddrplus(ld.Ctxt, got, plt, plt.Size)
|
||||||
|
|
||||||
|
// pushq $x
|
||||||
|
ld.Adduint8(ld.Ctxt, plt, 0x68)
|
||||||
|
|
||||||
|
ld.Adduint32(ld.Ctxt, plt, uint32((got.Size-24-8)/8))
|
||||||
|
|
||||||
|
// jmpq .plt
|
||||||
|
ld.Adduint8(ld.Ctxt, plt, 0xe9)
|
||||||
|
|
||||||
|
ld.Adduint32(ld.Ctxt, plt, uint32(-(plt.Size + 4)))
|
||||||
|
|
||||||
|
// rela
|
||||||
|
ld.Addaddrplus(ld.Ctxt, rela, got, got.Size-8)
|
||||||
|
|
||||||
|
ld.Adduint64(ld.Ctxt, rela, ld.ELF64_R_INFO(uint32(s.Dynid), ld.R_X86_64_JMP_SLOT))
|
||||||
|
ld.Adduint64(ld.Ctxt, rela, 0)
|
||||||
|
|
||||||
|
s.Plt = int32(plt.Size - 16)
|
||||||
|
} else if ld.HEADTYPE == ld.Hdarwin {
|
||||||
|
// To do lazy symbol lookup right, we're supposed
|
||||||
|
// to tell the dynamic loader which library each
|
||||||
|
// symbol comes from and format the link info
|
||||||
|
// section just so. I'm too lazy (ha!) to do that
|
||||||
|
// so for now we'll just use non-lazy pointers,
|
||||||
|
// which don't need to be told which library to use.
|
||||||
|
//
|
||||||
|
// http://networkpx.blogspot.com/2009/09/about-lcdyldinfoonly-command.html
|
||||||
|
// has details about what we're avoiding.
|
||||||
|
|
||||||
|
var plt *ld.LSym
|
||||||
|
|
||||||
|
addgotsym(s)
|
||||||
|
plt = ld.Linklookup(ld.Ctxt, ".plt", 0)
|
||||||
|
|
||||||
|
ld.Adduint32(ld.Ctxt, ld.Linklookup(ld.Ctxt, ".linkedit.plt", 0), uint32(s.Dynid))
|
||||||
|
|
||||||
|
// jmpq *got+size(IP)
|
||||||
|
s.Plt = int32(plt.Size)
|
||||||
|
|
||||||
|
ld.Adduint8(ld.Ctxt, plt, 0xff)
|
||||||
|
ld.Adduint8(ld.Ctxt, plt, 0x25)
|
||||||
|
ld.Addpcrelplus(ld.Ctxt, plt, ld.Linklookup(ld.Ctxt, ".got", 0), int64(s.Got))
|
||||||
|
} else {
|
||||||
|
ld.Diag("addpltsym: unsupported binary format")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func addgotsym(s *ld.LSym) {
|
||||||
|
var got *ld.LSym
|
||||||
|
var rela *ld.LSym
|
||||||
|
|
||||||
|
if s.Got >= 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
adddynsym(ld.Ctxt, s)
|
||||||
|
got = ld.Linklookup(ld.Ctxt, ".got", 0)
|
||||||
|
s.Got = int32(got.Size)
|
||||||
|
ld.Adduint64(ld.Ctxt, got, 0)
|
||||||
|
|
||||||
|
if ld.Iself {
|
||||||
|
rela = ld.Linklookup(ld.Ctxt, ".rela", 0)
|
||||||
|
ld.Addaddrplus(ld.Ctxt, rela, got, int64(s.Got))
|
||||||
|
ld.Adduint64(ld.Ctxt, rela, ld.ELF64_R_INFO(uint32(s.Dynid), ld.R_X86_64_GLOB_DAT))
|
||||||
|
ld.Adduint64(ld.Ctxt, rela, 0)
|
||||||
|
} else if ld.HEADTYPE == ld.Hdarwin {
|
||||||
|
ld.Adduint32(ld.Ctxt, ld.Linklookup(ld.Ctxt, ".linkedit.got", 0), uint32(s.Dynid))
|
||||||
|
} else {
|
||||||
|
ld.Diag("addgotsym: unsupported binary format")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func adddynsym(ctxt *ld.Link, s *ld.LSym) {
|
||||||
|
var d *ld.LSym
|
||||||
|
var t int
|
||||||
|
var name string
|
||||||
|
|
||||||
|
if s.Dynid >= 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if ld.Iself {
|
||||||
|
s.Dynid = int32(ld.Nelfsym)
|
||||||
|
ld.Nelfsym++
|
||||||
|
|
||||||
|
d = ld.Linklookup(ctxt, ".dynsym", 0)
|
||||||
|
|
||||||
|
name = s.Extname
|
||||||
|
ld.Adduint32(ctxt, d, uint32(ld.Addstring(ld.Linklookup(ctxt, ".dynstr", 0), name)))
|
||||||
|
|
||||||
|
/* type */
|
||||||
|
t = ld.STB_GLOBAL << 4
|
||||||
|
|
||||||
|
if s.Cgoexport != 0 && s.Type&ld.SMASK == ld.STEXT {
|
||||||
|
t |= ld.STT_FUNC
|
||||||
|
} else {
|
||||||
|
t |= ld.STT_OBJECT
|
||||||
|
}
|
||||||
|
ld.Adduint8(ctxt, d, uint8(t))
|
||||||
|
|
||||||
|
/* reserved */
|
||||||
|
ld.Adduint8(ctxt, d, 0)
|
||||||
|
|
||||||
|
/* section where symbol is defined */
|
||||||
|
if s.Type == ld.SDYNIMPORT {
|
||||||
|
ld.Adduint16(ctxt, d, ld.SHN_UNDEF)
|
||||||
|
} else {
|
||||||
|
ld.Adduint16(ctxt, d, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
/* value */
|
||||||
|
if s.Type == ld.SDYNIMPORT {
|
||||||
|
ld.Adduint64(ctxt, d, 0)
|
||||||
|
} else {
|
||||||
|
ld.Addaddr(ctxt, d, s)
|
||||||
|
}
|
||||||
|
|
||||||
|
/* size of object */
|
||||||
|
ld.Adduint64(ctxt, d, uint64(s.Size))
|
||||||
|
|
||||||
|
if s.Cgoexport&ld.CgoExportDynamic == 0 && s.Dynimplib != "" && needlib(s.Dynimplib) != 0 {
|
||||||
|
ld.Elfwritedynent(ld.Linklookup(ctxt, ".dynamic", 0), ld.DT_NEEDED, uint64(ld.Addstring(ld.Linklookup(ctxt, ".dynstr", 0), s.Dynimplib)))
|
||||||
|
}
|
||||||
|
} else if ld.HEADTYPE == ld.Hdarwin {
|
||||||
|
ld.Diag("adddynsym: missed symbol %s (%s)", s.Name, s.Extname)
|
||||||
|
} else if ld.HEADTYPE == ld.Hwindows {
|
||||||
|
} else // already taken care of
|
||||||
|
{
|
||||||
|
ld.Diag("adddynsym: unsupported binary format")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func adddynlib(lib string) {
|
||||||
|
var s *ld.LSym
|
||||||
|
|
||||||
|
if needlib(lib) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if ld.Iself {
|
||||||
|
s = ld.Linklookup(ld.Ctxt, ".dynstr", 0)
|
||||||
|
if s.Size == 0 {
|
||||||
|
ld.Addstring(s, "")
|
||||||
|
}
|
||||||
|
ld.Elfwritedynent(ld.Linklookup(ld.Ctxt, ".dynamic", 0), ld.DT_NEEDED, uint64(ld.Addstring(s, lib)))
|
||||||
|
} else if ld.HEADTYPE == ld.Hdarwin {
|
||||||
|
ld.Machoadddynlib(lib)
|
||||||
|
} else {
|
||||||
|
ld.Diag("adddynlib: unsupported binary format")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func asmb() {
|
||||||
|
var magic int32
|
||||||
|
var i int
|
||||||
|
var vl int64
|
||||||
|
var symo int64
|
||||||
|
var dwarfoff int64
|
||||||
|
var machlink int64
|
||||||
|
var sect *ld.Section
|
||||||
|
var sym *ld.LSym
|
||||||
|
|
||||||
|
if ld.Debug['v'] != 0 {
|
||||||
|
fmt.Fprintf(&ld.Bso, "%5.2f asmb\n", obj.Cputime())
|
||||||
|
}
|
||||||
|
ld.Bflush(&ld.Bso)
|
||||||
|
|
||||||
|
if ld.Debug['v'] != 0 {
|
||||||
|
fmt.Fprintf(&ld.Bso, "%5.2f codeblk\n", obj.Cputime())
|
||||||
|
}
|
||||||
|
ld.Bflush(&ld.Bso)
|
||||||
|
|
||||||
|
if ld.Iself {
|
||||||
|
ld.Asmbelfsetup()
|
||||||
|
}
|
||||||
|
|
||||||
|
sect = ld.Segtext.Sect
|
||||||
|
ld.Cseek(int64(sect.Vaddr - ld.Segtext.Vaddr + ld.Segtext.Fileoff))
|
||||||
|
ld.Codeblk(int64(sect.Vaddr), int64(sect.Length))
|
||||||
|
for sect = sect.Next; sect != nil; sect = sect.Next {
|
||||||
|
ld.Cseek(int64(sect.Vaddr - ld.Segtext.Vaddr + ld.Segtext.Fileoff))
|
||||||
|
ld.Datblk(int64(sect.Vaddr), int64(sect.Length))
|
||||||
|
}
|
||||||
|
|
||||||
|
if ld.Segrodata.Filelen > 0 {
|
||||||
|
if ld.Debug['v'] != 0 {
|
||||||
|
fmt.Fprintf(&ld.Bso, "%5.2f rodatblk\n", obj.Cputime())
|
||||||
|
}
|
||||||
|
ld.Bflush(&ld.Bso)
|
||||||
|
|
||||||
|
ld.Cseek(int64(ld.Segrodata.Fileoff))
|
||||||
|
ld.Datblk(int64(ld.Segrodata.Vaddr), int64(ld.Segrodata.Filelen))
|
||||||
|
}
|
||||||
|
|
||||||
|
if ld.Debug['v'] != 0 {
|
||||||
|
fmt.Fprintf(&ld.Bso, "%5.2f datblk\n", obj.Cputime())
|
||||||
|
}
|
||||||
|
ld.Bflush(&ld.Bso)
|
||||||
|
|
||||||
|
ld.Cseek(int64(ld.Segdata.Fileoff))
|
||||||
|
ld.Datblk(int64(ld.Segdata.Vaddr), int64(ld.Segdata.Filelen))
|
||||||
|
|
||||||
|
machlink = 0
|
||||||
|
if ld.HEADTYPE == ld.Hdarwin {
|
||||||
|
if ld.Debug['v'] != 0 {
|
||||||
|
fmt.Fprintf(&ld.Bso, "%5.2f dwarf\n", obj.Cputime())
|
||||||
|
}
|
||||||
|
|
||||||
|
dwarfoff = ld.Rnd(int64(uint64(ld.HEADR)+ld.Segtext.Length), int64(ld.INITRND)) + ld.Rnd(int64(ld.Segdata.Filelen), int64(ld.INITRND))
|
||||||
|
ld.Cseek(dwarfoff)
|
||||||
|
|
||||||
|
ld.Segdwarf.Fileoff = uint64(ld.Cpos())
|
||||||
|
ld.Dwarfemitdebugsections()
|
||||||
|
ld.Segdwarf.Filelen = uint64(ld.Cpos()) - ld.Segdwarf.Fileoff
|
||||||
|
|
||||||
|
machlink = ld.Domacholink()
|
||||||
|
}
|
||||||
|
|
||||||
|
switch ld.HEADTYPE {
|
||||||
|
default:
|
||||||
|
ld.Diag("unknown header type %d", ld.HEADTYPE)
|
||||||
|
fallthrough
|
||||||
|
|
||||||
|
case ld.Hplan9,
|
||||||
|
ld.Helf:
|
||||||
|
break
|
||||||
|
|
||||||
|
case ld.Hdarwin:
|
||||||
|
ld.Debug['8'] = 1 /* 64-bit addresses */
|
||||||
|
|
||||||
|
case ld.Hlinux,
|
||||||
|
ld.Hfreebsd,
|
||||||
|
ld.Hnetbsd,
|
||||||
|
ld.Hopenbsd,
|
||||||
|
ld.Hdragonfly,
|
||||||
|
ld.Hsolaris:
|
||||||
|
ld.Debug['8'] = 1 /* 64-bit addresses */
|
||||||
|
|
||||||
|
case ld.Hnacl,
|
||||||
|
ld.Hwindows:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
ld.Symsize = 0
|
||||||
|
ld.Spsize = 0
|
||||||
|
ld.Lcsize = 0
|
||||||
|
symo = 0
|
||||||
|
if ld.Debug['s'] == 0 {
|
||||||
|
if ld.Debug['v'] != 0 {
|
||||||
|
fmt.Fprintf(&ld.Bso, "%5.2f sym\n", obj.Cputime())
|
||||||
|
}
|
||||||
|
ld.Bflush(&ld.Bso)
|
||||||
|
switch ld.HEADTYPE {
|
||||||
|
default:
|
||||||
|
case ld.Hplan9,
|
||||||
|
ld.Helf:
|
||||||
|
ld.Debug['s'] = 1
|
||||||
|
symo = int64(ld.Segdata.Fileoff + ld.Segdata.Filelen)
|
||||||
|
|
||||||
|
case ld.Hdarwin:
|
||||||
|
symo = int64(ld.Segdata.Fileoff + uint64(ld.Rnd(int64(ld.Segdata.Filelen), int64(ld.INITRND))) + uint64(machlink))
|
||||||
|
|
||||||
|
case ld.Hlinux,
|
||||||
|
ld.Hfreebsd,
|
||||||
|
ld.Hnetbsd,
|
||||||
|
ld.Hopenbsd,
|
||||||
|
ld.Hdragonfly,
|
||||||
|
ld.Hsolaris,
|
||||||
|
ld.Hnacl:
|
||||||
|
symo = int64(ld.Segdata.Fileoff + ld.Segdata.Filelen)
|
||||||
|
symo = ld.Rnd(symo, int64(ld.INITRND))
|
||||||
|
|
||||||
|
case ld.Hwindows:
|
||||||
|
symo = int64(ld.Segdata.Fileoff + ld.Segdata.Filelen)
|
||||||
|
symo = ld.Rnd(symo, ld.PEFILEALIGN)
|
||||||
|
}
|
||||||
|
|
||||||
|
ld.Cseek(symo)
|
||||||
|
switch ld.HEADTYPE {
|
||||||
|
default:
|
||||||
|
if ld.Iself {
|
||||||
|
ld.Cseek(symo)
|
||||||
|
ld.Asmelfsym()
|
||||||
|
ld.Cflush()
|
||||||
|
ld.Cwrite(ld.Elfstrdat)
|
||||||
|
|
||||||
|
if ld.Debug['v'] != 0 {
|
||||||
|
fmt.Fprintf(&ld.Bso, "%5.2f dwarf\n", obj.Cputime())
|
||||||
|
}
|
||||||
|
|
||||||
|
ld.Dwarfemitdebugsections()
|
||||||
|
|
||||||
|
if ld.Linkmode == ld.LinkExternal {
|
||||||
|
ld.Elfemitreloc()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
case ld.Hplan9:
|
||||||
|
ld.Asmplan9sym()
|
||||||
|
ld.Cflush()
|
||||||
|
|
||||||
|
sym = ld.Linklookup(ld.Ctxt, "pclntab", 0)
|
||||||
|
if sym != nil {
|
||||||
|
ld.Lcsize = int32(len(sym.P))
|
||||||
|
for i = 0; int32(i) < ld.Lcsize; i++ {
|
||||||
|
ld.Cput(uint8(sym.P[i]))
|
||||||
|
}
|
||||||
|
|
||||||
|
ld.Cflush()
|
||||||
|
}
|
||||||
|
|
||||||
|
case ld.Hwindows:
|
||||||
|
if ld.Debug['v'] != 0 {
|
||||||
|
fmt.Fprintf(&ld.Bso, "%5.2f dwarf\n", obj.Cputime())
|
||||||
|
}
|
||||||
|
|
||||||
|
ld.Dwarfemitdebugsections()
|
||||||
|
|
||||||
|
case ld.Hdarwin:
|
||||||
|
if ld.Linkmode == ld.LinkExternal {
|
||||||
|
ld.Machoemitreloc()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ld.Debug['v'] != 0 {
|
||||||
|
fmt.Fprintf(&ld.Bso, "%5.2f headr\n", obj.Cputime())
|
||||||
|
}
|
||||||
|
ld.Bflush(&ld.Bso)
|
||||||
|
ld.Cseek(0)
|
||||||
|
switch ld.HEADTYPE {
|
||||||
|
default:
|
||||||
|
case ld.Hplan9: /* plan9 */
|
||||||
|
magic = 4*26*26 + 7
|
||||||
|
|
||||||
|
magic |= 0x00008000 /* fat header */
|
||||||
|
ld.Lputb(uint32(magic)) /* magic */
|
||||||
|
ld.Lputb(uint32(ld.Segtext.Filelen)) /* sizes */
|
||||||
|
ld.Lputb(uint32(ld.Segdata.Filelen))
|
||||||
|
ld.Lputb(uint32(ld.Segdata.Length - ld.Segdata.Filelen))
|
||||||
|
ld.Lputb(uint32(ld.Symsize)) /* nsyms */
|
||||||
|
vl = ld.Entryvalue()
|
||||||
|
ld.Lputb(PADDR(uint32(vl))) /* va of entry */
|
||||||
|
ld.Lputb(uint32(ld.Spsize)) /* sp offsets */
|
||||||
|
ld.Lputb(uint32(ld.Lcsize)) /* line offsets */
|
||||||
|
ld.Vputb(uint64(vl)) /* va of entry */
|
||||||
|
|
||||||
|
case ld.Hdarwin:
|
||||||
|
ld.Asmbmacho()
|
||||||
|
|
||||||
|
case ld.Hlinux,
|
||||||
|
ld.Hfreebsd,
|
||||||
|
ld.Hnetbsd,
|
||||||
|
ld.Hopenbsd,
|
||||||
|
ld.Hdragonfly,
|
||||||
|
ld.Hsolaris,
|
||||||
|
ld.Hnacl:
|
||||||
|
ld.Asmbelf(symo)
|
||||||
|
|
||||||
|
case ld.Hwindows:
|
||||||
|
ld.Asmbpe()
|
||||||
|
}
|
||||||
|
|
||||||
|
ld.Cflush()
|
||||||
|
}
|
||||||
78
src/cmd/new6l/l.go
Normal file
78
src/cmd/new6l/l.go
Normal file
|
|
@ -0,0 +1,78 @@
|
||||||
|
// Inferno utils/6l/asm.c
|
||||||
|
// http://code.google.com/p/inferno-os/source/browse/utils/6l/asm.c
|
||||||
|
//
|
||||||
|
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
|
||||||
|
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
|
||||||
|
// Portions Copyright © 1997-1999 Vita Nuova Limited
|
||||||
|
// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
|
||||||
|
// Portions Copyright © 2004,2006 Bruce Ellis
|
||||||
|
// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
|
||||||
|
// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
|
||||||
|
// Portions Copyright © 2009 The Go Authors. All rights reserved.
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
|
// in the Software without restriction, including without limitation the rights
|
||||||
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
// THE SOFTWARE.
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
// Writing object files.
|
||||||
|
|
||||||
|
// Inferno utils/6l/l.h
|
||||||
|
// http://code.google.com/p/inferno-os/source/browse/utils/6l/l.h
|
||||||
|
//
|
||||||
|
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
|
||||||
|
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
|
||||||
|
// Portions Copyright © 1997-1999 Vita Nuova Limited
|
||||||
|
// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
|
||||||
|
// Portions Copyright © 2004,2006 Bruce Ellis
|
||||||
|
// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
|
||||||
|
// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
|
||||||
|
// Portions Copyright © 2009 The Go Authors. All rights reserved.
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
|
// in the Software without restriction, including without limitation the rights
|
||||||
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
// THE SOFTWARE.
|
||||||
|
|
||||||
|
const (
|
||||||
|
thechar = '6'
|
||||||
|
MaxAlign = 32
|
||||||
|
FuncAlign = 16
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
MINLC = 1
|
||||||
|
)
|
||||||
|
|
||||||
|
/* Used by ../ld/dwarf.c */
|
||||||
|
const (
|
||||||
|
DWARFREGSP = 7
|
||||||
|
)
|
||||||
215
src/cmd/new6l/obj.go
Normal file
215
src/cmd/new6l/obj.go
Normal file
|
|
@ -0,0 +1,215 @@
|
||||||
|
// Inferno utils/6l/obj.c
|
||||||
|
// http://code.google.com/p/inferno-os/source/browse/utils/6l/obj.c
|
||||||
|
//
|
||||||
|
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
|
||||||
|
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
|
||||||
|
// Portions Copyright © 1997-1999 Vita Nuova Limited
|
||||||
|
// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
|
||||||
|
// Portions Copyright © 2004,2006 Bruce Ellis
|
||||||
|
// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
|
||||||
|
// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
|
||||||
|
// Portions Copyright © 2009 The Go Authors. All rights reserved.
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
|
// in the Software without restriction, including without limitation the rights
|
||||||
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
// THE SOFTWARE.
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"cmd/internal/obj"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
)
|
||||||
|
import "cmd/internal/ld"
|
||||||
|
|
||||||
|
// Reading object files.
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
linkarchinit()
|
||||||
|
ld.Ldmain()
|
||||||
|
}
|
||||||
|
|
||||||
|
func linkarchinit() {
|
||||||
|
ld.Thestring = "amd64"
|
||||||
|
ld.Thelinkarch = &ld.Linkamd64
|
||||||
|
if obj.Getgoarch() == "amd64p32" {
|
||||||
|
ld.Thelinkarch = &ld.Linkamd64p32
|
||||||
|
}
|
||||||
|
|
||||||
|
ld.Thearch.Thechar = thechar
|
||||||
|
ld.Thearch.Ptrsize = ld.Thelinkarch.Ptrsize
|
||||||
|
ld.Thearch.Intsize = ld.Thelinkarch.Ptrsize
|
||||||
|
ld.Thearch.Regsize = ld.Thelinkarch.Regsize
|
||||||
|
ld.Thearch.Funcalign = FuncAlign
|
||||||
|
ld.Thearch.Maxalign = MaxAlign
|
||||||
|
ld.Thearch.Minlc = MINLC
|
||||||
|
ld.Thearch.Dwarfregsp = DWARFREGSP
|
||||||
|
|
||||||
|
ld.Thearch.Adddynlib = adddynlib
|
||||||
|
ld.Thearch.Adddynrel = adddynrel
|
||||||
|
ld.Thearch.Adddynsym = adddynsym
|
||||||
|
ld.Thearch.Archinit = archinit
|
||||||
|
ld.Thearch.Archreloc = archreloc
|
||||||
|
ld.Thearch.Archrelocvariant = archrelocvariant
|
||||||
|
ld.Thearch.Asmb = asmb
|
||||||
|
ld.Thearch.Elfreloc1 = elfreloc1
|
||||||
|
ld.Thearch.Elfsetupplt = elfsetupplt
|
||||||
|
ld.Thearch.Gentext = gentext
|
||||||
|
ld.Thearch.Machoreloc1 = machoreloc1
|
||||||
|
ld.Thearch.Lput = ld.Lputl
|
||||||
|
ld.Thearch.Wput = ld.Wputl
|
||||||
|
ld.Thearch.Vput = ld.Vputl
|
||||||
|
|
||||||
|
ld.Thearch.Linuxdynld = "/lib64/ld-linux-x86-64.so.2"
|
||||||
|
ld.Thearch.Freebsddynld = "/libexec/ld-elf.so.1"
|
||||||
|
ld.Thearch.Openbsddynld = "/usr/libexec/ld.so"
|
||||||
|
ld.Thearch.Netbsddynld = "/libexec/ld.elf_so"
|
||||||
|
ld.Thearch.Dragonflydynld = "/usr/libexec/ld-elf.so.2"
|
||||||
|
ld.Thearch.Solarisdynld = "/lib/amd64/ld.so.1"
|
||||||
|
}
|
||||||
|
|
||||||
|
func archinit() {
|
||||||
|
// getgoextlinkenabled is based on GO_EXTLINK_ENABLED when
|
||||||
|
// Go was built; see ../../make.bash.
|
||||||
|
if ld.Linkmode == ld.LinkAuto && obj.Getgoextlinkenabled() == "0" {
|
||||||
|
ld.Linkmode = ld.LinkInternal
|
||||||
|
}
|
||||||
|
|
||||||
|
if ld.Flag_shared != 0 {
|
||||||
|
ld.Linkmode = ld.LinkExternal
|
||||||
|
}
|
||||||
|
|
||||||
|
switch ld.HEADTYPE {
|
||||||
|
default:
|
||||||
|
if ld.Linkmode == ld.LinkAuto {
|
||||||
|
ld.Linkmode = ld.LinkInternal
|
||||||
|
}
|
||||||
|
if ld.Linkmode == ld.LinkExternal && obj.Getgoextlinkenabled() != "1" {
|
||||||
|
log.Fatalf("cannot use -linkmode=external with -H %s", ld.Headstr(int(ld.HEADTYPE)))
|
||||||
|
}
|
||||||
|
|
||||||
|
case ld.Hdarwin,
|
||||||
|
ld.Hdragonfly,
|
||||||
|
ld.Hfreebsd,
|
||||||
|
ld.Hlinux,
|
||||||
|
ld.Hnacl,
|
||||||
|
ld.Hnetbsd,
|
||||||
|
ld.Hopenbsd,
|
||||||
|
ld.Hsolaris:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
switch ld.HEADTYPE {
|
||||||
|
default:
|
||||||
|
ld.Diag("unknown -H option")
|
||||||
|
ld.Errorexit()
|
||||||
|
fallthrough
|
||||||
|
|
||||||
|
case ld.Hplan9: /* plan 9 */
|
||||||
|
ld.HEADR = 32 + 8
|
||||||
|
|
||||||
|
if ld.INITTEXT == -1 {
|
||||||
|
ld.INITTEXT = 0x200000 + int64(ld.HEADR)
|
||||||
|
}
|
||||||
|
if ld.INITDAT == -1 {
|
||||||
|
ld.INITDAT = 0
|
||||||
|
}
|
||||||
|
if ld.INITRND == -1 {
|
||||||
|
ld.INITRND = 0x200000
|
||||||
|
}
|
||||||
|
|
||||||
|
case ld.Helf: /* elf32 executable */
|
||||||
|
ld.HEADR = int32(ld.Rnd(52+3*32, 16))
|
||||||
|
|
||||||
|
if ld.INITTEXT == -1 {
|
||||||
|
ld.INITTEXT = 0x80110000
|
||||||
|
}
|
||||||
|
if ld.INITDAT == -1 {
|
||||||
|
ld.INITDAT = 0
|
||||||
|
}
|
||||||
|
if ld.INITRND == -1 {
|
||||||
|
ld.INITRND = 4096
|
||||||
|
}
|
||||||
|
|
||||||
|
case ld.Hdarwin: /* apple MACH */
|
||||||
|
ld.Machoinit()
|
||||||
|
|
||||||
|
ld.HEADR = ld.INITIAL_MACHO_HEADR
|
||||||
|
if ld.INITRND == -1 {
|
||||||
|
ld.INITRND = 4096
|
||||||
|
}
|
||||||
|
if ld.INITTEXT == -1 {
|
||||||
|
ld.INITTEXT = 4096 + int64(ld.HEADR)
|
||||||
|
}
|
||||||
|
if ld.INITDAT == -1 {
|
||||||
|
ld.INITDAT = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
case ld.Hlinux, /* elf64 executable */
|
||||||
|
ld.Hfreebsd, /* freebsd */
|
||||||
|
ld.Hnetbsd, /* netbsd */
|
||||||
|
ld.Hopenbsd, /* openbsd */
|
||||||
|
ld.Hdragonfly, /* dragonfly */
|
||||||
|
ld.Hsolaris: /* solaris */
|
||||||
|
ld.Elfinit()
|
||||||
|
|
||||||
|
ld.HEADR = ld.ELFRESERVE
|
||||||
|
if ld.INITTEXT == -1 {
|
||||||
|
ld.INITTEXT = (1 << 22) + int64(ld.HEADR)
|
||||||
|
}
|
||||||
|
if ld.INITDAT == -1 {
|
||||||
|
ld.INITDAT = 0
|
||||||
|
}
|
||||||
|
if ld.INITRND == -1 {
|
||||||
|
ld.INITRND = 4096
|
||||||
|
}
|
||||||
|
|
||||||
|
case ld.Hnacl:
|
||||||
|
ld.Elfinit()
|
||||||
|
ld.Debug['w']++ // disable dwarf, which gets confused and is useless anyway
|
||||||
|
ld.HEADR = 0x10000
|
||||||
|
ld.Funcalign = 32
|
||||||
|
if ld.INITTEXT == -1 {
|
||||||
|
ld.INITTEXT = 0x20000
|
||||||
|
}
|
||||||
|
if ld.INITDAT == -1 {
|
||||||
|
ld.INITDAT = 0
|
||||||
|
}
|
||||||
|
if ld.INITRND == -1 {
|
||||||
|
ld.INITRND = 0x10000
|
||||||
|
}
|
||||||
|
|
||||||
|
case ld.Hwindows: /* PE executable */
|
||||||
|
ld.Peinit()
|
||||||
|
|
||||||
|
ld.HEADR = ld.PEFILEHEADR
|
||||||
|
if ld.INITTEXT == -1 {
|
||||||
|
ld.INITTEXT = ld.PEBASE + int64(ld.PESECTHEADR)
|
||||||
|
}
|
||||||
|
if ld.INITDAT == -1 {
|
||||||
|
ld.INITDAT = 0
|
||||||
|
}
|
||||||
|
if ld.INITRND == -1 {
|
||||||
|
ld.INITRND = ld.PESECTALIGN
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ld.INITDAT != 0 && ld.INITRND != 0 {
|
||||||
|
fmt.Printf("warning: -D0x%x is ignored because of -R0x%x\n", uint64(ld.INITDAT), uint32(ld.INITRND))
|
||||||
|
}
|
||||||
|
}
|
||||||
1
src/cmd/new6l/z.go
Normal file
1
src/cmd/new6l/z.go
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
package main
|
||||||
734
src/cmd/new8l/asm.go
Normal file
734
src/cmd/new8l/asm.go
Normal file
|
|
@ -0,0 +1,734 @@
|
||||||
|
// Inferno utils/8l/asm.c
|
||||||
|
// http://code.google.com/p/inferno-os/source/browse/utils/8l/asm.c
|
||||||
|
//
|
||||||
|
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
|
||||||
|
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
|
||||||
|
// Portions Copyright © 1997-1999 Vita Nuova Limited
|
||||||
|
// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
|
||||||
|
// Portions Copyright © 2004,2006 Bruce Ellis
|
||||||
|
// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
|
||||||
|
// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
|
||||||
|
// Portions Copyright © 2009 The Go Authors. All rights reserved.
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
|
// in the Software without restriction, including without limitation the rights
|
||||||
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
// THE SOFTWARE.
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"cmd/internal/obj"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
)
|
||||||
|
import "cmd/internal/ld"
|
||||||
|
|
||||||
|
func needlib(name string) int {
|
||||||
|
var p string
|
||||||
|
var s *ld.LSym
|
||||||
|
|
||||||
|
if name[0] == '\x00' {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
/* reuse hash code in symbol table */
|
||||||
|
p = fmt.Sprintf(".dynlib.%s", name)
|
||||||
|
|
||||||
|
s = ld.Linklookup(ld.Ctxt, p, 0)
|
||||||
|
|
||||||
|
if s.Type == 0 {
|
||||||
|
s.Type = 100 // avoid SDATA, etc.
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func gentext() {
|
||||||
|
}
|
||||||
|
|
||||||
|
func adddynrela(rela *ld.LSym, s *ld.LSym, r *ld.Reloc) {
|
||||||
|
log.Fatalf("adddynrela not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
func adddynrel(s *ld.LSym, r *ld.Reloc) {
|
||||||
|
var targ *ld.LSym
|
||||||
|
var rel *ld.LSym
|
||||||
|
var got *ld.LSym
|
||||||
|
|
||||||
|
targ = r.Sym
|
||||||
|
ld.Ctxt.Cursym = s
|
||||||
|
|
||||||
|
switch r.Type {
|
||||||
|
default:
|
||||||
|
if r.Type >= 256 {
|
||||||
|
ld.Diag("unexpected relocation type %d", r.Type)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle relocations found in ELF object files.
|
||||||
|
case 256 + ld.R_386_PC32:
|
||||||
|
if targ.Type == ld.SDYNIMPORT {
|
||||||
|
ld.Diag("unexpected R_386_PC32 relocation for dynamic symbol %s", targ.Name)
|
||||||
|
}
|
||||||
|
if targ.Type == 0 || targ.Type == ld.SXREF {
|
||||||
|
ld.Diag("unknown symbol %s in pcrel", targ.Name)
|
||||||
|
}
|
||||||
|
r.Type = ld.R_PCREL
|
||||||
|
r.Add += 4
|
||||||
|
return
|
||||||
|
|
||||||
|
case 256 + ld.R_386_PLT32:
|
||||||
|
r.Type = ld.R_PCREL
|
||||||
|
r.Add += 4
|
||||||
|
if targ.Type == ld.SDYNIMPORT {
|
||||||
|
addpltsym(ld.Ctxt, targ)
|
||||||
|
r.Sym = ld.Linklookup(ld.Ctxt, ".plt", 0)
|
||||||
|
r.Add += int64(targ.Plt)
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
|
case 256 + ld.R_386_GOT32:
|
||||||
|
if targ.Type != ld.SDYNIMPORT {
|
||||||
|
// have symbol
|
||||||
|
if r.Off >= 2 && s.P[r.Off-2] == 0x8b {
|
||||||
|
// turn MOVL of GOT entry into LEAL of symbol address, relative to GOT.
|
||||||
|
s.P[r.Off-2] = 0x8d
|
||||||
|
|
||||||
|
r.Type = ld.R_GOTOFF
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if r.Off >= 2 && s.P[r.Off-2] == 0xff && s.P[r.Off-1] == 0xb3 {
|
||||||
|
// turn PUSHL of GOT entry into PUSHL of symbol itself.
|
||||||
|
// use unnecessary SS prefix to keep instruction same length.
|
||||||
|
s.P[r.Off-2] = 0x36
|
||||||
|
|
||||||
|
s.P[r.Off-1] = 0x68
|
||||||
|
r.Type = ld.R_ADDR
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ld.Diag("unexpected GOT reloc for non-dynamic symbol %s", targ.Name)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
addgotsym(ld.Ctxt, targ)
|
||||||
|
r.Type = ld.R_CONST // write r->add during relocsym
|
||||||
|
r.Sym = nil
|
||||||
|
r.Add += int64(targ.Got)
|
||||||
|
return
|
||||||
|
|
||||||
|
case 256 + ld.R_386_GOTOFF:
|
||||||
|
r.Type = ld.R_GOTOFF
|
||||||
|
return
|
||||||
|
|
||||||
|
case 256 + ld.R_386_GOTPC:
|
||||||
|
r.Type = ld.R_PCREL
|
||||||
|
r.Sym = ld.Linklookup(ld.Ctxt, ".got", 0)
|
||||||
|
r.Add += 4
|
||||||
|
return
|
||||||
|
|
||||||
|
case 256 + ld.R_386_32:
|
||||||
|
if targ.Type == ld.SDYNIMPORT {
|
||||||
|
ld.Diag("unexpected R_386_32 relocation for dynamic symbol %s", targ.Name)
|
||||||
|
}
|
||||||
|
r.Type = ld.R_ADDR
|
||||||
|
return
|
||||||
|
|
||||||
|
case 512 + ld.MACHO_GENERIC_RELOC_VANILLA*2 + 0:
|
||||||
|
r.Type = ld.R_ADDR
|
||||||
|
if targ.Type == ld.SDYNIMPORT {
|
||||||
|
ld.Diag("unexpected reloc for dynamic symbol %s", targ.Name)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
|
||||||
|
case 512 + ld.MACHO_GENERIC_RELOC_VANILLA*2 + 1:
|
||||||
|
if targ.Type == ld.SDYNIMPORT {
|
||||||
|
addpltsym(ld.Ctxt, targ)
|
||||||
|
r.Sym = ld.Linklookup(ld.Ctxt, ".plt", 0)
|
||||||
|
r.Add = int64(targ.Plt)
|
||||||
|
r.Type = ld.R_PCREL
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
r.Type = ld.R_PCREL
|
||||||
|
return
|
||||||
|
|
||||||
|
case 512 + ld.MACHO_FAKE_GOTPCREL:
|
||||||
|
if targ.Type != ld.SDYNIMPORT {
|
||||||
|
// have symbol
|
||||||
|
// turn MOVL of GOT entry into LEAL of symbol itself
|
||||||
|
if r.Off < 2 || s.P[r.Off-2] != 0x8b {
|
||||||
|
ld.Diag("unexpected GOT reloc for non-dynamic symbol %s", targ.Name)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
s.P[r.Off-2] = 0x8d
|
||||||
|
r.Type = ld.R_PCREL
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
addgotsym(ld.Ctxt, targ)
|
||||||
|
r.Sym = ld.Linklookup(ld.Ctxt, ".got", 0)
|
||||||
|
r.Add += int64(targ.Got)
|
||||||
|
r.Type = ld.R_PCREL
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle references to ELF symbols from our own object files.
|
||||||
|
if targ.Type != ld.SDYNIMPORT {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
switch r.Type {
|
||||||
|
case ld.R_CALL,
|
||||||
|
ld.R_PCREL:
|
||||||
|
addpltsym(ld.Ctxt, targ)
|
||||||
|
r.Sym = ld.Linklookup(ld.Ctxt, ".plt", 0)
|
||||||
|
r.Add = int64(targ.Plt)
|
||||||
|
return
|
||||||
|
|
||||||
|
case ld.R_ADDR:
|
||||||
|
if s.Type != ld.SDATA {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if ld.Iself {
|
||||||
|
adddynsym(ld.Ctxt, targ)
|
||||||
|
rel = ld.Linklookup(ld.Ctxt, ".rel", 0)
|
||||||
|
ld.Addaddrplus(ld.Ctxt, rel, s, int64(r.Off))
|
||||||
|
ld.Adduint32(ld.Ctxt, rel, ld.ELF32_R_INFO(uint32(targ.Dynid), ld.R_386_32))
|
||||||
|
r.Type = ld.R_CONST // write r->add during relocsym
|
||||||
|
r.Sym = nil
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if ld.HEADTYPE == ld.Hdarwin && s.Size == PtrSize && r.Off == 0 {
|
||||||
|
// Mach-O relocations are a royal pain to lay out.
|
||||||
|
// They use a compact stateful bytecode representation
|
||||||
|
// that is too much bother to deal with.
|
||||||
|
// Instead, interpret the C declaration
|
||||||
|
// void *_Cvar_stderr = &stderr;
|
||||||
|
// as making _Cvar_stderr the name of a GOT entry
|
||||||
|
// for stderr. This is separate from the usual GOT entry,
|
||||||
|
// just in case the C code assigns to the variable,
|
||||||
|
// and of course it only works for single pointers,
|
||||||
|
// but we only need to support cgo and that's all it needs.
|
||||||
|
adddynsym(ld.Ctxt, targ)
|
||||||
|
|
||||||
|
got = ld.Linklookup(ld.Ctxt, ".got", 0)
|
||||||
|
s.Type = got.Type | ld.SSUB
|
||||||
|
s.Outer = got
|
||||||
|
s.Sub = got.Sub
|
||||||
|
got.Sub = s
|
||||||
|
s.Value = got.Size
|
||||||
|
ld.Adduint32(ld.Ctxt, got, 0)
|
||||||
|
ld.Adduint32(ld.Ctxt, ld.Linklookup(ld.Ctxt, ".linkedit.got", 0), uint32(targ.Dynid))
|
||||||
|
r.Type = 256 // ignore during relocsym
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ld.Ctxt.Cursym = s
|
||||||
|
ld.Diag("unsupported relocation for dynamic symbol %s (type=%d stype=%d)", targ.Name, r.Type, targ.Type)
|
||||||
|
}
|
||||||
|
|
||||||
|
func elfreloc1(r *ld.Reloc, sectoff int64) int {
|
||||||
|
var elfsym int32
|
||||||
|
|
||||||
|
ld.Thearch.Lput(uint32(sectoff))
|
||||||
|
|
||||||
|
elfsym = r.Xsym.Elfsym
|
||||||
|
switch r.Type {
|
||||||
|
default:
|
||||||
|
return -1
|
||||||
|
|
||||||
|
case ld.R_ADDR:
|
||||||
|
if r.Siz == 4 {
|
||||||
|
ld.Thearch.Lput(ld.R_386_32 | uint32(elfsym)<<8)
|
||||||
|
} else {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|
||||||
|
case ld.R_CALL,
|
||||||
|
ld.R_PCREL:
|
||||||
|
if r.Siz == 4 {
|
||||||
|
ld.Thearch.Lput(ld.R_386_PC32 | uint32(elfsym)<<8)
|
||||||
|
} else {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|
||||||
|
case ld.R_TLS_LE,
|
||||||
|
ld.R_TLS_IE:
|
||||||
|
if r.Siz == 4 {
|
||||||
|
ld.Thearch.Lput(ld.R_386_TLS_LE | uint32(elfsym)<<8)
|
||||||
|
} else {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func machoreloc1(r *ld.Reloc, sectoff int64) int {
|
||||||
|
var v uint32
|
||||||
|
var rs *ld.LSym
|
||||||
|
|
||||||
|
rs = r.Xsym
|
||||||
|
|
||||||
|
if rs.Type == ld.SHOSTOBJ {
|
||||||
|
if rs.Dynid < 0 {
|
||||||
|
ld.Diag("reloc %d to non-macho symbol %s type=%d", r.Type, rs.Name, rs.Type)
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|
||||||
|
v = uint32(rs.Dynid)
|
||||||
|
v |= 1 << 27 // external relocation
|
||||||
|
} else {
|
||||||
|
v = uint32((rs.Sect.(*ld.Section)).Extnum)
|
||||||
|
if v == 0 {
|
||||||
|
ld.Diag("reloc %d to symbol %s in non-macho section %s type=%d", r.Type, rs.Name, (rs.Sect.(*ld.Section)).Name, rs.Type)
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch r.Type {
|
||||||
|
default:
|
||||||
|
return -1
|
||||||
|
|
||||||
|
case ld.R_ADDR:
|
||||||
|
v |= ld.MACHO_GENERIC_RELOC_VANILLA << 28
|
||||||
|
|
||||||
|
case ld.R_CALL,
|
||||||
|
ld.R_PCREL:
|
||||||
|
v |= 1 << 24 // pc-relative bit
|
||||||
|
v |= ld.MACHO_GENERIC_RELOC_VANILLA << 28
|
||||||
|
}
|
||||||
|
|
||||||
|
switch r.Siz {
|
||||||
|
default:
|
||||||
|
return -1
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
v |= 0 << 25
|
||||||
|
|
||||||
|
case 2:
|
||||||
|
v |= 1 << 25
|
||||||
|
|
||||||
|
case 4:
|
||||||
|
v |= 2 << 25
|
||||||
|
|
||||||
|
case 8:
|
||||||
|
v |= 3 << 25
|
||||||
|
}
|
||||||
|
|
||||||
|
ld.Thearch.Lput(uint32(sectoff))
|
||||||
|
ld.Thearch.Lput(v)
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func archreloc(r *ld.Reloc, s *ld.LSym, val *int64) int {
|
||||||
|
if ld.Linkmode == ld.LinkExternal {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
switch r.Type {
|
||||||
|
case ld.R_CONST:
|
||||||
|
*val = r.Add
|
||||||
|
return 0
|
||||||
|
|
||||||
|
case ld.R_GOTOFF:
|
||||||
|
*val = ld.Symaddr(r.Sym) + r.Add - ld.Symaddr(ld.Linklookup(ld.Ctxt, ".got", 0))
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|
||||||
|
func archrelocvariant(r *ld.Reloc, s *ld.LSym, t int64) int64 {
|
||||||
|
log.Fatalf("unexpected relocation variant")
|
||||||
|
return t
|
||||||
|
}
|
||||||
|
|
||||||
|
func elfsetupplt() {
|
||||||
|
var plt *ld.LSym
|
||||||
|
var got *ld.LSym
|
||||||
|
|
||||||
|
plt = ld.Linklookup(ld.Ctxt, ".plt", 0)
|
||||||
|
got = ld.Linklookup(ld.Ctxt, ".got.plt", 0)
|
||||||
|
if plt.Size == 0 {
|
||||||
|
// pushl got+4
|
||||||
|
ld.Adduint8(ld.Ctxt, plt, 0xff)
|
||||||
|
|
||||||
|
ld.Adduint8(ld.Ctxt, plt, 0x35)
|
||||||
|
ld.Addaddrplus(ld.Ctxt, plt, got, 4)
|
||||||
|
|
||||||
|
// jmp *got+8
|
||||||
|
ld.Adduint8(ld.Ctxt, plt, 0xff)
|
||||||
|
|
||||||
|
ld.Adduint8(ld.Ctxt, plt, 0x25)
|
||||||
|
ld.Addaddrplus(ld.Ctxt, plt, got, 8)
|
||||||
|
|
||||||
|
// zero pad
|
||||||
|
ld.Adduint32(ld.Ctxt, plt, 0)
|
||||||
|
|
||||||
|
// assume got->size == 0 too
|
||||||
|
ld.Addaddrplus(ld.Ctxt, got, ld.Linklookup(ld.Ctxt, ".dynamic", 0), 0)
|
||||||
|
|
||||||
|
ld.Adduint32(ld.Ctxt, got, 0)
|
||||||
|
ld.Adduint32(ld.Ctxt, got, 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func addpltsym(ctxt *ld.Link, s *ld.LSym) {
|
||||||
|
var plt *ld.LSym
|
||||||
|
var got *ld.LSym
|
||||||
|
var rel *ld.LSym
|
||||||
|
|
||||||
|
if s.Plt >= 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
adddynsym(ctxt, s)
|
||||||
|
|
||||||
|
if ld.Iself {
|
||||||
|
plt = ld.Linklookup(ctxt, ".plt", 0)
|
||||||
|
got = ld.Linklookup(ctxt, ".got.plt", 0)
|
||||||
|
rel = ld.Linklookup(ctxt, ".rel.plt", 0)
|
||||||
|
if plt.Size == 0 {
|
||||||
|
elfsetupplt()
|
||||||
|
}
|
||||||
|
|
||||||
|
// jmpq *got+size
|
||||||
|
ld.Adduint8(ctxt, plt, 0xff)
|
||||||
|
|
||||||
|
ld.Adduint8(ctxt, plt, 0x25)
|
||||||
|
ld.Addaddrplus(ctxt, plt, got, got.Size)
|
||||||
|
|
||||||
|
// add to got: pointer to current pos in plt
|
||||||
|
ld.Addaddrplus(ctxt, got, plt, plt.Size)
|
||||||
|
|
||||||
|
// pushl $x
|
||||||
|
ld.Adduint8(ctxt, plt, 0x68)
|
||||||
|
|
||||||
|
ld.Adduint32(ctxt, plt, uint32(rel.Size))
|
||||||
|
|
||||||
|
// jmp .plt
|
||||||
|
ld.Adduint8(ctxt, plt, 0xe9)
|
||||||
|
|
||||||
|
ld.Adduint32(ctxt, plt, uint32(-(plt.Size + 4)))
|
||||||
|
|
||||||
|
// rel
|
||||||
|
ld.Addaddrplus(ctxt, rel, got, got.Size-4)
|
||||||
|
|
||||||
|
ld.Adduint32(ctxt, rel, ld.ELF32_R_INFO(uint32(s.Dynid), ld.R_386_JMP_SLOT))
|
||||||
|
|
||||||
|
s.Plt = int32(plt.Size - 16)
|
||||||
|
} else if ld.HEADTYPE == ld.Hdarwin {
|
||||||
|
// Same laziness as in 6l.
|
||||||
|
|
||||||
|
var plt *ld.LSym
|
||||||
|
|
||||||
|
plt = ld.Linklookup(ctxt, ".plt", 0)
|
||||||
|
|
||||||
|
addgotsym(ctxt, s)
|
||||||
|
|
||||||
|
ld.Adduint32(ctxt, ld.Linklookup(ctxt, ".linkedit.plt", 0), uint32(s.Dynid))
|
||||||
|
|
||||||
|
// jmpq *got+size(IP)
|
||||||
|
s.Plt = int32(plt.Size)
|
||||||
|
|
||||||
|
ld.Adduint8(ctxt, plt, 0xff)
|
||||||
|
ld.Adduint8(ctxt, plt, 0x25)
|
||||||
|
ld.Addaddrplus(ctxt, plt, ld.Linklookup(ctxt, ".got", 0), int64(s.Got))
|
||||||
|
} else {
|
||||||
|
ld.Diag("addpltsym: unsupported binary format")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func addgotsym(ctxt *ld.Link, s *ld.LSym) {
|
||||||
|
var got *ld.LSym
|
||||||
|
var rel *ld.LSym
|
||||||
|
|
||||||
|
if s.Got >= 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
adddynsym(ctxt, s)
|
||||||
|
got = ld.Linklookup(ctxt, ".got", 0)
|
||||||
|
s.Got = int32(got.Size)
|
||||||
|
ld.Adduint32(ctxt, got, 0)
|
||||||
|
|
||||||
|
if ld.Iself {
|
||||||
|
rel = ld.Linklookup(ctxt, ".rel", 0)
|
||||||
|
ld.Addaddrplus(ctxt, rel, got, int64(s.Got))
|
||||||
|
ld.Adduint32(ctxt, rel, ld.ELF32_R_INFO(uint32(s.Dynid), ld.R_386_GLOB_DAT))
|
||||||
|
} else if ld.HEADTYPE == ld.Hdarwin {
|
||||||
|
ld.Adduint32(ctxt, ld.Linklookup(ctxt, ".linkedit.got", 0), uint32(s.Dynid))
|
||||||
|
} else {
|
||||||
|
ld.Diag("addgotsym: unsupported binary format")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func adddynsym(ctxt *ld.Link, s *ld.LSym) {
|
||||||
|
var d *ld.LSym
|
||||||
|
var t int
|
||||||
|
var name string
|
||||||
|
|
||||||
|
if s.Dynid >= 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if ld.Iself {
|
||||||
|
s.Dynid = int32(ld.Nelfsym)
|
||||||
|
ld.Nelfsym++
|
||||||
|
|
||||||
|
d = ld.Linklookup(ctxt, ".dynsym", 0)
|
||||||
|
|
||||||
|
/* name */
|
||||||
|
name = s.Extname
|
||||||
|
|
||||||
|
ld.Adduint32(ctxt, d, uint32(ld.Addstring(ld.Linklookup(ctxt, ".dynstr", 0), name)))
|
||||||
|
|
||||||
|
/* value */
|
||||||
|
if s.Type == ld.SDYNIMPORT {
|
||||||
|
ld.Adduint32(ctxt, d, 0)
|
||||||
|
} else {
|
||||||
|
ld.Addaddr(ctxt, d, s)
|
||||||
|
}
|
||||||
|
|
||||||
|
/* size */
|
||||||
|
ld.Adduint32(ctxt, d, 0)
|
||||||
|
|
||||||
|
/* type */
|
||||||
|
t = ld.STB_GLOBAL << 4
|
||||||
|
|
||||||
|
if s.Cgoexport != 0 && s.Type&ld.SMASK == ld.STEXT {
|
||||||
|
t |= ld.STT_FUNC
|
||||||
|
} else {
|
||||||
|
t |= ld.STT_OBJECT
|
||||||
|
}
|
||||||
|
ld.Adduint8(ctxt, d, uint8(t))
|
||||||
|
ld.Adduint8(ctxt, d, 0)
|
||||||
|
|
||||||
|
/* shndx */
|
||||||
|
if s.Type == ld.SDYNIMPORT {
|
||||||
|
ld.Adduint16(ctxt, d, ld.SHN_UNDEF)
|
||||||
|
} else {
|
||||||
|
ld.Adduint16(ctxt, d, 1)
|
||||||
|
}
|
||||||
|
} else if ld.HEADTYPE == ld.Hdarwin {
|
||||||
|
ld.Diag("adddynsym: missed symbol %s (%s)", s.Name, s.Extname)
|
||||||
|
} else if ld.HEADTYPE == ld.Hwindows {
|
||||||
|
} else // already taken care of
|
||||||
|
{
|
||||||
|
ld.Diag("adddynsym: unsupported binary format")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func adddynlib(lib string) {
|
||||||
|
var s *ld.LSym
|
||||||
|
|
||||||
|
if needlib(lib) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if ld.Iself {
|
||||||
|
s = ld.Linklookup(ld.Ctxt, ".dynstr", 0)
|
||||||
|
if s.Size == 0 {
|
||||||
|
ld.Addstring(s, "")
|
||||||
|
}
|
||||||
|
ld.Elfwritedynent(ld.Linklookup(ld.Ctxt, ".dynamic", 0), ld.DT_NEEDED, uint64(ld.Addstring(s, lib)))
|
||||||
|
} else if ld.HEADTYPE == ld.Hdarwin {
|
||||||
|
ld.Machoadddynlib(lib)
|
||||||
|
} else if ld.HEADTYPE != ld.Hwindows {
|
||||||
|
ld.Diag("adddynlib: unsupported binary format")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func asmb() {
|
||||||
|
var magic int32
|
||||||
|
var symo uint32
|
||||||
|
var dwarfoff uint32
|
||||||
|
var machlink uint32
|
||||||
|
var sect *ld.Section
|
||||||
|
var sym *ld.LSym
|
||||||
|
var i int
|
||||||
|
|
||||||
|
if ld.Debug['v'] != 0 {
|
||||||
|
fmt.Fprintf(&ld.Bso, "%5.2f asmb\n", obj.Cputime())
|
||||||
|
}
|
||||||
|
ld.Bflush(&ld.Bso)
|
||||||
|
|
||||||
|
if ld.Iself {
|
||||||
|
ld.Asmbelfsetup()
|
||||||
|
}
|
||||||
|
|
||||||
|
sect = ld.Segtext.Sect
|
||||||
|
ld.Cseek(int64(sect.Vaddr - ld.Segtext.Vaddr + ld.Segtext.Fileoff))
|
||||||
|
ld.Codeblk(int64(sect.Vaddr), int64(sect.Length))
|
||||||
|
for sect = sect.Next; sect != nil; sect = sect.Next {
|
||||||
|
ld.Cseek(int64(sect.Vaddr - ld.Segtext.Vaddr + ld.Segtext.Fileoff))
|
||||||
|
ld.Datblk(int64(sect.Vaddr), int64(sect.Length))
|
||||||
|
}
|
||||||
|
|
||||||
|
if ld.Segrodata.Filelen > 0 {
|
||||||
|
if ld.Debug['v'] != 0 {
|
||||||
|
fmt.Fprintf(&ld.Bso, "%5.2f rodatblk\n", obj.Cputime())
|
||||||
|
}
|
||||||
|
ld.Bflush(&ld.Bso)
|
||||||
|
|
||||||
|
ld.Cseek(int64(ld.Segrodata.Fileoff))
|
||||||
|
ld.Datblk(int64(ld.Segrodata.Vaddr), int64(ld.Segrodata.Filelen))
|
||||||
|
}
|
||||||
|
|
||||||
|
if ld.Debug['v'] != 0 {
|
||||||
|
fmt.Fprintf(&ld.Bso, "%5.2f datblk\n", obj.Cputime())
|
||||||
|
}
|
||||||
|
ld.Bflush(&ld.Bso)
|
||||||
|
|
||||||
|
ld.Cseek(int64(ld.Segdata.Fileoff))
|
||||||
|
ld.Datblk(int64(ld.Segdata.Vaddr), int64(ld.Segdata.Filelen))
|
||||||
|
|
||||||
|
machlink = 0
|
||||||
|
if ld.HEADTYPE == ld.Hdarwin {
|
||||||
|
if ld.Debug['v'] != 0 {
|
||||||
|
fmt.Fprintf(&ld.Bso, "%5.2f dwarf\n", obj.Cputime())
|
||||||
|
}
|
||||||
|
|
||||||
|
dwarfoff = uint32(ld.Rnd(int64(uint64(ld.HEADR)+ld.Segtext.Length), int64(ld.INITRND)) + ld.Rnd(int64(ld.Segdata.Filelen), int64(ld.INITRND)))
|
||||||
|
ld.Cseek(int64(dwarfoff))
|
||||||
|
|
||||||
|
ld.Segdwarf.Fileoff = uint64(ld.Cpos())
|
||||||
|
ld.Dwarfemitdebugsections()
|
||||||
|
ld.Segdwarf.Filelen = uint64(ld.Cpos()) - ld.Segdwarf.Fileoff
|
||||||
|
|
||||||
|
machlink = uint32(ld.Domacholink())
|
||||||
|
}
|
||||||
|
|
||||||
|
ld.Symsize = 0
|
||||||
|
ld.Spsize = 0
|
||||||
|
ld.Lcsize = 0
|
||||||
|
symo = 0
|
||||||
|
if ld.Debug['s'] == 0 {
|
||||||
|
// TODO: rationalize
|
||||||
|
if ld.Debug['v'] != 0 {
|
||||||
|
fmt.Fprintf(&ld.Bso, "%5.2f sym\n", obj.Cputime())
|
||||||
|
}
|
||||||
|
ld.Bflush(&ld.Bso)
|
||||||
|
switch ld.HEADTYPE {
|
||||||
|
default:
|
||||||
|
if ld.Iself {
|
||||||
|
symo = uint32(ld.Segdata.Fileoff + ld.Segdata.Filelen)
|
||||||
|
symo = uint32(ld.Rnd(int64(symo), int64(ld.INITRND)))
|
||||||
|
}
|
||||||
|
|
||||||
|
case ld.Hplan9:
|
||||||
|
symo = uint32(ld.Segdata.Fileoff + ld.Segdata.Filelen)
|
||||||
|
|
||||||
|
case ld.Hdarwin:
|
||||||
|
symo = uint32(ld.Segdata.Fileoff + uint64(ld.Rnd(int64(ld.Segdata.Filelen), int64(ld.INITRND))) + uint64(machlink))
|
||||||
|
|
||||||
|
case ld.Hwindows:
|
||||||
|
symo = uint32(ld.Segdata.Fileoff + ld.Segdata.Filelen)
|
||||||
|
symo = uint32(ld.Rnd(int64(symo), ld.PEFILEALIGN))
|
||||||
|
}
|
||||||
|
|
||||||
|
ld.Cseek(int64(symo))
|
||||||
|
switch ld.HEADTYPE {
|
||||||
|
default:
|
||||||
|
if ld.Iself {
|
||||||
|
if ld.Debug['v'] != 0 {
|
||||||
|
fmt.Fprintf(&ld.Bso, "%5.2f elfsym\n", obj.Cputime())
|
||||||
|
}
|
||||||
|
ld.Asmelfsym()
|
||||||
|
ld.Cflush()
|
||||||
|
ld.Cwrite(ld.Elfstrdat)
|
||||||
|
|
||||||
|
if ld.Debug['v'] != 0 {
|
||||||
|
fmt.Fprintf(&ld.Bso, "%5.2f dwarf\n", obj.Cputime())
|
||||||
|
}
|
||||||
|
ld.Dwarfemitdebugsections()
|
||||||
|
|
||||||
|
if ld.Linkmode == ld.LinkExternal {
|
||||||
|
ld.Elfemitreloc()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
case ld.Hplan9:
|
||||||
|
ld.Asmplan9sym()
|
||||||
|
ld.Cflush()
|
||||||
|
|
||||||
|
sym = ld.Linklookup(ld.Ctxt, "pclntab", 0)
|
||||||
|
if sym != nil {
|
||||||
|
ld.Lcsize = int32(len(sym.P))
|
||||||
|
for i = 0; int32(i) < ld.Lcsize; i++ {
|
||||||
|
ld.Cput(uint8(sym.P[i]))
|
||||||
|
}
|
||||||
|
|
||||||
|
ld.Cflush()
|
||||||
|
}
|
||||||
|
|
||||||
|
case ld.Hwindows:
|
||||||
|
if ld.Debug['v'] != 0 {
|
||||||
|
fmt.Fprintf(&ld.Bso, "%5.2f dwarf\n", obj.Cputime())
|
||||||
|
}
|
||||||
|
ld.Dwarfemitdebugsections()
|
||||||
|
|
||||||
|
case ld.Hdarwin:
|
||||||
|
if ld.Linkmode == ld.LinkExternal {
|
||||||
|
ld.Machoemitreloc()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ld.Debug['v'] != 0 {
|
||||||
|
fmt.Fprintf(&ld.Bso, "%5.2f headr\n", obj.Cputime())
|
||||||
|
}
|
||||||
|
ld.Bflush(&ld.Bso)
|
||||||
|
ld.Cseek(0)
|
||||||
|
switch ld.HEADTYPE {
|
||||||
|
default:
|
||||||
|
case ld.Hplan9: /* plan9 */
|
||||||
|
magic = 4*11*11 + 7
|
||||||
|
|
||||||
|
ld.Lputb(uint32(magic)) /* magic */
|
||||||
|
ld.Lputb(uint32(ld.Segtext.Filelen)) /* sizes */
|
||||||
|
ld.Lputb(uint32(ld.Segdata.Filelen))
|
||||||
|
ld.Lputb(uint32(ld.Segdata.Length - ld.Segdata.Filelen))
|
||||||
|
ld.Lputb(uint32(ld.Symsize)) /* nsyms */
|
||||||
|
ld.Lputb(uint32(ld.Entryvalue())) /* va of entry */
|
||||||
|
ld.Lputb(uint32(ld.Spsize)) /* sp offsets */
|
||||||
|
ld.Lputb(uint32(ld.Lcsize)) /* line offsets */
|
||||||
|
|
||||||
|
case ld.Hdarwin:
|
||||||
|
ld.Asmbmacho()
|
||||||
|
|
||||||
|
case ld.Hlinux,
|
||||||
|
ld.Hfreebsd,
|
||||||
|
ld.Hnetbsd,
|
||||||
|
ld.Hopenbsd,
|
||||||
|
ld.Hdragonfly,
|
||||||
|
ld.Hnacl:
|
||||||
|
ld.Asmbelf(int64(symo))
|
||||||
|
|
||||||
|
case ld.Hwindows:
|
||||||
|
ld.Asmbpe()
|
||||||
|
}
|
||||||
|
|
||||||
|
ld.Cflush()
|
||||||
|
}
|
||||||
78
src/cmd/new8l/l.go
Normal file
78
src/cmd/new8l/l.go
Normal file
|
|
@ -0,0 +1,78 @@
|
||||||
|
// Inferno utils/8l/asm.c
|
||||||
|
// http://code.google.com/p/inferno-os/source/browse/utils/8l/asm.c
|
||||||
|
//
|
||||||
|
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
|
||||||
|
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
|
||||||
|
// Portions Copyright © 1997-1999 Vita Nuova Limited
|
||||||
|
// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
|
||||||
|
// Portions Copyright © 2004,2006 Bruce Ellis
|
||||||
|
// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
|
||||||
|
// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
|
||||||
|
// Portions Copyright © 2009 The Go Authors. All rights reserved.
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
|
// in the Software without restriction, including without limitation the rights
|
||||||
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
// THE SOFTWARE.
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
// Writing object files.
|
||||||
|
|
||||||
|
// Inferno utils/8l/l.h
|
||||||
|
// http://code.google.com/p/inferno-os/source/browse/utils/8l/l.h
|
||||||
|
//
|
||||||
|
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
|
||||||
|
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
|
||||||
|
// Portions Copyright © 1997-1999 Vita Nuova Limited
|
||||||
|
// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
|
||||||
|
// Portions Copyright © 2004,2006 Bruce Ellis
|
||||||
|
// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
|
||||||
|
// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
|
||||||
|
// Portions Copyright © 2009 The Go Authors. All rights reserved.
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
|
// in the Software without restriction, including without limitation the rights
|
||||||
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
// THE SOFTWARE.
|
||||||
|
|
||||||
|
const (
|
||||||
|
thechar = '8'
|
||||||
|
PtrSize = 4
|
||||||
|
IntSize = 4
|
||||||
|
RegSize = 4
|
||||||
|
MaxAlign = 32
|
||||||
|
FuncAlign = 16
|
||||||
|
MINLC = 1
|
||||||
|
)
|
||||||
|
|
||||||
|
/* Used by ../ld/dwarf.c */
|
||||||
|
const (
|
||||||
|
DWARFREGSP = 4
|
||||||
|
)
|
||||||
191
src/cmd/new8l/obj.go
Normal file
191
src/cmd/new8l/obj.go
Normal file
|
|
@ -0,0 +1,191 @@
|
||||||
|
// Inferno utils/8l/obj.c
|
||||||
|
// http://code.google.com/p/inferno-os/source/browse/utils/8l/obj.c
|
||||||
|
//
|
||||||
|
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
|
||||||
|
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
|
||||||
|
// Portions Copyright © 1997-1999 Vita Nuova Limited
|
||||||
|
// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
|
||||||
|
// Portions Copyright © 2004,2006 Bruce Ellis
|
||||||
|
// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
|
||||||
|
// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
|
||||||
|
// Portions Copyright © 2009 The Go Authors. All rights reserved.
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
|
// in the Software without restriction, including without limitation the rights
|
||||||
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
// THE SOFTWARE.
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"cmd/internal/obj"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
)
|
||||||
|
import "cmd/internal/ld"
|
||||||
|
|
||||||
|
// Reading object files.
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
linkarchinit()
|
||||||
|
ld.Ldmain()
|
||||||
|
}
|
||||||
|
|
||||||
|
func linkarchinit() {
|
||||||
|
ld.Thestring = "386"
|
||||||
|
ld.Thelinkarch = &ld.Link386
|
||||||
|
|
||||||
|
ld.Thearch.Thechar = thechar
|
||||||
|
ld.Thearch.Ptrsize = ld.Thelinkarch.Ptrsize
|
||||||
|
ld.Thearch.Intsize = ld.Thelinkarch.Ptrsize
|
||||||
|
ld.Thearch.Regsize = ld.Thelinkarch.Regsize
|
||||||
|
ld.Thearch.Funcalign = FuncAlign
|
||||||
|
ld.Thearch.Maxalign = MaxAlign
|
||||||
|
ld.Thearch.Minlc = MINLC
|
||||||
|
ld.Thearch.Dwarfregsp = DWARFREGSP
|
||||||
|
|
||||||
|
ld.Thearch.Adddynlib = adddynlib
|
||||||
|
ld.Thearch.Adddynrel = adddynrel
|
||||||
|
ld.Thearch.Adddynsym = adddynsym
|
||||||
|
ld.Thearch.Archinit = archinit
|
||||||
|
ld.Thearch.Archreloc = archreloc
|
||||||
|
ld.Thearch.Archrelocvariant = archrelocvariant
|
||||||
|
ld.Thearch.Asmb = asmb
|
||||||
|
ld.Thearch.Elfreloc1 = elfreloc1
|
||||||
|
ld.Thearch.Elfsetupplt = elfsetupplt
|
||||||
|
ld.Thearch.Gentext = gentext
|
||||||
|
ld.Thearch.Machoreloc1 = machoreloc1
|
||||||
|
ld.Thearch.Lput = ld.Lputl
|
||||||
|
ld.Thearch.Wput = ld.Wputl
|
||||||
|
ld.Thearch.Vput = ld.Vputl
|
||||||
|
|
||||||
|
ld.Thearch.Linuxdynld = "/lib/ld-linux.so.2"
|
||||||
|
ld.Thearch.Freebsddynld = "/usr/libexec/ld-elf.so.1"
|
||||||
|
ld.Thearch.Openbsddynld = "/usr/libexec/ld.so"
|
||||||
|
ld.Thearch.Netbsddynld = "/usr/libexec/ld.elf_so"
|
||||||
|
ld.Thearch.Dragonflydynld = "/usr/libexec/ld-elf.so.2"
|
||||||
|
ld.Thearch.Solarisdynld = "/lib/ld.so.1"
|
||||||
|
}
|
||||||
|
|
||||||
|
func archinit() {
|
||||||
|
// getgoextlinkenabled is based on GO_EXTLINK_ENABLED when
|
||||||
|
// Go was built; see ../../make.bash.
|
||||||
|
if ld.Linkmode == ld.LinkAuto && obj.Getgoextlinkenabled() == "0" {
|
||||||
|
ld.Linkmode = ld.LinkInternal
|
||||||
|
}
|
||||||
|
|
||||||
|
switch ld.HEADTYPE {
|
||||||
|
default:
|
||||||
|
if ld.Linkmode == ld.LinkAuto {
|
||||||
|
ld.Linkmode = ld.LinkInternal
|
||||||
|
}
|
||||||
|
if ld.Linkmode == ld.LinkExternal && obj.Getgoextlinkenabled() != "1" {
|
||||||
|
log.Fatalf("cannot use -linkmode=external with -H %s", ld.Headstr(int(ld.HEADTYPE)))
|
||||||
|
}
|
||||||
|
|
||||||
|
case ld.Hdarwin,
|
||||||
|
ld.Hdragonfly,
|
||||||
|
ld.Hfreebsd,
|
||||||
|
ld.Hlinux,
|
||||||
|
ld.Hnetbsd,
|
||||||
|
ld.Hopenbsd:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
switch ld.HEADTYPE {
|
||||||
|
default:
|
||||||
|
ld.Diag("unknown -H option")
|
||||||
|
ld.Errorexit()
|
||||||
|
fallthrough
|
||||||
|
|
||||||
|
case ld.Hplan9: /* plan 9 */
|
||||||
|
ld.HEADR = 32
|
||||||
|
|
||||||
|
if ld.INITTEXT == -1 {
|
||||||
|
ld.INITTEXT = 4096 + 32
|
||||||
|
}
|
||||||
|
if ld.INITDAT == -1 {
|
||||||
|
ld.INITDAT = 0
|
||||||
|
}
|
||||||
|
if ld.INITRND == -1 {
|
||||||
|
ld.INITRND = 4096
|
||||||
|
}
|
||||||
|
|
||||||
|
case ld.Hdarwin: /* apple MACH */
|
||||||
|
ld.Machoinit()
|
||||||
|
|
||||||
|
ld.HEADR = ld.INITIAL_MACHO_HEADR
|
||||||
|
if ld.INITTEXT == -1 {
|
||||||
|
ld.INITTEXT = 4096 + int64(ld.HEADR)
|
||||||
|
}
|
||||||
|
if ld.INITDAT == -1 {
|
||||||
|
ld.INITDAT = 0
|
||||||
|
}
|
||||||
|
if ld.INITRND == -1 {
|
||||||
|
ld.INITRND = 4096
|
||||||
|
}
|
||||||
|
|
||||||
|
case ld.Hlinux, /* elf32 executable */
|
||||||
|
ld.Hfreebsd,
|
||||||
|
ld.Hnetbsd,
|
||||||
|
ld.Hopenbsd,
|
||||||
|
ld.Hdragonfly:
|
||||||
|
ld.Elfinit()
|
||||||
|
|
||||||
|
ld.HEADR = ld.ELFRESERVE
|
||||||
|
if ld.INITTEXT == -1 {
|
||||||
|
ld.INITTEXT = 0x08048000 + int64(ld.HEADR)
|
||||||
|
}
|
||||||
|
if ld.INITDAT == -1 {
|
||||||
|
ld.INITDAT = 0
|
||||||
|
}
|
||||||
|
if ld.INITRND == -1 {
|
||||||
|
ld.INITRND = 4096
|
||||||
|
}
|
||||||
|
|
||||||
|
case ld.Hnacl:
|
||||||
|
ld.Elfinit()
|
||||||
|
ld.HEADR = 0x10000
|
||||||
|
ld.Funcalign = 32
|
||||||
|
if ld.INITTEXT == -1 {
|
||||||
|
ld.INITTEXT = 0x20000
|
||||||
|
}
|
||||||
|
if ld.INITDAT == -1 {
|
||||||
|
ld.INITDAT = 0
|
||||||
|
}
|
||||||
|
if ld.INITRND == -1 {
|
||||||
|
ld.INITRND = 0x10000
|
||||||
|
}
|
||||||
|
|
||||||
|
case ld.Hwindows: /* PE executable */
|
||||||
|
ld.Peinit()
|
||||||
|
|
||||||
|
ld.HEADR = ld.PEFILEHEADR
|
||||||
|
if ld.INITTEXT == -1 {
|
||||||
|
ld.INITTEXT = ld.PEBASE + int64(ld.PESECTHEADR)
|
||||||
|
}
|
||||||
|
if ld.INITDAT == -1 {
|
||||||
|
ld.INITDAT = 0
|
||||||
|
}
|
||||||
|
if ld.INITRND == -1 {
|
||||||
|
ld.INITRND = ld.PESECTALIGN
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ld.INITDAT != 0 && ld.INITRND != 0 {
|
||||||
|
fmt.Printf("warning: -D0x%x is ignored because of -R0x%x\n", uint64(ld.INITDAT), uint32(ld.INITRND))
|
||||||
|
}
|
||||||
|
}
|
||||||
851
src/cmd/new9l/asm.go
Normal file
851
src/cmd/new9l/asm.go
Normal file
|
|
@ -0,0 +1,851 @@
|
||||||
|
// Inferno utils/5l/asm.c
|
||||||
|
// http://code.google.com/p/inferno-os/source/browse/utils/5l/asm.c
|
||||||
|
//
|
||||||
|
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
|
||||||
|
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
|
||||||
|
// Portions Copyright © 1997-1999 Vita Nuova Limited
|
||||||
|
// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
|
||||||
|
// Portions Copyright © 2004,2006 Bruce Ellis
|
||||||
|
// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
|
||||||
|
// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
|
||||||
|
// Portions Copyright © 2009 The Go Authors. All rights reserved.
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
|
// in the Software without restriction, including without limitation the rights
|
||||||
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
// THE SOFTWARE.
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"cmd/internal/obj"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
)
|
||||||
|
import "cmd/internal/ld"
|
||||||
|
|
||||||
|
func needlib(name string) int {
|
||||||
|
var p string
|
||||||
|
var s *ld.LSym
|
||||||
|
|
||||||
|
if name[0] == '\x00' {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
/* reuse hash code in symbol table */
|
||||||
|
p = fmt.Sprintf(".dynlib.%s", name)
|
||||||
|
|
||||||
|
s = ld.Linklookup(ld.Ctxt, p, 0)
|
||||||
|
|
||||||
|
if s.Type == 0 {
|
||||||
|
s.Type = 100 // avoid SDATA, etc.
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func gentext() {
|
||||||
|
var s *ld.LSym
|
||||||
|
var stub *ld.LSym
|
||||||
|
var pprevtextp **ld.LSym
|
||||||
|
var r *ld.Reloc
|
||||||
|
var n string
|
||||||
|
var o1 uint32
|
||||||
|
var i int
|
||||||
|
|
||||||
|
// The ppc64 ABI PLT has similar concepts to other
|
||||||
|
// architectures, but is laid out quite differently. When we
|
||||||
|
// see an R_PPC64_REL24 relocation to a dynamic symbol
|
||||||
|
// (indicating that the call needs to go through the PLT), we
|
||||||
|
// generate up to three stubs and reserve a PLT slot.
|
||||||
|
//
|
||||||
|
// 1) The call site will be bl x; nop (where the relocation
|
||||||
|
// applies to the bl). We rewrite this to bl x_stub; ld
|
||||||
|
// r2,24(r1). The ld is necessary because x_stub will save
|
||||||
|
// r2 (the TOC pointer) at 24(r1) (the "TOC save slot").
|
||||||
|
//
|
||||||
|
// 2) We reserve space for a pointer in the .plt section (once
|
||||||
|
// per referenced dynamic function). .plt is a data
|
||||||
|
// section filled solely by the dynamic linker (more like
|
||||||
|
// .plt.got on other architectures). Initially, the
|
||||||
|
// dynamic linker will fill each slot with a pointer to the
|
||||||
|
// corresponding x@plt entry point.
|
||||||
|
//
|
||||||
|
// 3) We generate the "call stub" x_stub (once per dynamic
|
||||||
|
// function/object file pair). This saves the TOC in the
|
||||||
|
// TOC save slot, reads the function pointer from x's .plt
|
||||||
|
// slot and calls it like any other global entry point
|
||||||
|
// (including setting r12 to the function address).
|
||||||
|
//
|
||||||
|
// 4) We generate the "symbol resolver stub" x@plt (once per
|
||||||
|
// dynamic function). This is solely a branch to the glink
|
||||||
|
// resolver stub.
|
||||||
|
//
|
||||||
|
// 5) We generate the glink resolver stub (only once). This
|
||||||
|
// computes which symbol resolver stub we came through and
|
||||||
|
// invokes the dynamic resolver via a pointer provided by
|
||||||
|
// the dynamic linker. This will patch up the .plt slot to
|
||||||
|
// point directly at the function so future calls go
|
||||||
|
// straight from the call stub to the real function, and
|
||||||
|
// then call the function.
|
||||||
|
|
||||||
|
// NOTE: It's possible we could make ppc64 closer to other
|
||||||
|
// architectures: ppc64's .plt is like .plt.got on other
|
||||||
|
// platforms and ppc64's .glink is like .plt on other
|
||||||
|
// platforms.
|
||||||
|
|
||||||
|
// Find all R_PPC64_REL24 relocations that reference dynamic
|
||||||
|
// imports. Reserve PLT entries for these symbols and
|
||||||
|
// generate call stubs. The call stubs need to live in .text,
|
||||||
|
// which is why we need to do this pass this early.
|
||||||
|
//
|
||||||
|
// This assumes "case 1" from the ABI, where the caller needs
|
||||||
|
// us to save and restore the TOC pointer.
|
||||||
|
pprevtextp = &ld.Ctxt.Textp
|
||||||
|
|
||||||
|
for s = *pprevtextp; s != nil; (func() { pprevtextp = &s.Next; s = *pprevtextp })() {
|
||||||
|
for i = range s.R {
|
||||||
|
r = &s.R[i]
|
||||||
|
if r.Type != 256+ld.R_PPC64_REL24 || r.Sym.Type != ld.SDYNIMPORT {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reserve PLT entry and generate symbol
|
||||||
|
// resolver
|
||||||
|
addpltsym(ld.Ctxt, r.Sym)
|
||||||
|
|
||||||
|
// Generate call stub
|
||||||
|
n = fmt.Sprintf("%s.%s", s.Name, r.Sym.Name)
|
||||||
|
|
||||||
|
stub = ld.Linklookup(ld.Ctxt, n, 0)
|
||||||
|
stub.Reachable = stub.Reachable || s.Reachable
|
||||||
|
if stub.Size == 0 {
|
||||||
|
// Need outer to resolve .TOC.
|
||||||
|
stub.Outer = s
|
||||||
|
|
||||||
|
// Link in to textp before s (we could
|
||||||
|
// do it after, but would have to skip
|
||||||
|
// the subsymbols)
|
||||||
|
*pprevtextp = stub
|
||||||
|
|
||||||
|
stub.Next = s
|
||||||
|
pprevtextp = &stub.Next
|
||||||
|
|
||||||
|
gencallstub(1, stub, r.Sym)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the relocation to use the call stub
|
||||||
|
r.Sym = stub
|
||||||
|
|
||||||
|
// Restore TOC after bl. The compiler put a
|
||||||
|
// nop here for us to overwrite.
|
||||||
|
o1 = 0xe8410018 // ld r2,24(r1)
|
||||||
|
ld.Ctxt.Arch.ByteOrder.PutUint32(s.P[r.Off:], o1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Construct a call stub in stub that calls symbol targ via its PLT
|
||||||
|
// entry.
|
||||||
|
func gencallstub(abicase int, stub *ld.LSym, targ *ld.LSym) {
|
||||||
|
var plt *ld.LSym
|
||||||
|
var r *ld.Reloc
|
||||||
|
|
||||||
|
if abicase != 1 {
|
||||||
|
// If we see R_PPC64_TOCSAVE or R_PPC64_REL24_NOTOC
|
||||||
|
// relocations, we'll need to implement cases 2 and 3.
|
||||||
|
log.Fatalf("gencallstub only implements case 1 calls")
|
||||||
|
}
|
||||||
|
|
||||||
|
plt = ld.Linklookup(ld.Ctxt, ".plt", 0)
|
||||||
|
|
||||||
|
stub.Type = ld.STEXT
|
||||||
|
|
||||||
|
// Save TOC pointer in TOC save slot
|
||||||
|
ld.Adduint32(ld.Ctxt, stub, 0xf8410018) // std r2,24(r1)
|
||||||
|
|
||||||
|
// Load the function pointer from the PLT.
|
||||||
|
r = ld.Addrel(stub)
|
||||||
|
|
||||||
|
r.Off = int32(stub.Size)
|
||||||
|
r.Sym = plt
|
||||||
|
r.Add = int64(targ.Plt)
|
||||||
|
r.Siz = 2
|
||||||
|
if ld.Ctxt.Arch.Endian == ld.BigEndian {
|
||||||
|
r.Off += int32(r.Siz)
|
||||||
|
}
|
||||||
|
r.Type = ld.R_POWER_TOC
|
||||||
|
r.Variant = ld.RV_POWER_HA
|
||||||
|
ld.Adduint32(ld.Ctxt, stub, 0x3d820000) // addis r12,r2,targ@plt@toc@ha
|
||||||
|
r = ld.Addrel(stub)
|
||||||
|
r.Off = int32(stub.Size)
|
||||||
|
r.Sym = plt
|
||||||
|
r.Add = int64(targ.Plt)
|
||||||
|
r.Siz = 2
|
||||||
|
if ld.Ctxt.Arch.Endian == ld.BigEndian {
|
||||||
|
r.Off += int32(r.Siz)
|
||||||
|
}
|
||||||
|
r.Type = ld.R_POWER_TOC
|
||||||
|
r.Variant = ld.RV_POWER_LO
|
||||||
|
ld.Adduint32(ld.Ctxt, stub, 0xe98c0000) // ld r12,targ@plt@toc@l(r12)
|
||||||
|
|
||||||
|
// Jump to the loaded pointer
|
||||||
|
ld.Adduint32(ld.Ctxt, stub, 0x7d8903a6) // mtctr r12
|
||||||
|
ld.Adduint32(ld.Ctxt, stub, 0x4e800420) // bctr
|
||||||
|
}
|
||||||
|
|
||||||
|
func adddynrela(rel *ld.LSym, s *ld.LSym, r *ld.Reloc) {
|
||||||
|
log.Fatalf("adddynrela not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
func adddynrel(s *ld.LSym, r *ld.Reloc) {
|
||||||
|
var targ *ld.LSym
|
||||||
|
var rela *ld.LSym
|
||||||
|
|
||||||
|
targ = r.Sym
|
||||||
|
ld.Ctxt.Cursym = s
|
||||||
|
|
||||||
|
switch r.Type {
|
||||||
|
default:
|
||||||
|
if r.Type >= 256 {
|
||||||
|
ld.Diag("unexpected relocation type %d", r.Type)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle relocations found in ELF object files.
|
||||||
|
case 256 + ld.R_PPC64_REL24:
|
||||||
|
r.Type = ld.R_CALLPOWER
|
||||||
|
|
||||||
|
// This is a local call, so the caller isn't setting
|
||||||
|
// up r12 and r2 is the same for the caller and
|
||||||
|
// callee. Hence, we need to go to the local entry
|
||||||
|
// point. (If we don't do this, the callee will try
|
||||||
|
// to use r12 to compute r2.)
|
||||||
|
r.Add += int64(r.Sym.Localentry) * 4
|
||||||
|
|
||||||
|
if targ.Type == ld.SDYNIMPORT {
|
||||||
|
// Should have been handled in elfsetupplt
|
||||||
|
ld.Diag("unexpected R_PPC64_REL24 for dyn import")
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
|
case 256 + ld.R_PPC64_ADDR64:
|
||||||
|
r.Type = ld.R_ADDR
|
||||||
|
if targ.Type == ld.SDYNIMPORT {
|
||||||
|
// These happen in .toc sections
|
||||||
|
adddynsym(ld.Ctxt, targ)
|
||||||
|
|
||||||
|
rela = ld.Linklookup(ld.Ctxt, ".rela", 0)
|
||||||
|
ld.Addaddrplus(ld.Ctxt, rela, s, int64(r.Off))
|
||||||
|
ld.Adduint64(ld.Ctxt, rela, ld.ELF64_R_INFO(uint32(targ.Dynid), ld.R_PPC64_ADDR64))
|
||||||
|
ld.Adduint64(ld.Ctxt, rela, uint64(r.Add))
|
||||||
|
r.Type = 256 // ignore during relocsym
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
|
case 256 + ld.R_PPC64_TOC16:
|
||||||
|
r.Type = ld.R_POWER_TOC
|
||||||
|
r.Variant = ld.RV_POWER_LO | ld.RV_CHECK_OVERFLOW
|
||||||
|
return
|
||||||
|
|
||||||
|
case 256 + ld.R_PPC64_TOC16_LO:
|
||||||
|
r.Type = ld.R_POWER_TOC
|
||||||
|
r.Variant = ld.RV_POWER_LO
|
||||||
|
return
|
||||||
|
|
||||||
|
case 256 + ld.R_PPC64_TOC16_HA:
|
||||||
|
r.Type = ld.R_POWER_TOC
|
||||||
|
r.Variant = ld.RV_POWER_HA | ld.RV_CHECK_OVERFLOW
|
||||||
|
return
|
||||||
|
|
||||||
|
case 256 + ld.R_PPC64_TOC16_HI:
|
||||||
|
r.Type = ld.R_POWER_TOC
|
||||||
|
r.Variant = ld.RV_POWER_HI | ld.RV_CHECK_OVERFLOW
|
||||||
|
return
|
||||||
|
|
||||||
|
case 256 + ld.R_PPC64_TOC16_DS:
|
||||||
|
r.Type = ld.R_POWER_TOC
|
||||||
|
r.Variant = ld.RV_POWER_DS | ld.RV_CHECK_OVERFLOW
|
||||||
|
return
|
||||||
|
|
||||||
|
case 256 + ld.R_PPC64_TOC16_LO_DS:
|
||||||
|
r.Type = ld.R_POWER_TOC
|
||||||
|
r.Variant = ld.RV_POWER_DS
|
||||||
|
return
|
||||||
|
|
||||||
|
case 256 + ld.R_PPC64_REL16_LO:
|
||||||
|
r.Type = ld.R_PCREL
|
||||||
|
r.Variant = ld.RV_POWER_LO
|
||||||
|
r.Add += 2 // Compensate for relocation size of 2
|
||||||
|
return
|
||||||
|
|
||||||
|
case 256 + ld.R_PPC64_REL16_HI:
|
||||||
|
r.Type = ld.R_PCREL
|
||||||
|
r.Variant = ld.RV_POWER_HI | ld.RV_CHECK_OVERFLOW
|
||||||
|
r.Add += 2
|
||||||
|
return
|
||||||
|
|
||||||
|
case 256 + ld.R_PPC64_REL16_HA:
|
||||||
|
r.Type = ld.R_PCREL
|
||||||
|
r.Variant = ld.RV_POWER_HA | ld.RV_CHECK_OVERFLOW
|
||||||
|
r.Add += 2
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle references to ELF symbols from our own object files.
|
||||||
|
if targ.Type != ld.SDYNIMPORT {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(austin): Translate our relocations to ELF
|
||||||
|
|
||||||
|
ld.Diag("unsupported relocation for dynamic symbol %s (type=%d stype=%d)", targ.Name, r.Type, targ.Type)
|
||||||
|
}
|
||||||
|
|
||||||
|
func elfreloc1(r *ld.Reloc, sectoff int64) int {
|
||||||
|
// TODO(minux)
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|
||||||
|
func elfsetupplt() {
|
||||||
|
var plt *ld.LSym
|
||||||
|
|
||||||
|
plt = ld.Linklookup(ld.Ctxt, ".plt", 0)
|
||||||
|
if plt.Size == 0 {
|
||||||
|
// The dynamic linker stores the address of the
|
||||||
|
// dynamic resolver and the DSO identifier in the two
|
||||||
|
// doublewords at the beginning of the .plt section
|
||||||
|
// before the PLT array. Reserve space for these.
|
||||||
|
plt.Size = 16
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func machoreloc1(r *ld.Reloc, sectoff int64) int {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return the value of .TOC. for symbol s
|
||||||
|
func symtoc(s *ld.LSym) int64 {
|
||||||
|
var toc *ld.LSym
|
||||||
|
|
||||||
|
if s.Outer != nil {
|
||||||
|
toc = ld.Linkrlookup(ld.Ctxt, ".TOC.", int(s.Outer.Version))
|
||||||
|
} else {
|
||||||
|
toc = ld.Linkrlookup(ld.Ctxt, ".TOC.", int(s.Version))
|
||||||
|
}
|
||||||
|
|
||||||
|
if toc == nil {
|
||||||
|
ld.Diag("TOC-relative relocation in object without .TOC.")
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
return toc.Value
|
||||||
|
}
|
||||||
|
|
||||||
|
func archreloc(r *ld.Reloc, s *ld.LSym, val *int64) int {
|
||||||
|
var o1 uint32
|
||||||
|
var o2 uint32
|
||||||
|
var t int64
|
||||||
|
|
||||||
|
if ld.Linkmode == ld.LinkExternal {
|
||||||
|
// TODO(minux): translate R_ADDRPOWER and R_CALLPOWER into standard ELF relocations.
|
||||||
|
// R_ADDRPOWER corresponds to R_PPC_ADDR16_HA and R_PPC_ADDR16_LO.
|
||||||
|
// R_CALLPOWER corresponds to R_PPC_REL24.
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|
||||||
|
switch r.Type {
|
||||||
|
case ld.R_CONST:
|
||||||
|
*val = r.Add
|
||||||
|
return 0
|
||||||
|
|
||||||
|
case ld.R_GOTOFF:
|
||||||
|
*val = ld.Symaddr(r.Sym) + r.Add - ld.Symaddr(ld.Linklookup(ld.Ctxt, ".got", 0))
|
||||||
|
return 0
|
||||||
|
|
||||||
|
// r->add is two ppc64 instructions holding an immediate 32-bit constant.
|
||||||
|
// We want to add r->sym's address to that constant.
|
||||||
|
// The encoding of the immediate x<<16 + y,
|
||||||
|
// where x is the low 16 bits of the first instruction and y is the low 16
|
||||||
|
// bits of the second. Both x and y are signed (int16, not uint16).
|
||||||
|
case ld.R_ADDRPOWER:
|
||||||
|
o1 = uint32(r.Add >> 32)
|
||||||
|
|
||||||
|
o2 = uint32(r.Add)
|
||||||
|
t = ld.Symaddr(r.Sym)
|
||||||
|
if t < 0 {
|
||||||
|
ld.Ctxt.Diag("relocation for %s is too big (>=2G): %d", s.Name, ld.Symaddr(r.Sym))
|
||||||
|
}
|
||||||
|
|
||||||
|
t += ((int64(o1) & 0xffff) << 16) + (int64(int32(o2)) << 16 >> 16)
|
||||||
|
if t&0x8000 != 0 {
|
||||||
|
t += 0x10000
|
||||||
|
}
|
||||||
|
o1 = uint32(int64(o1&0xffff0000) | (t>>16)&0xffff)
|
||||||
|
o2 = uint32(int64(o2&0xffff0000) | t&0xffff)
|
||||||
|
|
||||||
|
// when laid out, the instruction order must always be o1, o2.
|
||||||
|
if ld.Ctxt.Arch.Endian == ld.BigEndian {
|
||||||
|
*val = int64(o1)<<32 | int64(o2)
|
||||||
|
} else {
|
||||||
|
*val = int64(o2)<<32 | int64(o1)
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
|
||||||
|
// Bits 6 through 29 = (S + A - P) >> 2
|
||||||
|
case ld.R_CALLPOWER:
|
||||||
|
if ld.Ctxt.Arch.Endian == ld.BigEndian {
|
||||||
|
o1 = ld.Be32(s.P[r.Off:])
|
||||||
|
} else {
|
||||||
|
o1 = ld.Le32(s.P[r.Off:])
|
||||||
|
}
|
||||||
|
|
||||||
|
t = ld.Symaddr(r.Sym) + r.Add - (s.Value + int64(r.Off))
|
||||||
|
if t&3 != 0 {
|
||||||
|
ld.Ctxt.Diag("relocation for %s+%d is not aligned: %d", r.Sym.Name, r.Off, t)
|
||||||
|
}
|
||||||
|
if int64(int32(t<<6)>>6) != t {
|
||||||
|
// TODO(austin) This can happen if text > 32M.
|
||||||
|
// Add a call trampoline to .text in that case.
|
||||||
|
ld.Ctxt.Diag("relocation for %s+%d is too big: %d", r.Sym.Name, r.Off, t)
|
||||||
|
}
|
||||||
|
|
||||||
|
*val = int64(o1)&0xfc000003 | t&^0xfc000003
|
||||||
|
return 0
|
||||||
|
|
||||||
|
case ld.R_POWER_TOC: // S + A - .TOC.
|
||||||
|
*val = ld.Symaddr(r.Sym) + r.Add - symtoc(s)
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|
||||||
|
func archrelocvariant(r *ld.Reloc, s *ld.LSym, t int64) int64 {
|
||||||
|
var o1 uint32
|
||||||
|
switch r.Variant & ld.RV_TYPE_MASK {
|
||||||
|
default:
|
||||||
|
ld.Diag("unexpected relocation variant %d", r.Variant)
|
||||||
|
fallthrough
|
||||||
|
|
||||||
|
case ld.RV_NONE:
|
||||||
|
return t
|
||||||
|
|
||||||
|
case ld.RV_POWER_LO:
|
||||||
|
if r.Variant&ld.RV_CHECK_OVERFLOW != 0 {
|
||||||
|
// Whether to check for signed or unsigned
|
||||||
|
// overflow depends on the instruction
|
||||||
|
if ld.Ctxt.Arch.Endian == ld.BigEndian {
|
||||||
|
o1 = ld.Be32(s.P[r.Off-2:])
|
||||||
|
} else {
|
||||||
|
o1 = ld.Le32(s.P[r.Off:])
|
||||||
|
}
|
||||||
|
switch o1 >> 26 {
|
||||||
|
case 24, // ori
|
||||||
|
26, // xori
|
||||||
|
28: // andi
|
||||||
|
if t>>16 != 0 {
|
||||||
|
goto overflow
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
if int64(int16(t)) != t {
|
||||||
|
goto overflow
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return int64(int16(t))
|
||||||
|
|
||||||
|
case ld.RV_POWER_HA:
|
||||||
|
t += 0x8000
|
||||||
|
fallthrough
|
||||||
|
|
||||||
|
// Fallthrough
|
||||||
|
case ld.RV_POWER_HI:
|
||||||
|
t >>= 16
|
||||||
|
|
||||||
|
if r.Variant&ld.RV_CHECK_OVERFLOW != 0 {
|
||||||
|
// Whether to check for signed or unsigned
|
||||||
|
// overflow depends on the instruction
|
||||||
|
if ld.Ctxt.Arch.Endian == ld.BigEndian {
|
||||||
|
o1 = ld.Be32(s.P[r.Off-2:])
|
||||||
|
} else {
|
||||||
|
o1 = ld.Le32(s.P[r.Off:])
|
||||||
|
}
|
||||||
|
switch o1 >> 26 {
|
||||||
|
case 25, // oris
|
||||||
|
27, // xoris
|
||||||
|
29: // andis
|
||||||
|
if t>>16 != 0 {
|
||||||
|
goto overflow
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
if int64(int16(t)) != t {
|
||||||
|
goto overflow
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return int64(int16(t))
|
||||||
|
|
||||||
|
case ld.RV_POWER_DS:
|
||||||
|
if ld.Ctxt.Arch.Endian == ld.BigEndian {
|
||||||
|
o1 = uint32(ld.Be16(s.P[r.Off:]))
|
||||||
|
} else {
|
||||||
|
o1 = uint32(ld.Le16(s.P[r.Off:]))
|
||||||
|
}
|
||||||
|
if t&3 != 0 {
|
||||||
|
ld.Diag("relocation for %s+%d is not aligned: %d", r.Sym.Name, r.Off, t)
|
||||||
|
}
|
||||||
|
if (r.Variant&ld.RV_CHECK_OVERFLOW != 0) && int64(int16(t)) != t {
|
||||||
|
goto overflow
|
||||||
|
}
|
||||||
|
return int64(o1)&0x3 | int64(int16(t))
|
||||||
|
}
|
||||||
|
|
||||||
|
overflow:
|
||||||
|
ld.Diag("relocation for %s+%d is too big: %d", r.Sym.Name, r.Off, t)
|
||||||
|
return t
|
||||||
|
}
|
||||||
|
|
||||||
|
func addpltsym(ctxt *ld.Link, s *ld.LSym) {
|
||||||
|
if s.Plt >= 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
adddynsym(ctxt, s)
|
||||||
|
|
||||||
|
if ld.Iself {
|
||||||
|
var plt *ld.LSym
|
||||||
|
var rela *ld.LSym
|
||||||
|
var glink *ld.LSym
|
||||||
|
var r *ld.Reloc
|
||||||
|
|
||||||
|
plt = ld.Linklookup(ctxt, ".plt", 0)
|
||||||
|
rela = ld.Linklookup(ctxt, ".rela.plt", 0)
|
||||||
|
if plt.Size == 0 {
|
||||||
|
elfsetupplt()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the glink resolver if necessary
|
||||||
|
glink = ensureglinkresolver()
|
||||||
|
|
||||||
|
// Write symbol resolver stub (just a branch to the
|
||||||
|
// glink resolver stub)
|
||||||
|
r = ld.Addrel(glink)
|
||||||
|
|
||||||
|
r.Sym = glink
|
||||||
|
r.Off = int32(glink.Size)
|
||||||
|
r.Siz = 4
|
||||||
|
r.Type = ld.R_CALLPOWER
|
||||||
|
ld.Adduint32(ctxt, glink, 0x48000000) // b .glink
|
||||||
|
|
||||||
|
// In the ppc64 ABI, the dynamic linker is responsible
|
||||||
|
// for writing the entire PLT. We just need to
|
||||||
|
// reserve 8 bytes for each PLT entry and generate a
|
||||||
|
// JMP_SLOT dynamic relocation for it.
|
||||||
|
//
|
||||||
|
// TODO(austin): ABI v1 is different
|
||||||
|
s.Plt = int32(plt.Size)
|
||||||
|
|
||||||
|
plt.Size += 8
|
||||||
|
|
||||||
|
ld.Addaddrplus(ctxt, rela, plt, int64(s.Plt))
|
||||||
|
ld.Adduint64(ctxt, rela, ld.ELF64_R_INFO(uint32(s.Dynid), ld.R_PPC64_JMP_SLOT))
|
||||||
|
ld.Adduint64(ctxt, rela, 0)
|
||||||
|
} else {
|
||||||
|
ld.Diag("addpltsym: unsupported binary format")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate the glink resolver stub if necessary and return the .glink section
|
||||||
|
func ensureglinkresolver() *ld.LSym {
|
||||||
|
var glink *ld.LSym
|
||||||
|
var s *ld.LSym
|
||||||
|
var r *ld.Reloc
|
||||||
|
|
||||||
|
glink = ld.Linklookup(ld.Ctxt, ".glink", 0)
|
||||||
|
if glink.Size != 0 {
|
||||||
|
return glink
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is essentially the resolver from the ppc64 ELF ABI.
|
||||||
|
// At entry, r12 holds the address of the symbol resolver stub
|
||||||
|
// for the target routine and the argument registers hold the
|
||||||
|
// arguments for the target routine.
|
||||||
|
//
|
||||||
|
// This stub is PIC, so first get the PC of label 1 into r11.
|
||||||
|
// Other things will be relative to this.
|
||||||
|
ld.Adduint32(ld.Ctxt, glink, 0x7c0802a6) // mflr r0
|
||||||
|
ld.Adduint32(ld.Ctxt, glink, 0x429f0005) // bcl 20,31,1f
|
||||||
|
ld.Adduint32(ld.Ctxt, glink, 0x7d6802a6) // 1: mflr r11
|
||||||
|
ld.Adduint32(ld.Ctxt, glink, 0x7c0803a6) // mtlf r0
|
||||||
|
|
||||||
|
// Compute the .plt array index from the entry point address.
|
||||||
|
// Because this is PIC, everything is relative to label 1b (in
|
||||||
|
// r11):
|
||||||
|
// r0 = ((r12 - r11) - (res_0 - r11)) / 4 = (r12 - res_0) / 4
|
||||||
|
ld.Adduint32(ld.Ctxt, glink, 0x3800ffd0) // li r0,-(res_0-1b)=-48
|
||||||
|
ld.Adduint32(ld.Ctxt, glink, 0x7c006214) // add r0,r0,r12
|
||||||
|
ld.Adduint32(ld.Ctxt, glink, 0x7c0b0050) // sub r0,r0,r11
|
||||||
|
ld.Adduint32(ld.Ctxt, glink, 0x7800f082) // srdi r0,r0,2
|
||||||
|
|
||||||
|
// r11 = address of the first byte of the PLT
|
||||||
|
r = ld.Addrel(glink)
|
||||||
|
|
||||||
|
r.Off = int32(glink.Size)
|
||||||
|
r.Sym = ld.Linklookup(ld.Ctxt, ".plt", 0)
|
||||||
|
r.Siz = 8
|
||||||
|
r.Type = ld.R_ADDRPOWER
|
||||||
|
|
||||||
|
// addis r11,0,.plt@ha; addi r11,r11,.plt@l
|
||||||
|
r.Add = 0x3d600000<<32 | 0x396b0000
|
||||||
|
|
||||||
|
glink.Size += 8
|
||||||
|
|
||||||
|
// Load r12 = dynamic resolver address and r11 = DSO
|
||||||
|
// identifier from the first two doublewords of the PLT.
|
||||||
|
ld.Adduint32(ld.Ctxt, glink, 0xe98b0000) // ld r12,0(r11)
|
||||||
|
ld.Adduint32(ld.Ctxt, glink, 0xe96b0008) // ld r11,8(r11)
|
||||||
|
|
||||||
|
// Jump to the dynamic resolver
|
||||||
|
ld.Adduint32(ld.Ctxt, glink, 0x7d8903a6) // mtctr r12
|
||||||
|
ld.Adduint32(ld.Ctxt, glink, 0x4e800420) // bctr
|
||||||
|
|
||||||
|
// The symbol resolvers must immediately follow.
|
||||||
|
// res_0:
|
||||||
|
|
||||||
|
// Add DT_PPC64_GLINK .dynamic entry, which points to 32 bytes
|
||||||
|
// before the first symbol resolver stub.
|
||||||
|
s = ld.Linklookup(ld.Ctxt, ".dynamic", 0)
|
||||||
|
|
||||||
|
ld.Elfwritedynentsymplus(s, ld.DT_PPC64_GLINK, glink, glink.Size-32)
|
||||||
|
|
||||||
|
return glink
|
||||||
|
}
|
||||||
|
|
||||||
|
func adddynsym(ctxt *ld.Link, s *ld.LSym) {
|
||||||
|
var d *ld.LSym
|
||||||
|
var t int
|
||||||
|
var name string
|
||||||
|
|
||||||
|
if s.Dynid >= 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if ld.Iself {
|
||||||
|
s.Dynid = int32(ld.Nelfsym)
|
||||||
|
ld.Nelfsym++
|
||||||
|
|
||||||
|
d = ld.Linklookup(ctxt, ".dynsym", 0)
|
||||||
|
|
||||||
|
name = s.Extname
|
||||||
|
ld.Adduint32(ctxt, d, uint32(ld.Addstring(ld.Linklookup(ctxt, ".dynstr", 0), name)))
|
||||||
|
|
||||||
|
/* type */
|
||||||
|
t = ld.STB_GLOBAL << 4
|
||||||
|
|
||||||
|
if s.Cgoexport != 0 && s.Type&ld.SMASK == ld.STEXT {
|
||||||
|
t |= ld.STT_FUNC
|
||||||
|
} else {
|
||||||
|
t |= ld.STT_OBJECT
|
||||||
|
}
|
||||||
|
ld.Adduint8(ctxt, d, uint8(t))
|
||||||
|
|
||||||
|
/* reserved */
|
||||||
|
ld.Adduint8(ctxt, d, 0)
|
||||||
|
|
||||||
|
/* section where symbol is defined */
|
||||||
|
if s.Type == ld.SDYNIMPORT {
|
||||||
|
ld.Adduint16(ctxt, d, ld.SHN_UNDEF)
|
||||||
|
} else {
|
||||||
|
ld.Adduint16(ctxt, d, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
/* value */
|
||||||
|
if s.Type == ld.SDYNIMPORT {
|
||||||
|
ld.Adduint64(ctxt, d, 0)
|
||||||
|
} else {
|
||||||
|
ld.Addaddr(ctxt, d, s)
|
||||||
|
}
|
||||||
|
|
||||||
|
/* size of object */
|
||||||
|
ld.Adduint64(ctxt, d, uint64(s.Size))
|
||||||
|
} else {
|
||||||
|
ld.Diag("adddynsym: unsupported binary format")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func adddynlib(lib string) {
|
||||||
|
var s *ld.LSym
|
||||||
|
|
||||||
|
if needlib(lib) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if ld.Iself {
|
||||||
|
s = ld.Linklookup(ld.Ctxt, ".dynstr", 0)
|
||||||
|
if s.Size == 0 {
|
||||||
|
ld.Addstring(s, "")
|
||||||
|
}
|
||||||
|
ld.Elfwritedynent(ld.Linklookup(ld.Ctxt, ".dynamic", 0), ld.DT_NEEDED, uint64(ld.Addstring(s, lib)))
|
||||||
|
} else {
|
||||||
|
ld.Diag("adddynlib: unsupported binary format")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func asmb() {
|
||||||
|
var symo uint32
|
||||||
|
var sect *ld.Section
|
||||||
|
var sym *ld.LSym
|
||||||
|
var i int
|
||||||
|
|
||||||
|
if ld.Debug['v'] != 0 {
|
||||||
|
fmt.Fprintf(&ld.Bso, "%5.2f asmb\n", obj.Cputime())
|
||||||
|
}
|
||||||
|
ld.Bflush(&ld.Bso)
|
||||||
|
|
||||||
|
if ld.Iself {
|
||||||
|
ld.Asmbelfsetup()
|
||||||
|
}
|
||||||
|
|
||||||
|
sect = ld.Segtext.Sect
|
||||||
|
ld.Cseek(int64(sect.Vaddr - ld.Segtext.Vaddr + ld.Segtext.Fileoff))
|
||||||
|
ld.Codeblk(int64(sect.Vaddr), int64(sect.Length))
|
||||||
|
for sect = sect.Next; sect != nil; sect = sect.Next {
|
||||||
|
ld.Cseek(int64(sect.Vaddr - ld.Segtext.Vaddr + ld.Segtext.Fileoff))
|
||||||
|
ld.Datblk(int64(sect.Vaddr), int64(sect.Length))
|
||||||
|
}
|
||||||
|
|
||||||
|
if ld.Segrodata.Filelen > 0 {
|
||||||
|
if ld.Debug['v'] != 0 {
|
||||||
|
fmt.Fprintf(&ld.Bso, "%5.2f rodatblk\n", obj.Cputime())
|
||||||
|
}
|
||||||
|
ld.Bflush(&ld.Bso)
|
||||||
|
|
||||||
|
ld.Cseek(int64(ld.Segrodata.Fileoff))
|
||||||
|
ld.Datblk(int64(ld.Segrodata.Vaddr), int64(ld.Segrodata.Filelen))
|
||||||
|
}
|
||||||
|
|
||||||
|
if ld.Debug['v'] != 0 {
|
||||||
|
fmt.Fprintf(&ld.Bso, "%5.2f datblk\n", obj.Cputime())
|
||||||
|
}
|
||||||
|
ld.Bflush(&ld.Bso)
|
||||||
|
|
||||||
|
ld.Cseek(int64(ld.Segdata.Fileoff))
|
||||||
|
ld.Datblk(int64(ld.Segdata.Vaddr), int64(ld.Segdata.Filelen))
|
||||||
|
|
||||||
|
/* output symbol table */
|
||||||
|
ld.Symsize = 0
|
||||||
|
|
||||||
|
ld.Lcsize = 0
|
||||||
|
symo = 0
|
||||||
|
if ld.Debug['s'] == 0 {
|
||||||
|
// TODO: rationalize
|
||||||
|
if ld.Debug['v'] != 0 {
|
||||||
|
fmt.Fprintf(&ld.Bso, "%5.2f sym\n", obj.Cputime())
|
||||||
|
}
|
||||||
|
ld.Bflush(&ld.Bso)
|
||||||
|
switch ld.HEADTYPE {
|
||||||
|
default:
|
||||||
|
if ld.Iself {
|
||||||
|
symo = uint32(ld.Segdata.Fileoff + ld.Segdata.Filelen)
|
||||||
|
symo = uint32(ld.Rnd(int64(symo), int64(ld.INITRND)))
|
||||||
|
}
|
||||||
|
|
||||||
|
case ld.Hplan9:
|
||||||
|
symo = uint32(ld.Segdata.Fileoff + ld.Segdata.Filelen)
|
||||||
|
}
|
||||||
|
|
||||||
|
ld.Cseek(int64(symo))
|
||||||
|
switch ld.HEADTYPE {
|
||||||
|
default:
|
||||||
|
if ld.Iself {
|
||||||
|
if ld.Debug['v'] != 0 {
|
||||||
|
fmt.Fprintf(&ld.Bso, "%5.2f elfsym\n", obj.Cputime())
|
||||||
|
}
|
||||||
|
ld.Asmelfsym()
|
||||||
|
ld.Cflush()
|
||||||
|
ld.Cwrite(ld.Elfstrdat)
|
||||||
|
|
||||||
|
if ld.Debug['v'] != 0 {
|
||||||
|
fmt.Fprintf(&ld.Bso, "%5.2f dwarf\n", obj.Cputime())
|
||||||
|
}
|
||||||
|
ld.Dwarfemitdebugsections()
|
||||||
|
|
||||||
|
if ld.Linkmode == ld.LinkExternal {
|
||||||
|
ld.Elfemitreloc()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
case ld.Hplan9:
|
||||||
|
ld.Asmplan9sym()
|
||||||
|
ld.Cflush()
|
||||||
|
|
||||||
|
sym = ld.Linklookup(ld.Ctxt, "pclntab", 0)
|
||||||
|
if sym != nil {
|
||||||
|
ld.Lcsize = int32(len(sym.P))
|
||||||
|
for i = 0; int32(i) < ld.Lcsize; i++ {
|
||||||
|
ld.Cput(uint8(sym.P[i]))
|
||||||
|
}
|
||||||
|
|
||||||
|
ld.Cflush()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ld.Ctxt.Cursym = nil
|
||||||
|
if ld.Debug['v'] != 0 {
|
||||||
|
fmt.Fprintf(&ld.Bso, "%5.2f header\n", obj.Cputime())
|
||||||
|
}
|
||||||
|
ld.Bflush(&ld.Bso)
|
||||||
|
ld.Cseek(0)
|
||||||
|
switch ld.HEADTYPE {
|
||||||
|
default:
|
||||||
|
case ld.Hplan9: /* plan 9 */
|
||||||
|
ld.Thearch.Lput(0x647) /* magic */
|
||||||
|
ld.Thearch.Lput(uint32(ld.Segtext.Filelen)) /* sizes */
|
||||||
|
ld.Thearch.Lput(uint32(ld.Segdata.Filelen))
|
||||||
|
ld.Thearch.Lput(uint32(ld.Segdata.Length - ld.Segdata.Filelen))
|
||||||
|
ld.Thearch.Lput(uint32(ld.Symsize)) /* nsyms */
|
||||||
|
ld.Thearch.Lput(uint32(ld.Entryvalue())) /* va of entry */
|
||||||
|
ld.Thearch.Lput(0)
|
||||||
|
ld.Thearch.Lput(uint32(ld.Lcsize))
|
||||||
|
|
||||||
|
case ld.Hlinux,
|
||||||
|
ld.Hfreebsd,
|
||||||
|
ld.Hnetbsd,
|
||||||
|
ld.Hopenbsd,
|
||||||
|
ld.Hnacl:
|
||||||
|
ld.Asmbelf(int64(symo))
|
||||||
|
}
|
||||||
|
|
||||||
|
ld.Cflush()
|
||||||
|
if ld.Debug['c'] != 0 {
|
||||||
|
fmt.Printf("textsize=%d\n", ld.Segtext.Filelen)
|
||||||
|
fmt.Printf("datsize=%d\n", ld.Segdata.Filelen)
|
||||||
|
fmt.Printf("bsssize=%d\n", ld.Segdata.Length-ld.Segdata.Filelen)
|
||||||
|
fmt.Printf("symsize=%d\n", ld.Symsize)
|
||||||
|
fmt.Printf("lcsize=%d\n", ld.Lcsize)
|
||||||
|
fmt.Printf("total=%d\n", ld.Segtext.Filelen+ld.Segdata.Length+uint64(ld.Symsize)+uint64(ld.Lcsize))
|
||||||
|
}
|
||||||
|
}
|
||||||
77
src/cmd/new9l/l.go
Normal file
77
src/cmd/new9l/l.go
Normal file
|
|
@ -0,0 +1,77 @@
|
||||||
|
// Inferno utils/5l/asm.c
|
||||||
|
// http://code.google.com/p/inferno-os/source/browse/utils/5l/asm.c
|
||||||
|
//
|
||||||
|
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
|
||||||
|
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
|
||||||
|
// Portions Copyright © 1997-1999 Vita Nuova Limited
|
||||||
|
// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
|
||||||
|
// Portions Copyright © 2004,2006 Bruce Ellis
|
||||||
|
// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
|
||||||
|
// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
|
||||||
|
// Portions Copyright © 2009 The Go Authors. All rights reserved.
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
|
// in the Software without restriction, including without limitation the rights
|
||||||
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
// THE SOFTWARE.
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
// Writing object files.
|
||||||
|
|
||||||
|
// cmd/9l/l.h from Vita Nuova.
|
||||||
|
//
|
||||||
|
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
|
||||||
|
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
|
||||||
|
// Portions Copyright © 1997-1999 Vita Nuova Limited
|
||||||
|
// Portions Copyright © 2000-2008 Vita Nuova Holdings Limited (www.vitanuova.com)
|
||||||
|
// Portions Copyright © 2004,2006 Bruce Ellis
|
||||||
|
// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
|
||||||
|
// Revisions Copyright © 2000-2008 Lucent Technologies Inc. and others
|
||||||
|
// Portions Copyright © 2009 The Go Authors. All rights reserved.
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
|
// in the Software without restriction, including without limitation the rights
|
||||||
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
// THE SOFTWARE.
|
||||||
|
|
||||||
|
const (
|
||||||
|
thechar = '9'
|
||||||
|
PtrSize = 8
|
||||||
|
IntSize = 8
|
||||||
|
RegSize = 8
|
||||||
|
MaxAlign = 32
|
||||||
|
FuncAlign = 8
|
||||||
|
MINLC = 4
|
||||||
|
)
|
||||||
|
|
||||||
|
/* Used by ../ld/dwarf.c */
|
||||||
|
const (
|
||||||
|
DWARFREGSP = 1
|
||||||
|
)
|
||||||
165
src/cmd/new9l/obj.go
Normal file
165
src/cmd/new9l/obj.go
Normal file
|
|
@ -0,0 +1,165 @@
|
||||||
|
// Inferno utils/5l/obj.c
|
||||||
|
// http://code.google.com/p/inferno-os/source/browse/utils/5l/obj.c
|
||||||
|
//
|
||||||
|
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
|
||||||
|
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
|
||||||
|
// Portions Copyright © 1997-1999 Vita Nuova Limited
|
||||||
|
// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
|
||||||
|
// Portions Copyright © 2004,2006 Bruce Ellis
|
||||||
|
// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
|
||||||
|
// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
|
||||||
|
// Portions Copyright © 2009 The Go Authors. All rights reserved.
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
|
// in the Software without restriction, including without limitation the rights
|
||||||
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
// THE SOFTWARE.
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"cmd/internal/obj"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
)
|
||||||
|
import "cmd/internal/ld"
|
||||||
|
|
||||||
|
// Reading object files.
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
linkarchinit()
|
||||||
|
ld.Ldmain()
|
||||||
|
}
|
||||||
|
|
||||||
|
func linkarchinit() {
|
||||||
|
ld.Thestring = obj.Getgoarch()
|
||||||
|
if ld.Thestring == "ppc64le" {
|
||||||
|
ld.Thelinkarch = &ld.Linkppc64le
|
||||||
|
} else {
|
||||||
|
ld.Thelinkarch = &ld.Linkppc64
|
||||||
|
}
|
||||||
|
|
||||||
|
ld.Thearch.Thechar = thechar
|
||||||
|
ld.Thearch.Ptrsize = ld.Thelinkarch.Ptrsize
|
||||||
|
ld.Thearch.Intsize = ld.Thelinkarch.Ptrsize
|
||||||
|
ld.Thearch.Regsize = ld.Thelinkarch.Regsize
|
||||||
|
ld.Thearch.Funcalign = FuncAlign
|
||||||
|
ld.Thearch.Maxalign = MaxAlign
|
||||||
|
ld.Thearch.Minlc = MINLC
|
||||||
|
ld.Thearch.Dwarfregsp = DWARFREGSP
|
||||||
|
|
||||||
|
ld.Thearch.Adddynlib = adddynlib
|
||||||
|
ld.Thearch.Adddynrel = adddynrel
|
||||||
|
ld.Thearch.Adddynsym = adddynsym
|
||||||
|
ld.Thearch.Archinit = archinit
|
||||||
|
ld.Thearch.Archreloc = archreloc
|
||||||
|
ld.Thearch.Archrelocvariant = archrelocvariant
|
||||||
|
ld.Thearch.Asmb = asmb
|
||||||
|
ld.Thearch.Elfreloc1 = elfreloc1
|
||||||
|
ld.Thearch.Elfsetupplt = elfsetupplt
|
||||||
|
ld.Thearch.Gentext = gentext
|
||||||
|
ld.Thearch.Machoreloc1 = machoreloc1
|
||||||
|
if ld.Thelinkarch == &ld.Linkppc64le {
|
||||||
|
ld.Thearch.Lput = ld.Lputl
|
||||||
|
ld.Thearch.Wput = ld.Wputl
|
||||||
|
ld.Thearch.Vput = ld.Vputl
|
||||||
|
} else {
|
||||||
|
ld.Thearch.Lput = ld.Lputb
|
||||||
|
ld.Thearch.Wput = ld.Wputb
|
||||||
|
ld.Thearch.Vput = ld.Vputb
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(austin): ABI v1 uses /usr/lib/ld.so.1
|
||||||
|
ld.Thearch.Linuxdynld = "/lib64/ld64.so.1"
|
||||||
|
|
||||||
|
ld.Thearch.Freebsddynld = "XXX"
|
||||||
|
ld.Thearch.Openbsddynld = "XXX"
|
||||||
|
ld.Thearch.Netbsddynld = "XXX"
|
||||||
|
ld.Thearch.Dragonflydynld = "XXX"
|
||||||
|
ld.Thearch.Solarisdynld = "XXX"
|
||||||
|
}
|
||||||
|
|
||||||
|
func archinit() {
|
||||||
|
// getgoextlinkenabled is based on GO_EXTLINK_ENABLED when
|
||||||
|
// Go was built; see ../../make.bash.
|
||||||
|
if ld.Linkmode == ld.LinkAuto && obj.Getgoextlinkenabled() == "0" {
|
||||||
|
ld.Linkmode = ld.LinkInternal
|
||||||
|
}
|
||||||
|
|
||||||
|
switch ld.HEADTYPE {
|
||||||
|
default:
|
||||||
|
if ld.Linkmode == ld.LinkAuto {
|
||||||
|
ld.Linkmode = ld.LinkInternal
|
||||||
|
}
|
||||||
|
if ld.Linkmode == ld.LinkExternal && obj.Getgoextlinkenabled() != "1" {
|
||||||
|
log.Fatalf("cannot use -linkmode=external with -H %s", ld.Headstr(int(ld.HEADTYPE)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch ld.HEADTYPE {
|
||||||
|
default:
|
||||||
|
ld.Diag("unknown -H option")
|
||||||
|
ld.Errorexit()
|
||||||
|
fallthrough
|
||||||
|
|
||||||
|
case ld.Hplan9: /* plan 9 */
|
||||||
|
ld.HEADR = 32
|
||||||
|
|
||||||
|
if ld.INITTEXT == -1 {
|
||||||
|
ld.INITTEXT = 4128
|
||||||
|
}
|
||||||
|
if ld.INITDAT == -1 {
|
||||||
|
ld.INITDAT = 0
|
||||||
|
}
|
||||||
|
if ld.INITRND == -1 {
|
||||||
|
ld.INITRND = 4096
|
||||||
|
}
|
||||||
|
|
||||||
|
case ld.Hlinux: /* ppc64 elf */
|
||||||
|
if ld.Thestring == "ppc64" {
|
||||||
|
ld.Debug['d'] = 1 // TODO(austin): ELF ABI v1 not supported yet
|
||||||
|
}
|
||||||
|
ld.Elfinit()
|
||||||
|
ld.HEADR = ld.ELFRESERVE
|
||||||
|
if ld.INITTEXT == -1 {
|
||||||
|
ld.INITTEXT = 0x10000 + int64(ld.HEADR)
|
||||||
|
}
|
||||||
|
if ld.INITDAT == -1 {
|
||||||
|
ld.INITDAT = 0
|
||||||
|
}
|
||||||
|
if ld.INITRND == -1 {
|
||||||
|
ld.INITRND = 0x10000
|
||||||
|
}
|
||||||
|
|
||||||
|
case ld.Hnacl:
|
||||||
|
ld.Elfinit()
|
||||||
|
ld.HEADR = 0x10000
|
||||||
|
ld.Funcalign = 16
|
||||||
|
if ld.INITTEXT == -1 {
|
||||||
|
ld.INITTEXT = 0x20000
|
||||||
|
}
|
||||||
|
if ld.INITDAT == -1 {
|
||||||
|
ld.INITDAT = 0
|
||||||
|
}
|
||||||
|
if ld.INITRND == -1 {
|
||||||
|
ld.INITRND = 0x10000
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ld.INITDAT != 0 && ld.INITRND != 0 {
|
||||||
|
fmt.Printf("warning: -D0x%x is ignored because of -R0x%x\n", uint64(ld.INITDAT), uint32(ld.INITRND))
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue