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:
Russ Cox 2015-02-27 22:57:28 -05:00
parent 30e36983f3
commit 1f9dbb60ef
38 changed files with 21892 additions and 0 deletions

51
src/cmd/internal/ld/ar.go Normal file
View 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
}

View 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

File diff suppressed because it is too large Load diff

View 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

File diff suppressed because it is too large Load diff

View 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

File diff suppressed because it is too large Load diff

View 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
View 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
View 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

File diff suppressed because it is too large Load diff

View 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 = &sect.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
View 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

File diff suppressed because it is too large Load diff

299
src/cmd/internal/ld/link.go Normal file
View 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
)

View 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)
}
}

View 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
View 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

File diff suppressed because it is too large Load diff

224
src/cmd/internal/ld/pobj.go Normal file
View 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
View 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
}

View 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)
}
}
}

View 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
View 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
View file

@ -0,0 +1 @@
package ld

777
src/cmd/new5l/asm.go Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View file

@ -0,0 +1 @@
package main

734
src/cmd/new8l/asm.go Normal file
View 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
View 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
View 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
View 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
View 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
View 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))
}
}