mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
cmd/new5l etc: convert from C to Go
Using rsc.io/c2go rev fc8cbfa's run.ld script. Change-Id: I4d4d14fce96f8ce7a934bf8b9701b84fa9cf772d Reviewed-on: https://go-review.googlesource.com/6335 Reviewed-by: Rob Pike <r@golang.org>
This commit is contained in:
parent
30e36983f3
commit
1f9dbb60ef
38 changed files with 21892 additions and 0 deletions
51
src/cmd/internal/ld/ar.go
Normal file
51
src/cmd/internal/ld/ar.go
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
// Inferno utils/include/ar.h
|
||||
// http://code.google.com/p/inferno-os/source/browse/utils/include/ar.h
|
||||
//
|
||||
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
|
||||
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
|
||||
// Portions Copyright © 1997-1999 Vita Nuova Limited
|
||||
// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
|
||||
// Portions Copyright © 2004,2006 Bruce Ellis
|
||||
// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
|
||||
// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
|
||||
// Portions Copyright © 2009 The Go Authors. All rights reserved.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
package ld
|
||||
|
||||
const (
|
||||
SARMAG = 8
|
||||
SARNAME = 16
|
||||
SAR_HDR = 16 + 44
|
||||
)
|
||||
|
||||
var ARMAG string = "!<arch>\n"
|
||||
|
||||
var ARFMAG string = "`\n"
|
||||
|
||||
type ArHdr struct {
|
||||
name string
|
||||
date string
|
||||
uid string
|
||||
gid string
|
||||
mode string
|
||||
size string
|
||||
fmag string
|
||||
}
|
||||
67
src/cmd/internal/ld/arch.go
Normal file
67
src/cmd/internal/ld/arch.go
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
// Copyright 2015 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package ld
|
||||
|
||||
import "encoding/binary"
|
||||
|
||||
var Linkarm = LinkArch{
|
||||
ByteOrder: binary.LittleEndian,
|
||||
Name: "arm",
|
||||
Thechar: '5',
|
||||
Endian: LittleEndian,
|
||||
Minlc: 4,
|
||||
Ptrsize: 4,
|
||||
Regsize: 4,
|
||||
}
|
||||
|
||||
var Linkamd64 = LinkArch{
|
||||
ByteOrder: binary.LittleEndian,
|
||||
Name: "amd64",
|
||||
Thechar: '6',
|
||||
Endian: LittleEndian,
|
||||
Minlc: 1,
|
||||
Ptrsize: 8,
|
||||
Regsize: 8,
|
||||
}
|
||||
|
||||
var Linkamd64p32 = LinkArch{
|
||||
ByteOrder: binary.LittleEndian,
|
||||
Name: "amd64p32",
|
||||
Thechar: '6',
|
||||
Endian: LittleEndian,
|
||||
Minlc: 1,
|
||||
Ptrsize: 4,
|
||||
Regsize: 8,
|
||||
}
|
||||
|
||||
var Link386 = LinkArch{
|
||||
ByteOrder: binary.LittleEndian,
|
||||
Name: "386",
|
||||
Thechar: '8',
|
||||
Endian: LittleEndian,
|
||||
Minlc: 1,
|
||||
Ptrsize: 4,
|
||||
Regsize: 4,
|
||||
}
|
||||
|
||||
var Linkppc64 = LinkArch{
|
||||
ByteOrder: binary.BigEndian,
|
||||
Name: "ppc64",
|
||||
Thechar: '9',
|
||||
Endian: BigEndian,
|
||||
Minlc: 4,
|
||||
Ptrsize: 8,
|
||||
Regsize: 8,
|
||||
}
|
||||
|
||||
var Linkppc64le = LinkArch{
|
||||
ByteOrder: binary.LittleEndian,
|
||||
Name: "ppc64le",
|
||||
Thechar: '9',
|
||||
Endian: LittleEndian,
|
||||
Minlc: 4,
|
||||
Ptrsize: 8,
|
||||
Regsize: 8,
|
||||
}
|
||||
1798
src/cmd/internal/ld/data.go
Normal file
1798
src/cmd/internal/ld/data.go
Normal file
File diff suppressed because it is too large
Load diff
183
src/cmd/internal/ld/decodesym.go
Normal file
183
src/cmd/internal/ld/decodesym.go
Normal file
|
|
@ -0,0 +1,183 @@
|
|||
// Copyright 2012 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package ld
|
||||
|
||||
import "cmd/internal/obj"
|
||||
|
||||
// Decoding the type.* symbols. This has to be in sync with
|
||||
// ../../runtime/type.go, or more specifically, with what
|
||||
// ../gc/reflect.c stuffs in these.
|
||||
|
||||
func decode_reloc(s *LSym, off int32) *Reloc {
|
||||
var i int
|
||||
|
||||
for i = 0; i < len(s.R); i++ {
|
||||
if s.R[i].Off == off {
|
||||
return &s.R[i:][0]
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func decode_reloc_sym(s *LSym, off int32) *LSym {
|
||||
var r *Reloc
|
||||
|
||||
r = decode_reloc(s, off)
|
||||
if r == nil {
|
||||
return nil
|
||||
}
|
||||
return r.Sym
|
||||
}
|
||||
|
||||
func decode_inuxi(p []byte, sz int) uint64 {
|
||||
switch sz {
|
||||
case 2:
|
||||
return uint64(Ctxt.Arch.ByteOrder.Uint16(p))
|
||||
case 4:
|
||||
return uint64(Ctxt.Arch.ByteOrder.Uint32(p))
|
||||
case 8:
|
||||
return Ctxt.Arch.ByteOrder.Uint64(p)
|
||||
}
|
||||
Diag("dwarf: decode inuxi %d", sz)
|
||||
Errorexit()
|
||||
return 0
|
||||
}
|
||||
|
||||
func commonsize() int {
|
||||
return 8*Thearch.Ptrsize + 8
|
||||
}
|
||||
|
||||
// Type.commonType.kind
|
||||
func decodetype_kind(s *LSym) uint8 {
|
||||
return uint8(s.P[1*Thearch.Ptrsize+7] & obj.KindMask) // 0x13 / 0x1f
|
||||
}
|
||||
|
||||
// Type.commonType.kind
|
||||
func decodetype_noptr(s *LSym) uint8 {
|
||||
return uint8(s.P[1*Thearch.Ptrsize+7] & obj.KindNoPointers) // 0x13 / 0x1f
|
||||
}
|
||||
|
||||
// Type.commonType.kind
|
||||
func decodetype_usegcprog(s *LSym) uint8 {
|
||||
return uint8(s.P[1*Thearch.Ptrsize+7] & obj.KindGCProg) // 0x13 / 0x1f
|
||||
}
|
||||
|
||||
// Type.commonType.size
|
||||
func decodetype_size(s *LSym) int64 {
|
||||
return int64(decode_inuxi(s.P, Thearch.Ptrsize)) // 0x8 / 0x10
|
||||
}
|
||||
|
||||
// Type.commonType.gc
|
||||
func decodetype_gcprog(s *LSym) *LSym {
|
||||
return decode_reloc_sym(s, 1*int32(Thearch.Ptrsize)+8+2*int32(Thearch.Ptrsize))
|
||||
}
|
||||
|
||||
func decodetype_gcmask(s *LSym) []byte {
|
||||
var mask *LSym
|
||||
|
||||
mask = decode_reloc_sym(s, 1*int32(Thearch.Ptrsize)+8+1*int32(Thearch.Ptrsize))
|
||||
return mask.P
|
||||
}
|
||||
|
||||
// Type.ArrayType.elem and Type.SliceType.Elem
|
||||
func decodetype_arrayelem(s *LSym) *LSym {
|
||||
return decode_reloc_sym(s, int32(commonsize())) // 0x1c / 0x30
|
||||
}
|
||||
|
||||
func decodetype_arraylen(s *LSym) int64 {
|
||||
return int64(decode_inuxi(s.P[commonsize()+2*Thearch.Ptrsize:], Thearch.Ptrsize))
|
||||
}
|
||||
|
||||
// Type.PtrType.elem
|
||||
func decodetype_ptrelem(s *LSym) *LSym {
|
||||
return decode_reloc_sym(s, int32(commonsize())) // 0x1c / 0x30
|
||||
}
|
||||
|
||||
// Type.MapType.key, elem
|
||||
func decodetype_mapkey(s *LSym) *LSym {
|
||||
return decode_reloc_sym(s, int32(commonsize())) // 0x1c / 0x30
|
||||
}
|
||||
|
||||
func decodetype_mapvalue(s *LSym) *LSym {
|
||||
return decode_reloc_sym(s, int32(commonsize())+int32(Thearch.Ptrsize)) // 0x20 / 0x38
|
||||
}
|
||||
|
||||
// Type.ChanType.elem
|
||||
func decodetype_chanelem(s *LSym) *LSym {
|
||||
return decode_reloc_sym(s, int32(commonsize())) // 0x1c / 0x30
|
||||
}
|
||||
|
||||
// Type.FuncType.dotdotdot
|
||||
func decodetype_funcdotdotdot(s *LSym) int {
|
||||
return int(s.P[commonsize()])
|
||||
}
|
||||
|
||||
// Type.FuncType.in.length
|
||||
func decodetype_funcincount(s *LSym) int {
|
||||
return int(decode_inuxi(s.P[commonsize()+2*Thearch.Ptrsize:], Thearch.Intsize))
|
||||
}
|
||||
|
||||
func decodetype_funcoutcount(s *LSym) int {
|
||||
return int(decode_inuxi(s.P[commonsize()+3*Thearch.Ptrsize+2*Thearch.Intsize:], Thearch.Intsize))
|
||||
}
|
||||
|
||||
func decodetype_funcintype(s *LSym, i int) *LSym {
|
||||
var r *Reloc
|
||||
|
||||
r = decode_reloc(s, int32(commonsize())+int32(Thearch.Ptrsize))
|
||||
if r == nil {
|
||||
return nil
|
||||
}
|
||||
return decode_reloc_sym(r.Sym, int32(r.Add+int64(int32(i)*int32(Thearch.Ptrsize))))
|
||||
}
|
||||
|
||||
func decodetype_funcouttype(s *LSym, i int) *LSym {
|
||||
var r *Reloc
|
||||
|
||||
r = decode_reloc(s, int32(commonsize())+2*int32(Thearch.Ptrsize)+2*int32(Thearch.Intsize))
|
||||
if r == nil {
|
||||
return nil
|
||||
}
|
||||
return decode_reloc_sym(r.Sym, int32(r.Add+int64(int32(i)*int32(Thearch.Ptrsize))))
|
||||
}
|
||||
|
||||
// Type.StructType.fields.Slice::length
|
||||
func decodetype_structfieldcount(s *LSym) int {
|
||||
return int(decode_inuxi(s.P[commonsize()+Thearch.Ptrsize:], Thearch.Intsize))
|
||||
}
|
||||
|
||||
func structfieldsize() int {
|
||||
return 5 * Thearch.Ptrsize
|
||||
}
|
||||
|
||||
// Type.StructType.fields[]-> name, typ and offset.
|
||||
func decodetype_structfieldname(s *LSym, i int) string {
|
||||
var r *Reloc
|
||||
|
||||
// go.string."foo" 0x28 / 0x40
|
||||
s = decode_reloc_sym(s, int32(commonsize())+int32(Thearch.Ptrsize)+2*int32(Thearch.Intsize)+int32(i)*int32(structfieldsize()))
|
||||
|
||||
if s == nil { // embedded structs have a nil name.
|
||||
return ""
|
||||
}
|
||||
r = decode_reloc(s, 0) // s has a pointer to the string data at offset 0
|
||||
if r == nil { // shouldn't happen.
|
||||
return ""
|
||||
}
|
||||
return cstring(r.Sym.P[r.Add:])
|
||||
}
|
||||
|
||||
func decodetype_structfieldtype(s *LSym, i int) *LSym {
|
||||
return decode_reloc_sym(s, int32(commonsize())+int32(Thearch.Ptrsize)+2*int32(Thearch.Intsize)+int32(i)*int32(structfieldsize())+2*int32(Thearch.Ptrsize))
|
||||
}
|
||||
|
||||
func decodetype_structfieldoffs(s *LSym, i int) int64 {
|
||||
return int64(decode_inuxi(s.P[commonsize()+Thearch.Ptrsize+2*Thearch.Intsize+i*structfieldsize()+4*Thearch.Ptrsize:], Thearch.Intsize))
|
||||
}
|
||||
|
||||
// InterfaceTYpe.methods.length
|
||||
func decodetype_ifacemethodcount(s *LSym) int64 {
|
||||
return int64(decode_inuxi(s.P[commonsize()+Thearch.Ptrsize:], Thearch.Intsize))
|
||||
}
|
||||
2744
src/cmd/internal/ld/dwarf.go
Normal file
2744
src/cmd/internal/ld/dwarf.go
Normal file
File diff suppressed because it is too large
Load diff
500
src/cmd/internal/ld/dwarf_defs.go
Normal file
500
src/cmd/internal/ld/dwarf_defs.go
Normal file
|
|
@ -0,0 +1,500 @@
|
|||
// Copyright 2010 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package ld
|
||||
|
||||
// TODO/NICETOHAVE:
|
||||
// - eliminate DW_CLS_ if not used
|
||||
// - package info in compilation units
|
||||
// - assign global variables and types to their packages
|
||||
// - gdb uses c syntax, meaning clumsy quoting is needed for go identifiers. eg
|
||||
// ptype struct '[]uint8' and qualifiers need to be quoted away
|
||||
// - lexical scoping is lost, so gdb gets confused as to which 'obj.i' you mean.
|
||||
// - file:line info for variables
|
||||
// - make strings a typedef so prettyprinters can see the underlying string type
|
||||
//
|
||||
// Copyright 2010 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
/*
|
||||
* Emit debug_abbrevs, debug_info and debug_line sections to current
|
||||
* offset in cout.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Add the dwarf section names to the ELF
|
||||
* s[ection]h[eader]str[ing]tab. Prerequisite for
|
||||
* dwarfaddelfheaders().
|
||||
*/
|
||||
|
||||
/*
|
||||
* Add section headers pointing to the sections emitted in
|
||||
* dwarfemitdebugsections.
|
||||
*/
|
||||
// Copyright 2010 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Cut, pasted, tr-and-awk'ed from tables in
|
||||
// http://dwarfstd.org/doc/Dwarf3.pdf
|
||||
|
||||
// Table 18
|
||||
const (
|
||||
DW_TAG_array_type = 0x01
|
||||
DW_TAG_class_type = 0x02
|
||||
DW_TAG_entry_point = 0x03
|
||||
DW_TAG_enumeration_type = 0x04
|
||||
DW_TAG_formal_parameter = 0x05
|
||||
DW_TAG_imported_declaration = 0x08
|
||||
DW_TAG_label = 0x0a
|
||||
DW_TAG_lexical_block = 0x0b
|
||||
DW_TAG_member = 0x0d
|
||||
DW_TAG_pointer_type = 0x0f
|
||||
DW_TAG_reference_type = 0x10
|
||||
DW_TAG_compile_unit = 0x11
|
||||
DW_TAG_string_type = 0x12
|
||||
DW_TAG_structure_type = 0x13
|
||||
DW_TAG_subroutine_type = 0x15
|
||||
DW_TAG_typedef = 0x16
|
||||
DW_TAG_union_type = 0x17
|
||||
DW_TAG_unspecified_parameters = 0x18
|
||||
DW_TAG_variant = 0x19
|
||||
DW_TAG_common_block = 0x1a
|
||||
DW_TAG_common_inclusion = 0x1b
|
||||
DW_TAG_inheritance = 0x1c
|
||||
DW_TAG_inlined_subroutine = 0x1d
|
||||
DW_TAG_module = 0x1e
|
||||
DW_TAG_ptr_to_member_type = 0x1f
|
||||
DW_TAG_set_type = 0x20
|
||||
DW_TAG_subrange_type = 0x21
|
||||
DW_TAG_with_stmt = 0x22
|
||||
DW_TAG_access_declaration = 0x23
|
||||
DW_TAG_base_type = 0x24
|
||||
DW_TAG_catch_block = 0x25
|
||||
DW_TAG_const_type = 0x26
|
||||
DW_TAG_constant = 0x27
|
||||
DW_TAG_enumerator = 0x28
|
||||
DW_TAG_file_type = 0x29
|
||||
DW_TAG_friend = 0x2a
|
||||
DW_TAG_namelist = 0x2b
|
||||
DW_TAG_namelist_item = 0x2c
|
||||
DW_TAG_packed_type = 0x2d
|
||||
DW_TAG_subprogram = 0x2e
|
||||
DW_TAG_template_type_parameter = 0x2f
|
||||
DW_TAG_template_value_parameter = 0x30
|
||||
DW_TAG_thrown_type = 0x31
|
||||
DW_TAG_try_block = 0x32
|
||||
DW_TAG_variant_part = 0x33
|
||||
DW_TAG_variable = 0x34
|
||||
DW_TAG_volatile_type = 0x35
|
||||
DW_TAG_dwarf_procedure = 0x36
|
||||
DW_TAG_restrict_type = 0x37
|
||||
DW_TAG_interface_type = 0x38
|
||||
DW_TAG_namespace = 0x39
|
||||
DW_TAG_imported_module = 0x3a
|
||||
DW_TAG_unspecified_type = 0x3b
|
||||
DW_TAG_partial_unit = 0x3c
|
||||
DW_TAG_imported_unit = 0x3d
|
||||
DW_TAG_condition = 0x3f
|
||||
DW_TAG_shared_type = 0x40
|
||||
DW_TAG_type_unit = 0x41
|
||||
DW_TAG_rvalue_reference_type = 0x42
|
||||
DW_TAG_template_alias = 0x43
|
||||
DW_TAG_lo_user = 0x4080
|
||||
DW_TAG_hi_user = 0xffff
|
||||
)
|
||||
|
||||
// Table 19
|
||||
const (
|
||||
DW_CHILDREN_no = 0x00
|
||||
DW_CHILDREN_yes = 0x01
|
||||
)
|
||||
|
||||
// Not from the spec, but logicaly belongs here
|
||||
const (
|
||||
DW_CLS_ADDRESS = 0x01 + iota
|
||||
DW_CLS_BLOCK
|
||||
DW_CLS_CONSTANT
|
||||
DW_CLS_FLAG
|
||||
DW_CLS_PTR
|
||||
DW_CLS_REFERENCE
|
||||
DW_CLS_ADDRLOC
|
||||
DW_CLS_STRING
|
||||
)
|
||||
|
||||
// Table 20
|
||||
const (
|
||||
DW_AT_sibling = 0x01
|
||||
DW_AT_location = 0x02
|
||||
DW_AT_name = 0x03
|
||||
DW_AT_ordering = 0x09
|
||||
DW_AT_byte_size = 0x0b
|
||||
DW_AT_bit_offset = 0x0c
|
||||
DW_AT_bit_size = 0x0d
|
||||
DW_AT_stmt_list = 0x10
|
||||
DW_AT_low_pc = 0x11
|
||||
DW_AT_high_pc = 0x12
|
||||
DW_AT_language = 0x13
|
||||
DW_AT_discr = 0x15
|
||||
DW_AT_discr_value = 0x16
|
||||
DW_AT_visibility = 0x17
|
||||
DW_AT_import = 0x18
|
||||
DW_AT_string_length = 0x19
|
||||
DW_AT_common_reference = 0x1a
|
||||
DW_AT_comp_dir = 0x1b
|
||||
DW_AT_const_value = 0x1c
|
||||
DW_AT_containing_type = 0x1d
|
||||
DW_AT_default_value = 0x1e
|
||||
DW_AT_inline = 0x20
|
||||
DW_AT_is_optional = 0x21
|
||||
DW_AT_lower_bound = 0x22
|
||||
DW_AT_producer = 0x25
|
||||
DW_AT_prototyped = 0x27
|
||||
DW_AT_return_addr = 0x2a
|
||||
DW_AT_start_scope = 0x2c
|
||||
DW_AT_bit_stride = 0x2e
|
||||
DW_AT_upper_bound = 0x2f
|
||||
DW_AT_abstract_origin = 0x31
|
||||
DW_AT_accessibility = 0x32
|
||||
DW_AT_address_class = 0x33
|
||||
DW_AT_artificial = 0x34
|
||||
DW_AT_base_types = 0x35
|
||||
DW_AT_calling_convention = 0x36
|
||||
DW_AT_count = 0x37
|
||||
DW_AT_data_member_location = 0x38
|
||||
DW_AT_decl_column = 0x39
|
||||
DW_AT_decl_file = 0x3a
|
||||
DW_AT_decl_line = 0x3b
|
||||
DW_AT_declaration = 0x3c
|
||||
DW_AT_discr_list = 0x3d
|
||||
DW_AT_encoding = 0x3e
|
||||
DW_AT_external = 0x3f
|
||||
DW_AT_frame_base = 0x40
|
||||
DW_AT_friend = 0x41
|
||||
DW_AT_identifier_case = 0x42
|
||||
DW_AT_macro_info = 0x43
|
||||
DW_AT_namelist_item = 0x44
|
||||
DW_AT_priority = 0x45
|
||||
DW_AT_segment = 0x46
|
||||
DW_AT_specification = 0x47
|
||||
DW_AT_static_link = 0x48
|
||||
DW_AT_type = 0x49
|
||||
DW_AT_use_location = 0x4a
|
||||
DW_AT_variable_parameter = 0x4b
|
||||
DW_AT_virtuality = 0x4c
|
||||
DW_AT_vtable_elem_location = 0x4d
|
||||
DW_AT_allocated = 0x4e
|
||||
DW_AT_associated = 0x4f
|
||||
DW_AT_data_location = 0x50
|
||||
DW_AT_byte_stride = 0x51
|
||||
DW_AT_entry_pc = 0x52
|
||||
DW_AT_use_UTF8 = 0x53
|
||||
DW_AT_extension = 0x54
|
||||
DW_AT_ranges = 0x55
|
||||
DW_AT_trampoline = 0x56
|
||||
DW_AT_call_column = 0x57
|
||||
DW_AT_call_file = 0x58
|
||||
DW_AT_call_line = 0x59
|
||||
DW_AT_description = 0x5a
|
||||
DW_AT_binary_scale = 0x5b
|
||||
DW_AT_decimal_scale = 0x5c
|
||||
DW_AT_small = 0x5d
|
||||
DW_AT_decimal_sign = 0x5e
|
||||
DW_AT_digit_count = 0x5f
|
||||
DW_AT_picture_string = 0x60
|
||||
DW_AT_mutable = 0x61
|
||||
DW_AT_threads_scaled = 0x62
|
||||
DW_AT_explicit = 0x63
|
||||
DW_AT_object_pointer = 0x64
|
||||
DW_AT_endianity = 0x65
|
||||
DW_AT_elemental = 0x66
|
||||
DW_AT_pure = 0x67
|
||||
DW_AT_recursive = 0x68
|
||||
DW_AT_lo_user = 0x2000
|
||||
DW_AT_hi_user = 0x3fff
|
||||
)
|
||||
|
||||
// Table 21
|
||||
const (
|
||||
DW_FORM_addr = 0x01
|
||||
DW_FORM_block2 = 0x03
|
||||
DW_FORM_block4 = 0x04
|
||||
DW_FORM_data2 = 0x05
|
||||
DW_FORM_data4 = 0x06
|
||||
DW_FORM_data8 = 0x07
|
||||
DW_FORM_string = 0x08
|
||||
DW_FORM_block = 0x09
|
||||
DW_FORM_block1 = 0x0a
|
||||
DW_FORM_data1 = 0x0b
|
||||
DW_FORM_flag = 0x0c
|
||||
DW_FORM_sdata = 0x0d
|
||||
DW_FORM_strp = 0x0e
|
||||
DW_FORM_udata = 0x0f
|
||||
DW_FORM_ref_addr = 0x10
|
||||
DW_FORM_ref1 = 0x11
|
||||
DW_FORM_ref2 = 0x12
|
||||
DW_FORM_ref4 = 0x13
|
||||
DW_FORM_ref8 = 0x14
|
||||
DW_FORM_ref_udata = 0x15
|
||||
DW_FORM_indirect = 0x16
|
||||
)
|
||||
|
||||
// Table 24 (#operands, notes)
|
||||
const (
|
||||
DW_OP_addr = 0x03
|
||||
DW_OP_deref = 0x06
|
||||
DW_OP_const1u = 0x08
|
||||
DW_OP_const1s = 0x09
|
||||
DW_OP_const2u = 0x0a
|
||||
DW_OP_const2s = 0x0b
|
||||
DW_OP_const4u = 0x0c
|
||||
DW_OP_const4s = 0x0d
|
||||
DW_OP_const8u = 0x0e
|
||||
DW_OP_const8s = 0x0f
|
||||
DW_OP_constu = 0x10
|
||||
DW_OP_consts = 0x11
|
||||
DW_OP_dup = 0x12
|
||||
DW_OP_drop = 0x13
|
||||
DW_OP_over = 0x14
|
||||
DW_OP_pick = 0x15
|
||||
DW_OP_swap = 0x16
|
||||
DW_OP_rot = 0x17
|
||||
DW_OP_xderef = 0x18
|
||||
DW_OP_abs = 0x19
|
||||
DW_OP_and = 0x1a
|
||||
DW_OP_div = 0x1b
|
||||
DW_OP_minus = 0x1c
|
||||
DW_OP_mod = 0x1d
|
||||
DW_OP_mul = 0x1e
|
||||
DW_OP_neg = 0x1f
|
||||
DW_OP_not = 0x20
|
||||
DW_OP_or = 0x21
|
||||
DW_OP_plus = 0x22
|
||||
DW_OP_plus_uconst = 0x23
|
||||
DW_OP_shl = 0x24
|
||||
DW_OP_shr = 0x25
|
||||
DW_OP_shra = 0x26
|
||||
DW_OP_xor = 0x27
|
||||
DW_OP_skip = 0x2f
|
||||
DW_OP_bra = 0x28
|
||||
DW_OP_eq = 0x29
|
||||
DW_OP_ge = 0x2a
|
||||
DW_OP_gt = 0x2b
|
||||
DW_OP_le = 0x2c
|
||||
DW_OP_lt = 0x2d
|
||||
DW_OP_ne = 0x2e
|
||||
DW_OP_lit0 = 0x30
|
||||
DW_OP_lit31 = 0x4f
|
||||
DW_OP_reg0 = 0x50
|
||||
DW_OP_reg31 = 0x6f
|
||||
DW_OP_breg0 = 0x70
|
||||
DW_OP_breg31 = 0x8f
|
||||
DW_OP_regx = 0x90
|
||||
DW_OP_fbreg = 0x91
|
||||
DW_OP_bregx = 0x92
|
||||
DW_OP_piece = 0x93
|
||||
DW_OP_deref_size = 0x94
|
||||
DW_OP_xderef_size = 0x95
|
||||
DW_OP_nop = 0x96
|
||||
DW_OP_push_object_address = 0x97
|
||||
DW_OP_call2 = 0x98
|
||||
DW_OP_call4 = 0x99
|
||||
DW_OP_call_ref = 0x9a
|
||||
DW_OP_form_tls_address = 0x9b
|
||||
DW_OP_call_frame_cfa = 0x9c
|
||||
DW_OP_bit_piece = 0x9d
|
||||
DW_OP_lo_user = 0xe0
|
||||
DW_OP_hi_user = 0xff
|
||||
)
|
||||
|
||||
// Table 25
|
||||
const (
|
||||
DW_ATE_address = 0x01
|
||||
DW_ATE_boolean = 0x02
|
||||
DW_ATE_complex_float = 0x03
|
||||
DW_ATE_float = 0x04
|
||||
DW_ATE_signed = 0x05
|
||||
DW_ATE_signed_char = 0x06
|
||||
DW_ATE_unsigned = 0x07
|
||||
DW_ATE_unsigned_char = 0x08
|
||||
DW_ATE_imaginary_float = 0x09
|
||||
DW_ATE_packed_decimal = 0x0a
|
||||
DW_ATE_numeric_string = 0x0b
|
||||
DW_ATE_edited = 0x0c
|
||||
DW_ATE_signed_fixed = 0x0d
|
||||
DW_ATE_unsigned_fixed = 0x0e
|
||||
DW_ATE_decimal_float = 0x0f
|
||||
DW_ATE_lo_user = 0x80
|
||||
DW_ATE_hi_user = 0xff
|
||||
)
|
||||
|
||||
// Table 26
|
||||
const (
|
||||
DW_DS_unsigned = 0x01
|
||||
DW_DS_leading_overpunch = 0x02
|
||||
DW_DS_trailing_overpunch = 0x03
|
||||
DW_DS_leading_separate = 0x04
|
||||
DW_DS_trailing_separate = 0x05
|
||||
)
|
||||
|
||||
// Table 27
|
||||
const (
|
||||
DW_END_default = 0x00
|
||||
DW_END_big = 0x01
|
||||
DW_END_little = 0x02
|
||||
DW_END_lo_user = 0x40
|
||||
DW_END_hi_user = 0xff
|
||||
)
|
||||
|
||||
// Table 28
|
||||
const (
|
||||
DW_ACCESS_public = 0x01
|
||||
DW_ACCESS_protected = 0x02
|
||||
DW_ACCESS_private = 0x03
|
||||
)
|
||||
|
||||
// Table 29
|
||||
const (
|
||||
DW_VIS_local = 0x01
|
||||
DW_VIS_exported = 0x02
|
||||
DW_VIS_qualified = 0x03
|
||||
)
|
||||
|
||||
// Table 30
|
||||
const (
|
||||
DW_VIRTUALITY_none = 0x00
|
||||
DW_VIRTUALITY_virtual = 0x01
|
||||
DW_VIRTUALITY_pure_virtual = 0x02
|
||||
)
|
||||
|
||||
// Table 31
|
||||
const (
|
||||
DW_LANG_C89 = 0x0001
|
||||
DW_LANG_C = 0x0002
|
||||
DW_LANG_Ada83 = 0x0003
|
||||
DW_LANG_C_plus_plus = 0x0004
|
||||
DW_LANG_Cobol74 = 0x0005
|
||||
DW_LANG_Cobol85 = 0x0006
|
||||
DW_LANG_Fortran77 = 0x0007
|
||||
DW_LANG_Fortran90 = 0x0008
|
||||
DW_LANG_Pascal83 = 0x0009
|
||||
DW_LANG_Modula2 = 0x000a
|
||||
DW_LANG_Java = 0x000b
|
||||
DW_LANG_C99 = 0x000c
|
||||
DW_LANG_Ada95 = 0x000d
|
||||
DW_LANG_Fortran95 = 0x000e
|
||||
DW_LANG_PLI = 0x000f
|
||||
DW_LANG_ObjC = 0x0010
|
||||
DW_LANG_ObjC_plus_plus = 0x0011
|
||||
DW_LANG_UPC = 0x0012
|
||||
DW_LANG_D = 0x0013
|
||||
DW_LANG_Python = 0x0014
|
||||
DW_LANG_Go = 0x0016
|
||||
DW_LANG_lo_user = 0x8000
|
||||
DW_LANG_hi_user = 0xffff
|
||||
)
|
||||
|
||||
// Table 32
|
||||
const (
|
||||
DW_ID_case_sensitive = 0x00
|
||||
DW_ID_up_case = 0x01
|
||||
DW_ID_down_case = 0x02
|
||||
DW_ID_case_insensitive = 0x03
|
||||
)
|
||||
|
||||
// Table 33
|
||||
const (
|
||||
DW_CC_normal = 0x01
|
||||
DW_CC_program = 0x02
|
||||
DW_CC_nocall = 0x03
|
||||
DW_CC_lo_user = 0x40
|
||||
DW_CC_hi_user = 0xff
|
||||
)
|
||||
|
||||
// Table 34
|
||||
const (
|
||||
DW_INL_not_inlined = 0x00
|
||||
DW_INL_inlined = 0x01
|
||||
DW_INL_declared_not_inlined = 0x02
|
||||
DW_INL_declared_inlined = 0x03
|
||||
)
|
||||
|
||||
// Table 35
|
||||
const (
|
||||
DW_ORD_row_major = 0x00
|
||||
DW_ORD_col_major = 0x01
|
||||
)
|
||||
|
||||
// Table 36
|
||||
const (
|
||||
DW_DSC_label = 0x00
|
||||
DW_DSC_range = 0x01
|
||||
)
|
||||
|
||||
// Table 37
|
||||
const (
|
||||
DW_LNS_copy = 0x01
|
||||
DW_LNS_advance_pc = 0x02
|
||||
DW_LNS_advance_line = 0x03
|
||||
DW_LNS_set_file = 0x04
|
||||
DW_LNS_set_column = 0x05
|
||||
DW_LNS_negate_stmt = 0x06
|
||||
DW_LNS_set_basic_block = 0x07
|
||||
DW_LNS_const_add_pc = 0x08
|
||||
DW_LNS_fixed_advance_pc = 0x09
|
||||
DW_LNS_set_prologue_end = 0x0a
|
||||
DW_LNS_set_epilogue_begin = 0x0b
|
||||
DW_LNS_set_isa = 0x0c
|
||||
)
|
||||
|
||||
// Table 38
|
||||
const (
|
||||
DW_LNE_end_sequence = 0x01
|
||||
DW_LNE_set_address = 0x02
|
||||
DW_LNE_define_file = 0x03
|
||||
DW_LNE_lo_user = 0x80
|
||||
DW_LNE_hi_user = 0xff
|
||||
)
|
||||
|
||||
// Table 39
|
||||
const (
|
||||
DW_MACINFO_define = 0x01
|
||||
DW_MACINFO_undef = 0x02
|
||||
DW_MACINFO_start_file = 0x03
|
||||
DW_MACINFO_end_file = 0x04
|
||||
DW_MACINFO_vendor_ext = 0xff
|
||||
)
|
||||
|
||||
// Table 40.
|
||||
const (
|
||||
DW_CFA_nop = 0x00
|
||||
DW_CFA_set_loc = 0x01
|
||||
DW_CFA_advance_loc1 = 0x02
|
||||
DW_CFA_advance_loc2 = 0x03
|
||||
DW_CFA_advance_loc4 = 0x04
|
||||
DW_CFA_offset_extended = 0x05
|
||||
DW_CFA_restore_extended = 0x06
|
||||
DW_CFA_undefined = 0x07
|
||||
DW_CFA_same_value = 0x08
|
||||
DW_CFA_register = 0x09
|
||||
DW_CFA_remember_state = 0x0a
|
||||
DW_CFA_restore_state = 0x0b
|
||||
DW_CFA_def_cfa = 0x0c
|
||||
DW_CFA_def_cfa_register = 0x0d
|
||||
DW_CFA_def_cfa_offset = 0x0e
|
||||
DW_CFA_def_cfa_expression = 0x0f
|
||||
DW_CFA_expression = 0x10
|
||||
DW_CFA_offset_extended_sf = 0x11
|
||||
DW_CFA_def_cfa_sf = 0x12
|
||||
DW_CFA_def_cfa_offset_sf = 0x13
|
||||
DW_CFA_val_offset = 0x14
|
||||
DW_CFA_val_offset_sf = 0x15
|
||||
DW_CFA_val_expression = 0x16
|
||||
DW_CFA_lo_user = 0x1c
|
||||
DW_CFA_hi_user = 0x3f
|
||||
DW_CFA_advance_loc = 0x1 << 6
|
||||
DW_CFA_offset = 0x2 << 6
|
||||
DW_CFA_restore = 0x3 << 6
|
||||
)
|
||||
2448
src/cmd/internal/ld/elf.go
Normal file
2448
src/cmd/internal/ld/elf.go
Normal file
File diff suppressed because it is too large
Load diff
60
src/cmd/internal/ld/fmt.go
Normal file
60
src/cmd/internal/ld/fmt.go
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
* The authors of this software are Rob Pike and Ken Thompson.
|
||||
* Copyright (c) 2002 by Lucent Technologies.
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose without fee is hereby granted, provided that this entire notice
|
||||
* is included in all copies of any software which is or includes a copy
|
||||
* or modification of this software and in all copies of the supporting
|
||||
* documentation for such software.
|
||||
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
|
||||
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
|
||||
* REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
|
||||
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
|
||||
*/
|
||||
|
||||
package ld
|
||||
|
||||
// (The comments in this file were copied from the manpage files rune.3,
|
||||
// isalpharune.3, and runestrcat.3. Some formatting changes were also made
|
||||
// to conform to Google style. /JRM 11/11/05)
|
||||
|
||||
type Fmt struct {
|
||||
runes uint8
|
||||
start interface{}
|
||||
to interface{}
|
||||
stop interface{}
|
||||
flush func(*Fmt) int
|
||||
farg interface{}
|
||||
nfmt int
|
||||
args []interface{}
|
||||
r uint
|
||||
width int
|
||||
prec int
|
||||
flags uint32
|
||||
decimal string
|
||||
thousands string
|
||||
grouping string
|
||||
}
|
||||
|
||||
const (
|
||||
FmtWidth = 1
|
||||
FmtLeft = FmtWidth << 1
|
||||
FmtPrec = FmtLeft << 1
|
||||
FmtSharp = FmtPrec << 1
|
||||
FmtSpace = FmtSharp << 1
|
||||
FmtSign = FmtSpace << 1
|
||||
FmtApost = FmtSign << 1
|
||||
FmtZero = FmtApost << 1
|
||||
FmtUnsigned = FmtZero << 1
|
||||
FmtShort = FmtUnsigned << 1
|
||||
FmtLong = FmtShort << 1
|
||||
FmtVLong = FmtLong << 1
|
||||
FmtComma = FmtVLong << 1
|
||||
FmtByte = FmtComma << 1
|
||||
FmtLDouble = FmtByte << 1
|
||||
FmtFlag = FmtLDouble << 1
|
||||
)
|
||||
|
||||
var fmtdoquote func(int) int
|
||||
|
||||
/* Edit .+1,/^$/ | cfn $PLAN9/src/lib9/fmt/?*.c | grep -v static |grep -v __ */
|
||||
929
src/cmd/internal/ld/go.go
Normal file
929
src/cmd/internal/ld/go.go
Normal file
|
|
@ -0,0 +1,929 @@
|
|||
// Copyright 2009 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package ld
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"cmd/internal/obj"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
// go-specific code shared across loaders (5l, 6l, 8l).
|
||||
|
||||
// replace all "". with pkg.
|
||||
func expandpkg(t0 string, pkg string) string {
|
||||
return strings.Replace(t0, `"".`, pkg+".", -1)
|
||||
}
|
||||
|
||||
// Copyright 2009 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// go-specific code shared across loaders (5l, 6l, 8l).
|
||||
|
||||
// accumulate all type information from .6 files.
|
||||
// check for inconsistencies.
|
||||
|
||||
// TODO:
|
||||
// generate debugging section in binary.
|
||||
// once the dust settles, try to move some code to
|
||||
// libmach, so that other linkers and ar can share.
|
||||
|
||||
/*
|
||||
* package import data
|
||||
*/
|
||||
type Import struct {
|
||||
hash *Import
|
||||
prefix string
|
||||
name string
|
||||
def string
|
||||
file string
|
||||
}
|
||||
|
||||
const (
|
||||
NIHASH = 1024
|
||||
)
|
||||
|
||||
var ihash [NIHASH]*Import
|
||||
|
||||
var nimport int
|
||||
|
||||
func hashstr(name string) int {
|
||||
var h uint32
|
||||
var cp string
|
||||
|
||||
h = 0
|
||||
for cp = name; cp != ""; cp = cp[1:] {
|
||||
h = h*1119 + uint32(cp[0])
|
||||
}
|
||||
h &= 0xffffff
|
||||
return int(h)
|
||||
}
|
||||
|
||||
func ilookup(name string) *Import {
|
||||
var h int
|
||||
var x *Import
|
||||
|
||||
h = hashstr(name) % NIHASH
|
||||
for x = ihash[h]; x != nil; x = x.hash {
|
||||
if x.name[0] == name[0] && x.name == name {
|
||||
return x
|
||||
}
|
||||
}
|
||||
x = new(Import)
|
||||
x.name = name
|
||||
x.hash = ihash[h]
|
||||
ihash[h] = x
|
||||
nimport++
|
||||
return x
|
||||
}
|
||||
|
||||
func ldpkg(f *Biobuf, pkg string, length int64, filename string, whence int) {
|
||||
var bdata []byte
|
||||
var data string
|
||||
var p0, p1 int
|
||||
var name string
|
||||
|
||||
if Debug['g'] != 0 {
|
||||
return
|
||||
}
|
||||
|
||||
if int64(int(length)) != length {
|
||||
fmt.Fprintf(os.Stderr, "%s: too much pkg data in %s\n", os.Args[0], filename)
|
||||
if Debug['u'] != 0 {
|
||||
Errorexit()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
bdata = make([]byte, length)
|
||||
if int64(Bread(f, bdata)) != length {
|
||||
fmt.Fprintf(os.Stderr, "%s: short pkg read %s\n", os.Args[0], filename)
|
||||
if Debug['u'] != 0 {
|
||||
Errorexit()
|
||||
}
|
||||
return
|
||||
}
|
||||
data = string(bdata)
|
||||
|
||||
// first \n$$ marks beginning of exports - skip rest of line
|
||||
p0 = strings.Index(data, "\n$$")
|
||||
if p0 < 0 {
|
||||
if Debug['u'] != 0 && whence != ArchiveObj {
|
||||
fmt.Fprintf(os.Stderr, "%s: cannot find export data in %s\n", os.Args[0], filename)
|
||||
Errorexit()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
p0 += 3
|
||||
for p0 < len(data) && data[0] != '\n' {
|
||||
p0++
|
||||
}
|
||||
|
||||
// second marks end of exports / beginning of local data
|
||||
p1 = strings.Index(data[p0:], "\n$$")
|
||||
if p1 < 0 {
|
||||
fmt.Fprintf(os.Stderr, "%s: cannot find end of exports in %s\n", os.Args[0], filename)
|
||||
if Debug['u'] != 0 {
|
||||
Errorexit()
|
||||
}
|
||||
return
|
||||
}
|
||||
p1 += p0
|
||||
|
||||
for p0 < p1 && (data[p0] == ' ' || data[0] == '\t' || data[0] == '\n') {
|
||||
p0++
|
||||
}
|
||||
if p0 < p1 {
|
||||
if !strings.HasPrefix(data[p0:], "package ") {
|
||||
fmt.Fprintf(os.Stderr, "%s: bad package section in %s - %.20s\n", os.Args[0], filename, data[p0:])
|
||||
if Debug['u'] != 0 {
|
||||
Errorexit()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
p0 += 8
|
||||
for p0 < p1 && (data[p0] == ' ' || data[p0] == '\t' || data[p0] == '\n') {
|
||||
p0++
|
||||
}
|
||||
name = data[p0:]
|
||||
for p0 < p1 && data[p0] != ' ' && data[p0] != '\t' && data[p0] != '\n' {
|
||||
p0++
|
||||
}
|
||||
if Debug['u'] != 0 && whence != ArchiveObj && (p0+6 > p1 || !strings.HasPrefix(data[p0:], " safe\n")) {
|
||||
fmt.Fprintf(os.Stderr, "%s: load of unsafe package %s\n", os.Args[0], filename)
|
||||
nerrors++
|
||||
Errorexit()
|
||||
}
|
||||
|
||||
name = name[:p1-p0]
|
||||
if p0 < p1 {
|
||||
if data[p0] == '\n' {
|
||||
p0++
|
||||
} else {
|
||||
p0++
|
||||
for p0 < p1 && data[p0] != '\n' {
|
||||
p0++
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if pkg == "main" && name != "main" {
|
||||
fmt.Fprintf(os.Stderr, "%s: %s: not package main (package %s)\n", os.Args[0], filename, name)
|
||||
nerrors++
|
||||
Errorexit()
|
||||
}
|
||||
|
||||
loadpkgdata(filename, pkg, data[p0:p1])
|
||||
}
|
||||
|
||||
// __.PKGDEF has no cgo section - those are in the C compiler-generated object files.
|
||||
if whence == Pkgdef {
|
||||
return
|
||||
}
|
||||
|
||||
// look for cgo section
|
||||
p0 = strings.Index(data[p1:], "\n$$ // cgo")
|
||||
if p0 >= 0 {
|
||||
p0 += p1
|
||||
i := strings.IndexByte(data[p0+1:], '\n')
|
||||
if i < 0 {
|
||||
fmt.Fprintf(os.Stderr, "%s: found $$ // cgo but no newline in %s\n", os.Args[0], filename)
|
||||
if Debug['u'] != 0 {
|
||||
Errorexit()
|
||||
}
|
||||
return
|
||||
}
|
||||
p0 += 1 + i
|
||||
|
||||
p1 = strings.Index(data[p0:], "\n$$")
|
||||
if p1 < 0 {
|
||||
p1 = strings.Index(data[p0:], "\n!\n")
|
||||
}
|
||||
if p1 < 0 {
|
||||
fmt.Fprintf(os.Stderr, "%s: cannot find end of // cgo section in %s\n", os.Args[0], filename)
|
||||
if Debug['u'] != 0 {
|
||||
Errorexit()
|
||||
}
|
||||
return
|
||||
}
|
||||
p1 += p0
|
||||
|
||||
loadcgo(filename, pkg, data[p0:p1])
|
||||
}
|
||||
}
|
||||
|
||||
func loadpkgdata(file string, pkg string, data string) {
|
||||
var p string
|
||||
var prefix string
|
||||
var name string
|
||||
var def string
|
||||
var x *Import
|
||||
|
||||
file = file
|
||||
p = data
|
||||
for parsepkgdata(file, pkg, &p, &prefix, &name, &def) > 0 {
|
||||
x = ilookup(name)
|
||||
if x.prefix == "" {
|
||||
x.prefix = prefix
|
||||
x.def = def
|
||||
x.file = file
|
||||
} else if x.prefix != prefix {
|
||||
fmt.Fprintf(os.Stderr, "%s: conflicting definitions for %s\n", os.Args[0], name)
|
||||
fmt.Fprintf(os.Stderr, "%s:\t%s %s ...\n", x.file, x.prefix, name)
|
||||
fmt.Fprintf(os.Stderr, "%s:\t%s %s ...\n", file, prefix, name)
|
||||
nerrors++
|
||||
} else if x.def != def {
|
||||
fmt.Fprintf(os.Stderr, "%s: conflicting definitions for %s\n", os.Args[0], name)
|
||||
fmt.Fprintf(os.Stderr, "%s:\t%s %s %s\n", x.file, x.prefix, name, x.def)
|
||||
fmt.Fprintf(os.Stderr, "%s:\t%s %s %s\n", file, prefix, name, def)
|
||||
nerrors++
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func parsepkgdata(file string, pkg string, pp *string, prefixp *string, namep *string, defp *string) int {
|
||||
var p string
|
||||
var prefix string
|
||||
var name string
|
||||
var def string
|
||||
var meth string
|
||||
var inquote bool
|
||||
|
||||
// skip white space
|
||||
p = *pp
|
||||
|
||||
loop:
|
||||
for len(p) > 0 && (p[0] == ' ' || p[0] == '\t' || p[0] == '\n') {
|
||||
p = p[1:]
|
||||
}
|
||||
if len(p) == 0 || strings.HasPrefix(p, "$$\n") {
|
||||
return 0
|
||||
}
|
||||
|
||||
// prefix: (var|type|func|const)
|
||||
prefix = p
|
||||
|
||||
if len(p) < 7 {
|
||||
return -1
|
||||
}
|
||||
if strings.HasPrefix(p, "var ") {
|
||||
p = p[4:]
|
||||
} else if strings.HasPrefix(p, "type ") {
|
||||
p = p[5:]
|
||||
} else if strings.HasPrefix(p, "func ") {
|
||||
p = p[5:]
|
||||
} else if strings.HasPrefix(p, "const ") {
|
||||
p = p[6:]
|
||||
} else if strings.HasPrefix(p, "import ") {
|
||||
p = p[7:]
|
||||
for len(p) > 0 && p[0] != ' ' {
|
||||
p = p[1:]
|
||||
}
|
||||
p = p[1:]
|
||||
name := p
|
||||
for len(p) > 0 && p[0] != '\n' {
|
||||
p = p[1:]
|
||||
}
|
||||
if len(p) == 0 {
|
||||
fmt.Fprintf(os.Stderr, "%s: %s: confused in import line\n", os.Args[0], file)
|
||||
nerrors++
|
||||
return -1
|
||||
}
|
||||
name = name[:len(name)-len(p)]
|
||||
p = p[1:]
|
||||
imported(pkg, name)
|
||||
goto loop
|
||||
} else {
|
||||
fmt.Fprintf(os.Stderr, "%s: %s: confused in pkg data near <<%.40s>>\n", os.Args[0], file, prefix)
|
||||
nerrors++
|
||||
return -1
|
||||
}
|
||||
|
||||
prefix = prefix[:len(prefix)-len(p)-1]
|
||||
|
||||
// name: a.b followed by space
|
||||
name = p
|
||||
|
||||
inquote = false
|
||||
for len(p) > 0 {
|
||||
if p[0] == ' ' && !inquote {
|
||||
break
|
||||
}
|
||||
|
||||
if p[0] == '\\' {
|
||||
p = p[1:]
|
||||
} else if p[0] == '"' {
|
||||
inquote = !inquote
|
||||
}
|
||||
|
||||
p = p[1:]
|
||||
}
|
||||
|
||||
if len(p) == 0 {
|
||||
return -1
|
||||
}
|
||||
name = name[:len(name)-len(p)]
|
||||
p = p[1:]
|
||||
|
||||
// def: free form to new line
|
||||
def = p
|
||||
|
||||
for len(p) > 0 && p[0] != '\n' {
|
||||
p = p[1:]
|
||||
}
|
||||
if len(p) == 0 {
|
||||
return -1
|
||||
}
|
||||
def = def[:len(def)-len(p)]
|
||||
var defbuf *bytes.Buffer
|
||||
p = p[1:]
|
||||
|
||||
// include methods on successive lines in def of named type
|
||||
for parsemethod(&p, &meth) > 0 {
|
||||
if defbuf == nil {
|
||||
defbuf = new(bytes.Buffer)
|
||||
defbuf.WriteString(def)
|
||||
}
|
||||
defbuf.WriteString("\n\t")
|
||||
defbuf.WriteString(meth)
|
||||
}
|
||||
if defbuf != nil {
|
||||
def = defbuf.String()
|
||||
}
|
||||
|
||||
name = expandpkg(name, pkg)
|
||||
def = expandpkg(def, pkg)
|
||||
|
||||
// done
|
||||
*pp = p
|
||||
|
||||
*prefixp = prefix
|
||||
*namep = name
|
||||
*defp = def
|
||||
return 1
|
||||
}
|
||||
|
||||
func parsemethod(pp *string, methp *string) int {
|
||||
var p string
|
||||
|
||||
// skip white space
|
||||
p = *pp
|
||||
|
||||
for len(p) > 0 && (p[0] == ' ' || p[0] == '\t') {
|
||||
p = p[1:]
|
||||
}
|
||||
if len(p) == 0 {
|
||||
return 0
|
||||
}
|
||||
|
||||
// might be a comment about the method
|
||||
if strings.HasPrefix(p, "//") {
|
||||
goto useline
|
||||
}
|
||||
|
||||
// if it says "func (", it's a method
|
||||
if strings.HasPrefix(p, "func (") {
|
||||
goto useline
|
||||
}
|
||||
return 0
|
||||
|
||||
// definition to end of line
|
||||
useline:
|
||||
*methp = p
|
||||
|
||||
for len(p) > 0 && p[0] != '\n' {
|
||||
p = p[1:]
|
||||
}
|
||||
if len(p) == 0 {
|
||||
fmt.Fprintf(os.Stderr, "%s: lost end of line in method definition\n", os.Args[0])
|
||||
*pp = ""
|
||||
return -1
|
||||
}
|
||||
|
||||
*methp = (*methp)[:len(*methp)-len(p)]
|
||||
*pp = p[1:]
|
||||
return 1
|
||||
}
|
||||
|
||||
func loadcgo(file string, pkg string, p string) {
|
||||
var next string
|
||||
var p0 string
|
||||
var q string
|
||||
var f []string
|
||||
var local string
|
||||
var remote string
|
||||
var lib string
|
||||
var s *LSym
|
||||
|
||||
p0 = ""
|
||||
for ; p != ""; p = next {
|
||||
if i := strings.Index(p, "\n"); i >= 0 {
|
||||
p, next = p[:i], p[i+1:]
|
||||
} else {
|
||||
next = ""
|
||||
}
|
||||
|
||||
p0 = p // save for error message
|
||||
f = tokenize(p)
|
||||
if len(f) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
if f[0] == "cgo_import_dynamic" {
|
||||
if len(f) < 2 || len(f) > 4 {
|
||||
goto err
|
||||
}
|
||||
|
||||
local = f[1]
|
||||
remote = local
|
||||
if len(f) > 2 {
|
||||
remote = f[2]
|
||||
}
|
||||
lib = ""
|
||||
if len(f) > 3 {
|
||||
lib = f[3]
|
||||
}
|
||||
|
||||
if Debug['d'] != 0 {
|
||||
fmt.Fprintf(os.Stderr, "%s: %s: cannot use dynamic imports with -d flag\n", os.Args[0], file)
|
||||
nerrors++
|
||||
return
|
||||
}
|
||||
|
||||
if local == "_" && remote == "_" {
|
||||
// allow #pragma dynimport _ _ "foo.so"
|
||||
// to force a link of foo.so.
|
||||
havedynamic = 1
|
||||
|
||||
Thearch.Adddynlib(lib)
|
||||
continue
|
||||
}
|
||||
|
||||
local = expandpkg(local, pkg)
|
||||
q = ""
|
||||
if i := strings.Index(remote, "#"); i >= 0 {
|
||||
remote, q = remote[:i], remote[i+1:]
|
||||
}
|
||||
s = Linklookup(Ctxt, local, 0)
|
||||
if local != f[1] {
|
||||
}
|
||||
if s.Type == 0 || s.Type == SXREF || s.Type == SHOSTOBJ {
|
||||
s.Dynimplib = lib
|
||||
s.Extname = remote
|
||||
s.Dynimpvers = q
|
||||
if s.Type != SHOSTOBJ {
|
||||
s.Type = SDYNIMPORT
|
||||
}
|
||||
havedynamic = 1
|
||||
}
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
if f[0] == "cgo_import_static" {
|
||||
if len(f) != 2 {
|
||||
goto err
|
||||
}
|
||||
local = f[1]
|
||||
s = Linklookup(Ctxt, local, 0)
|
||||
s.Type = SHOSTOBJ
|
||||
s.Size = 0
|
||||
continue
|
||||
}
|
||||
|
||||
if f[0] == "cgo_export_static" || f[0] == "cgo_export_dynamic" {
|
||||
// TODO: Remove once we know Windows is okay.
|
||||
if f[0] == "cgo_export_static" && HEADTYPE == Hwindows {
|
||||
continue
|
||||
}
|
||||
|
||||
if len(f) < 2 || len(f) > 3 {
|
||||
goto err
|
||||
}
|
||||
local = f[1]
|
||||
if len(f) > 2 {
|
||||
remote = f[2]
|
||||
} else {
|
||||
remote = local
|
||||
}
|
||||
local = expandpkg(local, pkg)
|
||||
s = Linklookup(Ctxt, local, 0)
|
||||
|
||||
if Flag_shared != 0 && s == Linklookup(Ctxt, "main", 0) {
|
||||
continue
|
||||
}
|
||||
|
||||
// export overrides import, for openbsd/cgo.
|
||||
// see issue 4878.
|
||||
if s.Dynimplib != "" {
|
||||
s.Dynimplib = ""
|
||||
s.Extname = ""
|
||||
s.Dynimpvers = ""
|
||||
s.Type = 0
|
||||
}
|
||||
|
||||
if s.Cgoexport == 0 {
|
||||
s.Extname = remote
|
||||
dynexp = append(dynexp, s)
|
||||
} else if s.Extname != remote {
|
||||
fmt.Fprintf(os.Stderr, "%s: conflicting cgo_export directives: %s as %s and %s\n", os.Args[0], s.Name, s.Extname, remote)
|
||||
nerrors++
|
||||
return
|
||||
}
|
||||
|
||||
if f[0] == "cgo_export_static" {
|
||||
s.Cgoexport |= CgoExportStatic
|
||||
} else {
|
||||
s.Cgoexport |= CgoExportDynamic
|
||||
}
|
||||
if local != f[1] {
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
if f[0] == "cgo_dynamic_linker" {
|
||||
if len(f) != 2 {
|
||||
goto err
|
||||
}
|
||||
|
||||
if Debug['I'] == 0 {
|
||||
if interpreter != "" && interpreter != f[1] {
|
||||
fmt.Fprintf(os.Stderr, "%s: conflict dynlinker: %s and %s\n", os.Args[0], interpreter, f[1])
|
||||
nerrors++
|
||||
return
|
||||
}
|
||||
|
||||
interpreter = f[1]
|
||||
}
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
if f[0] == "cgo_ldflag" {
|
||||
if len(f) != 2 {
|
||||
goto err
|
||||
}
|
||||
ldflag = append(ldflag, f[1])
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
|
||||
err:
|
||||
fmt.Fprintf(os.Stderr, "%s: %s: invalid dynimport line: %s\n", os.Args[0], file, p0)
|
||||
nerrors++
|
||||
}
|
||||
|
||||
var markq *LSym
|
||||
|
||||
var emarkq *LSym
|
||||
|
||||
func mark1(s *LSym, parent *LSym) {
|
||||
if s == nil || s.Reachable {
|
||||
return
|
||||
}
|
||||
if strings.HasPrefix(s.Name, "go.weak.") {
|
||||
return
|
||||
}
|
||||
s.Reachable = true
|
||||
s.Reachparent = parent
|
||||
if markq == nil {
|
||||
markq = s
|
||||
} else {
|
||||
emarkq.Queue = s
|
||||
}
|
||||
emarkq = s
|
||||
}
|
||||
|
||||
func mark(s *LSym) {
|
||||
mark1(s, nil)
|
||||
}
|
||||
|
||||
func markflood() {
|
||||
var a *Auto
|
||||
var s *LSym
|
||||
var i int
|
||||
|
||||
for s = markq; s != nil; s = s.Queue {
|
||||
if s.Type == STEXT {
|
||||
if Debug['v'] > 1 {
|
||||
fmt.Fprintf(&Bso, "marktext %s\n", s.Name)
|
||||
}
|
||||
for a = s.Autom; a != nil; a = a.Link {
|
||||
mark1(a.Gotype, s)
|
||||
}
|
||||
}
|
||||
|
||||
for i = 0; i < len(s.R); i++ {
|
||||
mark1(s.R[i].Sym, s)
|
||||
}
|
||||
if s.Pcln != nil {
|
||||
for i = 0; i < s.Pcln.Nfuncdata; i++ {
|
||||
mark1(s.Pcln.Funcdata[i], s)
|
||||
}
|
||||
}
|
||||
|
||||
mark1(s.Gotype, s)
|
||||
mark1(s.Sub, s)
|
||||
mark1(s.Outer, s)
|
||||
}
|
||||
}
|
||||
|
||||
var markextra = []string{
|
||||
"runtime.morestack",
|
||||
"runtime.morestackx",
|
||||
"runtime.morestack00",
|
||||
"runtime.morestack10",
|
||||
"runtime.morestack01",
|
||||
"runtime.morestack11",
|
||||
"runtime.morestack8",
|
||||
"runtime.morestack16",
|
||||
"runtime.morestack24",
|
||||
"runtime.morestack32",
|
||||
"runtime.morestack40",
|
||||
"runtime.morestack48",
|
||||
// on arm, lock in the div/mod helpers too
|
||||
"_div",
|
||||
"_divu",
|
||||
"_mod",
|
||||
"_modu",
|
||||
}
|
||||
|
||||
func deadcode() {
|
||||
var i int
|
||||
var s *LSym
|
||||
var last *LSym
|
||||
var p *LSym
|
||||
var fmt_ string
|
||||
|
||||
if Debug['v'] != 0 {
|
||||
fmt.Fprintf(&Bso, "%5.2f deadcode\n", obj.Cputime())
|
||||
}
|
||||
|
||||
mark(Linklookup(Ctxt, INITENTRY, 0))
|
||||
for i = 0; i < len(markextra); i++ {
|
||||
mark(Linklookup(Ctxt, markextra[i], 0))
|
||||
}
|
||||
|
||||
for i = 0; i < len(dynexp); i++ {
|
||||
mark(dynexp[i])
|
||||
}
|
||||
|
||||
markflood()
|
||||
|
||||
// keep each beginning with 'typelink.' if the symbol it points at is being kept.
|
||||
for s = Ctxt.Allsym; s != nil; s = s.Allsym {
|
||||
if strings.HasPrefix(s.Name, "go.typelink.") {
|
||||
s.Reachable = len(s.R) == 1 && s.R[0].Sym.Reachable
|
||||
}
|
||||
}
|
||||
|
||||
// remove dead text but keep file information (z symbols).
|
||||
last = nil
|
||||
|
||||
for s = Ctxt.Textp; s != nil; s = s.Next {
|
||||
if !s.Reachable {
|
||||
continue
|
||||
}
|
||||
|
||||
// NOTE: Removing s from old textp and adding to new, shorter textp.
|
||||
if last == nil {
|
||||
Ctxt.Textp = s
|
||||
} else {
|
||||
last.Next = s
|
||||
}
|
||||
last = s
|
||||
}
|
||||
|
||||
if last == nil {
|
||||
Ctxt.Textp = nil
|
||||
} else {
|
||||
last.Next = nil
|
||||
}
|
||||
|
||||
for s = Ctxt.Allsym; s != nil; s = s.Allsym {
|
||||
if strings.HasPrefix(s.Name, "go.weak.") {
|
||||
s.Special = 1 // do not lay out in data segment
|
||||
s.Reachable = true
|
||||
s.Hide = 1
|
||||
}
|
||||
}
|
||||
|
||||
// record field tracking references
|
||||
fmt_ = ""
|
||||
|
||||
for s = Ctxt.Allsym; s != nil; s = s.Allsym {
|
||||
if strings.HasPrefix(s.Name, "go.track.") {
|
||||
s.Special = 1 // do not lay out in data segment
|
||||
s.Hide = 1
|
||||
if s.Reachable {
|
||||
fmt_ += fmt.Sprintf("%s", s.Name[9:])
|
||||
for p = s.Reachparent; p != nil; p = p.Reachparent {
|
||||
fmt_ += fmt.Sprintf("\t%s", p.Name)
|
||||
}
|
||||
fmt_ += fmt.Sprintf("\n")
|
||||
}
|
||||
|
||||
s.Type = SCONST
|
||||
s.Value = 0
|
||||
}
|
||||
}
|
||||
|
||||
if tracksym == "" {
|
||||
return
|
||||
}
|
||||
s = Linklookup(Ctxt, tracksym, 0)
|
||||
if !s.Reachable {
|
||||
return
|
||||
}
|
||||
addstrdata(tracksym, fmt_)
|
||||
}
|
||||
|
||||
func doweak() {
|
||||
var s *LSym
|
||||
var t *LSym
|
||||
|
||||
// resolve weak references only if
|
||||
// target symbol will be in binary anyway.
|
||||
for s = Ctxt.Allsym; s != nil; s = s.Allsym {
|
||||
if strings.HasPrefix(s.Name, "go.weak.") {
|
||||
t = Linkrlookup(Ctxt, s.Name[8:], int(s.Version))
|
||||
if t != nil && t.Type != 0 && t.Reachable {
|
||||
s.Value = t.Value
|
||||
s.Type = t.Type
|
||||
s.Outer = t
|
||||
} else {
|
||||
s.Type = SCONST
|
||||
s.Value = 0
|
||||
}
|
||||
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func addexport() {
|
||||
var i int
|
||||
|
||||
if HEADTYPE == Hdarwin {
|
||||
return
|
||||
}
|
||||
|
||||
for i = 0; i < len(dynexp); i++ {
|
||||
Thearch.Adddynsym(Ctxt, dynexp[i])
|
||||
}
|
||||
}
|
||||
|
||||
/* %Z from gc, for quoting import paths */
|
||||
func Zconv(s string, flag int) string {
|
||||
// NOTE: Keep in sync with gc Zconv.
|
||||
var n int
|
||||
var fp string
|
||||
for i := 0; i < len(s); i += n {
|
||||
var r rune
|
||||
r, n = utf8.DecodeRuneInString(s[i:])
|
||||
switch r {
|
||||
case utf8.RuneError:
|
||||
if n == 1 {
|
||||
fp += fmt.Sprintf("\\x%02x", s[i])
|
||||
break
|
||||
}
|
||||
fallthrough
|
||||
|
||||
// fall through
|
||||
default:
|
||||
if r < ' ' {
|
||||
fp += fmt.Sprintf("\\x%02x", r)
|
||||
break
|
||||
}
|
||||
|
||||
fp += string(r)
|
||||
|
||||
case '\t':
|
||||
fp += "\\t"
|
||||
|
||||
case '\n':
|
||||
fp += "\\n"
|
||||
|
||||
case '"',
|
||||
'\\':
|
||||
fp += `\` + string(r)
|
||||
|
||||
case 0xFEFF: // BOM, basically disallowed in source code
|
||||
fp += "\\uFEFF"
|
||||
}
|
||||
}
|
||||
|
||||
return fp
|
||||
}
|
||||
|
||||
type Pkg struct {
|
||||
mark uint8
|
||||
checked uint8
|
||||
next *Pkg
|
||||
path_ string
|
||||
impby []*Pkg
|
||||
all *Pkg
|
||||
}
|
||||
|
||||
var phash [1024]*Pkg
|
||||
|
||||
var pkgall *Pkg
|
||||
|
||||
func getpkg(path_ string) *Pkg {
|
||||
var p *Pkg
|
||||
var h int
|
||||
|
||||
h = hashstr(path_) % len(phash)
|
||||
for p = phash[h]; p != nil; p = p.next {
|
||||
if p.path_ == path_ {
|
||||
return p
|
||||
}
|
||||
}
|
||||
p = new(Pkg)
|
||||
p.path_ = path_
|
||||
p.next = phash[h]
|
||||
phash[h] = p
|
||||
p.all = pkgall
|
||||
pkgall = p
|
||||
return p
|
||||
}
|
||||
|
||||
func imported(pkg string, import_ string) {
|
||||
var p *Pkg
|
||||
var i *Pkg
|
||||
|
||||
// everyone imports runtime, even runtime.
|
||||
if import_ == "\"runtime\"" {
|
||||
return
|
||||
}
|
||||
|
||||
pkg = fmt.Sprintf("\"%v\"", Zconv(pkg, 0)) // turn pkg path into quoted form, freed below
|
||||
p = getpkg(pkg)
|
||||
i = getpkg(import_)
|
||||
i.impby = append(i.impby, p)
|
||||
}
|
||||
|
||||
func cycle(p *Pkg) *Pkg {
|
||||
var i int
|
||||
var bad *Pkg
|
||||
|
||||
if p.checked != 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
if p.mark != 0 {
|
||||
nerrors++
|
||||
fmt.Printf("import cycle:\n")
|
||||
fmt.Printf("\t%s\n", p.path_)
|
||||
return p
|
||||
}
|
||||
|
||||
p.mark = 1
|
||||
for i = 0; i < len(p.impby); i++ {
|
||||
bad = cycle(p.impby[i])
|
||||
if bad != nil {
|
||||
p.mark = 0
|
||||
p.checked = 1
|
||||
fmt.Printf("\timports %s\n", p.path_)
|
||||
if bad == p {
|
||||
return nil
|
||||
}
|
||||
return bad
|
||||
}
|
||||
}
|
||||
|
||||
p.checked = 1
|
||||
p.mark = 0
|
||||
return nil
|
||||
}
|
||||
|
||||
func importcycles() {
|
||||
var p *Pkg
|
||||
|
||||
for p = pkgall; p != nil; p = p.all {
|
||||
cycle(p)
|
||||
}
|
||||
}
|
||||
|
||||
func setlinkmode(arg string) {
|
||||
if arg == "internal" {
|
||||
Linkmode = LinkInternal
|
||||
} else if arg == "external" {
|
||||
Linkmode = LinkExternal
|
||||
} else if arg == "auto" {
|
||||
Linkmode = LinkAuto
|
||||
} else {
|
||||
fmt.Fprintf(os.Stderr, "unknown link mode -linkmode %s\n", arg)
|
||||
Errorexit()
|
||||
}
|
||||
}
|
||||
123
src/cmd/internal/ld/ld.go
Normal file
123
src/cmd/internal/ld/ld.go
Normal file
|
|
@ -0,0 +1,123 @@
|
|||
// Derived from Inferno utils/6l/obj.c and utils/6l/span.c
|
||||
// http://code.google.com/p/inferno-os/source/browse/utils/6l/obj.c
|
||||
// http://code.google.com/p/inferno-os/source/browse/utils/6l/span.c
|
||||
//
|
||||
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
|
||||
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
|
||||
// Portions Copyright © 1997-1999 Vita Nuova Limited
|
||||
// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
|
||||
// Portions Copyright © 2004,2006 Bruce Ellis
|
||||
// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
|
||||
// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
|
||||
// Portions Copyright © 2009 The Go Authors. All rights reserved.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
package ld
|
||||
|
||||
import (
|
||||
"cmd/internal/obj"
|
||||
"fmt"
|
||||
"os"
|
||||
"path"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func addlib(ctxt *Link, src string, obj string, pathname string) {
|
||||
name := path.Clean(pathname)
|
||||
|
||||
// runtime.a -> runtime, runtime.6 -> runtime
|
||||
pkg := name
|
||||
if len(pkg) >= 2 && pkg[len(pkg)-2] == '.' {
|
||||
pkg = pkg[:len(pkg)-2]
|
||||
}
|
||||
|
||||
// already loaded?
|
||||
for i := 0; i < len(ctxt.Library); i++ {
|
||||
if ctxt.Library[i].Pkg == pkg {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
var pname string
|
||||
if (ctxt.Windows == 0 && strings.HasPrefix(name, "/")) || (ctxt.Windows != 0 && len(name) >= 2 && name[1] == ':') {
|
||||
pname = name
|
||||
} else {
|
||||
// try dot, -L "libdir", and then goroot.
|
||||
for _, dir := range ctxt.Libdir {
|
||||
pname = dir + "/" + name
|
||||
if _, err := os.Stat(pname); err == nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pname = path.Clean(pname)
|
||||
|
||||
if ctxt.Debugvlog > 1 && ctxt.Bso != nil {
|
||||
fmt.Fprintf(ctxt.Bso, "%5.2f addlib: %s %s pulls in %s\n", elapsed(), obj, src, pname)
|
||||
}
|
||||
|
||||
addlibpath(ctxt, src, obj, pname, pkg)
|
||||
}
|
||||
|
||||
/*
|
||||
* add library to library list.
|
||||
* srcref: src file referring to package
|
||||
* objref: object file referring to package
|
||||
* file: object file, e.g., /home/rsc/go/pkg/container/vector.a
|
||||
* pkg: package import path, e.g. container/vector
|
||||
*/
|
||||
func addlibpath(ctxt *Link, srcref string, objref string, file string, pkg string) {
|
||||
var i int
|
||||
var l *Library
|
||||
|
||||
for i = 0; i < len(ctxt.Library); i++ {
|
||||
if file == ctxt.Library[i].File {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if ctxt.Debugvlog > 1 && ctxt.Bso != nil {
|
||||
fmt.Fprintf(ctxt.Bso, "%5.2f addlibpath: srcref: %s objref: %s file: %s pkg: %s\n", obj.Cputime(), srcref, objref, file, pkg)
|
||||
}
|
||||
|
||||
ctxt.Library = append(ctxt.Library, Library{})
|
||||
l = &ctxt.Library[len(ctxt.Library)-1]
|
||||
l.Objref = objref
|
||||
l.Srcref = srcref
|
||||
l.File = file
|
||||
l.Pkg = pkg
|
||||
}
|
||||
|
||||
var fnuxi8 [8]uint8
|
||||
|
||||
var fnuxi4 [4]uint8
|
||||
|
||||
var inuxi1 [1]uint8
|
||||
|
||||
var inuxi2 [2]uint8
|
||||
|
||||
var inuxi8 [8]uint8
|
||||
|
||||
func atolwhex(s string) int64 {
|
||||
n, _ := strconv.ParseInt(s, 0, 64)
|
||||
return n
|
||||
}
|
||||
1004
src/cmd/internal/ld/ldelf.go
Normal file
1004
src/cmd/internal/ld/ldelf.go
Normal file
File diff suppressed because it is too large
Load diff
919
src/cmd/internal/ld/ldmacho.go
Normal file
919
src/cmd/internal/ld/ldmacho.go
Normal file
|
|
@ -0,0 +1,919 @@
|
|||
package ld
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"log"
|
||||
"sort"
|
||||
)
|
||||
|
||||
/*
|
||||
Derived from Plan 9 from User Space's src/libmach/elf.h, elf.c
|
||||
http://code.swtch.com/plan9port/src/tip/src/libmach/
|
||||
|
||||
Copyright © 2004 Russ Cox.
|
||||
Portions Copyright © 2008-2010 Google Inc.
|
||||
Portions Copyright © 2010 The Go Authors.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
const (
|
||||
N_EXT = 0x01
|
||||
N_TYPE = 0x1e
|
||||
N_STAB = 0xe0
|
||||
)
|
||||
|
||||
type LdMachoObj struct {
|
||||
f *Biobuf
|
||||
base int64
|
||||
length int64
|
||||
is64 bool
|
||||
name string
|
||||
e binary.ByteOrder
|
||||
cputype uint
|
||||
subcputype uint
|
||||
filetype uint32
|
||||
flags uint32
|
||||
cmd []LdMachoCmd
|
||||
ncmd uint
|
||||
}
|
||||
|
||||
type LdMachoCmd struct {
|
||||
type_ int
|
||||
off uint32
|
||||
size uint32
|
||||
seg LdMachoSeg
|
||||
sym LdMachoSymtab
|
||||
dsym LdMachoDysymtab
|
||||
}
|
||||
|
||||
type LdMachoSeg struct {
|
||||
name string
|
||||
vmaddr uint64
|
||||
vmsize uint64
|
||||
fileoff uint32
|
||||
filesz uint32
|
||||
maxprot uint32
|
||||
initprot uint32
|
||||
nsect uint32
|
||||
flags uint32
|
||||
sect []LdMachoSect
|
||||
}
|
||||
|
||||
type LdMachoSect struct {
|
||||
name string
|
||||
segname string
|
||||
addr uint64
|
||||
size uint64
|
||||
off uint32
|
||||
align uint32
|
||||
reloff uint32
|
||||
nreloc uint32
|
||||
flags uint32
|
||||
res1 uint32
|
||||
res2 uint32
|
||||
sym *LSym
|
||||
rel []LdMachoRel
|
||||
}
|
||||
|
||||
type LdMachoRel struct {
|
||||
addr uint32
|
||||
symnum uint32
|
||||
pcrel uint8
|
||||
length uint8
|
||||
extrn uint8
|
||||
type_ uint8
|
||||
scattered uint8
|
||||
value uint32
|
||||
}
|
||||
|
||||
type LdMachoSymtab struct {
|
||||
symoff uint32
|
||||
nsym uint32
|
||||
stroff uint32
|
||||
strsize uint32
|
||||
str []byte
|
||||
sym []LdMachoSym
|
||||
}
|
||||
|
||||
type LdMachoSym struct {
|
||||
name string
|
||||
type_ uint8
|
||||
sectnum uint8
|
||||
desc uint16
|
||||
kind int8
|
||||
value uint64
|
||||
sym *LSym
|
||||
}
|
||||
|
||||
type LdMachoDysymtab struct {
|
||||
ilocalsym uint32
|
||||
nlocalsym uint32
|
||||
iextdefsym uint32
|
||||
nextdefsym uint32
|
||||
iundefsym uint32
|
||||
nundefsym uint32
|
||||
tocoff uint32
|
||||
ntoc uint32
|
||||
modtaboff uint32
|
||||
nmodtab uint32
|
||||
extrefsymoff uint32
|
||||
nextrefsyms uint32
|
||||
indirectsymoff uint32
|
||||
nindirectsyms uint32
|
||||
extreloff uint32
|
||||
nextrel uint32
|
||||
locreloff uint32
|
||||
nlocrel uint32
|
||||
indir []uint32
|
||||
}
|
||||
|
||||
const (
|
||||
LdMachoCpuVax = 1
|
||||
LdMachoCpu68000 = 6
|
||||
LdMachoCpu386 = 7
|
||||
LdMachoCpuAmd64 = 0x1000007
|
||||
LdMachoCpuMips = 8
|
||||
LdMachoCpu98000 = 10
|
||||
LdMachoCpuHppa = 11
|
||||
LdMachoCpuArm = 12
|
||||
LdMachoCpu88000 = 13
|
||||
LdMachoCpuSparc = 14
|
||||
LdMachoCpu860 = 15
|
||||
LdMachoCpuAlpha = 16
|
||||
LdMachoCpuPower = 18
|
||||
LdMachoCmdSegment = 1
|
||||
LdMachoCmdSymtab = 2
|
||||
LdMachoCmdSymseg = 3
|
||||
LdMachoCmdThread = 4
|
||||
LdMachoCmdDysymtab = 11
|
||||
LdMachoCmdSegment64 = 25
|
||||
LdMachoFileObject = 1
|
||||
LdMachoFileExecutable = 2
|
||||
LdMachoFileFvmlib = 3
|
||||
LdMachoFileCore = 4
|
||||
LdMachoFilePreload = 5
|
||||
)
|
||||
|
||||
func unpackcmd(p []byte, m *LdMachoObj, c *LdMachoCmd, type_ uint, sz uint) int {
|
||||
var e4 func([]byte) uint32
|
||||
var e8 func([]byte) uint64
|
||||
var s *LdMachoSect
|
||||
var i int
|
||||
|
||||
e4 = m.e.Uint32
|
||||
e8 = m.e.Uint64
|
||||
|
||||
c.type_ = int(type_)
|
||||
c.size = uint32(sz)
|
||||
switch type_ {
|
||||
default:
|
||||
return -1
|
||||
|
||||
case LdMachoCmdSegment:
|
||||
if sz < 56 {
|
||||
return -1
|
||||
}
|
||||
c.seg.name = cstring(p[8:24])
|
||||
c.seg.vmaddr = uint64(e4(p[24:]))
|
||||
c.seg.vmsize = uint64(e4(p[28:]))
|
||||
c.seg.fileoff = e4(p[32:])
|
||||
c.seg.filesz = e4(p[36:])
|
||||
c.seg.maxprot = e4(p[40:])
|
||||
c.seg.initprot = e4(p[44:])
|
||||
c.seg.nsect = e4(p[48:])
|
||||
c.seg.flags = e4(p[52:])
|
||||
c.seg.sect = make([]LdMachoSect, c.seg.nsect)
|
||||
if uint32(sz) < 56+c.seg.nsect*68 {
|
||||
return -1
|
||||
}
|
||||
p = p[56:]
|
||||
for i = 0; uint32(i) < c.seg.nsect; i++ {
|
||||
s = &c.seg.sect[i]
|
||||
s.name = cstring(p[0:16])
|
||||
s.segname = cstring(p[16:32])
|
||||
s.addr = uint64(e4(p[32:]))
|
||||
s.size = uint64(e4(p[36:]))
|
||||
s.off = e4(p[40:])
|
||||
s.align = e4(p[44:])
|
||||
s.reloff = e4(p[48:])
|
||||
s.nreloc = e4(p[52:])
|
||||
s.flags = e4(p[56:])
|
||||
s.res1 = e4(p[60:])
|
||||
s.res2 = e4(p[64:])
|
||||
p = p[68:]
|
||||
}
|
||||
|
||||
case LdMachoCmdSegment64:
|
||||
if sz < 72 {
|
||||
return -1
|
||||
}
|
||||
c.seg.name = cstring(p[8:24])
|
||||
c.seg.vmaddr = e8(p[24:])
|
||||
c.seg.vmsize = e8(p[32:])
|
||||
c.seg.fileoff = uint32(e8(p[40:]))
|
||||
c.seg.filesz = uint32(e8(p[48:]))
|
||||
c.seg.maxprot = e4(p[56:])
|
||||
c.seg.initprot = e4(p[60:])
|
||||
c.seg.nsect = e4(p[64:])
|
||||
c.seg.flags = e4(p[68:])
|
||||
c.seg.sect = make([]LdMachoSect, c.seg.nsect)
|
||||
if uint32(sz) < 72+c.seg.nsect*80 {
|
||||
return -1
|
||||
}
|
||||
p = p[72:]
|
||||
for i = 0; uint32(i) < c.seg.nsect; i++ {
|
||||
s = &c.seg.sect[i]
|
||||
s.name = cstring(p[0:16])
|
||||
s.segname = cstring(p[16:32])
|
||||
s.addr = e8(p[32:])
|
||||
s.size = e8(p[40:])
|
||||
s.off = e4(p[48:])
|
||||
s.align = e4(p[52:])
|
||||
s.reloff = e4(p[56:])
|
||||
s.nreloc = e4(p[60:])
|
||||
s.flags = e4(p[64:])
|
||||
s.res1 = e4(p[68:])
|
||||
s.res2 = e4(p[72:])
|
||||
|
||||
// p+76 is reserved
|
||||
p = p[80:]
|
||||
}
|
||||
|
||||
case LdMachoCmdSymtab:
|
||||
if sz < 24 {
|
||||
return -1
|
||||
}
|
||||
c.sym.symoff = e4(p[8:])
|
||||
c.sym.nsym = e4(p[12:])
|
||||
c.sym.stroff = e4(p[16:])
|
||||
c.sym.strsize = e4(p[20:])
|
||||
|
||||
case LdMachoCmdDysymtab:
|
||||
if sz < 80 {
|
||||
return -1
|
||||
}
|
||||
c.dsym.ilocalsym = e4(p[8:])
|
||||
c.dsym.nlocalsym = e4(p[12:])
|
||||
c.dsym.iextdefsym = e4(p[16:])
|
||||
c.dsym.nextdefsym = e4(p[20:])
|
||||
c.dsym.iundefsym = e4(p[24:])
|
||||
c.dsym.nundefsym = e4(p[28:])
|
||||
c.dsym.tocoff = e4(p[32:])
|
||||
c.dsym.ntoc = e4(p[36:])
|
||||
c.dsym.modtaboff = e4(p[40:])
|
||||
c.dsym.nmodtab = e4(p[44:])
|
||||
c.dsym.extrefsymoff = e4(p[48:])
|
||||
c.dsym.nextrefsyms = e4(p[52:])
|
||||
c.dsym.indirectsymoff = e4(p[56:])
|
||||
c.dsym.nindirectsyms = e4(p[60:])
|
||||
c.dsym.extreloff = e4(p[64:])
|
||||
c.dsym.nextrel = e4(p[68:])
|
||||
c.dsym.locreloff = e4(p[72:])
|
||||
c.dsym.nlocrel = e4(p[76:])
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
func macholoadrel(m *LdMachoObj, sect *LdMachoSect) int {
|
||||
var rel []LdMachoRel
|
||||
var r *LdMachoRel
|
||||
var buf []byte
|
||||
var p []byte
|
||||
var i int
|
||||
var n int
|
||||
var v uint32
|
||||
|
||||
if sect.rel != nil || sect.nreloc == 0 {
|
||||
return 0
|
||||
}
|
||||
rel = make([]LdMachoRel, sect.nreloc)
|
||||
n = int(sect.nreloc * 8)
|
||||
buf = make([]byte, n)
|
||||
if Bseek(m.f, m.base+int64(sect.reloff), 0) < 0 || Bread(m.f, buf) != n {
|
||||
return -1
|
||||
}
|
||||
for i = 0; uint32(i) < sect.nreloc; i++ {
|
||||
r = &rel[i]
|
||||
p = buf[i*8:]
|
||||
r.addr = m.e.Uint32(p)
|
||||
|
||||
// TODO(rsc): Wrong interpretation for big-endian bitfields?
|
||||
if r.addr&0x80000000 != 0 {
|
||||
// scatterbrained relocation
|
||||
r.scattered = 1
|
||||
|
||||
v = r.addr >> 24
|
||||
r.addr &= 0xFFFFFF
|
||||
r.type_ = uint8(v & 0xF)
|
||||
v >>= 4
|
||||
r.length = 1 << (v & 3)
|
||||
v >>= 2
|
||||
r.pcrel = uint8(v & 1)
|
||||
r.value = m.e.Uint32(p[4:])
|
||||
} else {
|
||||
v = m.e.Uint32(p[4:])
|
||||
r.symnum = v & 0xFFFFFF
|
||||
v >>= 24
|
||||
r.pcrel = uint8(v & 1)
|
||||
v >>= 1
|
||||
r.length = 1 << (v & 3)
|
||||
v >>= 2
|
||||
r.extrn = uint8(v & 1)
|
||||
v >>= 1
|
||||
r.type_ = uint8(v)
|
||||
}
|
||||
}
|
||||
|
||||
sect.rel = rel
|
||||
return 0
|
||||
}
|
||||
|
||||
func macholoaddsym(m *LdMachoObj, d *LdMachoDysymtab) int {
|
||||
var p []byte
|
||||
var i int
|
||||
var n int
|
||||
|
||||
n = int(d.nindirectsyms)
|
||||
|
||||
p = make([]byte, n*4)
|
||||
if Bseek(m.f, m.base+int64(d.indirectsymoff), 0) < 0 || Bread(m.f, p) != len(p) {
|
||||
return -1
|
||||
}
|
||||
|
||||
d.indir = make([]uint32, n)
|
||||
for i = 0; i < n; i++ {
|
||||
d.indir[i] = m.e.Uint32(p[4*i:])
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func macholoadsym(m *LdMachoObj, symtab *LdMachoSymtab) int {
|
||||
var strbuf []byte
|
||||
var symbuf []byte
|
||||
var p []byte
|
||||
var i int
|
||||
var n int
|
||||
var symsize int
|
||||
var sym []LdMachoSym
|
||||
var s *LdMachoSym
|
||||
var v uint32
|
||||
|
||||
if symtab.sym != nil {
|
||||
return 0
|
||||
}
|
||||
|
||||
strbuf = make([]byte, symtab.strsize)
|
||||
if Bseek(m.f, m.base+int64(symtab.stroff), 0) < 0 || Bread(m.f, strbuf) != len(strbuf) {
|
||||
return -1
|
||||
}
|
||||
|
||||
symsize = 12
|
||||
if m.is64 {
|
||||
symsize = 16
|
||||
}
|
||||
n = int(symtab.nsym * uint32(symsize))
|
||||
symbuf = make([]byte, n)
|
||||
if Bseek(m.f, m.base+int64(symtab.symoff), 0) < 0 || Bread(m.f, symbuf) != len(symbuf) {
|
||||
return -1
|
||||
}
|
||||
sym = make([]LdMachoSym, symtab.nsym)
|
||||
p = symbuf
|
||||
for i = 0; uint32(i) < symtab.nsym; i++ {
|
||||
s = &sym[i]
|
||||
v = m.e.Uint32(p)
|
||||
if v >= symtab.strsize {
|
||||
return -1
|
||||
}
|
||||
s.name = cstring(strbuf[v:])
|
||||
s.type_ = uint8(p[4])
|
||||
s.sectnum = uint8(p[5])
|
||||
s.desc = m.e.Uint16(p[6:])
|
||||
if m.is64 {
|
||||
s.value = m.e.Uint64(p[8:])
|
||||
} else {
|
||||
s.value = uint64(m.e.Uint32(p[8:]))
|
||||
}
|
||||
p = p[symsize:]
|
||||
}
|
||||
|
||||
symtab.str = strbuf
|
||||
symtab.sym = sym
|
||||
return 0
|
||||
}
|
||||
|
||||
func ldmacho(f *Biobuf, pkg string, length int64, pn string) {
|
||||
var err error
|
||||
var i int
|
||||
var j int
|
||||
var is64 bool
|
||||
var secaddr uint64
|
||||
var hdr [7 * 4]uint8
|
||||
var cmdp []byte
|
||||
var tmp [4]uint8
|
||||
var dat []byte
|
||||
var ncmd uint32
|
||||
var cmdsz uint32
|
||||
var ty uint32
|
||||
var sz uint32
|
||||
var off uint32
|
||||
var m *LdMachoObj
|
||||
var e binary.ByteOrder
|
||||
var base int64
|
||||
var sect *LdMachoSect
|
||||
var rel *LdMachoRel
|
||||
var rpi int
|
||||
var s *LSym
|
||||
var s1 *LSym
|
||||
var outer *LSym
|
||||
var c *LdMachoCmd
|
||||
var symtab *LdMachoSymtab
|
||||
var dsymtab *LdMachoDysymtab
|
||||
var sym *LdMachoSym
|
||||
var r []Reloc
|
||||
var rp *Reloc
|
||||
var name string
|
||||
|
||||
Ctxt.Version++
|
||||
base = Boffset(f)
|
||||
if Bread(f, hdr[:]) != len(hdr) {
|
||||
goto bad
|
||||
}
|
||||
|
||||
if binary.BigEndian.Uint32(hdr[:])&^1 == 0xFEEDFACE {
|
||||
e = binary.BigEndian
|
||||
} else if binary.LittleEndian.Uint32(hdr[:])&^1 == 0xFEEDFACE {
|
||||
e = binary.LittleEndian
|
||||
} else {
|
||||
err = fmt.Errorf("bad magic - not mach-o file")
|
||||
goto bad
|
||||
}
|
||||
|
||||
is64 = e.Uint32(hdr[:]) == 0xFEEDFACF
|
||||
ncmd = e.Uint32([]byte(hdr[4*4:]))
|
||||
cmdsz = e.Uint32([]byte(hdr[5*4:]))
|
||||
if ncmd > 0x10000 || cmdsz >= 0x01000000 {
|
||||
err = fmt.Errorf("implausible mach-o header ncmd=%d cmdsz=%d", ncmd, cmdsz)
|
||||
goto bad
|
||||
}
|
||||
|
||||
if is64 {
|
||||
Bread(f, tmp[:4]) // skip reserved word in header
|
||||
}
|
||||
|
||||
m = new(LdMachoObj)
|
||||
|
||||
m.f = f
|
||||
m.e = e
|
||||
m.cputype = uint(e.Uint32([]byte(hdr[1*4:])))
|
||||
m.subcputype = uint(e.Uint32([]byte(hdr[2*4:])))
|
||||
m.filetype = e.Uint32([]byte(hdr[3*4:]))
|
||||
m.ncmd = uint(ncmd)
|
||||
m.flags = e.Uint32([]byte(hdr[6*4:]))
|
||||
m.is64 = is64
|
||||
m.base = base
|
||||
m.length = length
|
||||
m.name = pn
|
||||
|
||||
switch Thearch.Thechar {
|
||||
default:
|
||||
Diag("%s: mach-o %s unimplemented", pn, Thestring)
|
||||
return
|
||||
|
||||
case '6':
|
||||
if e != binary.LittleEndian || m.cputype != LdMachoCpuAmd64 {
|
||||
Diag("%s: mach-o object but not amd64", pn)
|
||||
return
|
||||
}
|
||||
|
||||
case '8':
|
||||
if e != binary.LittleEndian || m.cputype != LdMachoCpu386 {
|
||||
Diag("%s: mach-o object but not 386", pn)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
m.cmd = make([]LdMachoCmd, ncmd)
|
||||
off = uint32(len(hdr))
|
||||
cmdp = make([]byte, cmdsz)
|
||||
if Bread(f, cmdp) != len(cmdp) {
|
||||
err = fmt.Errorf("reading cmds: %v", err)
|
||||
goto bad
|
||||
}
|
||||
|
||||
// read and parse load commands
|
||||
c = nil
|
||||
|
||||
symtab = nil
|
||||
dsymtab = nil
|
||||
|
||||
for i = 0; uint32(i) < ncmd; i++ {
|
||||
ty = e.Uint32(cmdp)
|
||||
sz = e.Uint32(cmdp[4:])
|
||||
m.cmd[i].off = off
|
||||
unpackcmd(cmdp, m, &m.cmd[i], uint(ty), uint(sz))
|
||||
cmdp = cmdp[sz:]
|
||||
off += sz
|
||||
if ty == LdMachoCmdSymtab {
|
||||
if symtab != nil {
|
||||
err = fmt.Errorf("multiple symbol tables")
|
||||
goto bad
|
||||
}
|
||||
|
||||
symtab = &m.cmd[i].sym
|
||||
macholoadsym(m, symtab)
|
||||
}
|
||||
|
||||
if ty == LdMachoCmdDysymtab {
|
||||
dsymtab = &m.cmd[i].dsym
|
||||
macholoaddsym(m, dsymtab)
|
||||
}
|
||||
|
||||
if (is64 && ty == LdMachoCmdSegment64) || (!is64 && ty == LdMachoCmdSegment) {
|
||||
if c != nil {
|
||||
err = fmt.Errorf("multiple load commands")
|
||||
goto bad
|
||||
}
|
||||
|
||||
c = &m.cmd[i]
|
||||
}
|
||||
}
|
||||
|
||||
// load text and data segments into memory.
|
||||
// they are not as small as the load commands, but we'll need
|
||||
// the memory anyway for the symbol images, so we might
|
||||
// as well use one large chunk.
|
||||
if c == nil {
|
||||
err = fmt.Errorf("no load command")
|
||||
goto bad
|
||||
}
|
||||
|
||||
if symtab == nil {
|
||||
// our work is done here - no symbols means nothing can refer to this file
|
||||
return
|
||||
}
|
||||
|
||||
if int64(c.seg.fileoff+c.seg.filesz) >= length {
|
||||
err = fmt.Errorf("load segment out of range")
|
||||
goto bad
|
||||
}
|
||||
|
||||
dat = make([]byte, c.seg.filesz)
|
||||
if Bseek(f, m.base+int64(c.seg.fileoff), 0) < 0 || Bread(f, dat) != len(dat) {
|
||||
err = fmt.Errorf("cannot load object data: %v", err)
|
||||
goto bad
|
||||
}
|
||||
|
||||
for i = 0; uint32(i) < c.seg.nsect; i++ {
|
||||
sect = &c.seg.sect[i]
|
||||
if sect.segname != "__TEXT" && sect.segname != "__DATA" {
|
||||
continue
|
||||
}
|
||||
if sect.name == "__eh_frame" {
|
||||
continue
|
||||
}
|
||||
name = fmt.Sprintf("%s(%s/%s)", pkg, sect.segname, sect.name)
|
||||
s = Linklookup(Ctxt, name, Ctxt.Version)
|
||||
if s.Type != 0 {
|
||||
err = fmt.Errorf("duplicate %s/%s", sect.segname, sect.name)
|
||||
goto bad
|
||||
}
|
||||
|
||||
if sect.flags&0xff == 1 { // S_ZEROFILL
|
||||
s.P = make([]byte, sect.size)
|
||||
} else {
|
||||
s.P = dat[sect.addr-c.seg.vmaddr:][:sect.size]
|
||||
}
|
||||
s.Size = int64(len(s.P))
|
||||
|
||||
if sect.segname == "__TEXT" {
|
||||
if sect.name == "__text" {
|
||||
s.Type = STEXT
|
||||
} else {
|
||||
s.Type = SRODATA
|
||||
}
|
||||
} else {
|
||||
if sect.name == "__bss" {
|
||||
s.Type = SNOPTRBSS
|
||||
s.P = s.P[:0]
|
||||
} else {
|
||||
s.Type = SNOPTRDATA
|
||||
}
|
||||
}
|
||||
|
||||
sect.sym = s
|
||||
}
|
||||
|
||||
// enter sub-symbols into symbol table.
|
||||
// have to guess sizes from next symbol.
|
||||
for i = 0; uint32(i) < symtab.nsym; i++ {
|
||||
var v int
|
||||
sym = &symtab.sym[i]
|
||||
if sym.type_&N_STAB != 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
// TODO: check sym->type against outer->type.
|
||||
name = sym.name
|
||||
|
||||
if name[0] == '_' && name[1] != '\x00' {
|
||||
name = name[1:]
|
||||
}
|
||||
v = 0
|
||||
if sym.type_&N_EXT == 0 {
|
||||
v = Ctxt.Version
|
||||
}
|
||||
s = Linklookup(Ctxt, name, v)
|
||||
if sym.type_&N_EXT == 0 {
|
||||
s.Dupok = 1
|
||||
}
|
||||
sym.sym = s
|
||||
if sym.sectnum == 0 { // undefined
|
||||
continue
|
||||
}
|
||||
if uint32(sym.sectnum) > c.seg.nsect {
|
||||
err = fmt.Errorf("reference to invalid section %d", sym.sectnum)
|
||||
goto bad
|
||||
}
|
||||
|
||||
sect = &c.seg.sect[sym.sectnum-1]
|
||||
outer = sect.sym
|
||||
if outer == nil {
|
||||
err = fmt.Errorf("reference to invalid section %s/%s", sect.segname, sect.name)
|
||||
continue
|
||||
}
|
||||
|
||||
if s.Outer != nil {
|
||||
if s.Dupok != 0 {
|
||||
continue
|
||||
}
|
||||
Diag("%s: duplicate symbol reference: %s in both %s and %s", pn, s.Name, s.Outer.Name, sect.sym.Name)
|
||||
Errorexit()
|
||||
}
|
||||
|
||||
s.Type = outer.Type | SSUB
|
||||
s.Sub = outer.Sub
|
||||
outer.Sub = s
|
||||
s.Outer = outer
|
||||
s.Value = int64(sym.value - sect.addr)
|
||||
if s.Cgoexport&CgoExportDynamic == 0 {
|
||||
s.Dynimplib = "" // satisfy dynimport
|
||||
}
|
||||
if outer.Type == STEXT {
|
||||
if s.External != 0 && s.Dupok == 0 {
|
||||
Diag("%s: duplicate definition of %s", pn, s.Name)
|
||||
}
|
||||
s.External = 1
|
||||
}
|
||||
|
||||
sym.sym = s
|
||||
}
|
||||
|
||||
// Sort outer lists by address, adding to textp.
|
||||
// This keeps textp in increasing address order.
|
||||
for i = 0; uint32(i) < c.seg.nsect; i++ {
|
||||
sect = &c.seg.sect[i]
|
||||
s = sect.sym
|
||||
if s == nil {
|
||||
continue
|
||||
}
|
||||
if s.Sub != nil {
|
||||
s.Sub = listsort(s.Sub, valuecmp, listsubp)
|
||||
|
||||
// assign sizes, now that we know symbols in sorted order.
|
||||
for s1 = s.Sub; s1 != nil; s1 = s1.Sub {
|
||||
if s1.Sub != nil {
|
||||
s1.Size = s1.Sub.Value - s1.Value
|
||||
} else {
|
||||
s1.Size = s.Value + s.Size - s1.Value
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if s.Type == STEXT {
|
||||
if s.Onlist != 0 {
|
||||
log.Fatalf("symbol %s listed multiple times", s.Name)
|
||||
}
|
||||
s.Onlist = 1
|
||||
if Ctxt.Etextp != nil {
|
||||
Ctxt.Etextp.Next = s
|
||||
} else {
|
||||
Ctxt.Textp = s
|
||||
}
|
||||
Ctxt.Etextp = s
|
||||
for s1 = s.Sub; s1 != nil; s1 = s1.Sub {
|
||||
if s1.Onlist != 0 {
|
||||
log.Fatalf("symbol %s listed multiple times", s1.Name)
|
||||
}
|
||||
s1.Onlist = 1
|
||||
Ctxt.Etextp.Next = s1
|
||||
Ctxt.Etextp = s1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// load relocations
|
||||
for i = 0; uint32(i) < c.seg.nsect; i++ {
|
||||
sect = &c.seg.sect[i]
|
||||
s = sect.sym
|
||||
if s == nil {
|
||||
continue
|
||||
}
|
||||
macholoadrel(m, sect)
|
||||
if sect.rel == nil {
|
||||
continue
|
||||
}
|
||||
r = make([]Reloc, sect.nreloc)
|
||||
rpi = 0
|
||||
for j = 0; uint32(j) < sect.nreloc; j++ {
|
||||
rp = &r[rpi]
|
||||
rel = §.rel[j]
|
||||
if rel.scattered != 0 {
|
||||
var k int
|
||||
var ks *LdMachoSect
|
||||
|
||||
if Thearch.Thechar != '8' {
|
||||
// mach-o only uses scattered relocation on 32-bit platforms
|
||||
Diag("unexpected scattered relocation")
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
// on 386, rewrite scattered 4/1 relocation and some
|
||||
// scattered 2/1 relocation into the pseudo-pc-relative
|
||||
// reference that it is.
|
||||
// assume that the second in the pair is in this section
|
||||
// and use that as the pc-relative base.
|
||||
if uint32(j+1) >= sect.nreloc {
|
||||
err = fmt.Errorf("unsupported scattered relocation %d", int(rel.type_))
|
||||
goto bad
|
||||
}
|
||||
|
||||
if sect.rel[j+1].scattered == 0 || sect.rel[j+1].type_ != 1 || (rel.type_ != 4 && rel.type_ != 2) || uint64(sect.rel[j+1].value) < sect.addr || uint64(sect.rel[j+1].value) >= sect.addr+sect.size {
|
||||
err = fmt.Errorf("unsupported scattered relocation %d/%d", int(rel.type_), int(sect.rel[j+1].type_))
|
||||
goto bad
|
||||
}
|
||||
|
||||
rp.Siz = rel.length
|
||||
rp.Off = int32(rel.addr)
|
||||
|
||||
// NOTE(rsc): I haven't worked out why (really when)
|
||||
// we should ignore the addend on a
|
||||
// scattered relocation, but it seems that the
|
||||
// common case is we ignore it.
|
||||
// It's likely that this is not strictly correct
|
||||
// and that the math should look something
|
||||
// like the non-scattered case below.
|
||||
rp.Add = 0
|
||||
|
||||
// want to make it pc-relative aka relative to rp->off+4
|
||||
// but the scatter asks for relative to off = sect->rel[j+1].value - sect->addr.
|
||||
// adjust rp->add accordingly.
|
||||
rp.Type = R_PCREL
|
||||
|
||||
rp.Add += int64(uint64(int64(rp.Off)+4) - (uint64(sect.rel[j+1].value) - sect.addr))
|
||||
|
||||
// now consider the desired symbol.
|
||||
// find the section where it lives.
|
||||
for k = 0; uint32(k) < c.seg.nsect; k++ {
|
||||
ks = &c.seg.sect[k]
|
||||
if ks.addr <= uint64(rel.value) && uint64(rel.value) < ks.addr+ks.size {
|
||||
goto foundk
|
||||
}
|
||||
}
|
||||
|
||||
err = fmt.Errorf("unsupported scattered relocation: invalid address %#x", rel.addr)
|
||||
goto bad
|
||||
|
||||
foundk:
|
||||
if ks.sym != nil {
|
||||
rp.Sym = ks.sym
|
||||
rp.Add += int64(uint64(rel.value) - ks.addr)
|
||||
} else if ks.segname == "__IMPORT" && ks.name == "__pointers" {
|
||||
// handle reference to __IMPORT/__pointers.
|
||||
// how much worse can this get?
|
||||
// why are we supporting 386 on the mac anyway?
|
||||
rp.Type = 512 + MACHO_FAKE_GOTPCREL
|
||||
|
||||
// figure out which pointer this is a reference to.
|
||||
k = int(uint64(ks.res1) + (uint64(rel.value)-ks.addr)/4)
|
||||
|
||||
// load indirect table for __pointers
|
||||
// fetch symbol number
|
||||
if dsymtab == nil || k < 0 || uint32(k) >= dsymtab.nindirectsyms || dsymtab.indir == nil {
|
||||
err = fmt.Errorf("invalid scattered relocation: indirect symbol reference out of range")
|
||||
goto bad
|
||||
}
|
||||
|
||||
k = int(dsymtab.indir[k])
|
||||
if k < 0 || uint32(k) >= symtab.nsym {
|
||||
err = fmt.Errorf("invalid scattered relocation: symbol reference out of range")
|
||||
goto bad
|
||||
}
|
||||
|
||||
rp.Sym = symtab.sym[k].sym
|
||||
} else {
|
||||
err = fmt.Errorf("unsupported scattered relocation: reference to %s/%s", ks.segname, ks.name)
|
||||
goto bad
|
||||
}
|
||||
|
||||
rpi++
|
||||
|
||||
// skip #1 of 2 rel; continue skips #2 of 2.
|
||||
j++
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
rp.Siz = rel.length
|
||||
rp.Type = 512 + (int32(rel.type_) << 1) + int32(rel.pcrel)
|
||||
rp.Off = int32(rel.addr)
|
||||
|
||||
// Handle X86_64_RELOC_SIGNED referencing a section (rel->extrn == 0).
|
||||
if Thearch.Thechar == '6' && rel.extrn == 0 && rel.type_ == 1 {
|
||||
// Calculate the addend as the offset into the section.
|
||||
//
|
||||
// The rip-relative offset stored in the object file is encoded
|
||||
// as follows:
|
||||
//
|
||||
// movsd 0x00000360(%rip),%xmm0
|
||||
//
|
||||
// To get the absolute address of the value this rip-relative address is pointing
|
||||
// to, we must add the address of the next instruction to it. This is done by
|
||||
// taking the address of the relocation and adding 4 to it (since the rip-relative
|
||||
// offset can at most be 32 bits long). To calculate the offset into the section the
|
||||
// relocation is referencing, we subtract the vaddr of the start of the referenced
|
||||
// section found in the original object file.
|
||||
//
|
||||
// [For future reference, see Darwin's /usr/include/mach-o/x86_64/reloc.h]
|
||||
secaddr = c.seg.sect[rel.symnum-1].addr
|
||||
|
||||
rp.Add = int64(uint64(int64(int32(e.Uint32(s.P[rp.Off:])))+int64(rp.Off)+4) - secaddr)
|
||||
} else {
|
||||
rp.Add = int64(int32(e.Uint32(s.P[rp.Off:])))
|
||||
}
|
||||
|
||||
// For i386 Mach-O PC-relative, the addend is written such that
|
||||
// it *is* the PC being subtracted. Use that to make
|
||||
// it match our version of PC-relative.
|
||||
if rel.pcrel != 0 && Thearch.Thechar == '8' {
|
||||
rp.Add += int64(rp.Off) + int64(rp.Siz)
|
||||
}
|
||||
if rel.extrn == 0 {
|
||||
if rel.symnum < 1 || rel.symnum > c.seg.nsect {
|
||||
err = fmt.Errorf("invalid relocation: section reference out of range %d vs %d", rel.symnum, c.seg.nsect)
|
||||
goto bad
|
||||
}
|
||||
|
||||
rp.Sym = c.seg.sect[rel.symnum-1].sym
|
||||
if rp.Sym == nil {
|
||||
err = fmt.Errorf("invalid relocation: %s", c.seg.sect[rel.symnum-1].name)
|
||||
goto bad
|
||||
}
|
||||
|
||||
// References to symbols in other sections
|
||||
// include that information in the addend.
|
||||
// We only care about the delta from the
|
||||
// section base.
|
||||
if Thearch.Thechar == '8' {
|
||||
rp.Add -= int64(c.seg.sect[rel.symnum-1].addr)
|
||||
}
|
||||
} else {
|
||||
if rel.symnum >= symtab.nsym {
|
||||
err = fmt.Errorf("invalid relocation: symbol reference out of range")
|
||||
goto bad
|
||||
}
|
||||
|
||||
rp.Sym = symtab.sym[rel.symnum].sym
|
||||
}
|
||||
|
||||
rpi++
|
||||
}
|
||||
|
||||
sort.Sort(rbyoff(r[:rpi]))
|
||||
s.R = r
|
||||
s.R = s.R[:rpi]
|
||||
}
|
||||
|
||||
return
|
||||
|
||||
bad:
|
||||
Diag("%s: malformed mach-o file: %v", pn, err)
|
||||
}
|
||||
550
src/cmd/internal/ld/ldpe.go
Normal file
550
src/cmd/internal/ld/ldpe.go
Normal file
|
|
@ -0,0 +1,550 @@
|
|||
// Copyright 2010 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package ld
|
||||
|
||||
import (
|
||||
"cmd/internal/obj"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"log"
|
||||
"sort"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
IMAGE_SYM_UNDEFINED = 0
|
||||
IMAGE_SYM_ABSOLUTE = -1
|
||||
IMAGE_SYM_DEBUG = -2
|
||||
IMAGE_SYM_TYPE_NULL = 0
|
||||
IMAGE_SYM_TYPE_VOID = 1
|
||||
IMAGE_SYM_TYPE_CHAR = 2
|
||||
IMAGE_SYM_TYPE_SHORT = 3
|
||||
IMAGE_SYM_TYPE_INT = 4
|
||||
IMAGE_SYM_TYPE_LONG = 5
|
||||
IMAGE_SYM_TYPE_FLOAT = 6
|
||||
IMAGE_SYM_TYPE_DOUBLE = 7
|
||||
IMAGE_SYM_TYPE_STRUCT = 8
|
||||
IMAGE_SYM_TYPE_UNION = 9
|
||||
IMAGE_SYM_TYPE_ENUM = 10
|
||||
IMAGE_SYM_TYPE_MOE = 11
|
||||
IMAGE_SYM_TYPE_BYTE = 12
|
||||
IMAGE_SYM_TYPE_WORD = 13
|
||||
IMAGE_SYM_TYPE_UINT = 14
|
||||
IMAGE_SYM_TYPE_DWORD = 15
|
||||
IMAGE_SYM_TYPE_PCODE = 32768
|
||||
IMAGE_SYM_DTYPE_NULL = 0
|
||||
IMAGE_SYM_DTYPE_POINTER = 0x10
|
||||
IMAGE_SYM_DTYPE_FUNCTION = 0x20
|
||||
IMAGE_SYM_DTYPE_ARRAY = 0x30
|
||||
IMAGE_SYM_CLASS_END_OF_FUNCTION = -1
|
||||
IMAGE_SYM_CLASS_NULL = 0
|
||||
IMAGE_SYM_CLASS_AUTOMATIC = 1
|
||||
IMAGE_SYM_CLASS_EXTERNAL = 2
|
||||
IMAGE_SYM_CLASS_STATIC = 3
|
||||
IMAGE_SYM_CLASS_REGISTER = 4
|
||||
IMAGE_SYM_CLASS_EXTERNAL_DEF = 5
|
||||
IMAGE_SYM_CLASS_LABEL = 6
|
||||
IMAGE_SYM_CLASS_UNDEFINED_LABEL = 7
|
||||
IMAGE_SYM_CLASS_MEMBER_OF_STRUCT = 8
|
||||
IMAGE_SYM_CLASS_ARGUMENT = 9
|
||||
IMAGE_SYM_CLASS_STRUCT_TAG = 10
|
||||
IMAGE_SYM_CLASS_MEMBER_OF_UNION = 11
|
||||
IMAGE_SYM_CLASS_UNION_TAG = 12
|
||||
IMAGE_SYM_CLASS_TYPE_DEFINITION = 13
|
||||
IMAGE_SYM_CLASS_UNDEFINED_STATIC = 14
|
||||
IMAGE_SYM_CLASS_ENUM_TAG = 15
|
||||
IMAGE_SYM_CLASS_MEMBER_OF_ENUM = 16
|
||||
IMAGE_SYM_CLASS_REGISTER_PARAM = 17
|
||||
IMAGE_SYM_CLASS_BIT_FIELD = 18
|
||||
IMAGE_SYM_CLASS_FAR_EXTERNAL = 68
|
||||
IMAGE_SYM_CLASS_BLOCK = 100
|
||||
IMAGE_SYM_CLASS_FUNCTION = 101
|
||||
IMAGE_SYM_CLASS_END_OF_STRUCT = 102
|
||||
IMAGE_SYM_CLASS_FILE = 103
|
||||
IMAGE_SYM_CLASS_SECTION = 104
|
||||
IMAGE_SYM_CLASS_WEAK_EXTERNAL = 105
|
||||
IMAGE_SYM_CLASS_CLR_TOKEN = 107
|
||||
IMAGE_REL_I386_ABSOLUTE = 0x0000
|
||||
IMAGE_REL_I386_DIR16 = 0x0001
|
||||
IMAGE_REL_I386_REL16 = 0x0002
|
||||
IMAGE_REL_I386_DIR32 = 0x0006
|
||||
IMAGE_REL_I386_DIR32NB = 0x0007
|
||||
IMAGE_REL_I386_SEG12 = 0x0009
|
||||
IMAGE_REL_I386_SECTION = 0x000A
|
||||
IMAGE_REL_I386_SECREL = 0x000B
|
||||
IMAGE_REL_I386_TOKEN = 0x000C
|
||||
IMAGE_REL_I386_SECREL7 = 0x000D
|
||||
IMAGE_REL_I386_REL32 = 0x0014
|
||||
IMAGE_REL_AMD64_ABSOLUTE = 0x0000
|
||||
IMAGE_REL_AMD64_ADDR64 = 0x0001
|
||||
IMAGE_REL_AMD64_ADDR32 = 0x0002
|
||||
IMAGE_REL_AMD64_ADDR32NB = 0x0003
|
||||
IMAGE_REL_AMD64_REL32 = 0x0004
|
||||
IMAGE_REL_AMD64_REL32_1 = 0x0005
|
||||
IMAGE_REL_AMD64_REL32_2 = 0x0006
|
||||
IMAGE_REL_AMD64_REL32_3 = 0x0007
|
||||
IMAGE_REL_AMD64_REL32_4 = 0x0008
|
||||
IMAGE_REL_AMD64_REL32_5 = 0x0009
|
||||
IMAGE_REL_AMD64_SECTION = 0x000A
|
||||
IMAGE_REL_AMD64_SECREL = 0x000B
|
||||
IMAGE_REL_AMD64_SECREL7 = 0x000C
|
||||
IMAGE_REL_AMD64_TOKEN = 0x000D
|
||||
IMAGE_REL_AMD64_SREL32 = 0x000E
|
||||
IMAGE_REL_AMD64_PAIR = 0x000F
|
||||
IMAGE_REL_AMD64_SSPAN32 = 0x0010
|
||||
)
|
||||
|
||||
type PeSym struct {
|
||||
name string
|
||||
value uint32
|
||||
sectnum uint16
|
||||
type_ uint16
|
||||
sclass uint8
|
||||
aux uint8
|
||||
sym *LSym
|
||||
}
|
||||
|
||||
type PeSect struct {
|
||||
name string
|
||||
base []byte
|
||||
size uint64
|
||||
sym *LSym
|
||||
sh IMAGE_SECTION_HEADER
|
||||
}
|
||||
|
||||
type PeObj struct {
|
||||
f *Biobuf
|
||||
name string
|
||||
base uint32
|
||||
sect []PeSect
|
||||
nsect uint
|
||||
pesym []PeSym
|
||||
npesym uint
|
||||
fh IMAGE_FILE_HEADER
|
||||
snames []byte
|
||||
}
|
||||
|
||||
func ldpe(f *Biobuf, pkg string, length int64, pn string) {
|
||||
var err error
|
||||
var name string
|
||||
var base int32
|
||||
var l uint32
|
||||
var i int
|
||||
var j int
|
||||
var numaux int
|
||||
var peobj *PeObj
|
||||
var sect *PeSect
|
||||
var rsect *PeSect
|
||||
var symbuf [18]uint8
|
||||
var s *LSym
|
||||
var r []Reloc
|
||||
var rp *Reloc
|
||||
var sym *PeSym
|
||||
|
||||
if Debug['v'] != 0 {
|
||||
fmt.Fprintf(&Bso, "%5.2f ldpe %s\n", obj.Cputime(), pn)
|
||||
}
|
||||
|
||||
sect = nil
|
||||
Ctxt.Version++
|
||||
base = int32(Boffset(f))
|
||||
|
||||
peobj = new(PeObj)
|
||||
peobj.f = f
|
||||
peobj.base = uint32(base)
|
||||
peobj.name = pn
|
||||
|
||||
// read header
|
||||
if err = binary.Read(f, binary.LittleEndian, &peobj.fh); err != nil {
|
||||
goto bad
|
||||
}
|
||||
|
||||
// load section list
|
||||
peobj.sect = make([]PeSect, peobj.fh.NumberOfSections)
|
||||
|
||||
peobj.nsect = uint(peobj.fh.NumberOfSections)
|
||||
for i = 0; i < int(peobj.fh.NumberOfSections); i++ {
|
||||
if err = binary.Read(f, binary.LittleEndian, &peobj.sect[i].sh); err != nil {
|
||||
goto bad
|
||||
}
|
||||
peobj.sect[i].size = uint64(peobj.sect[i].sh.SizeOfRawData)
|
||||
peobj.sect[i].name = cstring(peobj.sect[i].sh.Name[:])
|
||||
}
|
||||
|
||||
// TODO return error if found .cormeta
|
||||
|
||||
// load string table
|
||||
Bseek(f, int64(base)+int64(peobj.fh.PointerToSymbolTable)+int64(len(symbuf))*int64(peobj.fh.NumberOfSymbols), 0)
|
||||
|
||||
if Bread(f, symbuf[:4]) != 4 {
|
||||
goto bad
|
||||
}
|
||||
l = Le32(symbuf[:])
|
||||
peobj.snames = make([]byte, l)
|
||||
Bseek(f, int64(base)+int64(peobj.fh.PointerToSymbolTable)+int64(len(symbuf))*int64(peobj.fh.NumberOfSymbols), 0)
|
||||
if Bread(f, peobj.snames) != len(peobj.snames) {
|
||||
goto bad
|
||||
}
|
||||
|
||||
// rewrite section names if they start with /
|
||||
for i = 0; i < int(peobj.fh.NumberOfSections); i++ {
|
||||
if peobj.sect[i].name == "" {
|
||||
continue
|
||||
}
|
||||
if peobj.sect[i].name[0] != '/' {
|
||||
continue
|
||||
}
|
||||
l = uint32(obj.Atoi(peobj.sect[i].name[1:]))
|
||||
peobj.sect[i].name = cstring(peobj.snames[l:])
|
||||
}
|
||||
|
||||
// read symbols
|
||||
peobj.pesym = make([]PeSym, peobj.fh.NumberOfSymbols)
|
||||
|
||||
peobj.npesym = uint(peobj.fh.NumberOfSymbols)
|
||||
Bseek(f, int64(base)+int64(peobj.fh.PointerToSymbolTable), 0)
|
||||
for i = 0; uint32(i) < peobj.fh.NumberOfSymbols; i += numaux + 1 {
|
||||
Bseek(f, int64(base)+int64(peobj.fh.PointerToSymbolTable)+int64(len(symbuf))*int64(i), 0)
|
||||
if Bread(f, symbuf[:]) != len(symbuf) {
|
||||
goto bad
|
||||
}
|
||||
|
||||
if (symbuf[0] == 0) && (symbuf[1] == 0) && (symbuf[2] == 0) && (symbuf[3] == 0) {
|
||||
l = Le32(symbuf[4:])
|
||||
peobj.pesym[i].name = cstring(peobj.snames[l:]) // sym name length <= 8
|
||||
} else {
|
||||
peobj.pesym[i].name = cstring(symbuf[:8])
|
||||
}
|
||||
|
||||
peobj.pesym[i].value = Le32(symbuf[8:])
|
||||
peobj.pesym[i].sectnum = Le16(symbuf[12:])
|
||||
peobj.pesym[i].sclass = symbuf[16]
|
||||
peobj.pesym[i].aux = symbuf[17]
|
||||
peobj.pesym[i].type_ = Le16(symbuf[14:])
|
||||
numaux = int(peobj.pesym[i].aux)
|
||||
if numaux < 0 {
|
||||
numaux = 0
|
||||
}
|
||||
}
|
||||
|
||||
// create symbols for mapped sections
|
||||
for i = 0; uint(i) < peobj.nsect; i++ {
|
||||
sect = &peobj.sect[i]
|
||||
if sect.sh.Characteristics&IMAGE_SCN_MEM_DISCARDABLE != 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
if sect.sh.Characteristics&(IMAGE_SCN_CNT_CODE|IMAGE_SCN_CNT_INITIALIZED_DATA|IMAGE_SCN_CNT_UNINITIALIZED_DATA) == 0 {
|
||||
// This has been seen for .idata sections, which we
|
||||
// want to ignore. See issues 5106 and 5273.
|
||||
continue
|
||||
}
|
||||
|
||||
if pemap(peobj, sect) < 0 {
|
||||
goto bad
|
||||
}
|
||||
|
||||
name = fmt.Sprintf("%s(%s)", pkg, sect.name)
|
||||
s = Linklookup(Ctxt, name, Ctxt.Version)
|
||||
|
||||
switch sect.sh.Characteristics & (IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE) {
|
||||
case IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ: //.rdata
|
||||
s.Type = SRODATA
|
||||
|
||||
case IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE: //.bss
|
||||
s.Type = SNOPTRBSS
|
||||
|
||||
case IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE: //.data
|
||||
s.Type = SNOPTRDATA
|
||||
|
||||
case IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ: //.text
|
||||
s.Type = STEXT
|
||||
|
||||
default:
|
||||
err = fmt.Errorf("unexpected flags %#06x for PE section %s", sect.sh.Characteristics, sect.name)
|
||||
goto bad
|
||||
}
|
||||
|
||||
s.P = sect.base
|
||||
s.P = s.P[:sect.size]
|
||||
s.Size = int64(sect.size)
|
||||
sect.sym = s
|
||||
if sect.name == ".rsrc" {
|
||||
setpersrc(sect.sym)
|
||||
}
|
||||
}
|
||||
|
||||
// load relocations
|
||||
for i = 0; uint(i) < peobj.nsect; i++ {
|
||||
rsect = &peobj.sect[i]
|
||||
if rsect.sym == nil || rsect.sh.NumberOfRelocations == 0 {
|
||||
continue
|
||||
}
|
||||
if rsect.sh.Characteristics&IMAGE_SCN_MEM_DISCARDABLE != 0 {
|
||||
continue
|
||||
}
|
||||
if sect.sh.Characteristics&(IMAGE_SCN_CNT_CODE|IMAGE_SCN_CNT_INITIALIZED_DATA|IMAGE_SCN_CNT_UNINITIALIZED_DATA) == 0 {
|
||||
// This has been seen for .idata sections, which we
|
||||
// want to ignore. See issues 5106 and 5273.
|
||||
continue
|
||||
}
|
||||
|
||||
r = make([]Reloc, rsect.sh.NumberOfRelocations)
|
||||
Bseek(f, int64(peobj.base)+int64(rsect.sh.PointerToRelocations), 0)
|
||||
for j = 0; j < int(rsect.sh.NumberOfRelocations); j++ {
|
||||
rp = &r[j]
|
||||
if Bread(f, symbuf[:10]) != 10 {
|
||||
goto bad
|
||||
}
|
||||
var rva uint32
|
||||
var symindex uint32
|
||||
var type_ uint16
|
||||
rva = Le32(symbuf[0:])
|
||||
symindex = Le32(symbuf[4:])
|
||||
type_ = Le16(symbuf[8:])
|
||||
if err = readpesym(peobj, int(symindex), &sym); err != nil {
|
||||
goto bad
|
||||
}
|
||||
if sym.sym == nil {
|
||||
err = fmt.Errorf("reloc of invalid sym %s idx=%d type=%d", sym.name, symindex, sym.type_)
|
||||
goto bad
|
||||
}
|
||||
|
||||
rp.Sym = sym.sym
|
||||
rp.Siz = 4
|
||||
rp.Off = int32(rva)
|
||||
switch type_ {
|
||||
default:
|
||||
Diag("%s: unknown relocation type %d;", pn, type_)
|
||||
fallthrough
|
||||
|
||||
case IMAGE_REL_I386_REL32,
|
||||
IMAGE_REL_AMD64_REL32,
|
||||
IMAGE_REL_AMD64_ADDR32, // R_X86_64_PC32
|
||||
IMAGE_REL_AMD64_ADDR32NB:
|
||||
rp.Type = R_PCREL
|
||||
|
||||
rp.Add = int64(int32(Le32(rsect.base[rp.Off:])))
|
||||
|
||||
case IMAGE_REL_I386_DIR32NB,
|
||||
IMAGE_REL_I386_DIR32:
|
||||
rp.Type = R_ADDR
|
||||
|
||||
// load addend from image
|
||||
rp.Add = int64(int32(Le32(rsect.base[rp.Off:])))
|
||||
|
||||
case IMAGE_REL_AMD64_ADDR64: // R_X86_64_64
|
||||
rp.Siz = 8
|
||||
|
||||
rp.Type = R_ADDR
|
||||
|
||||
// load addend from image
|
||||
rp.Add = int64(Le64(rsect.base[rp.Off:]))
|
||||
}
|
||||
|
||||
// ld -r could generate multiple section symbols for the
|
||||
// same section but with different values, we have to take
|
||||
// that into account
|
||||
if issect(&peobj.pesym[symindex]) {
|
||||
rp.Add += int64(peobj.pesym[symindex].value)
|
||||
}
|
||||
}
|
||||
|
||||
sort.Sort(rbyoff(r[:rsect.sh.NumberOfRelocations]))
|
||||
|
||||
s = rsect.sym
|
||||
s.R = r
|
||||
s.R = s.R[:rsect.sh.NumberOfRelocations]
|
||||
}
|
||||
|
||||
// enter sub-symbols into symbol table.
|
||||
for i = 0; uint(i) < peobj.npesym; i++ {
|
||||
if peobj.pesym[i].name == "" {
|
||||
continue
|
||||
}
|
||||
if issect(&peobj.pesym[i]) {
|
||||
continue
|
||||
}
|
||||
if uint(peobj.pesym[i].sectnum) > peobj.nsect {
|
||||
continue
|
||||
}
|
||||
if peobj.pesym[i].sectnum > 0 {
|
||||
sect = &peobj.sect[peobj.pesym[i].sectnum-1]
|
||||
if sect.sym == nil {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
if err = readpesym(peobj, i, &sym); err != nil {
|
||||
goto bad
|
||||
}
|
||||
|
||||
s = sym.sym
|
||||
if sym.sectnum == 0 { // extern
|
||||
if s.Type == SDYNIMPORT {
|
||||
s.Plt = -2 // flag for dynimport in PE object files.
|
||||
}
|
||||
if s.Type == SXREF && sym.value > 0 { // global data
|
||||
s.Type = SNOPTRDATA
|
||||
s.Size = int64(sym.value)
|
||||
}
|
||||
|
||||
continue
|
||||
} else if sym.sectnum > 0 && uint(sym.sectnum) <= peobj.nsect {
|
||||
sect = &peobj.sect[sym.sectnum-1]
|
||||
if sect.sym == nil {
|
||||
Diag("%s: %s sym == 0!", pn, s.Name)
|
||||
}
|
||||
} else {
|
||||
Diag("%s: %s sectnum < 0!", pn, s.Name)
|
||||
}
|
||||
|
||||
if sect == nil {
|
||||
return
|
||||
}
|
||||
|
||||
if s.Outer != nil {
|
||||
if s.Dupok != 0 {
|
||||
continue
|
||||
}
|
||||
Diag("%s: duplicate symbol reference: %s in both %s and %s", pn, s.Name, s.Outer.Name, sect.sym.Name)
|
||||
Errorexit()
|
||||
}
|
||||
|
||||
s.Sub = sect.sym.Sub
|
||||
sect.sym.Sub = s
|
||||
s.Type = sect.sym.Type | SSUB
|
||||
s.Value = int64(sym.value)
|
||||
s.Size = 4
|
||||
s.Outer = sect.sym
|
||||
if sect.sym.Type == STEXT {
|
||||
if s.External != 0 && s.Dupok == 0 {
|
||||
Diag("%s: duplicate definition of %s", pn, s.Name)
|
||||
}
|
||||
s.External = 1
|
||||
}
|
||||
}
|
||||
|
||||
// Sort outer lists by address, adding to textp.
|
||||
// This keeps textp in increasing address order.
|
||||
for i = 0; uint(i) < peobj.nsect; i++ {
|
||||
s = peobj.sect[i].sym
|
||||
if s == nil {
|
||||
continue
|
||||
}
|
||||
if s.Sub != nil {
|
||||
s.Sub = listsort(s.Sub, valuecmp, listsubp)
|
||||
}
|
||||
if s.Type == STEXT {
|
||||
if s.Onlist != 0 {
|
||||
log.Fatalf("symbol %s listed multiple times", s.Name)
|
||||
}
|
||||
s.Onlist = 1
|
||||
if Ctxt.Etextp != nil {
|
||||
Ctxt.Etextp.Next = s
|
||||
} else {
|
||||
Ctxt.Textp = s
|
||||
}
|
||||
Ctxt.Etextp = s
|
||||
for s = s.Sub; s != nil; s = s.Sub {
|
||||
if s.Onlist != 0 {
|
||||
log.Fatalf("symbol %s listed multiple times", s.Name)
|
||||
}
|
||||
s.Onlist = 1
|
||||
Ctxt.Etextp.Next = s
|
||||
Ctxt.Etextp = s
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
|
||||
bad:
|
||||
Diag("%s: malformed pe file: %v", pn, err)
|
||||
}
|
||||
|
||||
func pemap(peobj *PeObj, sect *PeSect) int {
|
||||
if sect.base != nil {
|
||||
return 0
|
||||
}
|
||||
|
||||
sect.base = make([]byte, sect.sh.SizeOfRawData)
|
||||
if sect.sh.PointerToRawData == 0 { // .bss doesn't have data in object file
|
||||
return 0
|
||||
}
|
||||
if Bseek(peobj.f, int64(peobj.base)+int64(sect.sh.PointerToRawData), 0) < 0 || Bread(peobj.f, sect.base) != len(sect.base) {
|
||||
return -1
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
func issect(s *PeSym) bool {
|
||||
return s.sclass == IMAGE_SYM_CLASS_STATIC && s.type_ == 0 && s.name[0] == '.'
|
||||
}
|
||||
|
||||
func readpesym(peobj *PeObj, i int, y **PeSym) (err error) {
|
||||
var s *LSym
|
||||
var sym *PeSym
|
||||
var name string
|
||||
|
||||
if uint(i) >= peobj.npesym || i < 0 {
|
||||
err = fmt.Errorf("invalid pe symbol index")
|
||||
return err
|
||||
}
|
||||
|
||||
sym = &peobj.pesym[i]
|
||||
*y = sym
|
||||
|
||||
if issect(sym) {
|
||||
name = peobj.sect[sym.sectnum-1].sym.Name
|
||||
} else {
|
||||
name = sym.name
|
||||
if strings.HasPrefix(name, "__imp_") {
|
||||
name = name[6:] // __imp_Name => Name
|
||||
}
|
||||
if Thearch.Thechar == '8' && name[0] == '_' {
|
||||
name = name[1:] // _Name => Name
|
||||
}
|
||||
}
|
||||
|
||||
// remove last @XXX
|
||||
if i := strings.LastIndex(name, "@"); i >= 0 {
|
||||
name = name[:i]
|
||||
}
|
||||
|
||||
switch sym.type_ {
|
||||
default:
|
||||
err = fmt.Errorf("%s: invalid symbol type %d", sym.name, sym.type_)
|
||||
return err
|
||||
|
||||
case IMAGE_SYM_DTYPE_FUNCTION,
|
||||
IMAGE_SYM_DTYPE_NULL:
|
||||
switch sym.sclass {
|
||||
case IMAGE_SYM_CLASS_EXTERNAL: //global
|
||||
s = Linklookup(Ctxt, name, 0)
|
||||
|
||||
case IMAGE_SYM_CLASS_NULL,
|
||||
IMAGE_SYM_CLASS_STATIC,
|
||||
IMAGE_SYM_CLASS_LABEL:
|
||||
s = Linklookup(Ctxt, name, Ctxt.Version)
|
||||
s.Dupok = 1
|
||||
|
||||
default:
|
||||
err = fmt.Errorf("%s: invalid symbol binding %d", sym.name, sym.sclass)
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if s != nil && s.Type == 0 && (sym.sclass != IMAGE_SYM_CLASS_STATIC || sym.value != 0) {
|
||||
s.Type = SXREF
|
||||
}
|
||||
if strings.HasPrefix(sym.name, "__imp_") {
|
||||
s.Got = -2 // flag for __imp_
|
||||
}
|
||||
sym.sym = s
|
||||
|
||||
return nil
|
||||
}
|
||||
1751
src/cmd/internal/ld/lib.go
Normal file
1751
src/cmd/internal/ld/lib.go
Normal file
File diff suppressed because it is too large
Load diff
299
src/cmd/internal/ld/link.go
Normal file
299
src/cmd/internal/ld/link.go
Normal file
|
|
@ -0,0 +1,299 @@
|
|||
// Derived from Inferno utils/6l/l.h and related files.
|
||||
// http://code.google.com/p/inferno-os/source/browse/utils/6l/l.h
|
||||
//
|
||||
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
|
||||
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
|
||||
// Portions Copyright © 1997-1999 Vita Nuova Limited
|
||||
// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
|
||||
// Portions Copyright © 2004,2006 Bruce Ellis
|
||||
// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
|
||||
// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
|
||||
// Portions Copyright © 2009 The Go Authors. All rights reserved.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
package ld
|
||||
|
||||
import "encoding/binary"
|
||||
|
||||
type LSym struct {
|
||||
Name string
|
||||
Extname string
|
||||
Type int16
|
||||
Version int16
|
||||
Dupok uint8
|
||||
Cfunc uint8
|
||||
External uint8
|
||||
Nosplit uint8
|
||||
Reachable bool
|
||||
Cgoexport uint8
|
||||
Special uint8
|
||||
Stkcheck uint8
|
||||
Hide uint8
|
||||
Leaf uint8
|
||||
Localentry uint8
|
||||
Onlist uint8
|
||||
Dynid int32
|
||||
Sig int32
|
||||
Plt int32
|
||||
Got int32
|
||||
Align int32
|
||||
Elfsym int32
|
||||
Args int32
|
||||
Locals int32
|
||||
Value int64
|
||||
Size int64
|
||||
Hash *LSym
|
||||
Allsym *LSym
|
||||
Next *LSym
|
||||
Sub *LSym
|
||||
Outer *LSym
|
||||
Gotype *LSym
|
||||
Reachparent *LSym
|
||||
Queue *LSym
|
||||
File string
|
||||
Dynimplib string
|
||||
Dynimpvers string
|
||||
Sect interface{}
|
||||
Autom *Auto
|
||||
Pcln *Pcln
|
||||
P []byte
|
||||
R []Reloc
|
||||
}
|
||||
|
||||
type Reloc struct {
|
||||
Off int32
|
||||
Siz uint8
|
||||
Done uint8
|
||||
Type int32
|
||||
Variant int32
|
||||
Add int64
|
||||
Xadd int64
|
||||
Sym *LSym
|
||||
Xsym *LSym
|
||||
}
|
||||
|
||||
type Auto struct {
|
||||
Asym *LSym
|
||||
Link *Auto
|
||||
Aoffset int32
|
||||
Name int16
|
||||
Gotype *LSym
|
||||
}
|
||||
|
||||
type Link struct {
|
||||
Thechar int32
|
||||
Thestring string
|
||||
Goarm int32
|
||||
Headtype int
|
||||
Arch *LinkArch
|
||||
Debugasm int32
|
||||
Debugvlog int32
|
||||
Bso *Biobuf
|
||||
Windows int32
|
||||
Goroot string
|
||||
Hash map[symVer]*LSym
|
||||
Allsym *LSym
|
||||
Nsymbol int32
|
||||
Tlsg *LSym
|
||||
Libdir []string
|
||||
Library []Library
|
||||
Tlsoffset int
|
||||
Diag func(string, ...interface{})
|
||||
Cursym *LSym
|
||||
Version int
|
||||
Textp *LSym
|
||||
Etextp *LSym
|
||||
Nhistfile int32
|
||||
Filesyms *LSym
|
||||
}
|
||||
|
||||
type LinkArch struct {
|
||||
ByteOrder binary.ByteOrder
|
||||
Name string
|
||||
Thechar int
|
||||
Endian int32
|
||||
Minlc int
|
||||
Ptrsize int
|
||||
Regsize int
|
||||
}
|
||||
|
||||
type Library struct {
|
||||
Objref string
|
||||
Srcref string
|
||||
File string
|
||||
Pkg string
|
||||
}
|
||||
|
||||
type Pcln struct {
|
||||
Pcsp Pcdata
|
||||
Pcfile Pcdata
|
||||
Pcline Pcdata
|
||||
Pcdata []Pcdata
|
||||
Npcdata int
|
||||
Funcdata []*LSym
|
||||
Funcdataoff []int64
|
||||
Nfuncdata int
|
||||
File []*LSym
|
||||
Nfile int
|
||||
Mfile int
|
||||
Lastfile *LSym
|
||||
Lastindex int
|
||||
}
|
||||
|
||||
type Pcdata struct {
|
||||
P []byte
|
||||
}
|
||||
|
||||
type Pciter struct {
|
||||
d Pcdata
|
||||
p []byte
|
||||
pc uint32
|
||||
nextpc uint32
|
||||
pcscale uint32
|
||||
value int32
|
||||
start int
|
||||
done int
|
||||
}
|
||||
|
||||
// LSym.type
|
||||
const (
|
||||
Sxxx = iota
|
||||
STEXT
|
||||
SELFRXSECT
|
||||
STYPE
|
||||
SSTRING
|
||||
SGOSTRING
|
||||
SGOFUNC
|
||||
SRODATA
|
||||
SFUNCTAB
|
||||
STYPELINK
|
||||
SSYMTAB
|
||||
SPCLNTAB
|
||||
SELFROSECT
|
||||
SMACHOPLT
|
||||
SELFSECT
|
||||
SMACHO
|
||||
SMACHOGOT
|
||||
SWINDOWS
|
||||
SELFGOT
|
||||
SNOPTRDATA
|
||||
SINITARR
|
||||
SDATA
|
||||
SBSS
|
||||
SNOPTRBSS
|
||||
STLSBSS
|
||||
SXREF
|
||||
SMACHOSYMSTR
|
||||
SMACHOSYMTAB
|
||||
SMACHOINDIRECTPLT
|
||||
SMACHOINDIRECTGOT
|
||||
SFILE
|
||||
SFILEPATH
|
||||
SCONST
|
||||
SDYNIMPORT
|
||||
SHOSTOBJ
|
||||
SSUB = 1 << 8
|
||||
SMASK = SSUB - 1
|
||||
SHIDDEN = 1 << 9
|
||||
)
|
||||
|
||||
// Reloc.type
|
||||
const (
|
||||
R_ADDR = 1 + iota
|
||||
R_ADDRPOWER
|
||||
R_SIZE
|
||||
R_CALL
|
||||
R_CALLARM
|
||||
R_CALLIND
|
||||
R_CALLPOWER
|
||||
R_CONST
|
||||
R_PCREL
|
||||
R_TLS
|
||||
R_TLS_LE
|
||||
R_TLS_IE
|
||||
R_GOTOFF
|
||||
R_PLT0
|
||||
R_PLT1
|
||||
R_PLT2
|
||||
R_USEFIELD
|
||||
R_POWER_TOC
|
||||
)
|
||||
|
||||
// Reloc.variant
|
||||
const (
|
||||
RV_NONE = iota
|
||||
RV_POWER_LO
|
||||
RV_POWER_HI
|
||||
RV_POWER_HA
|
||||
RV_POWER_DS
|
||||
RV_CHECK_OVERFLOW = 1 << 8
|
||||
RV_TYPE_MASK = RV_CHECK_OVERFLOW - 1
|
||||
)
|
||||
|
||||
// Auto.name
|
||||
const (
|
||||
A_AUTO = 1 + iota
|
||||
A_PARAM
|
||||
)
|
||||
|
||||
const (
|
||||
LINKHASH = 100003
|
||||
)
|
||||
|
||||
// Pcdata iterator.
|
||||
// for(pciterinit(ctxt, &it, &pcd); !it.done; pciternext(&it)) { it.value holds in [it.pc, it.nextpc) }
|
||||
|
||||
// symbol version, incremented each time a file is loaded.
|
||||
// version==1 is reserved for savehist.
|
||||
const (
|
||||
HistVersion = 1
|
||||
)
|
||||
|
||||
// Link holds the context for writing object code from a compiler
|
||||
// to be linker input or for reading that input into the linker.
|
||||
|
||||
const (
|
||||
LittleEndian = 0x04030201
|
||||
BigEndian = 0x01020304
|
||||
)
|
||||
|
||||
// LinkArch is the definition of a single architecture.
|
||||
|
||||
/* executable header types */
|
||||
const (
|
||||
Hunknown = 0 + iota
|
||||
Hdarwin
|
||||
Hdragonfly
|
||||
Helf
|
||||
Hfreebsd
|
||||
Hlinux
|
||||
Hnacl
|
||||
Hnetbsd
|
||||
Hopenbsd
|
||||
Hplan9
|
||||
Hsolaris
|
||||
Hwindows
|
||||
)
|
||||
|
||||
const (
|
||||
LinkAuto = 0 + iota
|
||||
LinkInternal
|
||||
LinkExternal
|
||||
)
|
||||
892
src/cmd/internal/ld/macho.go
Normal file
892
src/cmd/internal/ld/macho.go
Normal file
|
|
@ -0,0 +1,892 @@
|
|||
// Copyright 2009 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package ld
|
||||
|
||||
import (
|
||||
"sort"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type MachoHdr struct {
|
||||
cpu uint32
|
||||
subcpu uint32
|
||||
}
|
||||
|
||||
type MachoSect struct {
|
||||
name string
|
||||
segname string
|
||||
addr uint64
|
||||
size uint64
|
||||
off uint32
|
||||
align uint32
|
||||
reloc uint32
|
||||
nreloc uint32
|
||||
flag uint32
|
||||
res1 uint32
|
||||
res2 uint32
|
||||
}
|
||||
|
||||
type MachoSeg struct {
|
||||
name string
|
||||
vsize uint64
|
||||
vaddr uint64
|
||||
fileoffset uint64
|
||||
filesize uint64
|
||||
prot1 uint32
|
||||
prot2 uint32
|
||||
nsect uint32
|
||||
msect uint32
|
||||
sect []MachoSect
|
||||
flag uint32
|
||||
}
|
||||
|
||||
type MachoLoad struct {
|
||||
type_ uint32
|
||||
data []uint32
|
||||
}
|
||||
|
||||
/*
|
||||
* Total amount of space to reserve at the start of the file
|
||||
* for Header, PHeaders, and SHeaders.
|
||||
* May waste some.
|
||||
*/
|
||||
const (
|
||||
INITIAL_MACHO_HEADR = 4 * 1024
|
||||
)
|
||||
|
||||
const (
|
||||
MACHO_CPU_AMD64 = 1<<24 | 7
|
||||
MACHO_CPU_386 = 7
|
||||
MACHO_SUBCPU_X86 = 3
|
||||
MACHO_CPU_ARM = 12
|
||||
MACHO_SUBCPU_ARM = 0
|
||||
MACHO_SUBCPU_ARMV7 = 9
|
||||
MACHO32SYMSIZE = 12
|
||||
MACHO64SYMSIZE = 16
|
||||
MACHO_X86_64_RELOC_UNSIGNED = 0
|
||||
MACHO_X86_64_RELOC_SIGNED = 1
|
||||
MACHO_X86_64_RELOC_BRANCH = 2
|
||||
MACHO_X86_64_RELOC_GOT_LOAD = 3
|
||||
MACHO_X86_64_RELOC_GOT = 4
|
||||
MACHO_X86_64_RELOC_SUBTRACTOR = 5
|
||||
MACHO_X86_64_RELOC_SIGNED_1 = 6
|
||||
MACHO_X86_64_RELOC_SIGNED_2 = 7
|
||||
MACHO_X86_64_RELOC_SIGNED_4 = 8
|
||||
MACHO_ARM_RELOC_VANILLA = 0
|
||||
MACHO_ARM_RELOC_BR24 = 5
|
||||
MACHO_GENERIC_RELOC_VANILLA = 0
|
||||
MACHO_FAKE_GOTPCREL = 100
|
||||
)
|
||||
|
||||
// Copyright 2009 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Mach-O file writing
|
||||
// http://developer.apple.com/mac/library/DOCUMENTATION/DeveloperTools/Conceptual/MachORuntime/Reference/reference.html
|
||||
|
||||
var macho64 bool
|
||||
|
||||
var machohdr MachoHdr
|
||||
|
||||
var load []MachoLoad
|
||||
|
||||
var seg [16]MachoSeg
|
||||
|
||||
var nload int
|
||||
|
||||
var mload int
|
||||
|
||||
var nseg int
|
||||
|
||||
var ndebug int
|
||||
|
||||
var nsect int
|
||||
|
||||
const (
|
||||
SymKindLocal = 0 + iota
|
||||
SymKindExtdef
|
||||
SymKindUndef
|
||||
NumSymKind
|
||||
)
|
||||
|
||||
var nkind [NumSymKind]int
|
||||
|
||||
var sortsym []*LSym
|
||||
|
||||
var nsortsym int
|
||||
|
||||
// Amount of space left for adding load commands
|
||||
// that refer to dynamic libraries. Because these have
|
||||
// to go in the Mach-O header, we can't just pick a
|
||||
// "big enough" header size. The initial header is
|
||||
// one page, the non-dynamic library stuff takes
|
||||
// up about 1300 bytes; we overestimate that as 2k.
|
||||
var load_budget int = INITIAL_MACHO_HEADR - 2*1024
|
||||
|
||||
func Machoinit() {
|
||||
switch Thearch.Thechar {
|
||||
// 64-bit architectures
|
||||
case '6',
|
||||
'9':
|
||||
macho64 = true
|
||||
|
||||
// 32-bit architectures
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
func getMachoHdr() *MachoHdr {
|
||||
return &machohdr
|
||||
}
|
||||
|
||||
func newMachoLoad(type_ uint32, ndata uint32) *MachoLoad {
|
||||
if macho64 && (ndata&1 != 0) {
|
||||
ndata++
|
||||
}
|
||||
|
||||
load = append(load, MachoLoad{})
|
||||
l := &load[len(load)-1]
|
||||
l.type_ = type_
|
||||
l.data = make([]uint32, ndata)
|
||||
return l
|
||||
}
|
||||
|
||||
func newMachoSeg(name string, msect int) *MachoSeg {
|
||||
var s *MachoSeg
|
||||
|
||||
if nseg >= len(seg) {
|
||||
Diag("too many segs")
|
||||
Errorexit()
|
||||
}
|
||||
|
||||
s = &seg[nseg]
|
||||
nseg++
|
||||
s.name = name
|
||||
s.msect = uint32(msect)
|
||||
s.sect = make([]MachoSect, msect)
|
||||
return s
|
||||
}
|
||||
|
||||
func newMachoSect(seg *MachoSeg, name string, segname string) *MachoSect {
|
||||
var s *MachoSect
|
||||
|
||||
if seg.nsect >= seg.msect {
|
||||
Diag("too many sects in segment %s", seg.name)
|
||||
Errorexit()
|
||||
}
|
||||
|
||||
s = &seg.sect[seg.nsect]
|
||||
seg.nsect++
|
||||
s.name = name
|
||||
s.segname = segname
|
||||
nsect++
|
||||
return s
|
||||
}
|
||||
|
||||
// Generic linking code.
|
||||
|
||||
var dylib []string
|
||||
|
||||
var ndylib int
|
||||
|
||||
var linkoff int64
|
||||
|
||||
func machowrite() int {
|
||||
var o1 int64
|
||||
var loadsize int
|
||||
var i int
|
||||
var j int
|
||||
var s *MachoSeg
|
||||
var t *MachoSect
|
||||
var l *MachoLoad
|
||||
|
||||
o1 = Cpos()
|
||||
|
||||
loadsize = 4 * 4 * ndebug
|
||||
for i = 0; i < len(load); i++ {
|
||||
loadsize += 4 * (len(load[i].data) + 2)
|
||||
}
|
||||
if macho64 {
|
||||
loadsize += 18 * 4 * nseg
|
||||
loadsize += 20 * 4 * nsect
|
||||
} else {
|
||||
loadsize += 14 * 4 * nseg
|
||||
loadsize += 17 * 4 * nsect
|
||||
}
|
||||
|
||||
if macho64 {
|
||||
Thearch.Lput(0xfeedfacf)
|
||||
} else {
|
||||
Thearch.Lput(0xfeedface)
|
||||
}
|
||||
Thearch.Lput(machohdr.cpu)
|
||||
Thearch.Lput(machohdr.subcpu)
|
||||
if Linkmode == LinkExternal {
|
||||
Thearch.Lput(1) /* file type - mach object */
|
||||
} else {
|
||||
Thearch.Lput(2) /* file type - mach executable */
|
||||
}
|
||||
Thearch.Lput(uint32(len(load)) + uint32(nseg) + uint32(ndebug))
|
||||
Thearch.Lput(uint32(loadsize))
|
||||
Thearch.Lput(1) /* flags - no undefines */
|
||||
if macho64 {
|
||||
Thearch.Lput(0) /* reserved */
|
||||
}
|
||||
|
||||
for i = 0; i < nseg; i++ {
|
||||
s = &seg[i]
|
||||
if macho64 {
|
||||
Thearch.Lput(25) /* segment 64 */
|
||||
Thearch.Lput(72 + 80*s.nsect)
|
||||
strnput(s.name, 16)
|
||||
Thearch.Vput(s.vaddr)
|
||||
Thearch.Vput(s.vsize)
|
||||
Thearch.Vput(s.fileoffset)
|
||||
Thearch.Vput(s.filesize)
|
||||
Thearch.Lput(s.prot1)
|
||||
Thearch.Lput(s.prot2)
|
||||
Thearch.Lput(s.nsect)
|
||||
Thearch.Lput(s.flag)
|
||||
} else {
|
||||
Thearch.Lput(1) /* segment 32 */
|
||||
Thearch.Lput(56 + 68*s.nsect)
|
||||
strnput(s.name, 16)
|
||||
Thearch.Lput(uint32(s.vaddr))
|
||||
Thearch.Lput(uint32(s.vsize))
|
||||
Thearch.Lput(uint32(s.fileoffset))
|
||||
Thearch.Lput(uint32(s.filesize))
|
||||
Thearch.Lput(s.prot1)
|
||||
Thearch.Lput(s.prot2)
|
||||
Thearch.Lput(s.nsect)
|
||||
Thearch.Lput(s.flag)
|
||||
}
|
||||
|
||||
for j = 0; uint32(j) < s.nsect; j++ {
|
||||
t = &s.sect[j]
|
||||
if macho64 {
|
||||
strnput(t.name, 16)
|
||||
strnput(t.segname, 16)
|
||||
Thearch.Vput(t.addr)
|
||||
Thearch.Vput(t.size)
|
||||
Thearch.Lput(t.off)
|
||||
Thearch.Lput(t.align)
|
||||
Thearch.Lput(t.reloc)
|
||||
Thearch.Lput(t.nreloc)
|
||||
Thearch.Lput(t.flag)
|
||||
Thearch.Lput(t.res1) /* reserved */
|
||||
Thearch.Lput(t.res2) /* reserved */
|
||||
Thearch.Lput(0) /* reserved */
|
||||
} else {
|
||||
strnput(t.name, 16)
|
||||
strnput(t.segname, 16)
|
||||
Thearch.Lput(uint32(t.addr))
|
||||
Thearch.Lput(uint32(t.size))
|
||||
Thearch.Lput(t.off)
|
||||
Thearch.Lput(t.align)
|
||||
Thearch.Lput(t.reloc)
|
||||
Thearch.Lput(t.nreloc)
|
||||
Thearch.Lput(t.flag)
|
||||
Thearch.Lput(t.res1) /* reserved */
|
||||
Thearch.Lput(t.res2) /* reserved */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for i = 0; i < len(load); i++ {
|
||||
l = &load[i]
|
||||
Thearch.Lput(l.type_)
|
||||
Thearch.Lput(4 * (uint32(len(l.data)) + 2))
|
||||
for j = 0; j < len(l.data); j++ {
|
||||
Thearch.Lput(l.data[j])
|
||||
}
|
||||
}
|
||||
|
||||
return int(Cpos() - o1)
|
||||
}
|
||||
|
||||
func domacho() {
|
||||
var s *LSym
|
||||
|
||||
if Debug['d'] != 0 {
|
||||
return
|
||||
}
|
||||
|
||||
// empirically, string table must begin with " \x00".
|
||||
s = Linklookup(Ctxt, ".machosymstr", 0)
|
||||
|
||||
s.Type = SMACHOSYMSTR
|
||||
s.Reachable = true
|
||||
Adduint8(Ctxt, s, ' ')
|
||||
Adduint8(Ctxt, s, '\x00')
|
||||
|
||||
s = Linklookup(Ctxt, ".machosymtab", 0)
|
||||
s.Type = SMACHOSYMTAB
|
||||
s.Reachable = true
|
||||
|
||||
if Linkmode != LinkExternal {
|
||||
s = Linklookup(Ctxt, ".plt", 0) // will be __symbol_stub
|
||||
s.Type = SMACHOPLT
|
||||
s.Reachable = true
|
||||
|
||||
s = Linklookup(Ctxt, ".got", 0) // will be __nl_symbol_ptr
|
||||
s.Type = SMACHOGOT
|
||||
s.Reachable = true
|
||||
s.Align = 4
|
||||
|
||||
s = Linklookup(Ctxt, ".linkedit.plt", 0) // indirect table for .plt
|
||||
s.Type = SMACHOINDIRECTPLT
|
||||
s.Reachable = true
|
||||
|
||||
s = Linklookup(Ctxt, ".linkedit.got", 0) // indirect table for .got
|
||||
s.Type = SMACHOINDIRECTGOT
|
||||
s.Reachable = true
|
||||
}
|
||||
}
|
||||
|
||||
func Machoadddynlib(lib string) {
|
||||
// Will need to store the library name rounded up
|
||||
// and 24 bytes of header metadata. If not enough
|
||||
// space, grab another page of initial space at the
|
||||
// beginning of the output file.
|
||||
load_budget -= (len(lib)+7)/8*8 + 24
|
||||
|
||||
if load_budget < 0 {
|
||||
HEADR += 4096
|
||||
INITTEXT += 4096
|
||||
load_budget += 4096
|
||||
}
|
||||
|
||||
dylib = append(dylib, lib)
|
||||
}
|
||||
|
||||
func machoshbits(mseg *MachoSeg, sect *Section, segname string) {
|
||||
var msect *MachoSect
|
||||
var buf string
|
||||
|
||||
buf = "__" + strings.Replace(sect.Name[1:], ".", "_", -1)
|
||||
|
||||
msect = newMachoSect(mseg, buf, segname)
|
||||
if sect.Rellen > 0 {
|
||||
msect.reloc = uint32(sect.Reloff)
|
||||
msect.nreloc = uint32(sect.Rellen / 8)
|
||||
}
|
||||
|
||||
for 1<<msect.align < sect.Align {
|
||||
msect.align++
|
||||
}
|
||||
msect.addr = sect.Vaddr
|
||||
msect.size = sect.Length
|
||||
|
||||
if sect.Vaddr < sect.Seg.Vaddr+sect.Seg.Filelen {
|
||||
// data in file
|
||||
if sect.Length > sect.Seg.Vaddr+sect.Seg.Filelen-sect.Vaddr {
|
||||
Diag("macho cannot represent section %s crossing data and bss", sect.Name)
|
||||
}
|
||||
msect.off = uint32(sect.Seg.Fileoff + sect.Vaddr - sect.Seg.Vaddr)
|
||||
} else {
|
||||
// zero fill
|
||||
msect.off = 0
|
||||
|
||||
msect.flag |= 1
|
||||
}
|
||||
|
||||
if sect.Rwx&1 != 0 {
|
||||
msect.flag |= 0x400 /* has instructions */
|
||||
}
|
||||
|
||||
if sect.Name == ".plt" {
|
||||
msect.name = "__symbol_stub1"
|
||||
msect.flag = 0x80000408 /* only instructions, code, symbol stubs */
|
||||
msect.res1 = 0 //nkind[SymKindLocal];
|
||||
msect.res2 = 6
|
||||
}
|
||||
|
||||
if sect.Name == ".got" {
|
||||
msect.name = "__nl_symbol_ptr"
|
||||
msect.flag = 6 /* section with nonlazy symbol pointers */
|
||||
msect.res1 = uint32(Linklookup(Ctxt, ".linkedit.plt", 0).Size / 4) /* offset into indirect symbol table */
|
||||
}
|
||||
}
|
||||
|
||||
func Asmbmacho() {
|
||||
var v int64
|
||||
var w int64
|
||||
var va int64
|
||||
var a int
|
||||
var i int
|
||||
var mh *MachoHdr
|
||||
var ms *MachoSeg
|
||||
var ml *MachoLoad
|
||||
var sect *Section
|
||||
|
||||
/* apple MACH */
|
||||
va = INITTEXT - int64(HEADR)
|
||||
|
||||
mh = getMachoHdr()
|
||||
switch Thearch.Thechar {
|
||||
default:
|
||||
Diag("unknown mach architecture")
|
||||
Errorexit()
|
||||
fallthrough
|
||||
|
||||
case '5':
|
||||
mh.cpu = MACHO_CPU_ARM
|
||||
mh.subcpu = MACHO_SUBCPU_ARMV7
|
||||
|
||||
case '6':
|
||||
mh.cpu = MACHO_CPU_AMD64
|
||||
mh.subcpu = MACHO_SUBCPU_X86
|
||||
|
||||
case '8':
|
||||
mh.cpu = MACHO_CPU_386
|
||||
mh.subcpu = MACHO_SUBCPU_X86
|
||||
}
|
||||
|
||||
ms = nil
|
||||
if Linkmode == LinkExternal {
|
||||
/* segment for entire file */
|
||||
ms = newMachoSeg("", 40)
|
||||
|
||||
ms.fileoffset = Segtext.Fileoff
|
||||
ms.filesize = Segdata.Fileoff + Segdata.Filelen - Segtext.Fileoff
|
||||
}
|
||||
|
||||
/* segment for zero page */
|
||||
if Linkmode != LinkExternal {
|
||||
ms = newMachoSeg("__PAGEZERO", 0)
|
||||
ms.vsize = uint64(va)
|
||||
}
|
||||
|
||||
/* text */
|
||||
v = Rnd(int64(uint64(HEADR)+Segtext.Length), int64(INITRND))
|
||||
|
||||
if Linkmode != LinkExternal {
|
||||
ms = newMachoSeg("__TEXT", 20)
|
||||
ms.vaddr = uint64(va)
|
||||
ms.vsize = uint64(v)
|
||||
ms.fileoffset = 0
|
||||
ms.filesize = uint64(v)
|
||||
ms.prot1 = 7
|
||||
ms.prot2 = 5
|
||||
}
|
||||
|
||||
for sect = Segtext.Sect; sect != nil; sect = sect.Next {
|
||||
machoshbits(ms, sect, "__TEXT")
|
||||
}
|
||||
|
||||
/* data */
|
||||
if Linkmode != LinkExternal {
|
||||
w = int64(Segdata.Length)
|
||||
ms = newMachoSeg("__DATA", 20)
|
||||
ms.vaddr = uint64(va) + uint64(v)
|
||||
ms.vsize = uint64(w)
|
||||
ms.fileoffset = uint64(v)
|
||||
ms.filesize = Segdata.Filelen
|
||||
ms.prot1 = 3
|
||||
ms.prot2 = 3
|
||||
}
|
||||
|
||||
for sect = Segdata.Sect; sect != nil; sect = sect.Next {
|
||||
machoshbits(ms, sect, "__DATA")
|
||||
}
|
||||
|
||||
if Linkmode != LinkExternal {
|
||||
switch Thearch.Thechar {
|
||||
default:
|
||||
Diag("unknown macho architecture")
|
||||
Errorexit()
|
||||
fallthrough
|
||||
|
||||
case '5':
|
||||
ml = newMachoLoad(5, 17+2) /* unix thread */
|
||||
ml.data[0] = 1 /* thread type */
|
||||
ml.data[1] = 17 /* word count */
|
||||
ml.data[2+15] = uint32(Entryvalue()) /* start pc */
|
||||
|
||||
case '6':
|
||||
ml = newMachoLoad(5, 42+2) /* unix thread */
|
||||
ml.data[0] = 4 /* thread type */
|
||||
ml.data[1] = 42 /* word count */
|
||||
ml.data[2+32] = uint32(Entryvalue()) /* start pc */
|
||||
ml.data[2+32+1] = uint32(Entryvalue() >> 16 >> 16) // hide >>32 for 8l
|
||||
|
||||
case '8':
|
||||
ml = newMachoLoad(5, 16+2) /* unix thread */
|
||||
ml.data[0] = 1 /* thread type */
|
||||
ml.data[1] = 16 /* word count */
|
||||
ml.data[2+10] = uint32(Entryvalue()) /* start pc */
|
||||
}
|
||||
}
|
||||
|
||||
if Debug['d'] == 0 {
|
||||
var s1 *LSym
|
||||
var s2 *LSym
|
||||
var s3 *LSym
|
||||
var s4 *LSym
|
||||
|
||||
// must match domacholink below
|
||||
s1 = Linklookup(Ctxt, ".machosymtab", 0)
|
||||
|
||||
s2 = Linklookup(Ctxt, ".linkedit.plt", 0)
|
||||
s3 = Linklookup(Ctxt, ".linkedit.got", 0)
|
||||
s4 = Linklookup(Ctxt, ".machosymstr", 0)
|
||||
|
||||
if Linkmode != LinkExternal {
|
||||
ms = newMachoSeg("__LINKEDIT", 0)
|
||||
ms.vaddr = uint64(va) + uint64(v) + uint64(Rnd(int64(Segdata.Length), int64(INITRND)))
|
||||
ms.vsize = uint64(s1.Size) + uint64(s2.Size) + uint64(s3.Size) + uint64(s4.Size)
|
||||
ms.fileoffset = uint64(linkoff)
|
||||
ms.filesize = ms.vsize
|
||||
ms.prot1 = 7
|
||||
ms.prot2 = 3
|
||||
}
|
||||
|
||||
ml = newMachoLoad(2, 4) /* LC_SYMTAB */
|
||||
ml.data[0] = uint32(linkoff) /* symoff */
|
||||
ml.data[1] = uint32(nsortsym) /* nsyms */
|
||||
ml.data[2] = uint32(linkoff + s1.Size + s2.Size + s3.Size) /* stroff */
|
||||
ml.data[3] = uint32(s4.Size) /* strsize */
|
||||
|
||||
machodysymtab()
|
||||
|
||||
if Linkmode != LinkExternal {
|
||||
ml = newMachoLoad(14, 6) /* LC_LOAD_DYLINKER */
|
||||
ml.data[0] = 12 /* offset to string */
|
||||
stringtouint32(ml.data[1:], "/usr/lib/dyld")
|
||||
|
||||
for i = 0; i < len(dylib); i++ {
|
||||
ml = newMachoLoad(12, 4+(uint32(len(dylib[i]))+1+7)/8*2) /* LC_LOAD_DYLIB */
|
||||
ml.data[0] = 24 /* offset of string from beginning of load */
|
||||
ml.data[1] = 0 /* time stamp */
|
||||
ml.data[2] = 0 /* version */
|
||||
ml.data[3] = 0 /* compatibility version */
|
||||
stringtouint32(ml.data[4:], dylib[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: dwarf headers go in ms too
|
||||
if Debug['s'] == 0 && Linkmode != LinkExternal {
|
||||
dwarfaddmachoheaders()
|
||||
}
|
||||
|
||||
a = machowrite()
|
||||
if int32(a) > HEADR {
|
||||
Diag("HEADR too small: %d > %d", a, HEADR)
|
||||
}
|
||||
}
|
||||
|
||||
func symkind(s *LSym) int {
|
||||
if s.Type == SDYNIMPORT {
|
||||
return SymKindUndef
|
||||
}
|
||||
if s.Cgoexport != 0 {
|
||||
return SymKindExtdef
|
||||
}
|
||||
return SymKindLocal
|
||||
}
|
||||
|
||||
func addsym(s *LSym, name string, type_ int, addr int64, size int64, ver int, gotype *LSym) {
|
||||
if s == nil {
|
||||
return
|
||||
}
|
||||
|
||||
switch type_ {
|
||||
default:
|
||||
return
|
||||
|
||||
case 'D',
|
||||
'B',
|
||||
'T':
|
||||
break
|
||||
}
|
||||
|
||||
if sortsym != nil {
|
||||
sortsym[nsortsym] = s
|
||||
nkind[symkind(s)]++
|
||||
}
|
||||
|
||||
nsortsym++
|
||||
}
|
||||
|
||||
type machoscmp []*LSym
|
||||
|
||||
func (x machoscmp) Len() int {
|
||||
return len(x)
|
||||
}
|
||||
|
||||
func (x machoscmp) Swap(i, j int) {
|
||||
x[i], x[j] = x[j], x[i]
|
||||
}
|
||||
|
||||
func (x machoscmp) Less(i, j int) bool {
|
||||
var s1 *LSym
|
||||
var s2 *LSym
|
||||
var k1 int
|
||||
var k2 int
|
||||
|
||||
s1 = x[i]
|
||||
s2 = x[j]
|
||||
|
||||
k1 = symkind(s1)
|
||||
k2 = symkind(s2)
|
||||
if k1 != k2 {
|
||||
return k1-k2 < 0
|
||||
}
|
||||
|
||||
return stringsCompare(s1.Extname, s2.Extname) < 0
|
||||
}
|
||||
|
||||
func machogenasmsym(put func(*LSym, string, int, int64, int64, int, *LSym)) {
|
||||
var s *LSym
|
||||
|
||||
genasmsym(put)
|
||||
for s = Ctxt.Allsym; s != nil; s = s.Allsym {
|
||||
if s.Type == SDYNIMPORT || s.Type == SHOSTOBJ {
|
||||
if s.Reachable {
|
||||
put(s, "", 'D', 0, 0, 0, nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func machosymorder() {
|
||||
var i int
|
||||
|
||||
// On Mac OS X Mountain Lion, we must sort exported symbols
|
||||
// So we sort them here and pre-allocate dynid for them
|
||||
// See http://golang.org/issue/4029
|
||||
for i = 0; i < len(dynexp); i++ {
|
||||
dynexp[i].Reachable = true
|
||||
}
|
||||
machogenasmsym(addsym)
|
||||
sortsym = make([]*LSym, nsortsym)
|
||||
nsortsym = 0
|
||||
machogenasmsym(addsym)
|
||||
sort.Sort(machoscmp(sortsym[:nsortsym]))
|
||||
for i = 0; i < nsortsym; i++ {
|
||||
sortsym[i].Dynid = int32(i)
|
||||
}
|
||||
}
|
||||
|
||||
func machosymtab() {
|
||||
var i int
|
||||
var symtab *LSym
|
||||
var symstr *LSym
|
||||
var s *LSym
|
||||
var o *LSym
|
||||
var p string
|
||||
|
||||
symtab = Linklookup(Ctxt, ".machosymtab", 0)
|
||||
symstr = Linklookup(Ctxt, ".machosymstr", 0)
|
||||
|
||||
for i = 0; i < nsortsym; i++ {
|
||||
s = sortsym[i]
|
||||
Adduint32(Ctxt, symtab, uint32(symstr.Size))
|
||||
|
||||
// Only add _ to C symbols. Go symbols have dot in the name.
|
||||
if !strings.Contains(s.Extname, ".") {
|
||||
Adduint8(Ctxt, symstr, '_')
|
||||
}
|
||||
|
||||
// replace "·" as ".", because DTrace cannot handle it.
|
||||
if !strings.Contains(s.Extname, "·") {
|
||||
Addstring(symstr, s.Extname)
|
||||
} else {
|
||||
for p = s.Extname; p != ""; p = p[1:] {
|
||||
if uint8(p[0]) == 0xc2 && uint8((p[1:])[0]) == 0xb7 {
|
||||
Adduint8(Ctxt, symstr, '.')
|
||||
p = p[1:]
|
||||
} else {
|
||||
Adduint8(Ctxt, symstr, uint8(p[0]))
|
||||
}
|
||||
}
|
||||
|
||||
Adduint8(Ctxt, symstr, '\x00')
|
||||
}
|
||||
|
||||
if s.Type == SDYNIMPORT || s.Type == SHOSTOBJ {
|
||||
Adduint8(Ctxt, symtab, 0x01) // type N_EXT, external symbol
|
||||
Adduint8(Ctxt, symtab, 0) // no section
|
||||
Adduint16(Ctxt, symtab, 0) // desc
|
||||
adduintxx(Ctxt, symtab, 0, Thearch.Ptrsize) // no value
|
||||
} else {
|
||||
if s.Cgoexport != 0 {
|
||||
Adduint8(Ctxt, symtab, 0x0f)
|
||||
} else {
|
||||
Adduint8(Ctxt, symtab, 0x0e)
|
||||
}
|
||||
o = s
|
||||
for o.Outer != nil {
|
||||
o = o.Outer
|
||||
}
|
||||
if o.Sect == nil {
|
||||
Diag("missing section for %s", s.Name)
|
||||
Adduint8(Ctxt, symtab, 0)
|
||||
} else {
|
||||
Adduint8(Ctxt, symtab, uint8((o.Sect.(*Section)).Extnum))
|
||||
}
|
||||
Adduint16(Ctxt, symtab, 0) // desc
|
||||
adduintxx(Ctxt, symtab, uint64(Symaddr(s)), Thearch.Ptrsize)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func machodysymtab() {
|
||||
var n int
|
||||
var ml *MachoLoad
|
||||
var s1 *LSym
|
||||
var s2 *LSym
|
||||
var s3 *LSym
|
||||
|
||||
ml = newMachoLoad(11, 18) /* LC_DYSYMTAB */
|
||||
|
||||
n = 0
|
||||
ml.data[0] = uint32(n) /* ilocalsym */
|
||||
ml.data[1] = uint32(nkind[SymKindLocal]) /* nlocalsym */
|
||||
n += nkind[SymKindLocal]
|
||||
|
||||
ml.data[2] = uint32(n) /* iextdefsym */
|
||||
ml.data[3] = uint32(nkind[SymKindExtdef]) /* nextdefsym */
|
||||
n += nkind[SymKindExtdef]
|
||||
|
||||
ml.data[4] = uint32(n) /* iundefsym */
|
||||
ml.data[5] = uint32(nkind[SymKindUndef]) /* nundefsym */
|
||||
|
||||
ml.data[6] = 0 /* tocoffset */
|
||||
ml.data[7] = 0 /* ntoc */
|
||||
ml.data[8] = 0 /* modtaboff */
|
||||
ml.data[9] = 0 /* nmodtab */
|
||||
ml.data[10] = 0 /* extrefsymoff */
|
||||
ml.data[11] = 0 /* nextrefsyms */
|
||||
|
||||
// must match domacholink below
|
||||
s1 = Linklookup(Ctxt, ".machosymtab", 0)
|
||||
|
||||
s2 = Linklookup(Ctxt, ".linkedit.plt", 0)
|
||||
s3 = Linklookup(Ctxt, ".linkedit.got", 0)
|
||||
ml.data[12] = uint32(linkoff + s1.Size) /* indirectsymoff */
|
||||
ml.data[13] = uint32((s2.Size + s3.Size) / 4) /* nindirectsyms */
|
||||
|
||||
ml.data[14] = 0 /* extreloff */
|
||||
ml.data[15] = 0 /* nextrel */
|
||||
ml.data[16] = 0 /* locreloff */
|
||||
ml.data[17] = 0 /* nlocrel */
|
||||
}
|
||||
|
||||
func Domacholink() int64 {
|
||||
var size int
|
||||
var s1 *LSym
|
||||
var s2 *LSym
|
||||
var s3 *LSym
|
||||
var s4 *LSym
|
||||
|
||||
machosymtab()
|
||||
|
||||
// write data that will be linkedit section
|
||||
s1 = Linklookup(Ctxt, ".machosymtab", 0)
|
||||
|
||||
s2 = Linklookup(Ctxt, ".linkedit.plt", 0)
|
||||
s3 = Linklookup(Ctxt, ".linkedit.got", 0)
|
||||
s4 = Linklookup(Ctxt, ".machosymstr", 0)
|
||||
|
||||
// Force the linkedit section to end on a 16-byte
|
||||
// boundary. This allows pure (non-cgo) Go binaries
|
||||
// to be code signed correctly.
|
||||
//
|
||||
// Apple's codesign_allocate (a helper utility for
|
||||
// the codesign utility) can do this fine itself if
|
||||
// it is run on a dynamic Mach-O binary. However,
|
||||
// when it is run on a pure (non-cgo) Go binary, where
|
||||
// the linkedit section is mostly empty, it fails to
|
||||
// account for the extra padding that it itself adds
|
||||
// when adding the LC_CODE_SIGNATURE load command
|
||||
// (which must be aligned on a 16-byte boundary).
|
||||
//
|
||||
// By forcing the linkedit section to end on a 16-byte
|
||||
// boundary, codesign_allocate will not need to apply
|
||||
// any alignment padding itself, working around the
|
||||
// issue.
|
||||
for s4.Size%16 != 0 {
|
||||
Adduint8(Ctxt, s4, 0)
|
||||
}
|
||||
|
||||
size = int(s1.Size + s2.Size + s3.Size + s4.Size)
|
||||
|
||||
if size > 0 {
|
||||
linkoff = Rnd(int64(uint64(HEADR)+Segtext.Length), int64(INITRND)) + Rnd(int64(Segdata.Filelen), int64(INITRND)) + Rnd(int64(Segdwarf.Filelen), int64(INITRND))
|
||||
Cseek(linkoff)
|
||||
|
||||
Cwrite(s1.P[:s1.Size])
|
||||
Cwrite(s2.P[:s2.Size])
|
||||
Cwrite(s3.P[:s3.Size])
|
||||
Cwrite(s4.P[:s4.Size])
|
||||
}
|
||||
|
||||
return Rnd(int64(size), int64(INITRND))
|
||||
}
|
||||
|
||||
func machorelocsect(sect *Section, first *LSym) {
|
||||
var sym *LSym
|
||||
var eaddr int32
|
||||
var ri int
|
||||
var r *Reloc
|
||||
|
||||
// If main section has no bits, nothing to relocate.
|
||||
if sect.Vaddr >= sect.Seg.Vaddr+sect.Seg.Filelen {
|
||||
return
|
||||
}
|
||||
|
||||
sect.Reloff = uint64(Cpos())
|
||||
for sym = first; sym != nil; sym = sym.Next {
|
||||
if !sym.Reachable {
|
||||
continue
|
||||
}
|
||||
if uint64(sym.Value) >= sect.Vaddr {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
eaddr = int32(sect.Vaddr + sect.Length)
|
||||
for ; sym != nil; sym = sym.Next {
|
||||
if !sym.Reachable {
|
||||
continue
|
||||
}
|
||||
if sym.Value >= int64(eaddr) {
|
||||
break
|
||||
}
|
||||
Ctxt.Cursym = sym
|
||||
|
||||
for ri = 0; ri < len(sym.R); ri++ {
|
||||
r = &sym.R[ri]
|
||||
if r.Done != 0 {
|
||||
continue
|
||||
}
|
||||
if Thearch.Machoreloc1(r, int64(uint64(sym.Value+int64(r.Off))-sect.Vaddr)) < 0 {
|
||||
Diag("unsupported obj reloc %d/%d to %s", r.Type, r.Siz, r.Sym.Name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sect.Rellen = uint64(Cpos()) - sect.Reloff
|
||||
}
|
||||
|
||||
func Machoemitreloc() {
|
||||
var sect *Section
|
||||
|
||||
for Cpos()&7 != 0 {
|
||||
Cput(0)
|
||||
}
|
||||
|
||||
machorelocsect(Segtext.Sect, Ctxt.Textp)
|
||||
for sect = Segtext.Sect.Next; sect != nil; sect = sect.Next {
|
||||
machorelocsect(sect, datap)
|
||||
}
|
||||
for sect = Segdata.Sect; sect != nil; sect = sect.Next {
|
||||
machorelocsect(sect, datap)
|
||||
}
|
||||
}
|
||||
366
src/cmd/internal/ld/objfile.go
Normal file
366
src/cmd/internal/ld/objfile.go
Normal file
|
|
@ -0,0 +1,366 @@
|
|||
// Copyright 2013 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package ld
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"log"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var startmagic string = "\x00\x00go13ld"
|
||||
|
||||
var endmagic string = "\xff\xffgo13ld"
|
||||
|
||||
func ldobjfile(ctxt *Link, f *Biobuf, pkg string, length int64, pn string) {
|
||||
var c int
|
||||
var buf [8]uint8
|
||||
var start int64
|
||||
var lib string
|
||||
|
||||
start = Boffset(f)
|
||||
ctxt.Version++
|
||||
buf = [8]uint8{}
|
||||
Bread(f, buf[:])
|
||||
if string(buf[:]) != startmagic {
|
||||
log.Fatalf("%s: invalid file start %x %x %x %x %x %x %x %x", pn, buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7])
|
||||
}
|
||||
c = Bgetc(f)
|
||||
if c != 1 {
|
||||
log.Fatalf("%s: invalid file version number %d", pn, c)
|
||||
}
|
||||
|
||||
for {
|
||||
lib = rdstring(f)
|
||||
if lib == "" {
|
||||
break
|
||||
}
|
||||
addlib(ctxt, pkg, pn, lib)
|
||||
}
|
||||
|
||||
for {
|
||||
c = Bgetc(f)
|
||||
Bungetc(f)
|
||||
if c == 0xff {
|
||||
break
|
||||
}
|
||||
readsym(ctxt, f, pkg, pn)
|
||||
}
|
||||
|
||||
buf = [8]uint8{}
|
||||
Bread(f, buf[:])
|
||||
if string(buf[:]) != endmagic {
|
||||
log.Fatalf("%s: invalid file end", pn)
|
||||
}
|
||||
|
||||
if Boffset(f) != start+length {
|
||||
log.Fatalf("%s: unexpected end at %d, want %d", pn, int64(Boffset(f)), int64(start+length))
|
||||
}
|
||||
}
|
||||
|
||||
var readsym_ndup int
|
||||
|
||||
func readsym(ctxt *Link, f *Biobuf, pkg string, pn string) {
|
||||
var i int
|
||||
var j int
|
||||
var c int
|
||||
var t int
|
||||
var v int
|
||||
var n int
|
||||
var nreloc int
|
||||
var size int
|
||||
var dupok int
|
||||
var name string
|
||||
var data []byte
|
||||
var r *Reloc
|
||||
var s *LSym
|
||||
var dup *LSym
|
||||
var typ *LSym
|
||||
var pc *Pcln
|
||||
var a *Auto
|
||||
|
||||
if Bgetc(f) != 0xfe {
|
||||
log.Fatalf("readsym out of sync")
|
||||
}
|
||||
t = int(rdint(f))
|
||||
name = expandpkg(rdstring(f), pkg)
|
||||
v = int(rdint(f))
|
||||
if v != 0 && v != 1 {
|
||||
log.Fatalf("invalid symbol version %d", v)
|
||||
}
|
||||
dupok = int(rdint(f))
|
||||
dupok &= 1
|
||||
size = int(rdint(f))
|
||||
typ = rdsym(ctxt, f, pkg)
|
||||
rddata(f, &data)
|
||||
nreloc = int(rdint(f))
|
||||
|
||||
if v != 0 {
|
||||
v = ctxt.Version
|
||||
}
|
||||
s = Linklookup(ctxt, name, v)
|
||||
dup = nil
|
||||
if s.Type != 0 && s.Type != SXREF {
|
||||
if (t == SDATA || t == SBSS || t == SNOPTRBSS) && len(data) == 0 && nreloc == 0 {
|
||||
if s.Size < int64(size) {
|
||||
s.Size = int64(size)
|
||||
}
|
||||
if typ != nil && s.Gotype == nil {
|
||||
s.Gotype = typ
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if (s.Type == SDATA || s.Type == SBSS || s.Type == SNOPTRBSS) && len(s.P) == 0 && len(s.R) == 0 {
|
||||
goto overwrite
|
||||
}
|
||||
if s.Type != SBSS && s.Type != SNOPTRBSS && dupok == 0 && s.Dupok == 0 {
|
||||
log.Fatalf("duplicate symbol %s (types %d and %d) in %s and %s", s.Name, s.Type, t, s.File, pn)
|
||||
}
|
||||
if len(s.P) > 0 {
|
||||
dup = s
|
||||
s = linknewsym(ctxt, ".dup", readsym_ndup)
|
||||
readsym_ndup++ // scratch
|
||||
}
|
||||
}
|
||||
|
||||
overwrite:
|
||||
s.File = pkg
|
||||
s.Dupok = uint8(dupok)
|
||||
if t == SXREF {
|
||||
log.Fatalf("bad sxref")
|
||||
}
|
||||
if t == 0 {
|
||||
log.Fatalf("missing type for %s in %s", name, pn)
|
||||
}
|
||||
if t == SBSS && (s.Type == SRODATA || s.Type == SNOPTRBSS) {
|
||||
t = int(s.Type)
|
||||
}
|
||||
s.Type = int16(t)
|
||||
if s.Size < int64(size) {
|
||||
s.Size = int64(size)
|
||||
}
|
||||
if typ != nil { // if bss sym defined multiple times, take type from any one def
|
||||
s.Gotype = typ
|
||||
}
|
||||
if dup != nil && typ != nil {
|
||||
dup.Gotype = typ
|
||||
}
|
||||
s.P = data
|
||||
s.P = s.P[:len(data)]
|
||||
if nreloc > 0 {
|
||||
s.R = make([]Reloc, nreloc)
|
||||
s.R = s.R[:nreloc]
|
||||
for i = 0; i < nreloc; i++ {
|
||||
r = &s.R[i]
|
||||
r.Off = int32(rdint(f))
|
||||
r.Siz = uint8(rdint(f))
|
||||
r.Type = int32(rdint(f))
|
||||
r.Add = rdint(f)
|
||||
r.Xadd = rdint(f)
|
||||
r.Sym = rdsym(ctxt, f, pkg)
|
||||
r.Xsym = rdsym(ctxt, f, pkg)
|
||||
}
|
||||
}
|
||||
|
||||
if len(s.P) > 0 && dup != nil && len(dup.P) > 0 && strings.HasPrefix(s.Name, "gclocals·") {
|
||||
// content-addressed garbage collection liveness bitmap symbol.
|
||||
// double check for hash collisions.
|
||||
if !bytes.Equal(s.P, dup.P) {
|
||||
log.Fatalf("dupok hash collision for %s in %s and %s", s.Name, s.File, pn)
|
||||
}
|
||||
}
|
||||
|
||||
if s.Type == STEXT {
|
||||
s.Args = int32(rdint(f))
|
||||
s.Locals = int32(rdint(f))
|
||||
s.Nosplit = uint8(rdint(f))
|
||||
v = int(rdint(f))
|
||||
s.Leaf = uint8(v & 1)
|
||||
s.Cfunc = uint8(v & 2)
|
||||
n = int(rdint(f))
|
||||
for i = 0; i < n; i++ {
|
||||
a = new(Auto)
|
||||
a.Asym = rdsym(ctxt, f, pkg)
|
||||
a.Aoffset = int32(rdint(f))
|
||||
a.Name = int16(rdint(f))
|
||||
a.Gotype = rdsym(ctxt, f, pkg)
|
||||
a.Link = s.Autom
|
||||
s.Autom = a
|
||||
}
|
||||
|
||||
s.Pcln = new(Pcln)
|
||||
pc = s.Pcln
|
||||
rddata(f, &pc.Pcsp.P)
|
||||
rddata(f, &pc.Pcfile.P)
|
||||
rddata(f, &pc.Pcline.P)
|
||||
n = int(rdint(f))
|
||||
pc.Pcdata = make([]Pcdata, n)
|
||||
pc.Npcdata = n
|
||||
for i = 0; i < n; i++ {
|
||||
rddata(f, &pc.Pcdata[i].P)
|
||||
}
|
||||
n = int(rdint(f))
|
||||
pc.Funcdata = make([]*LSym, n)
|
||||
pc.Funcdataoff = make([]int64, n)
|
||||
pc.Nfuncdata = n
|
||||
for i = 0; i < n; i++ {
|
||||
pc.Funcdata[i] = rdsym(ctxt, f, pkg)
|
||||
}
|
||||
for i = 0; i < n; i++ {
|
||||
pc.Funcdataoff[i] = rdint(f)
|
||||
}
|
||||
n = int(rdint(f))
|
||||
pc.File = make([]*LSym, n)
|
||||
pc.Nfile = n
|
||||
for i = 0; i < n; i++ {
|
||||
pc.File[i] = rdsym(ctxt, f, pkg)
|
||||
}
|
||||
|
||||
if dup == nil {
|
||||
if s.Onlist != 0 {
|
||||
log.Fatalf("symbol %s listed multiple times", s.Name)
|
||||
}
|
||||
s.Onlist = 1
|
||||
if ctxt.Etextp != nil {
|
||||
ctxt.Etextp.Next = s
|
||||
} else {
|
||||
ctxt.Textp = s
|
||||
}
|
||||
ctxt.Etextp = s
|
||||
}
|
||||
}
|
||||
|
||||
if ctxt.Debugasm != 0 {
|
||||
fmt.Fprintf(ctxt.Bso, "%s ", s.Name)
|
||||
if s.Version != 0 {
|
||||
fmt.Fprintf(ctxt.Bso, "v=%d ", s.Version)
|
||||
}
|
||||
if s.Type != 0 {
|
||||
fmt.Fprintf(ctxt.Bso, "t=%d ", s.Type)
|
||||
}
|
||||
if s.Dupok != 0 {
|
||||
fmt.Fprintf(ctxt.Bso, "dupok ")
|
||||
}
|
||||
if s.Cfunc != 0 {
|
||||
fmt.Fprintf(ctxt.Bso, "cfunc ")
|
||||
}
|
||||
if s.Nosplit != 0 {
|
||||
fmt.Fprintf(ctxt.Bso, "nosplit ")
|
||||
}
|
||||
fmt.Fprintf(ctxt.Bso, "size=%d value=%d", int64(s.Size), int64(s.Value))
|
||||
if s.Type == STEXT {
|
||||
fmt.Fprintf(ctxt.Bso, " args=%#x locals=%#x", uint64(s.Args), uint64(s.Locals))
|
||||
}
|
||||
fmt.Fprintf(ctxt.Bso, "\n")
|
||||
for i = 0; i < len(s.P); {
|
||||
fmt.Fprintf(ctxt.Bso, "\t%#04x", uint(i))
|
||||
for j = i; j < i+16 && j < len(s.P); j++ {
|
||||
fmt.Fprintf(ctxt.Bso, " %02x", s.P[j])
|
||||
}
|
||||
for ; j < i+16; j++ {
|
||||
fmt.Fprintf(ctxt.Bso, " ")
|
||||
}
|
||||
fmt.Fprintf(ctxt.Bso, " ")
|
||||
for j = i; j < i+16 && j < len(s.P); j++ {
|
||||
c = int(s.P[j])
|
||||
if ' ' <= c && c <= 0x7e {
|
||||
fmt.Fprintf(ctxt.Bso, "%c", c)
|
||||
} else {
|
||||
fmt.Fprintf(ctxt.Bso, ".")
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Fprintf(ctxt.Bso, "\n")
|
||||
i += 16
|
||||
}
|
||||
|
||||
for i = 0; i < len(s.R); i++ {
|
||||
r = &s.R[i]
|
||||
fmt.Fprintf(ctxt.Bso, "\trel %d+%d t=%d %s+%d\n", int(r.Off), r.Siz, r.Type, r.Sym.Name, int64(r.Add))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func rdint(f *Biobuf) int64 {
|
||||
var c int
|
||||
var uv uint64
|
||||
var shift int
|
||||
|
||||
uv = 0
|
||||
for shift = 0; ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
log.Fatalf("corrupt input")
|
||||
}
|
||||
c = Bgetc(f)
|
||||
uv |= uint64(c&0x7F) << uint(shift)
|
||||
if c&0x80 == 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return int64(uv>>1) ^ (int64(uint64(uv)<<63) >> 63)
|
||||
}
|
||||
|
||||
func rdstring(f *Biobuf) string {
|
||||
n := rdint(f)
|
||||
p := make([]byte, n)
|
||||
Bread(f, p)
|
||||
return string(p)
|
||||
}
|
||||
|
||||
func rddata(f *Biobuf, pp *[]byte) {
|
||||
n := rdint(f)
|
||||
*pp = make([]byte, n)
|
||||
Bread(f, *pp)
|
||||
}
|
||||
|
||||
var symbuf []byte
|
||||
|
||||
func rdsym(ctxt *Link, f *Biobuf, pkg string) *LSym {
|
||||
var n int
|
||||
var v int
|
||||
var p string
|
||||
var s *LSym
|
||||
|
||||
n = int(rdint(f))
|
||||
if n == 0 {
|
||||
rdint(f)
|
||||
return nil
|
||||
}
|
||||
|
||||
if len(symbuf) < n {
|
||||
symbuf = make([]byte, n)
|
||||
}
|
||||
Bread(f, symbuf[:n])
|
||||
p = string(symbuf[:n])
|
||||
v = int(rdint(f))
|
||||
if v != 0 {
|
||||
v = ctxt.Version
|
||||
}
|
||||
s = Linklookup(ctxt, expandpkg(p, pkg), v)
|
||||
|
||||
if v == 0 && s.Name[0] == '$' && s.Type == 0 {
|
||||
if strings.HasPrefix(s.Name, "$f32.") {
|
||||
var i32 int32
|
||||
x, _ := strconv.ParseUint(s.Name[5:], 16, 32)
|
||||
i32 = int32(x)
|
||||
s.Type = SRODATA
|
||||
Adduint32(ctxt, s, uint32(i32))
|
||||
s.Reachable = false
|
||||
} else if strings.HasPrefix(s.Name, "$f64.") || strings.HasPrefix(s.Name, "$i64.") {
|
||||
var i64 int64
|
||||
x, _ := strconv.ParseUint(s.Name[5:], 16, 64)
|
||||
i64 = int64(x)
|
||||
s.Type = SRODATA
|
||||
Adduint64(ctxt, s, uint64(i64))
|
||||
s.Reachable = false
|
||||
}
|
||||
}
|
||||
|
||||
return s
|
||||
}
|
||||
487
src/cmd/internal/ld/pcln.go
Normal file
487
src/cmd/internal/ld/pcln.go
Normal file
|
|
@ -0,0 +1,487 @@
|
|||
// Copyright 2013 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package ld
|
||||
|
||||
import (
|
||||
"cmd/internal/obj"
|
||||
"fmt"
|
||||
"log"
|
||||
)
|
||||
|
||||
// funcpctab writes to dst a pc-value table mapping the code in func to the values
|
||||
// returned by valfunc parameterized by arg. The invocation of valfunc to update the
|
||||
// current value is, for each p,
|
||||
//
|
||||
// val = valfunc(func, val, p, 0, arg);
|
||||
// record val as value at p->pc;
|
||||
// val = valfunc(func, val, p, 1, arg);
|
||||
//
|
||||
// where func is the function, val is the current value, p is the instruction being
|
||||
// considered, and arg can be used to further parameterize valfunc.
|
||||
|
||||
// pctofileline computes either the file number (arg == 0)
|
||||
// or the line number (arg == 1) to use at p.
|
||||
// Because p->lineno applies to p, phase == 0 (before p)
|
||||
// takes care of the update.
|
||||
|
||||
// pctospadj computes the sp adjustment in effect.
|
||||
// It is oldval plus any adjustment made by p itself.
|
||||
// The adjustment by p takes effect only after p, so we
|
||||
// apply the change during phase == 1.
|
||||
|
||||
// pctopcdata computes the pcdata value in effect at p.
|
||||
// A PCDATA instruction sets the value in effect at future
|
||||
// non-PCDATA instructions.
|
||||
// Since PCDATA instructions have no width in the final code,
|
||||
// it does not matter which phase we use for the update.
|
||||
|
||||
// iteration over encoded pcdata tables.
|
||||
|
||||
func getvarint(pp *[]byte) uint32 {
|
||||
var p []byte
|
||||
var shift int
|
||||
var v uint32
|
||||
|
||||
v = 0
|
||||
p = *pp
|
||||
for shift = 0; ; shift += 7 {
|
||||
v |= uint32(p[0]&0x7F) << uint(shift)
|
||||
tmp4 := p
|
||||
p = p[1:]
|
||||
if tmp4[0]&0x80 == 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
*pp = p
|
||||
return v
|
||||
}
|
||||
|
||||
func pciternext(it *Pciter) {
|
||||
var v uint32
|
||||
var dv int32
|
||||
|
||||
it.pc = it.nextpc
|
||||
if it.done != 0 {
|
||||
return
|
||||
}
|
||||
if -cap(it.p) >= -cap(it.d.P[len(it.d.P):]) {
|
||||
it.done = 1
|
||||
return
|
||||
}
|
||||
|
||||
// value delta
|
||||
v = getvarint(&it.p)
|
||||
|
||||
if v == 0 && it.start == 0 {
|
||||
it.done = 1
|
||||
return
|
||||
}
|
||||
|
||||
it.start = 0
|
||||
dv = int32(v>>1) ^ (int32(v<<31) >> 31)
|
||||
it.value += dv
|
||||
|
||||
// pc delta
|
||||
v = getvarint(&it.p)
|
||||
|
||||
it.nextpc = it.pc + v*it.pcscale
|
||||
}
|
||||
|
||||
func pciterinit(ctxt *Link, it *Pciter, d *Pcdata) {
|
||||
it.d = *d
|
||||
it.p = it.d.P
|
||||
it.pc = 0
|
||||
it.nextpc = 0
|
||||
it.value = -1
|
||||
it.start = 1
|
||||
it.done = 0
|
||||
it.pcscale = uint32(ctxt.Arch.Minlc)
|
||||
pciternext(it)
|
||||
}
|
||||
|
||||
// Copyright 2013 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
func addvarint(d *Pcdata, val uint32) {
|
||||
var n int32
|
||||
var v uint32
|
||||
var p []byte
|
||||
|
||||
n = 0
|
||||
for v = val; v >= 0x80; v >>= 7 {
|
||||
n++
|
||||
}
|
||||
n++
|
||||
|
||||
old := len(d.P)
|
||||
for cap(d.P) < len(d.P)+int(n) {
|
||||
d.P = append(d.P[:cap(d.P)], 0)
|
||||
}
|
||||
d.P = d.P[:old+int(n)]
|
||||
|
||||
p = d.P[old:]
|
||||
for v = val; v >= 0x80; v >>= 7 {
|
||||
p[0] = byte(v | 0x80)
|
||||
p = p[1:]
|
||||
}
|
||||
p[0] = byte(v)
|
||||
}
|
||||
|
||||
func addpctab(ftab *LSym, off int32, d *Pcdata) int32 {
|
||||
var start int32
|
||||
|
||||
start = int32(len(ftab.P))
|
||||
Symgrow(Ctxt, ftab, int64(start)+int64(len(d.P)))
|
||||
copy(ftab.P[start:], d.P)
|
||||
|
||||
return int32(setuint32(Ctxt, ftab, int64(off), uint32(start)))
|
||||
}
|
||||
|
||||
func ftabaddstring(ftab *LSym, s string) int32 {
|
||||
var n int32
|
||||
var start int32
|
||||
|
||||
n = int32(len(s)) + 1
|
||||
start = int32(len(ftab.P))
|
||||
Symgrow(Ctxt, ftab, int64(start)+int64(n)+1)
|
||||
copy(ftab.P[start:], s)
|
||||
return start
|
||||
}
|
||||
|
||||
func renumberfiles(ctxt *Link, files []*LSym, d *Pcdata) {
|
||||
var i int
|
||||
var f *LSym
|
||||
var out Pcdata
|
||||
var it Pciter
|
||||
var v uint32
|
||||
var oldval int32
|
||||
var newval int32
|
||||
var val int32
|
||||
var dv int32
|
||||
|
||||
// Give files numbers.
|
||||
for i = 0; i < len(files); i++ {
|
||||
f = files[i]
|
||||
if f.Type != SFILEPATH {
|
||||
ctxt.Nhistfile++
|
||||
f.Value = int64(ctxt.Nhistfile)
|
||||
f.Type = SFILEPATH
|
||||
f.Next = ctxt.Filesyms
|
||||
ctxt.Filesyms = f
|
||||
}
|
||||
}
|
||||
|
||||
newval = -1
|
||||
out = Pcdata{}
|
||||
|
||||
for pciterinit(ctxt, &it, d); it.done == 0; pciternext(&it) {
|
||||
// value delta
|
||||
oldval = it.value
|
||||
|
||||
if oldval == -1 {
|
||||
val = -1
|
||||
} else {
|
||||
if oldval < 0 || oldval >= int32(len(files)) {
|
||||
log.Fatalf("bad pcdata %d", oldval)
|
||||
}
|
||||
val = int32(files[oldval].Value)
|
||||
}
|
||||
|
||||
dv = val - newval
|
||||
newval = val
|
||||
v = (uint32(dv) << 1) ^ uint32(int32(dv>>31))
|
||||
addvarint(&out, v)
|
||||
|
||||
// pc delta
|
||||
addvarint(&out, (it.nextpc-it.pc)/it.pcscale)
|
||||
}
|
||||
|
||||
// terminating value delta
|
||||
addvarint(&out, 0)
|
||||
|
||||
*d = out
|
||||
}
|
||||
|
||||
func container(s *LSym) int {
|
||||
// We want to generate func table entries only for the "lowest level" symbols,
|
||||
// not containers of subsymbols.
|
||||
if s != nil && s.Sub != nil {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// pclntab initializes the pclntab symbol with
|
||||
// runtime function and file name information.
|
||||
|
||||
var pclntab_zpcln Pcln
|
||||
|
||||
func pclntab() {
|
||||
var i int32
|
||||
var nfunc int32
|
||||
var start int32
|
||||
var funcstart int32
|
||||
var ftab *LSym
|
||||
var s *LSym
|
||||
var last *LSym
|
||||
var off int32
|
||||
var end int32
|
||||
var frameptrsize int32
|
||||
var funcdata_bytes int64
|
||||
var pcln *Pcln
|
||||
var it Pciter
|
||||
|
||||
funcdata_bytes = 0
|
||||
ftab = Linklookup(Ctxt, "runtime.pclntab", 0)
|
||||
ftab.Type = SPCLNTAB
|
||||
ftab.Reachable = true
|
||||
|
||||
// See golang.org/s/go12symtab for the format. Briefly:
|
||||
// 8-byte header
|
||||
// nfunc [thearch.ptrsize bytes]
|
||||
// function table, alternating PC and offset to func struct [each entry thearch.ptrsize bytes]
|
||||
// end PC [thearch.ptrsize bytes]
|
||||
// offset to file table [4 bytes]
|
||||
nfunc = 0
|
||||
|
||||
for Ctxt.Cursym = Ctxt.Textp; Ctxt.Cursym != nil; Ctxt.Cursym = Ctxt.Cursym.Next {
|
||||
if container(Ctxt.Cursym) == 0 {
|
||||
nfunc++
|
||||
}
|
||||
}
|
||||
|
||||
Symgrow(Ctxt, ftab, 8+int64(Thearch.Ptrsize)+int64(nfunc)*2*int64(Thearch.Ptrsize)+int64(Thearch.Ptrsize)+4)
|
||||
setuint32(Ctxt, ftab, 0, 0xfffffffb)
|
||||
setuint8(Ctxt, ftab, 6, uint8(Thearch.Minlc))
|
||||
setuint8(Ctxt, ftab, 7, uint8(Thearch.Ptrsize))
|
||||
setuintxx(Ctxt, ftab, 8, uint64(nfunc), int64(Thearch.Ptrsize))
|
||||
|
||||
nfunc = 0
|
||||
last = nil
|
||||
for Ctxt.Cursym = Ctxt.Textp; Ctxt.Cursym != nil; Ctxt.Cursym = Ctxt.Cursym.Next {
|
||||
last = Ctxt.Cursym
|
||||
if container(Ctxt.Cursym) != 0 {
|
||||
continue
|
||||
}
|
||||
pcln = Ctxt.Cursym.Pcln
|
||||
if pcln == nil {
|
||||
pcln = &pclntab_zpcln
|
||||
}
|
||||
|
||||
funcstart = int32(len(ftab.P))
|
||||
funcstart += int32(-len(ftab.P)) & (int32(Thearch.Ptrsize) - 1)
|
||||
|
||||
setaddr(Ctxt, ftab, 8+int64(Thearch.Ptrsize)+int64(nfunc)*2*int64(Thearch.Ptrsize), Ctxt.Cursym)
|
||||
setuintxx(Ctxt, ftab, 8+int64(Thearch.Ptrsize)+int64(nfunc)*2*int64(Thearch.Ptrsize)+int64(Thearch.Ptrsize), uint64(funcstart), int64(Thearch.Ptrsize))
|
||||
|
||||
// fixed size of struct, checked below
|
||||
off = funcstart
|
||||
|
||||
end = funcstart + int32(Thearch.Ptrsize) + 3*4 + 5*4 + int32(pcln.Npcdata)*4 + int32(pcln.Nfuncdata)*int32(Thearch.Ptrsize)
|
||||
if pcln.Nfuncdata > 0 && (end&int32(Thearch.Ptrsize-1) != 0) {
|
||||
end += 4
|
||||
}
|
||||
Symgrow(Ctxt, ftab, int64(end))
|
||||
|
||||
// entry uintptr
|
||||
off = int32(setaddr(Ctxt, ftab, int64(off), Ctxt.Cursym))
|
||||
|
||||
// name int32
|
||||
off = int32(setuint32(Ctxt, ftab, int64(off), uint32(ftabaddstring(ftab, Ctxt.Cursym.Name))))
|
||||
|
||||
// args int32
|
||||
// TODO: Move into funcinfo.
|
||||
off = int32(setuint32(Ctxt, ftab, int64(off), uint32(Ctxt.Cursym.Args)))
|
||||
|
||||
// frame int32
|
||||
// TODO: Remove entirely. The pcsp table is more precise.
|
||||
// This is only used by a fallback case during stack walking
|
||||
// when a called function doesn't have argument information.
|
||||
// We need to make sure everything has argument information
|
||||
// and then remove this.
|
||||
frameptrsize = int32(Thearch.Ptrsize)
|
||||
|
||||
if Ctxt.Cursym.Leaf != 0 {
|
||||
frameptrsize = 0
|
||||
}
|
||||
off = int32(setuint32(Ctxt, ftab, int64(off), uint32(Ctxt.Cursym.Locals)+uint32(frameptrsize)))
|
||||
|
||||
if pcln != &pclntab_zpcln {
|
||||
renumberfiles(Ctxt, pcln.File, &pcln.Pcfile)
|
||||
if false {
|
||||
// Sanity check the new numbering
|
||||
for pciterinit(Ctxt, &it, &pcln.Pcfile); it.done == 0; pciternext(&it) {
|
||||
if it.value < 1 || it.value > Ctxt.Nhistfile {
|
||||
Diag("bad file number in pcfile: %d not in range [1, %d]\n", it.value, Ctxt.Nhistfile)
|
||||
Errorexit()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// pcdata
|
||||
off = addpctab(ftab, off, &pcln.Pcsp)
|
||||
|
||||
off = addpctab(ftab, off, &pcln.Pcfile)
|
||||
off = addpctab(ftab, off, &pcln.Pcline)
|
||||
off = int32(setuint32(Ctxt, ftab, int64(off), uint32(pcln.Npcdata)))
|
||||
off = int32(setuint32(Ctxt, ftab, int64(off), uint32(pcln.Nfuncdata)))
|
||||
for i = 0; i < int32(pcln.Npcdata); i++ {
|
||||
off = addpctab(ftab, off, &pcln.Pcdata[i])
|
||||
}
|
||||
|
||||
// funcdata, must be pointer-aligned and we're only int32-aligned.
|
||||
// Missing funcdata will be 0 (nil pointer).
|
||||
if pcln.Nfuncdata > 0 {
|
||||
if off&int32(Thearch.Ptrsize-1) != 0 {
|
||||
off += 4
|
||||
}
|
||||
for i = 0; i < int32(pcln.Nfuncdata); i++ {
|
||||
if pcln.Funcdata[i] == nil {
|
||||
setuintxx(Ctxt, ftab, int64(off)+int64(Thearch.Ptrsize)*int64(i), uint64(pcln.Funcdataoff[i]), int64(Thearch.Ptrsize))
|
||||
} else {
|
||||
// TODO: Dedup.
|
||||
funcdata_bytes += pcln.Funcdata[i].Size
|
||||
|
||||
setaddrplus(Ctxt, ftab, int64(off)+int64(Thearch.Ptrsize)*int64(i), pcln.Funcdata[i], pcln.Funcdataoff[i])
|
||||
}
|
||||
}
|
||||
|
||||
off += int32(pcln.Nfuncdata) * int32(Thearch.Ptrsize)
|
||||
}
|
||||
|
||||
if off != end {
|
||||
Diag("bad math in functab: funcstart=%d off=%d but end=%d (npcdata=%d nfuncdata=%d ptrsize=%d)", funcstart, off, end, pcln.Npcdata, pcln.Nfuncdata, Thearch.Ptrsize)
|
||||
Errorexit()
|
||||
}
|
||||
|
||||
nfunc++
|
||||
}
|
||||
|
||||
// Final entry of table is just end pc.
|
||||
setaddrplus(Ctxt, ftab, 8+int64(Thearch.Ptrsize)+int64(nfunc)*2*int64(Thearch.Ptrsize), last, last.Size)
|
||||
|
||||
// Start file table.
|
||||
start = int32(len(ftab.P))
|
||||
|
||||
start += int32(-len(ftab.P)) & (int32(Thearch.Ptrsize) - 1)
|
||||
setuint32(Ctxt, ftab, 8+int64(Thearch.Ptrsize)+int64(nfunc)*2*int64(Thearch.Ptrsize)+int64(Thearch.Ptrsize), uint32(start))
|
||||
|
||||
Symgrow(Ctxt, ftab, int64(start)+(int64(Ctxt.Nhistfile)+1)*4)
|
||||
setuint32(Ctxt, ftab, int64(start), uint32(Ctxt.Nhistfile))
|
||||
for s = Ctxt.Filesyms; s != nil; s = s.Next {
|
||||
setuint32(Ctxt, ftab, int64(start)+s.Value*4, uint32(ftabaddstring(ftab, s.Name)))
|
||||
}
|
||||
|
||||
ftab.Size = int64(len(ftab.P))
|
||||
|
||||
if Debug['v'] != 0 {
|
||||
fmt.Fprintf(&Bso, "%5.2f pclntab=%d bytes, funcdata total %d bytes\n", obj.Cputime(), int64(ftab.Size), int64(funcdata_bytes))
|
||||
}
|
||||
}
|
||||
|
||||
const (
|
||||
BUCKETSIZE = 256 * MINFUNC
|
||||
SUBBUCKETS = 16
|
||||
SUBBUCKETSIZE = BUCKETSIZE / SUBBUCKETS
|
||||
NOIDX = 0x7fffffff
|
||||
)
|
||||
|
||||
// findfunctab generates a lookup table to quickly find the containing
|
||||
// function for a pc. See src/runtime/symtab.go:findfunc for details.
|
||||
func findfunctab() {
|
||||
var t *LSym
|
||||
var s *LSym
|
||||
var e *LSym
|
||||
var idx int32
|
||||
var i int32
|
||||
var j int32
|
||||
var nbuckets int32
|
||||
var n int32
|
||||
var base int32
|
||||
var min int64
|
||||
var max int64
|
||||
var p int64
|
||||
var q int64
|
||||
var indexes []int32
|
||||
|
||||
t = Linklookup(Ctxt, "runtime.findfunctab", 0)
|
||||
t.Type = SRODATA
|
||||
t.Reachable = true
|
||||
|
||||
// find min and max address
|
||||
min = Ctxt.Textp.Value
|
||||
|
||||
max = 0
|
||||
for s = Ctxt.Textp; s != nil; s = s.Next {
|
||||
max = s.Value + s.Size
|
||||
}
|
||||
|
||||
// for each subbucket, compute the minimum of all symbol indexes
|
||||
// that map to that subbucket.
|
||||
n = int32((max - min + SUBBUCKETSIZE - 1) / SUBBUCKETSIZE)
|
||||
|
||||
indexes = make([]int32, n)
|
||||
for i = 0; i < n; i++ {
|
||||
indexes[i] = NOIDX
|
||||
}
|
||||
idx = 0
|
||||
for s = Ctxt.Textp; s != nil; s = s.Next {
|
||||
if container(s) != 0 {
|
||||
continue
|
||||
}
|
||||
p = s.Value
|
||||
e = s.Next
|
||||
for container(e) != 0 {
|
||||
e = e.Next
|
||||
}
|
||||
if e != nil {
|
||||
q = e.Value
|
||||
} else {
|
||||
q = max
|
||||
}
|
||||
|
||||
//print("%d: [%lld %lld] %s\n", idx, p, q, s->name);
|
||||
for ; p < q; p += SUBBUCKETSIZE {
|
||||
i = int32((p - min) / SUBBUCKETSIZE)
|
||||
if indexes[i] > idx {
|
||||
indexes[i] = idx
|
||||
}
|
||||
}
|
||||
|
||||
i = int32((q - 1 - min) / SUBBUCKETSIZE)
|
||||
if indexes[i] > idx {
|
||||
indexes[i] = idx
|
||||
}
|
||||
idx++
|
||||
}
|
||||
|
||||
// allocate table
|
||||
nbuckets = int32((max - min + BUCKETSIZE - 1) / BUCKETSIZE)
|
||||
|
||||
Symgrow(Ctxt, t, 4*int64(nbuckets)+int64(n))
|
||||
|
||||
// fill in table
|
||||
for i = 0; i < nbuckets; i++ {
|
||||
base = indexes[i*SUBBUCKETS]
|
||||
if base == NOIDX {
|
||||
Diag("hole in findfunctab")
|
||||
}
|
||||
setuint32(Ctxt, t, int64(i)*(4+SUBBUCKETS), uint32(base))
|
||||
for j = 0; j < SUBBUCKETS && i*SUBBUCKETS+j < n; j++ {
|
||||
idx = indexes[i*SUBBUCKETS+j]
|
||||
if idx == NOIDX {
|
||||
Diag("hole in findfunctab")
|
||||
}
|
||||
if idx-base >= 256 {
|
||||
Diag("too many functions in a findfunc bucket! %d/%d %d %d", i, nbuckets, j, idx-base)
|
||||
}
|
||||
|
||||
setuint8(Ctxt, t, int64(i)*(4+SUBBUCKETS)+4+int64(j), uint8(idx-base))
|
||||
}
|
||||
}
|
||||
}
|
||||
1060
src/cmd/internal/ld/pe.go
Normal file
1060
src/cmd/internal/ld/pe.go
Normal file
File diff suppressed because it is too large
Load diff
224
src/cmd/internal/ld/pobj.go
Normal file
224
src/cmd/internal/ld/pobj.go
Normal file
|
|
@ -0,0 +1,224 @@
|
|||
// Inferno utils/6l/obj.c
|
||||
// http://code.google.com/p/inferno-os/source/browse/utils/6l/obj.c
|
||||
//
|
||||
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
|
||||
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
|
||||
// Portions Copyright © 1997-1999 Vita Nuova Limited
|
||||
// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
|
||||
// Portions Copyright © 2004,2006 Bruce Ellis
|
||||
// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
|
||||
// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
|
||||
// Portions Copyright © 2009 The Go Authors. All rights reserved.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
package ld
|
||||
|
||||
import (
|
||||
"cmd/internal/obj"
|
||||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Reading object files.
|
||||
|
||||
var noname string = "<none>"
|
||||
|
||||
var paramspace string = "FP"
|
||||
|
||||
func Ldmain() {
|
||||
Ctxt = linknew(Thelinkarch)
|
||||
Ctxt.Thechar = int32(Thearch.Thechar)
|
||||
Ctxt.Thestring = Thestring
|
||||
Ctxt.Diag = Diag
|
||||
Ctxt.Bso = &Bso
|
||||
|
||||
Bso = *Binitw(os.Stdout)
|
||||
Debug = [128]int{}
|
||||
nerrors = 0
|
||||
outfile = ""
|
||||
HEADTYPE = -1
|
||||
INITTEXT = -1
|
||||
INITDAT = -1
|
||||
INITRND = -1
|
||||
INITENTRY = ""
|
||||
Linkmode = LinkAuto
|
||||
|
||||
// For testing behavior of go command when tools crash.
|
||||
// Undocumented, not in standard flag parser to avoid
|
||||
// exposing in usage message.
|
||||
for _, arg := range os.Args {
|
||||
if arg == "-crash_for_testing" {
|
||||
*(*int)(nil) = 0
|
||||
}
|
||||
}
|
||||
|
||||
if Thearch.Thechar == '5' && Ctxt.Goarm == 5 {
|
||||
Debug['F'] = 1
|
||||
}
|
||||
|
||||
obj.Flagcount("1", "use alternate profiling code", &Debug['1'])
|
||||
if Thearch.Thechar == '6' {
|
||||
obj.Flagcount("8", "assume 64-bit addresses", &Debug['8'])
|
||||
}
|
||||
obj.Flagfn1("B", "info: define ELF NT_GNU_BUILD_ID note", addbuildinfo)
|
||||
obj.Flagcount("C", "check Go calls to C code", &Debug['C'])
|
||||
obj.Flagint64("D", "addr: data address", &INITDAT)
|
||||
obj.Flagstr("E", "sym: entry symbol", &INITENTRY)
|
||||
if Thearch.Thechar == '5' {
|
||||
obj.Flagcount("G", "debug pseudo-ops", &Debug['G'])
|
||||
}
|
||||
obj.Flagfn1("I", "interp: set ELF interp", setinterp)
|
||||
obj.Flagfn1("L", "dir: add dir to library path", Lflag)
|
||||
obj.Flagfn1("H", "head: header type", setheadtype)
|
||||
obj.Flagcount("K", "add stack underflow checks", &Debug['K'])
|
||||
if Thearch.Thechar == '5' {
|
||||
obj.Flagcount("M", "disable software div/mod", &Debug['M'])
|
||||
}
|
||||
obj.Flagcount("O", "print pc-line tables", &Debug['O'])
|
||||
obj.Flagcount("Q", "debug byte-register code gen", &Debug['Q'])
|
||||
if Thearch.Thechar == '5' {
|
||||
obj.Flagcount("P", "debug code generation", &Debug['P'])
|
||||
}
|
||||
obj.Flagint32("R", "rnd: address rounding", &INITRND)
|
||||
obj.Flagcount("nil", "check type signatures", &Debug['S'])
|
||||
obj.Flagint64("T", "addr: text address", &INITTEXT)
|
||||
obj.Flagfn0("V", "print version and exit", doversion)
|
||||
obj.Flagcount("W", "disassemble input", &Debug['W'])
|
||||
obj.Flagfn1("X", "name value: define string data", addstrdata1)
|
||||
obj.Flagcount("Z", "clear stack frame on entry", &Debug['Z'])
|
||||
obj.Flagcount("a", "disassemble output", &Debug['a'])
|
||||
obj.Flagcount("c", "dump call graph", &Debug['c'])
|
||||
obj.Flagcount("d", "disable dynamic executable", &Debug['d'])
|
||||
obj.Flagstr("extld", "ld: linker to run in external mode", &extld)
|
||||
obj.Flagstr("extldflags", "ldflags: flags for external linker", &extldflags)
|
||||
obj.Flagcount("f", "ignore version mismatch", &Debug['f'])
|
||||
obj.Flagcount("g", "disable go package data checks", &Debug['g'])
|
||||
obj.Flagstr("installsuffix", "suffix: pkg directory suffix", &flag_installsuffix)
|
||||
obj.Flagstr("k", "sym: set field tracking symbol", &tracksym)
|
||||
obj.Flagfn1("linkmode", "mode: set link mode (internal, external, auto)", setlinkmode)
|
||||
obj.Flagcount("n", "dump symbol table", &Debug['n'])
|
||||
obj.Flagstr("o", "outfile: set output file", &outfile)
|
||||
obj.Flagstr("r", "dir1:dir2:...: set ELF dynamic linker search path", &rpath)
|
||||
obj.Flagcount("race", "enable race detector", &flag_race)
|
||||
obj.Flagcount("s", "disable symbol table", &Debug['s'])
|
||||
if Thearch.Thechar == '5' || Thearch.Thechar == '6' {
|
||||
obj.Flagcount("shared", "generate shared object (implies -linkmode external)", &Flag_shared)
|
||||
}
|
||||
obj.Flagstr("tmpdir", "dir: leave temporary files in this directory", &tmpdir)
|
||||
obj.Flagcount("u", "reject unsafe packages", &Debug['u'])
|
||||
obj.Flagcount("v", "print link trace", &Debug['v'])
|
||||
obj.Flagcount("w", "disable DWARF generation", &Debug['w'])
|
||||
|
||||
// Clumsy hack to preserve old behavior of -X taking two arguments.
|
||||
for i := 0; i < len(os.Args); i++ {
|
||||
arg := os.Args[i]
|
||||
if (arg == "--X" || arg == "-X") && i+2 < len(os.Args) {
|
||||
os.Args[i+2] = "-X=VALUE:" + os.Args[i+2]
|
||||
i += 2
|
||||
} else if (strings.HasPrefix(arg, "--X=") || strings.HasPrefix(arg, "-X=")) && i+1 < len(os.Args) {
|
||||
os.Args[i+1] = "-X=VALUE:" + os.Args[i+1]
|
||||
i++
|
||||
}
|
||||
}
|
||||
obj.Flagstr("cpuprofile", "file: write cpu profile to file", &cpuprofile)
|
||||
obj.Flagstr("memprofile", "file: write memory profile to file", &memprofile)
|
||||
obj.Flagparse(usage)
|
||||
startProfile()
|
||||
Ctxt.Bso = &Bso
|
||||
Ctxt.Debugvlog = int32(Debug['v'])
|
||||
|
||||
if flag.NArg() != 1 {
|
||||
usage()
|
||||
}
|
||||
|
||||
if outfile == "" {
|
||||
if HEADTYPE == Hwindows {
|
||||
outfile = fmt.Sprintf("%c.out.exe", Thearch.Thechar)
|
||||
} else {
|
||||
outfile = fmt.Sprintf("%c.out", Thearch.Thechar)
|
||||
}
|
||||
}
|
||||
|
||||
libinit() // creates outfile
|
||||
|
||||
if HEADTYPE == -1 {
|
||||
HEADTYPE = int32(headtype(goos))
|
||||
}
|
||||
Ctxt.Headtype = int(HEADTYPE)
|
||||
if headstring == "" {
|
||||
headstring = Headstr(int(HEADTYPE))
|
||||
}
|
||||
|
||||
Thearch.Archinit()
|
||||
|
||||
if Debug['v'] != 0 {
|
||||
fmt.Fprintf(&Bso, "HEADER = -H%d -T0x%x -D0x%x -R0x%x\n", HEADTYPE, uint64(INITTEXT), uint64(INITDAT), uint32(INITRND))
|
||||
}
|
||||
Bflush(&Bso)
|
||||
|
||||
addlibpath(Ctxt, "command line", "command line", flag.Arg(0), "main")
|
||||
loadlib()
|
||||
|
||||
if Thearch.Thechar == '5' {
|
||||
// mark some functions that are only referenced after linker code editing
|
||||
if Debug['F'] != 0 {
|
||||
mark(Linkrlookup(Ctxt, "_sfloat", 0))
|
||||
}
|
||||
mark(Linklookup(Ctxt, "runtime.read_tls_fallback", 0))
|
||||
}
|
||||
|
||||
checkgo()
|
||||
deadcode()
|
||||
callgraph()
|
||||
paramspace = "SP" /* (FP) now (SP) on output */
|
||||
|
||||
doelf()
|
||||
if HEADTYPE == Hdarwin {
|
||||
domacho()
|
||||
}
|
||||
dostkcheck()
|
||||
if HEADTYPE == Hwindows {
|
||||
dope()
|
||||
}
|
||||
addexport()
|
||||
Thearch.Gentext() // trampolines, call stubs, etc.
|
||||
textaddress()
|
||||
pclntab()
|
||||
findfunctab()
|
||||
symtab()
|
||||
dodata()
|
||||
address()
|
||||
doweak()
|
||||
reloc()
|
||||
Thearch.Asmb()
|
||||
undef()
|
||||
hostlink()
|
||||
if Debug['v'] != 0 {
|
||||
fmt.Fprintf(&Bso, "%5.2f cpu time\n", obj.Cputime())
|
||||
fmt.Fprintf(&Bso, "%d symbols\n", Ctxt.Nsymbol)
|
||||
fmt.Fprintf(&Bso, "%d liveness data\n", liveness)
|
||||
}
|
||||
|
||||
Bflush(&Bso)
|
||||
|
||||
Errorexit()
|
||||
}
|
||||
238
src/cmd/internal/ld/sym.go
Normal file
238
src/cmd/internal/ld/sym.go
Normal file
|
|
@ -0,0 +1,238 @@
|
|||
// Derived from Inferno utils/6l/obj.c and utils/6l/span.c
|
||||
// http://code.google.com/p/inferno-os/source/browse/utils/6l/obj.c
|
||||
// http://code.google.com/p/inferno-os/source/browse/utils/6l/span.c
|
||||
//
|
||||
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
|
||||
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
|
||||
// Portions Copyright © 1997-1999 Vita Nuova Limited
|
||||
// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
|
||||
// Portions Copyright © 2004,2006 Bruce Ellis
|
||||
// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
|
||||
// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
|
||||
// Portions Copyright © 2009 The Go Authors. All rights reserved.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
package ld
|
||||
|
||||
import (
|
||||
"cmd/internal/obj"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
func yy_isalpha(c int) bool {
|
||||
return 'A' <= c && c <= 'Z' || 'a' <= c && c <= 'z'
|
||||
}
|
||||
|
||||
var headers = []struct {
|
||||
name string
|
||||
val int
|
||||
}{
|
||||
{"darwin", Hdarwin},
|
||||
{"dragonfly", Hdragonfly},
|
||||
{"elf", Helf},
|
||||
{"freebsd", Hfreebsd},
|
||||
{"linux", Hlinux},
|
||||
{"android", Hlinux}, // must be after "linux" entry or else headstr(Hlinux) == "android"
|
||||
{"nacl", Hnacl},
|
||||
{"netbsd", Hnetbsd},
|
||||
{"openbsd", Hopenbsd},
|
||||
{"plan9", Hplan9},
|
||||
{"solaris", Hsolaris},
|
||||
{"windows", Hwindows},
|
||||
{"windowsgui", Hwindows},
|
||||
}
|
||||
|
||||
func linknew(arch *LinkArch) *Link {
|
||||
var ctxt *Link
|
||||
var p string
|
||||
var buf string
|
||||
|
||||
ctxt = new(Link)
|
||||
ctxt.Hash = make(map[symVer]*LSym)
|
||||
ctxt.Arch = arch
|
||||
ctxt.Version = HistVersion
|
||||
ctxt.Goroot = obj.Getgoroot()
|
||||
|
||||
p = obj.Getgoarch()
|
||||
if p != arch.Name {
|
||||
log.Fatalf("invalid goarch %s (want %s)", p, arch.Name)
|
||||
}
|
||||
|
||||
buf, _ = os.Getwd()
|
||||
if buf == "" {
|
||||
buf = "/???"
|
||||
}
|
||||
buf = filepath.ToSlash(buf)
|
||||
|
||||
ctxt.Headtype = headtype(obj.Getgoos())
|
||||
if ctxt.Headtype < 0 {
|
||||
log.Fatalf("unknown goos %s", obj.Getgoos())
|
||||
}
|
||||
|
||||
// Record thread-local storage offset.
|
||||
// TODO(rsc): Move tlsoffset back into the linker.
|
||||
switch ctxt.Headtype {
|
||||
default:
|
||||
log.Fatalf("unknown thread-local storage offset for %s", Headstr(ctxt.Headtype))
|
||||
|
||||
case Hplan9,
|
||||
Hwindows:
|
||||
break
|
||||
|
||||
/*
|
||||
* ELF uses TLS offset negative from FS.
|
||||
* Translate 0(FS) and 8(FS) into -16(FS) and -8(FS).
|
||||
* Known to low-level assembly in package runtime and runtime/cgo.
|
||||
*/
|
||||
case Hlinux,
|
||||
Hfreebsd,
|
||||
Hnetbsd,
|
||||
Hopenbsd,
|
||||
Hdragonfly,
|
||||
Hsolaris:
|
||||
ctxt.Tlsoffset = -2 * ctxt.Arch.Ptrsize
|
||||
|
||||
case Hnacl:
|
||||
switch ctxt.Arch.Thechar {
|
||||
default:
|
||||
log.Fatalf("unknown thread-local storage offset for nacl/%s", ctxt.Arch.Name)
|
||||
|
||||
case '5':
|
||||
ctxt.Tlsoffset = 0
|
||||
|
||||
case '6':
|
||||
ctxt.Tlsoffset = 0
|
||||
|
||||
case '8':
|
||||
ctxt.Tlsoffset = -8
|
||||
}
|
||||
|
||||
/*
|
||||
* OS X system constants - offset from 0(GS) to our TLS.
|
||||
* Explained in ../../runtime/cgo/gcc_darwin_*.c.
|
||||
*/
|
||||
case Hdarwin:
|
||||
switch ctxt.Arch.Thechar {
|
||||
default:
|
||||
log.Fatalf("unknown thread-local storage offset for darwin/%s", ctxt.Arch.Name)
|
||||
|
||||
case '6':
|
||||
ctxt.Tlsoffset = 0x8a0
|
||||
|
||||
case '8':
|
||||
ctxt.Tlsoffset = 0x468
|
||||
|
||||
case '5':
|
||||
ctxt.Tlsoffset = 0 // dummy value, not needed
|
||||
}
|
||||
}
|
||||
|
||||
// On arm, record goarm.
|
||||
if ctxt.Arch.Thechar == '5' {
|
||||
p = obj.Getgoarm()
|
||||
if p != "" {
|
||||
ctxt.Goarm = int32(obj.Atoi(p))
|
||||
} else {
|
||||
ctxt.Goarm = 6
|
||||
}
|
||||
}
|
||||
|
||||
return ctxt
|
||||
}
|
||||
|
||||
func linknewsym(ctxt *Link, symb string, v int) *LSym {
|
||||
var s *LSym
|
||||
|
||||
s = new(LSym)
|
||||
*s = LSym{}
|
||||
|
||||
s.Dynid = -1
|
||||
s.Plt = -1
|
||||
s.Got = -1
|
||||
s.Name = symb
|
||||
s.Type = 0
|
||||
s.Version = int16(v)
|
||||
s.Value = 0
|
||||
s.Sig = 0
|
||||
s.Size = 0
|
||||
ctxt.Nsymbol++
|
||||
|
||||
s.Allsym = ctxt.Allsym
|
||||
ctxt.Allsym = s
|
||||
|
||||
return s
|
||||
}
|
||||
|
||||
type symVer struct {
|
||||
sym string
|
||||
ver int
|
||||
}
|
||||
|
||||
func _lookup(ctxt *Link, symb string, v int, creat int) *LSym {
|
||||
s := ctxt.Hash[symVer{symb, v}]
|
||||
if s != nil {
|
||||
return s
|
||||
}
|
||||
if creat == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
s = linknewsym(ctxt, symb, v)
|
||||
s.Extname = s.Name
|
||||
ctxt.Hash[symVer{symb, v}] = s
|
||||
return s
|
||||
}
|
||||
|
||||
func Linklookup(ctxt *Link, name string, v int) *LSym {
|
||||
return _lookup(ctxt, name, v, 1)
|
||||
}
|
||||
|
||||
// read-only lookup
|
||||
func Linkrlookup(ctxt *Link, name string, v int) *LSym {
|
||||
return _lookup(ctxt, name, v, 0)
|
||||
}
|
||||
|
||||
var headstr_buf string
|
||||
|
||||
func Headstr(v int) string {
|
||||
var i int
|
||||
|
||||
for i = 0; i < len(headers); i++ {
|
||||
if v == headers[i].val {
|
||||
return headers[i].name
|
||||
}
|
||||
}
|
||||
headstr_buf = fmt.Sprintf("%d", v)
|
||||
return headstr_buf
|
||||
}
|
||||
|
||||
func headtype(name string) int {
|
||||
var i int
|
||||
|
||||
for i = 0; i < len(headers); i++ {
|
||||
if name == headers[i].name {
|
||||
return headers[i].val
|
||||
}
|
||||
}
|
||||
return -1
|
||||
}
|
||||
440
src/cmd/internal/ld/symtab.go
Normal file
440
src/cmd/internal/ld/symtab.go
Normal file
|
|
@ -0,0 +1,440 @@
|
|||
// Inferno utils/6l/span.c
|
||||
// http://code.google.com/p/inferno-os/source/browse/utils/6l/span.c
|
||||
//
|
||||
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
|
||||
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
|
||||
// Portions Copyright © 1997-1999 Vita Nuova Limited
|
||||
// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
|
||||
// Portions Copyright © 2004,2006 Bruce Ellis
|
||||
// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
|
||||
// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
|
||||
// Portions Copyright © 2009 The Go Authors. All rights reserved.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
package ld
|
||||
|
||||
import "strings"
|
||||
|
||||
// Symbol table.
|
||||
|
||||
var maxelfstr int
|
||||
|
||||
func putelfstr(s string) int {
|
||||
var off int
|
||||
var n int
|
||||
|
||||
if len(Elfstrdat) == 0 && s != "" {
|
||||
// first entry must be empty string
|
||||
putelfstr("")
|
||||
}
|
||||
|
||||
// Rewrite · to . for ASCII-only tools like DTrace (sigh)
|
||||
s = strings.Replace(s, "·", ".", -1)
|
||||
|
||||
n = len(s) + 1
|
||||
for len(Elfstrdat)+n > cap(Elfstrdat) {
|
||||
Elfstrdat = append(Elfstrdat[:cap(Elfstrdat)], 0)[:len(Elfstrdat)]
|
||||
}
|
||||
|
||||
off = len(Elfstrdat)
|
||||
Elfstrdat = Elfstrdat[:off+n]
|
||||
copy(Elfstrdat[off:], s)
|
||||
|
||||
return off
|
||||
}
|
||||
|
||||
func putelfsyment(off int, addr int64, size int64, info int, shndx int, other int) {
|
||||
switch Thearch.Thechar {
|
||||
case '6',
|
||||
'9':
|
||||
Thearch.Lput(uint32(off))
|
||||
Cput(uint8(info))
|
||||
Cput(uint8(other))
|
||||
Thearch.Wput(uint16(shndx))
|
||||
Thearch.Vput(uint64(addr))
|
||||
Thearch.Vput(uint64(size))
|
||||
Symsize += ELF64SYMSIZE
|
||||
|
||||
default:
|
||||
Thearch.Lput(uint32(off))
|
||||
Thearch.Lput(uint32(addr))
|
||||
Thearch.Lput(uint32(size))
|
||||
Cput(uint8(info))
|
||||
Cput(uint8(other))
|
||||
Thearch.Wput(uint16(shndx))
|
||||
Symsize += ELF32SYMSIZE
|
||||
}
|
||||
}
|
||||
|
||||
var numelfsym int = 1 // 0 is reserved
|
||||
|
||||
var elfbind int
|
||||
|
||||
func putelfsym(x *LSym, s string, t int, addr int64, size int64, ver int, go_ *LSym) {
|
||||
var bind int
|
||||
var type_ int
|
||||
var off int
|
||||
var other int
|
||||
var xo *LSym
|
||||
|
||||
switch t {
|
||||
default:
|
||||
return
|
||||
|
||||
case 'T':
|
||||
type_ = STT_FUNC
|
||||
|
||||
case 'D':
|
||||
type_ = STT_OBJECT
|
||||
|
||||
case 'B':
|
||||
type_ = STT_OBJECT
|
||||
}
|
||||
|
||||
xo = x
|
||||
for xo.Outer != nil {
|
||||
xo = xo.Outer
|
||||
}
|
||||
if xo.Sect == nil {
|
||||
Ctxt.Cursym = x
|
||||
Diag("missing section in putelfsym")
|
||||
return
|
||||
}
|
||||
|
||||
if (xo.Sect.(*Section)).Elfsect == nil {
|
||||
Ctxt.Cursym = x
|
||||
Diag("missing ELF section in putelfsym")
|
||||
return
|
||||
}
|
||||
|
||||
// One pass for each binding: STB_LOCAL, STB_GLOBAL,
|
||||
// maybe one day STB_WEAK.
|
||||
bind = STB_GLOBAL
|
||||
|
||||
if ver != 0 || (x.Type&SHIDDEN != 0) {
|
||||
bind = STB_LOCAL
|
||||
}
|
||||
|
||||
// In external linking mode, we have to invoke gcc with -rdynamic
|
||||
// to get the exported symbols put into the dynamic symbol table.
|
||||
// To avoid filling the dynamic table with lots of unnecessary symbols,
|
||||
// mark all Go symbols local (not global) in the final executable.
|
||||
if Linkmode == LinkExternal && x.Cgoexport&CgoExportStatic == 0 {
|
||||
bind = STB_LOCAL
|
||||
}
|
||||
|
||||
if bind != elfbind {
|
||||
return
|
||||
}
|
||||
|
||||
off = putelfstr(s)
|
||||
if Linkmode == LinkExternal {
|
||||
addr -= int64((xo.Sect.(*Section)).Vaddr)
|
||||
}
|
||||
other = 2
|
||||
if x.Type&SHIDDEN != 0 {
|
||||
other = 0
|
||||
}
|
||||
putelfsyment(off, addr, size, bind<<4|type_&0xf, ((xo.Sect.(*Section)).Elfsect.(*ElfShdr)).shnum, other)
|
||||
x.Elfsym = int32(numelfsym)
|
||||
numelfsym++
|
||||
}
|
||||
|
||||
func putelfsectionsym(s *LSym, shndx int) {
|
||||
putelfsyment(0, 0, 0, STB_LOCAL<<4|STT_SECTION, shndx, 0)
|
||||
s.Elfsym = int32(numelfsym)
|
||||
numelfsym++
|
||||
}
|
||||
|
||||
func putelfsymshndx(sympos int64, shndx int) {
|
||||
var here int64
|
||||
|
||||
here = Cpos()
|
||||
switch Thearch.Thechar {
|
||||
case '6':
|
||||
Cseek(sympos + 6)
|
||||
|
||||
default:
|
||||
Cseek(sympos + 14)
|
||||
}
|
||||
|
||||
Thearch.Wput(uint16(shndx))
|
||||
Cseek(here)
|
||||
}
|
||||
|
||||
func Asmelfsym() {
|
||||
var s *LSym
|
||||
var name string
|
||||
|
||||
// the first symbol entry is reserved
|
||||
putelfsyment(0, 0, 0, STB_LOCAL<<4|STT_NOTYPE, 0, 0)
|
||||
|
||||
dwarfaddelfsectionsyms()
|
||||
|
||||
elfbind = STB_LOCAL
|
||||
genasmsym(putelfsym)
|
||||
|
||||
if Linkmode == LinkExternal && HEADTYPE != Hopenbsd {
|
||||
s = Linklookup(Ctxt, "runtime.tlsg", 0)
|
||||
if s.Sect == nil {
|
||||
Ctxt.Cursym = nil
|
||||
Diag("missing section for %s", s.Name)
|
||||
Errorexit()
|
||||
}
|
||||
|
||||
if goos == "android" {
|
||||
// Android emulates runtime.tlsg as a regular variable.
|
||||
putelfsyment(putelfstr(s.Name), 0, s.Size, STB_LOCAL<<4|STT_OBJECT, ((s.Sect.(*Section)).Elfsect.(*ElfShdr)).shnum, 0)
|
||||
} else {
|
||||
putelfsyment(putelfstr(s.Name), 0, s.Size, STB_LOCAL<<4|STT_TLS, ((s.Sect.(*Section)).Elfsect.(*ElfShdr)).shnum, 0)
|
||||
}
|
||||
|
||||
s.Elfsym = int32(numelfsym)
|
||||
numelfsym++
|
||||
}
|
||||
|
||||
elfbind = STB_GLOBAL
|
||||
elfglobalsymndx = numelfsym
|
||||
genasmsym(putelfsym)
|
||||
|
||||
for s = Ctxt.Allsym; s != nil; s = s.Allsym {
|
||||
if s.Type != SHOSTOBJ && (s.Type != SDYNIMPORT || !s.Reachable) {
|
||||
continue
|
||||
}
|
||||
if s.Type == SDYNIMPORT {
|
||||
name = s.Extname
|
||||
} else {
|
||||
name = s.Name
|
||||
}
|
||||
putelfsyment(putelfstr(name), 0, 0, STB_GLOBAL<<4|STT_NOTYPE, 0, 0)
|
||||
s.Elfsym = int32(numelfsym)
|
||||
numelfsym++
|
||||
}
|
||||
}
|
||||
|
||||
func putplan9sym(x *LSym, s string, t int, addr int64, size int64, ver int, go_ *LSym) {
|
||||
var i int
|
||||
var l int
|
||||
|
||||
switch t {
|
||||
case 'T',
|
||||
'L',
|
||||
'D',
|
||||
'B':
|
||||
if ver != 0 {
|
||||
t += 'a' - 'A'
|
||||
}
|
||||
fallthrough
|
||||
|
||||
case 'a',
|
||||
'p',
|
||||
'f',
|
||||
'z',
|
||||
'Z',
|
||||
'm':
|
||||
l = 4
|
||||
if HEADTYPE == Hplan9 && Thearch.Thechar == '6' && Debug['8'] == 0 {
|
||||
Lputb(uint32(addr >> 32))
|
||||
l = 8
|
||||
}
|
||||
|
||||
Lputb(uint32(addr))
|
||||
Cput(uint8(t + 0x80)) /* 0x80 is variable length */
|
||||
|
||||
if t == 'z' || t == 'Z' {
|
||||
Cput(uint8(s[0]))
|
||||
for i = 1; s[i] != 0 || s[i+1] != 0; i += 2 {
|
||||
Cput(uint8(s[i]))
|
||||
Cput(uint8(s[i+1]))
|
||||
}
|
||||
|
||||
Cput(0)
|
||||
Cput(0)
|
||||
i++
|
||||
} else {
|
||||
/* skip the '<' in filenames */
|
||||
if t == 'f' {
|
||||
s = s[1:]
|
||||
}
|
||||
for i = 0; i < len(s); i++ {
|
||||
Cput(uint8(s[i]))
|
||||
}
|
||||
Cput(0)
|
||||
}
|
||||
|
||||
Symsize += int32(l) + 1 + int32(i) + 1
|
||||
|
||||
default:
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func Asmplan9sym() {
|
||||
genasmsym(putplan9sym)
|
||||
}
|
||||
|
||||
var symt *LSym
|
||||
|
||||
func Wputl(w uint16) {
|
||||
Cput(uint8(w))
|
||||
Cput(uint8(w >> 8))
|
||||
}
|
||||
|
||||
func Wputb(w uint16) {
|
||||
Cput(uint8(w >> 8))
|
||||
Cput(uint8(w))
|
||||
}
|
||||
|
||||
func Lputb(l uint32) {
|
||||
Cput(uint8(l >> 24))
|
||||
Cput(uint8(l >> 16))
|
||||
Cput(uint8(l >> 8))
|
||||
Cput(uint8(l))
|
||||
}
|
||||
|
||||
func Lputl(l uint32) {
|
||||
Cput(uint8(l))
|
||||
Cput(uint8(l >> 8))
|
||||
Cput(uint8(l >> 16))
|
||||
Cput(uint8(l >> 24))
|
||||
}
|
||||
|
||||
func Vputb(v uint64) {
|
||||
Lputb(uint32(v >> 32))
|
||||
Lputb(uint32(v))
|
||||
}
|
||||
|
||||
func Vputl(v uint64) {
|
||||
Lputl(uint32(v))
|
||||
Lputl(uint32(v >> 32))
|
||||
}
|
||||
|
||||
func symtab() {
|
||||
var s *LSym
|
||||
var symtype *LSym
|
||||
var symtypelink *LSym
|
||||
var symgostring *LSym
|
||||
var symgofunc *LSym
|
||||
|
||||
dosymtype()
|
||||
|
||||
// Define these so that they'll get put into the symbol table.
|
||||
// data.c:/^address will provide the actual values.
|
||||
xdefine("runtime.text", STEXT, 0)
|
||||
|
||||
xdefine("runtime.etext", STEXT, 0)
|
||||
xdefine("runtime.typelink", SRODATA, 0)
|
||||
xdefine("runtime.etypelink", SRODATA, 0)
|
||||
xdefine("runtime.rodata", SRODATA, 0)
|
||||
xdefine("runtime.erodata", SRODATA, 0)
|
||||
xdefine("runtime.noptrdata", SNOPTRDATA, 0)
|
||||
xdefine("runtime.enoptrdata", SNOPTRDATA, 0)
|
||||
xdefine("runtime.data", SDATA, 0)
|
||||
xdefine("runtime.edata", SDATA, 0)
|
||||
xdefine("runtime.bss", SBSS, 0)
|
||||
xdefine("runtime.ebss", SBSS, 0)
|
||||
xdefine("runtime.noptrbss", SNOPTRBSS, 0)
|
||||
xdefine("runtime.enoptrbss", SNOPTRBSS, 0)
|
||||
xdefine("runtime.end", SBSS, 0)
|
||||
xdefine("runtime.epclntab", SRODATA, 0)
|
||||
xdefine("runtime.esymtab", SRODATA, 0)
|
||||
|
||||
// garbage collection symbols
|
||||
s = Linklookup(Ctxt, "runtime.gcdata", 0)
|
||||
|
||||
s.Type = SRODATA
|
||||
s.Size = 0
|
||||
s.Reachable = true
|
||||
xdefine("runtime.egcdata", SRODATA, 0)
|
||||
|
||||
s = Linklookup(Ctxt, "runtime.gcbss", 0)
|
||||
s.Type = SRODATA
|
||||
s.Size = 0
|
||||
s.Reachable = true
|
||||
xdefine("runtime.egcbss", SRODATA, 0)
|
||||
|
||||
// pseudo-symbols to mark locations of type, string, and go string data.
|
||||
s = Linklookup(Ctxt, "type.*", 0)
|
||||
|
||||
s.Type = STYPE
|
||||
s.Size = 0
|
||||
s.Reachable = true
|
||||
symtype = s
|
||||
|
||||
s = Linklookup(Ctxt, "go.string.*", 0)
|
||||
s.Type = SGOSTRING
|
||||
s.Size = 0
|
||||
s.Reachable = true
|
||||
symgostring = s
|
||||
|
||||
s = Linklookup(Ctxt, "go.func.*", 0)
|
||||
s.Type = SGOFUNC
|
||||
s.Size = 0
|
||||
s.Reachable = true
|
||||
symgofunc = s
|
||||
|
||||
symtypelink = Linklookup(Ctxt, "runtime.typelink", 0)
|
||||
|
||||
symt = Linklookup(Ctxt, "runtime.symtab", 0)
|
||||
symt.Type = SSYMTAB
|
||||
symt.Size = 0
|
||||
symt.Reachable = true
|
||||
|
||||
// assign specific types so that they sort together.
|
||||
// within a type they sort by size, so the .* symbols
|
||||
// just defined above will be first.
|
||||
// hide the specific symbols.
|
||||
for s = Ctxt.Allsym; s != nil; s = s.Allsym {
|
||||
if !s.Reachable || s.Special != 0 || s.Type != SRODATA {
|
||||
continue
|
||||
}
|
||||
if strings.HasPrefix(s.Name, "type.") {
|
||||
s.Type = STYPE
|
||||
s.Hide = 1
|
||||
s.Outer = symtype
|
||||
}
|
||||
|
||||
if strings.HasPrefix(s.Name, "go.typelink.") {
|
||||
s.Type = STYPELINK
|
||||
s.Hide = 1
|
||||
s.Outer = symtypelink
|
||||
}
|
||||
|
||||
if strings.HasPrefix(s.Name, "go.string.") {
|
||||
s.Type = SGOSTRING
|
||||
s.Hide = 1
|
||||
s.Outer = symgostring
|
||||
}
|
||||
|
||||
if strings.HasPrefix(s.Name, "go.func.") {
|
||||
s.Type = SGOFUNC
|
||||
s.Hide = 1
|
||||
s.Outer = symgofunc
|
||||
}
|
||||
|
||||
if strings.HasPrefix(s.Name, "gcargs.") || strings.HasPrefix(s.Name, "gclocals.") || strings.HasPrefix(s.Name, "gclocals·") {
|
||||
s.Type = SGOFUNC
|
||||
s.Hide = 1
|
||||
s.Outer = symgofunc
|
||||
s.Align = 4
|
||||
liveness += (s.Size + int64(s.Align) - 1) &^ (int64(s.Align) - 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
133
src/cmd/internal/ld/textflag.go
Normal file
133
src/cmd/internal/ld/textflag.go
Normal file
|
|
@ -0,0 +1,133 @@
|
|||
// Copyright 2013 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package ld
|
||||
|
||||
// Writing and reading of Go object files.
|
||||
//
|
||||
// Originally, Go object files were Plan 9 object files, but no longer.
|
||||
// Now they are more like standard object files, in that each symbol is defined
|
||||
// by an associated memory image (bytes) and a list of relocations to apply
|
||||
// during linking. We do not (yet?) use a standard file format, however.
|
||||
// For now, the format is chosen to be as simple as possible to read and write.
|
||||
// It may change for reasons of efficiency, or we may even switch to a
|
||||
// standard file format if there are compelling benefits to doing so.
|
||||
// See golang.org/s/go13linker for more background.
|
||||
//
|
||||
// The file format is:
|
||||
//
|
||||
// - magic header: "\x00\x00go13ld"
|
||||
// - byte 1 - version number
|
||||
// - sequence of strings giving dependencies (imported packages)
|
||||
// - empty string (marks end of sequence)
|
||||
// - sequence of defined symbols
|
||||
// - byte 0xff (marks end of sequence)
|
||||
// - magic footer: "\xff\xffgo13ld"
|
||||
//
|
||||
// All integers are stored in a zigzag varint format.
|
||||
// See golang.org/s/go12symtab for a definition.
|
||||
//
|
||||
// Data blocks and strings are both stored as an integer
|
||||
// followed by that many bytes.
|
||||
//
|
||||
// A symbol reference is a string name followed by a version.
|
||||
// An empty name corresponds to a nil LSym* pointer.
|
||||
//
|
||||
// Each symbol is laid out as the following fields (taken from LSym*):
|
||||
//
|
||||
// - byte 0xfe (sanity check for synchronization)
|
||||
// - type [int]
|
||||
// - name [string]
|
||||
// - version [int]
|
||||
// - flags [int]
|
||||
// 1 dupok
|
||||
// - size [int]
|
||||
// - gotype [symbol reference]
|
||||
// - p [data block]
|
||||
// - nr [int]
|
||||
// - r [nr relocations, sorted by off]
|
||||
//
|
||||
// If type == STEXT, there are a few more fields:
|
||||
//
|
||||
// - args [int]
|
||||
// - locals [int]
|
||||
// - nosplit [int]
|
||||
// - flags [int]
|
||||
// 1 leaf
|
||||
// 2 C function
|
||||
// - nlocal [int]
|
||||
// - local [nlocal automatics]
|
||||
// - pcln [pcln table]
|
||||
//
|
||||
// Each relocation has the encoding:
|
||||
//
|
||||
// - off [int]
|
||||
// - siz [int]
|
||||
// - type [int]
|
||||
// - add [int]
|
||||
// - xadd [int]
|
||||
// - sym [symbol reference]
|
||||
// - xsym [symbol reference]
|
||||
//
|
||||
// Each local has the encoding:
|
||||
//
|
||||
// - asym [symbol reference]
|
||||
// - offset [int]
|
||||
// - type [int]
|
||||
// - gotype [symbol reference]
|
||||
//
|
||||
// The pcln table has the encoding:
|
||||
//
|
||||
// - pcsp [data block]
|
||||
// - pcfile [data block]
|
||||
// - pcline [data block]
|
||||
// - npcdata [int]
|
||||
// - pcdata [npcdata data blocks]
|
||||
// - nfuncdata [int]
|
||||
// - funcdata [nfuncdata symbol references]
|
||||
// - funcdatasym [nfuncdata ints]
|
||||
// - nfile [int]
|
||||
// - file [nfile symbol references]
|
||||
//
|
||||
// The file layout and meaning of type integers are architecture-independent.
|
||||
//
|
||||
// TODO(rsc): The file format is good for a first pass but needs work.
|
||||
// - There are SymID in the object file that should really just be strings.
|
||||
// - The actual symbol memory images are interlaced with the symbol
|
||||
// metadata. They should be separated, to reduce the I/O required to
|
||||
// load just the metadata.
|
||||
// - The symbol references should be shortened, either with a symbol
|
||||
// table or by using a simple backward index to an earlier mentioned symbol.
|
||||
|
||||
// Copyright 2013 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// This file defines flags attached to various functions
|
||||
// and data objects. The compilers, assemblers, and linker must
|
||||
// all agree on these values.
|
||||
|
||||
// Don't profile the marked routine. This flag is deprecated.
|
||||
|
||||
// It is ok for the linker to get multiple of these symbols. It will
|
||||
// pick one of the duplicates to use.
|
||||
|
||||
// Don't insert stack check preamble.
|
||||
|
||||
// Put this data in a read-only section.
|
||||
|
||||
// This data contains no pointers.
|
||||
|
||||
// This is a wrapper function and should not count as disabling 'recover'.
|
||||
|
||||
// This function uses its incoming context register.
|
||||
const (
|
||||
NOPROF = 1
|
||||
DUPOK = 2
|
||||
NOSPLIT = 4
|
||||
RODATA = 8
|
||||
NOPTR = 16
|
||||
WRAPPER = 32
|
||||
NEEDCTXT = 64
|
||||
)
|
||||
369
src/cmd/internal/ld/util.go
Normal file
369
src/cmd/internal/ld/util.go
Normal file
|
|
@ -0,0 +1,369 @@
|
|||
// Copyright 2015 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package ld
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
"runtime/pprof"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
func cstring(x []byte) string {
|
||||
i := bytes.IndexByte(x, '\x00')
|
||||
if i >= 0 {
|
||||
x = x[:i]
|
||||
}
|
||||
return string(x)
|
||||
}
|
||||
|
||||
func plan9quote(s string) string {
|
||||
if s == "" {
|
||||
goto needquote
|
||||
}
|
||||
for i := 0; i < len(s); i++ {
|
||||
if s[i] <= ' ' || s[i] == '\'' {
|
||||
goto needquote
|
||||
}
|
||||
}
|
||||
return s
|
||||
|
||||
needquote:
|
||||
return "'" + strings.Replace(s, "'", "''", -1) + "'"
|
||||
}
|
||||
|
||||
func tokenize(s string) []string {
|
||||
var f []string
|
||||
for {
|
||||
s = strings.TrimLeft(s, " \t\r\n")
|
||||
if s == "" {
|
||||
break
|
||||
}
|
||||
quote := false
|
||||
i := 0
|
||||
for ; i < len(s); i++ {
|
||||
if s[i] == '\'' {
|
||||
if quote && i+1 < len(s) && s[i+1] == '\'' {
|
||||
i++
|
||||
continue
|
||||
}
|
||||
quote = !quote
|
||||
}
|
||||
if !quote && (s[i] == ' ' || s[i] == '\t' || s[i] == '\r' || s[i] == '\n') {
|
||||
break
|
||||
}
|
||||
}
|
||||
next := s[:i]
|
||||
s = s[i:]
|
||||
if strings.Contains(next, "'") {
|
||||
var buf []byte
|
||||
quote := false
|
||||
for i := 0; i < len(next); i++ {
|
||||
if next[i] == '\'' {
|
||||
if quote && i+1 < len(next) && next[i+1] == '\'' {
|
||||
i++
|
||||
buf = append(buf, '\'')
|
||||
}
|
||||
quote = !quote
|
||||
continue
|
||||
}
|
||||
buf = append(buf, next[i])
|
||||
}
|
||||
next = string(buf)
|
||||
}
|
||||
f = append(f, next)
|
||||
}
|
||||
return f
|
||||
}
|
||||
|
||||
func cutStringAtNUL(s string) string {
|
||||
if i := strings.Index(s, "\x00"); i >= 0 {
|
||||
s = s[:i]
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
type Biobuf struct {
|
||||
unget [2]int
|
||||
numUnget int
|
||||
f *os.File
|
||||
r *bufio.Reader
|
||||
w *bufio.Writer
|
||||
linelen int
|
||||
}
|
||||
|
||||
func Bopenw(name string) (*Biobuf, error) {
|
||||
f, err := os.Create(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Biobuf{f: f, w: bufio.NewWriter(f)}, nil
|
||||
}
|
||||
|
||||
func Bopenr(name string) (*Biobuf, error) {
|
||||
f, err := os.Open(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Biobuf{f: f, r: bufio.NewReader(f)}, nil
|
||||
}
|
||||
|
||||
func Binitw(w *os.File) *Biobuf {
|
||||
return &Biobuf{w: bufio.NewWriter(w), f: w}
|
||||
}
|
||||
|
||||
func (b *Biobuf) Write(p []byte) (int, error) {
|
||||
return b.w.Write(p)
|
||||
}
|
||||
|
||||
func Bwritestring(b *Biobuf, p string) (int, error) {
|
||||
return b.w.WriteString(p)
|
||||
}
|
||||
|
||||
func Bseek(b *Biobuf, offset int64, whence int) int64 {
|
||||
if b.w != nil {
|
||||
if err := b.w.Flush(); err != nil {
|
||||
log.Fatalf("writing output: %v", err)
|
||||
}
|
||||
} else if b.r != nil {
|
||||
if whence == 1 {
|
||||
offset -= int64(b.r.Buffered())
|
||||
}
|
||||
}
|
||||
off, err := b.f.Seek(offset, whence)
|
||||
if err != nil {
|
||||
log.Panicf("seeking in output [%d %d %p]: %v", offset, whence, b.f, err)
|
||||
}
|
||||
if b.r != nil {
|
||||
b.r.Reset(b.f)
|
||||
}
|
||||
return off
|
||||
}
|
||||
|
||||
func Boffset(b *Biobuf) int64 {
|
||||
if b.w != nil {
|
||||
if err := b.w.Flush(); err != nil {
|
||||
log.Fatalf("writing output: %v", err)
|
||||
}
|
||||
}
|
||||
off, err := b.f.Seek(0, 1)
|
||||
if err != nil {
|
||||
log.Fatalf("seeking in output [0, 1]: %v", err)
|
||||
}
|
||||
if b.r != nil {
|
||||
off -= int64(b.r.Buffered())
|
||||
}
|
||||
return off
|
||||
}
|
||||
|
||||
func (b *Biobuf) Flush() error {
|
||||
return b.w.Flush()
|
||||
}
|
||||
|
||||
func Bwrite(b *Biobuf, p []byte) (int, error) {
|
||||
return b.w.Write(p)
|
||||
}
|
||||
|
||||
func Bputc(b *Biobuf, c byte) {
|
||||
b.w.WriteByte(c)
|
||||
}
|
||||
|
||||
const Beof = -1
|
||||
|
||||
func Bread(b *Biobuf, p []byte) int {
|
||||
if b.numUnget > 0 {
|
||||
Bseek(b, -int64(b.numUnget), 1)
|
||||
b.numUnget = 0
|
||||
}
|
||||
n, err := io.ReadFull(b.r, p)
|
||||
if n == 0 {
|
||||
if err != nil && err != io.EOF {
|
||||
n = -1
|
||||
}
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
func Bgetc(b *Biobuf) int {
|
||||
if b.numUnget > 0 {
|
||||
b.numUnget--
|
||||
return int(b.unget[b.numUnget])
|
||||
}
|
||||
c, err := b.r.ReadByte()
|
||||
r := int(c)
|
||||
if err != nil {
|
||||
r = -1
|
||||
}
|
||||
b.unget[1] = b.unget[0]
|
||||
b.unget[0] = r
|
||||
return r
|
||||
}
|
||||
|
||||
func Bgetrune(b *Biobuf) int {
|
||||
if b.numUnget > 0 {
|
||||
Bseek(b, -int64(b.numUnget), 1)
|
||||
b.numUnget = 0
|
||||
}
|
||||
r, _, err := b.r.ReadRune()
|
||||
if err != nil {
|
||||
return -1
|
||||
}
|
||||
return int(r)
|
||||
}
|
||||
|
||||
func Bungetrune(b *Biobuf) {
|
||||
b.r.UnreadRune()
|
||||
}
|
||||
|
||||
func (b *Biobuf) Read(p []byte) (int, error) {
|
||||
return b.r.Read(p)
|
||||
}
|
||||
|
||||
func Brdline(b *Biobuf, delim int) string {
|
||||
if b.numUnget > 0 {
|
||||
Bseek(b, -int64(b.numUnget), 1)
|
||||
b.numUnget = 0
|
||||
}
|
||||
s, err := b.r.ReadBytes(byte(delim))
|
||||
if err != nil {
|
||||
log.Fatalf("reading input: %v", err)
|
||||
}
|
||||
b.linelen = len(s)
|
||||
return string(s)
|
||||
}
|
||||
|
||||
func Brdstr(b *Biobuf, delim int, cut int) string {
|
||||
if b.numUnget > 0 {
|
||||
Bseek(b, -int64(b.numUnget), 1)
|
||||
b.numUnget = 0
|
||||
}
|
||||
s, err := b.r.ReadString(byte(delim))
|
||||
if err != nil {
|
||||
log.Fatalf("reading input: %v", err)
|
||||
}
|
||||
if len(s) > 0 && cut > 0 {
|
||||
s = s[:len(s)-1]
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
func Access(name string, mode int) int {
|
||||
if mode != 0 {
|
||||
panic("bad access")
|
||||
}
|
||||
_, err := os.Stat(name)
|
||||
if err != nil {
|
||||
return -1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func Blinelen(b *Biobuf) int {
|
||||
return b.linelen
|
||||
}
|
||||
|
||||
func Bungetc(b *Biobuf) {
|
||||
b.numUnget++
|
||||
}
|
||||
|
||||
func Bflush(b *Biobuf) error {
|
||||
return b.w.Flush()
|
||||
}
|
||||
|
||||
func Bterm(b *Biobuf) error {
|
||||
var err error
|
||||
if b.w != nil {
|
||||
err = b.w.Flush()
|
||||
}
|
||||
err1 := b.f.Close()
|
||||
if err == nil {
|
||||
err = err1
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// strings.Compare, introduced in Go 1.5.
|
||||
func stringsCompare(a, b string) int {
|
||||
if a == b {
|
||||
return 0
|
||||
}
|
||||
if a < b {
|
||||
return -1
|
||||
}
|
||||
return +1
|
||||
}
|
||||
|
||||
var atExitFuncs []func()
|
||||
|
||||
func AtExit(f func()) {
|
||||
atExitFuncs = append(atExitFuncs, f)
|
||||
}
|
||||
|
||||
func Exit(code int) {
|
||||
for i := len(atExitFuncs) - 1; i >= 0; i-- {
|
||||
f := atExitFuncs[i]
|
||||
atExitFuncs = atExitFuncs[:i]
|
||||
f()
|
||||
}
|
||||
os.Exit(code)
|
||||
}
|
||||
|
||||
var cpuprofile string
|
||||
var memprofile string
|
||||
|
||||
func startProfile() {
|
||||
if cpuprofile != "" {
|
||||
f, err := os.Create(cpuprofile)
|
||||
if err != nil {
|
||||
log.Fatalf("%v", err)
|
||||
}
|
||||
if err := pprof.StartCPUProfile(f); err != nil {
|
||||
log.Fatalf("%v", err)
|
||||
}
|
||||
AtExit(pprof.StopCPUProfile)
|
||||
}
|
||||
if memprofile != "" {
|
||||
f, err := os.Create(memprofile)
|
||||
if err != nil {
|
||||
log.Fatalf("%v", err)
|
||||
}
|
||||
AtExit(func() {
|
||||
if err := pprof.WriteHeapProfile(f); err != nil {
|
||||
log.Fatalf("%v", err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func artrim(x []byte) string {
|
||||
i := 0
|
||||
j := len(x)
|
||||
for i < len(x) && x[i] == ' ' {
|
||||
i++
|
||||
}
|
||||
for j > i && x[j-1] == ' ' {
|
||||
j--
|
||||
}
|
||||
return string(x[i:j])
|
||||
}
|
||||
|
||||
func stringtouint32(x []uint32, s string) {
|
||||
for i := 0; len(s) > 0; i++ {
|
||||
var buf [4]byte
|
||||
s = s[copy(buf[:], s):]
|
||||
x[i] = binary.LittleEndian.Uint32(buf[:])
|
||||
}
|
||||
}
|
||||
|
||||
var start = time.Now()
|
||||
|
||||
func elapsed() float64 {
|
||||
return time.Since(start).Seconds()
|
||||
}
|
||||
1
src/cmd/internal/ld/z.go
Normal file
1
src/cmd/internal/ld/z.go
Normal file
|
|
@ -0,0 +1 @@
|
|||
package ld
|
||||
777
src/cmd/new5l/asm.go
Normal file
777
src/cmd/new5l/asm.go
Normal file
|
|
@ -0,0 +1,777 @@
|
|||
// Inferno utils/5l/asm.c
|
||||
// http://code.google.com/p/inferno-os/source/browse/utils/5l/asm.c
|
||||
//
|
||||
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
|
||||
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
|
||||
// Portions Copyright © 1997-1999 Vita Nuova Limited
|
||||
// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
|
||||
// Portions Copyright © 2004,2006 Bruce Ellis
|
||||
// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
|
||||
// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
|
||||
// Portions Copyright © 2009 The Go Authors. All rights reserved.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"cmd/internal/obj"
|
||||
"fmt"
|
||||
"log"
|
||||
)
|
||||
import "cmd/internal/ld"
|
||||
|
||||
func needlib(name string) int {
|
||||
var p string
|
||||
var s *ld.LSym
|
||||
|
||||
if name[0] == '\x00' {
|
||||
return 0
|
||||
}
|
||||
|
||||
/* reuse hash code in symbol table */
|
||||
p = fmt.Sprintf(".dynlib.%s", name)
|
||||
|
||||
s = ld.Linklookup(ld.Ctxt, p, 0)
|
||||
|
||||
if s.Type == 0 {
|
||||
s.Type = 100 // avoid SDATA, etc.
|
||||
return 1
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
func gentext() {
|
||||
}
|
||||
|
||||
// Preserve highest 8 bits of a, and do addition to lower 24-bit
|
||||
// of a and b; used to adjust ARM branch intruction's target
|
||||
func braddoff(a int32, b int32) int32 {
|
||||
return int32((uint32(a))&0xff000000 | 0x00ffffff&uint32(a+b))
|
||||
}
|
||||
|
||||
func adddynrela(rel *ld.LSym, s *ld.LSym, r *ld.Reloc) {
|
||||
ld.Addaddrplus(ld.Ctxt, rel, s, int64(r.Off))
|
||||
ld.Adduint32(ld.Ctxt, rel, ld.R_ARM_RELATIVE)
|
||||
}
|
||||
|
||||
func adddynrel(s *ld.LSym, r *ld.Reloc) {
|
||||
var targ *ld.LSym
|
||||
var rel *ld.LSym
|
||||
|
||||
targ = r.Sym
|
||||
ld.Ctxt.Cursym = s
|
||||
|
||||
switch r.Type {
|
||||
default:
|
||||
if r.Type >= 256 {
|
||||
ld.Diag("unexpected relocation type %d", r.Type)
|
||||
return
|
||||
}
|
||||
|
||||
// Handle relocations found in ELF object files.
|
||||
case 256 + ld.R_ARM_PLT32:
|
||||
r.Type = ld.R_CALLARM
|
||||
|
||||
if targ.Type == ld.SDYNIMPORT {
|
||||
addpltsym(ld.Ctxt, targ)
|
||||
r.Sym = ld.Linklookup(ld.Ctxt, ".plt", 0)
|
||||
r.Add = int64(braddoff(int32(r.Add), targ.Plt/4))
|
||||
}
|
||||
|
||||
return
|
||||
|
||||
case 256 + ld.R_ARM_THM_PC22: // R_ARM_THM_CALL
|
||||
ld.Diag("R_ARM_THM_CALL, are you using -marm?")
|
||||
|
||||
ld.Errorexit()
|
||||
return
|
||||
|
||||
case 256 + ld.R_ARM_GOT32: // R_ARM_GOT_BREL
|
||||
if targ.Type != ld.SDYNIMPORT {
|
||||
addgotsyminternal(ld.Ctxt, targ)
|
||||
} else {
|
||||
addgotsym(ld.Ctxt, targ)
|
||||
}
|
||||
|
||||
r.Type = ld.R_CONST // write r->add during relocsym
|
||||
r.Sym = nil
|
||||
r.Add += int64(targ.Got)
|
||||
return
|
||||
|
||||
case 256 + ld.R_ARM_GOT_PREL: // GOT(nil) + A - nil
|
||||
if targ.Type != ld.SDYNIMPORT {
|
||||
addgotsyminternal(ld.Ctxt, targ)
|
||||
} else {
|
||||
addgotsym(ld.Ctxt, targ)
|
||||
}
|
||||
|
||||
r.Type = ld.R_PCREL
|
||||
r.Sym = ld.Linklookup(ld.Ctxt, ".got", 0)
|
||||
r.Add += int64(targ.Got) + 4
|
||||
return
|
||||
|
||||
case 256 + ld.R_ARM_GOTOFF: // R_ARM_GOTOFF32
|
||||
r.Type = ld.R_GOTOFF
|
||||
|
||||
return
|
||||
|
||||
case 256 + ld.R_ARM_GOTPC: // R_ARM_BASE_PREL
|
||||
r.Type = ld.R_PCREL
|
||||
|
||||
r.Sym = ld.Linklookup(ld.Ctxt, ".got", 0)
|
||||
r.Add += 4
|
||||
return
|
||||
|
||||
case 256 + ld.R_ARM_CALL:
|
||||
r.Type = ld.R_CALLARM
|
||||
if targ.Type == ld.SDYNIMPORT {
|
||||
addpltsym(ld.Ctxt, targ)
|
||||
r.Sym = ld.Linklookup(ld.Ctxt, ".plt", 0)
|
||||
r.Add = int64(braddoff(int32(r.Add), targ.Plt/4))
|
||||
}
|
||||
|
||||
return
|
||||
|
||||
case 256 + ld.R_ARM_REL32: // R_ARM_REL32
|
||||
r.Type = ld.R_PCREL
|
||||
|
||||
r.Add += 4
|
||||
return
|
||||
|
||||
case 256 + ld.R_ARM_ABS32:
|
||||
if targ.Type == ld.SDYNIMPORT {
|
||||
ld.Diag("unexpected R_ARM_ABS32 relocation for dynamic symbol %s", targ.Name)
|
||||
}
|
||||
r.Type = ld.R_ADDR
|
||||
return
|
||||
|
||||
// we can just ignore this, because we are targeting ARM V5+ anyway
|
||||
case 256 + ld.R_ARM_V4BX:
|
||||
if r.Sym != nil {
|
||||
// R_ARM_V4BX is ABS relocation, so this symbol is a dummy symbol, ignore it
|
||||
r.Sym.Type = 0
|
||||
}
|
||||
|
||||
r.Sym = nil
|
||||
return
|
||||
|
||||
case 256 + ld.R_ARM_PC24,
|
||||
256 + ld.R_ARM_JUMP24:
|
||||
r.Type = ld.R_CALLARM
|
||||
if targ.Type == ld.SDYNIMPORT {
|
||||
addpltsym(ld.Ctxt, targ)
|
||||
r.Sym = ld.Linklookup(ld.Ctxt, ".plt", 0)
|
||||
r.Add = int64(braddoff(int32(r.Add), targ.Plt/4))
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Handle references to ELF symbols from our own object files.
|
||||
if targ.Type != ld.SDYNIMPORT {
|
||||
return
|
||||
}
|
||||
|
||||
switch r.Type {
|
||||
case ld.R_CALLARM:
|
||||
addpltsym(ld.Ctxt, targ)
|
||||
r.Sym = ld.Linklookup(ld.Ctxt, ".plt", 0)
|
||||
r.Add = int64(targ.Plt)
|
||||
return
|
||||
|
||||
case ld.R_ADDR:
|
||||
if s.Type != ld.SDATA {
|
||||
break
|
||||
}
|
||||
if ld.Iself {
|
||||
adddynsym(ld.Ctxt, targ)
|
||||
rel = ld.Linklookup(ld.Ctxt, ".rel", 0)
|
||||
ld.Addaddrplus(ld.Ctxt, rel, s, int64(r.Off))
|
||||
ld.Adduint32(ld.Ctxt, rel, ld.ELF32_R_INFO(uint32(targ.Dynid), ld.R_ARM_GLOB_DAT)) // we need a nil + A dynmic reloc
|
||||
r.Type = ld.R_CONST // write r->add during relocsym
|
||||
r.Sym = nil
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
ld.Ctxt.Cursym = s
|
||||
ld.Diag("unsupported relocation for dynamic symbol %s (type=%d stype=%d)", targ.Name, r.Type, targ.Type)
|
||||
}
|
||||
|
||||
func elfreloc1(r *ld.Reloc, sectoff int64) int {
|
||||
var elfsym int32
|
||||
|
||||
ld.Thearch.Lput(uint32(sectoff))
|
||||
|
||||
elfsym = r.Xsym.Elfsym
|
||||
switch r.Type {
|
||||
default:
|
||||
return -1
|
||||
|
||||
case ld.R_ADDR:
|
||||
if r.Siz == 4 {
|
||||
ld.Thearch.Lput(ld.R_ARM_ABS32 | uint32(elfsym)<<8)
|
||||
} else {
|
||||
return -1
|
||||
}
|
||||
|
||||
case ld.R_PCREL:
|
||||
if r.Siz == 4 {
|
||||
ld.Thearch.Lput(ld.R_ARM_REL32 | uint32(elfsym)<<8)
|
||||
} else {
|
||||
return -1
|
||||
}
|
||||
|
||||
case ld.R_CALLARM:
|
||||
if r.Siz == 4 {
|
||||
if r.Add&0xff000000 == 0xeb000000 { // BL
|
||||
ld.Thearch.Lput(ld.R_ARM_CALL | uint32(elfsym)<<8)
|
||||
} else {
|
||||
ld.Thearch.Lput(ld.R_ARM_JUMP24 | uint32(elfsym)<<8)
|
||||
}
|
||||
} else {
|
||||
return -1
|
||||
}
|
||||
|
||||
case ld.R_TLS:
|
||||
if r.Siz == 4 {
|
||||
if ld.Flag_shared != 0 {
|
||||
ld.Thearch.Lput(ld.R_ARM_TLS_IE32 | uint32(elfsym)<<8)
|
||||
} else {
|
||||
ld.Thearch.Lput(ld.R_ARM_TLS_LE32 | uint32(elfsym)<<8)
|
||||
}
|
||||
} else {
|
||||
return -1
|
||||
}
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
func elfsetupplt() {
|
||||
var plt *ld.LSym
|
||||
var got *ld.LSym
|
||||
|
||||
plt = ld.Linklookup(ld.Ctxt, ".plt", 0)
|
||||
got = ld.Linklookup(ld.Ctxt, ".got.plt", 0)
|
||||
if plt.Size == 0 {
|
||||
// str lr, [sp, #-4]!
|
||||
ld.Adduint32(ld.Ctxt, plt, 0xe52de004)
|
||||
|
||||
// ldr lr, [pc, #4]
|
||||
ld.Adduint32(ld.Ctxt, plt, 0xe59fe004)
|
||||
|
||||
// add lr, pc, lr
|
||||
ld.Adduint32(ld.Ctxt, plt, 0xe08fe00e)
|
||||
|
||||
// ldr pc, [lr, #8]!
|
||||
ld.Adduint32(ld.Ctxt, plt, 0xe5bef008)
|
||||
|
||||
// .word &GLOBAL_OFFSET_TABLE[0] - .
|
||||
ld.Addpcrelplus(ld.Ctxt, plt, got, 4)
|
||||
|
||||
// the first .plt entry requires 3 .plt.got entries
|
||||
ld.Adduint32(ld.Ctxt, got, 0)
|
||||
|
||||
ld.Adduint32(ld.Ctxt, got, 0)
|
||||
ld.Adduint32(ld.Ctxt, got, 0)
|
||||
}
|
||||
}
|
||||
|
||||
func machoreloc1(r *ld.Reloc, sectoff int64) int {
|
||||
var v uint32
|
||||
var rs *ld.LSym
|
||||
|
||||
rs = r.Xsym
|
||||
|
||||
if rs.Type == ld.SHOSTOBJ || r.Type == ld.R_CALLARM {
|
||||
if rs.Dynid < 0 {
|
||||
ld.Diag("reloc %d to non-macho symbol %s type=%d", r.Type, rs.Name, rs.Type)
|
||||
return -1
|
||||
}
|
||||
|
||||
v = uint32(rs.Dynid)
|
||||
v |= 1 << 27 // external relocation
|
||||
} else {
|
||||
v = uint32((rs.Sect.(*ld.Section)).Extnum)
|
||||
if v == 0 {
|
||||
ld.Diag("reloc %d to symbol %s in non-macho section %s type=%d", r.Type, rs.Name, (rs.Sect.(*ld.Section)).Name, rs.Type)
|
||||
return -1
|
||||
}
|
||||
}
|
||||
|
||||
switch r.Type {
|
||||
default:
|
||||
return -1
|
||||
|
||||
case ld.R_ADDR:
|
||||
v |= ld.MACHO_GENERIC_RELOC_VANILLA << 28
|
||||
|
||||
case ld.R_CALLARM:
|
||||
v |= 1 << 24 // pc-relative bit
|
||||
v |= ld.MACHO_ARM_RELOC_BR24 << 28
|
||||
}
|
||||
|
||||
switch r.Siz {
|
||||
default:
|
||||
return -1
|
||||
|
||||
case 1:
|
||||
v |= 0 << 25
|
||||
|
||||
case 2:
|
||||
v |= 1 << 25
|
||||
|
||||
case 4:
|
||||
v |= 2 << 25
|
||||
|
||||
case 8:
|
||||
v |= 3 << 25
|
||||
}
|
||||
|
||||
ld.Thearch.Lput(uint32(sectoff))
|
||||
ld.Thearch.Lput(v)
|
||||
return 0
|
||||
}
|
||||
|
||||
func archreloc(r *ld.Reloc, s *ld.LSym, val *int64) int {
|
||||
var rs *ld.LSym
|
||||
|
||||
if ld.Linkmode == ld.LinkExternal {
|
||||
switch r.Type {
|
||||
case ld.R_CALLARM:
|
||||
r.Done = 0
|
||||
|
||||
// set up addend for eventual relocation via outer symbol.
|
||||
rs = r.Sym
|
||||
|
||||
r.Xadd = r.Add
|
||||
if r.Xadd&0x800000 != 0 {
|
||||
r.Xadd |= ^0xffffff
|
||||
}
|
||||
r.Xadd *= 4
|
||||
for rs.Outer != nil {
|
||||
r.Xadd += ld.Symaddr(rs) - ld.Symaddr(rs.Outer)
|
||||
rs = rs.Outer
|
||||
}
|
||||
|
||||
if rs.Type != ld.SHOSTOBJ && rs.Sect == nil {
|
||||
ld.Diag("missing section for %s", rs.Name)
|
||||
}
|
||||
r.Xsym = rs
|
||||
|
||||
// ld64 for arm seems to want the symbol table to contain offset
|
||||
// into the section rather than pseudo virtual address that contains
|
||||
// the section load address.
|
||||
// we need to compensate that by removing the instruction's address
|
||||
// from addend.
|
||||
if ld.HEADTYPE == ld.Hdarwin {
|
||||
r.Xadd -= ld.Symaddr(s) + int64(r.Off)
|
||||
}
|
||||
|
||||
*val = int64(braddoff(int32(0xff000000&uint32(r.Add)), int32(0xffffff&uint32(r.Xadd/4))))
|
||||
return 0
|
||||
}
|
||||
|
||||
return -1
|
||||
}
|
||||
|
||||
switch r.Type {
|
||||
case ld.R_CONST:
|
||||
*val = r.Add
|
||||
return 0
|
||||
|
||||
case ld.R_GOTOFF:
|
||||
*val = ld.Symaddr(r.Sym) + r.Add - ld.Symaddr(ld.Linklookup(ld.Ctxt, ".got", 0))
|
||||
return 0
|
||||
|
||||
// The following three arch specific relocations are only for generation of
|
||||
// Linux/ARM ELF's PLT entry (3 assembler instruction)
|
||||
case ld.R_PLT0: // add ip, pc, #0xXX00000
|
||||
if ld.Symaddr(ld.Linklookup(ld.Ctxt, ".got.plt", 0)) < ld.Symaddr(ld.Linklookup(ld.Ctxt, ".plt", 0)) {
|
||||
ld.Diag(".got.plt should be placed after .plt section.")
|
||||
}
|
||||
*val = 0xe28fc600 + (0xff & (int64(uint32(ld.Symaddr(r.Sym)-(ld.Symaddr(ld.Linklookup(ld.Ctxt, ".plt", 0))+int64(r.Off))+r.Add)) >> 20))
|
||||
return 0
|
||||
|
||||
case ld.R_PLT1: // add ip, ip, #0xYY000
|
||||
*val = 0xe28cca00 + (0xff & (int64(uint32(ld.Symaddr(r.Sym)-(ld.Symaddr(ld.Linklookup(ld.Ctxt, ".plt", 0))+int64(r.Off))+r.Add+4)) >> 12))
|
||||
|
||||
return 0
|
||||
|
||||
case ld.R_PLT2: // ldr pc, [ip, #0xZZZ]!
|
||||
*val = 0xe5bcf000 + (0xfff & int64(uint32(ld.Symaddr(r.Sym)-(ld.Symaddr(ld.Linklookup(ld.Ctxt, ".plt", 0))+int64(r.Off))+r.Add+8)))
|
||||
|
||||
return 0
|
||||
|
||||
case ld.R_CALLARM: // bl XXXXXX or b YYYYYY
|
||||
*val = int64(braddoff(int32(0xff000000&uint32(r.Add)), int32(0xffffff&uint32((ld.Symaddr(r.Sym)+int64((uint32(r.Add))*4)-(s.Value+int64(r.Off)))/4))))
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
return -1
|
||||
}
|
||||
|
||||
func archrelocvariant(r *ld.Reloc, s *ld.LSym, t int64) int64 {
|
||||
log.Fatalf("unexpected relocation variant")
|
||||
return t
|
||||
}
|
||||
|
||||
func addpltreloc(ctxt *ld.Link, plt *ld.LSym, got *ld.LSym, sym *ld.LSym, typ int) *ld.Reloc {
|
||||
var r *ld.Reloc
|
||||
|
||||
r = ld.Addrel(plt)
|
||||
r.Sym = got
|
||||
r.Off = int32(plt.Size)
|
||||
r.Siz = 4
|
||||
r.Type = int32(typ)
|
||||
r.Add = int64(sym.Got) - 8
|
||||
|
||||
plt.Reachable = true
|
||||
plt.Size += 4
|
||||
ld.Symgrow(ctxt, plt, plt.Size)
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
func addpltsym(ctxt *ld.Link, s *ld.LSym) {
|
||||
var plt *ld.LSym
|
||||
var got *ld.LSym
|
||||
var rel *ld.LSym
|
||||
|
||||
if s.Plt >= 0 {
|
||||
return
|
||||
}
|
||||
|
||||
adddynsym(ctxt, s)
|
||||
|
||||
if ld.Iself {
|
||||
plt = ld.Linklookup(ctxt, ".plt", 0)
|
||||
got = ld.Linklookup(ctxt, ".got.plt", 0)
|
||||
rel = ld.Linklookup(ctxt, ".rel.plt", 0)
|
||||
if plt.Size == 0 {
|
||||
elfsetupplt()
|
||||
}
|
||||
|
||||
// .got entry
|
||||
s.Got = int32(got.Size)
|
||||
|
||||
// In theory, all GOT should point to the first PLT entry,
|
||||
// Linux/ARM's dynamic linker will do that for us, but FreeBSD/ARM's
|
||||
// dynamic linker won't, so we'd better do it ourselves.
|
||||
ld.Addaddrplus(ctxt, got, plt, 0)
|
||||
|
||||
// .plt entry, this depends on the .got entry
|
||||
s.Plt = int32(plt.Size)
|
||||
|
||||
addpltreloc(ctxt, plt, got, s, ld.R_PLT0) // add lr, pc, #0xXX00000
|
||||
addpltreloc(ctxt, plt, got, s, ld.R_PLT1) // add lr, lr, #0xYY000
|
||||
addpltreloc(ctxt, plt, got, s, ld.R_PLT2) // ldr pc, [lr, #0xZZZ]!
|
||||
|
||||
// rel
|
||||
ld.Addaddrplus(ctxt, rel, got, int64(s.Got))
|
||||
|
||||
ld.Adduint32(ctxt, rel, ld.ELF32_R_INFO(uint32(s.Dynid), ld.R_ARM_JUMP_SLOT))
|
||||
} else {
|
||||
ld.Diag("addpltsym: unsupported binary format")
|
||||
}
|
||||
}
|
||||
|
||||
func addgotsyminternal(ctxt *ld.Link, s *ld.LSym) {
|
||||
var got *ld.LSym
|
||||
|
||||
if s.Got >= 0 {
|
||||
return
|
||||
}
|
||||
|
||||
got = ld.Linklookup(ctxt, ".got", 0)
|
||||
s.Got = int32(got.Size)
|
||||
|
||||
ld.Addaddrplus(ctxt, got, s, 0)
|
||||
|
||||
if ld.Iself {
|
||||
} else {
|
||||
ld.Diag("addgotsyminternal: unsupported binary format")
|
||||
}
|
||||
}
|
||||
|
||||
func addgotsym(ctxt *ld.Link, s *ld.LSym) {
|
||||
var got *ld.LSym
|
||||
var rel *ld.LSym
|
||||
|
||||
if s.Got >= 0 {
|
||||
return
|
||||
}
|
||||
|
||||
adddynsym(ctxt, s)
|
||||
got = ld.Linklookup(ctxt, ".got", 0)
|
||||
s.Got = int32(got.Size)
|
||||
ld.Adduint32(ctxt, got, 0)
|
||||
|
||||
if ld.Iself {
|
||||
rel = ld.Linklookup(ctxt, ".rel", 0)
|
||||
ld.Addaddrplus(ctxt, rel, got, int64(s.Got))
|
||||
ld.Adduint32(ctxt, rel, ld.ELF32_R_INFO(uint32(s.Dynid), ld.R_ARM_GLOB_DAT))
|
||||
} else {
|
||||
ld.Diag("addgotsym: unsupported binary format")
|
||||
}
|
||||
}
|
||||
|
||||
func adddynsym(ctxt *ld.Link, s *ld.LSym) {
|
||||
var d *ld.LSym
|
||||
var t int
|
||||
var name string
|
||||
|
||||
if s.Dynid >= 0 {
|
||||
return
|
||||
}
|
||||
|
||||
if ld.Iself {
|
||||
s.Dynid = int32(ld.Nelfsym)
|
||||
ld.Nelfsym++
|
||||
|
||||
d = ld.Linklookup(ctxt, ".dynsym", 0)
|
||||
|
||||
/* name */
|
||||
name = s.Extname
|
||||
|
||||
ld.Adduint32(ctxt, d, uint32(ld.Addstring(ld.Linklookup(ctxt, ".dynstr", 0), name)))
|
||||
|
||||
/* value */
|
||||
if s.Type == ld.SDYNIMPORT {
|
||||
ld.Adduint32(ctxt, d, 0)
|
||||
} else {
|
||||
ld.Addaddr(ctxt, d, s)
|
||||
}
|
||||
|
||||
/* size */
|
||||
ld.Adduint32(ctxt, d, 0)
|
||||
|
||||
/* type */
|
||||
t = ld.STB_GLOBAL << 4
|
||||
|
||||
if (s.Cgoexport&ld.CgoExportDynamic != 0) && s.Type&ld.SMASK == ld.STEXT {
|
||||
t |= ld.STT_FUNC
|
||||
} else {
|
||||
t |= ld.STT_OBJECT
|
||||
}
|
||||
ld.Adduint8(ctxt, d, uint8(t))
|
||||
ld.Adduint8(ctxt, d, 0)
|
||||
|
||||
/* shndx */
|
||||
if s.Type == ld.SDYNIMPORT {
|
||||
ld.Adduint16(ctxt, d, ld.SHN_UNDEF)
|
||||
} else {
|
||||
ld.Adduint16(ctxt, d, 1)
|
||||
}
|
||||
} else {
|
||||
ld.Diag("adddynsym: unsupported binary format")
|
||||
}
|
||||
}
|
||||
|
||||
func adddynlib(lib string) {
|
||||
var s *ld.LSym
|
||||
|
||||
if needlib(lib) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
if ld.Iself {
|
||||
s = ld.Linklookup(ld.Ctxt, ".dynstr", 0)
|
||||
if s.Size == 0 {
|
||||
ld.Addstring(s, "")
|
||||
}
|
||||
ld.Elfwritedynent(ld.Linklookup(ld.Ctxt, ".dynamic", 0), ld.DT_NEEDED, uint64(ld.Addstring(s, lib)))
|
||||
} else if ld.HEADTYPE == ld.Hdarwin {
|
||||
ld.Machoadddynlib(lib)
|
||||
} else {
|
||||
ld.Diag("adddynlib: unsupported binary format")
|
||||
}
|
||||
}
|
||||
|
||||
func asmb() {
|
||||
var symo uint32
|
||||
var dwarfoff uint32
|
||||
var machlink uint32
|
||||
var sect *ld.Section
|
||||
var sym *ld.LSym
|
||||
var i int
|
||||
|
||||
if ld.Debug['v'] != 0 {
|
||||
fmt.Fprintf(&ld.Bso, "%5.2f asmb\n", obj.Cputime())
|
||||
}
|
||||
ld.Bflush(&ld.Bso)
|
||||
|
||||
if ld.Iself {
|
||||
ld.Asmbelfsetup()
|
||||
}
|
||||
|
||||
sect = ld.Segtext.Sect
|
||||
ld.Cseek(int64(sect.Vaddr - ld.Segtext.Vaddr + ld.Segtext.Fileoff))
|
||||
ld.Codeblk(int64(sect.Vaddr), int64(sect.Length))
|
||||
for sect = sect.Next; sect != nil; sect = sect.Next {
|
||||
ld.Cseek(int64(sect.Vaddr - ld.Segtext.Vaddr + ld.Segtext.Fileoff))
|
||||
ld.Datblk(int64(sect.Vaddr), int64(sect.Length))
|
||||
}
|
||||
|
||||
if ld.Segrodata.Filelen > 0 {
|
||||
if ld.Debug['v'] != 0 {
|
||||
fmt.Fprintf(&ld.Bso, "%5.2f rodatblk\n", obj.Cputime())
|
||||
}
|
||||
ld.Bflush(&ld.Bso)
|
||||
|
||||
ld.Cseek(int64(ld.Segrodata.Fileoff))
|
||||
ld.Datblk(int64(ld.Segrodata.Vaddr), int64(ld.Segrodata.Filelen))
|
||||
}
|
||||
|
||||
if ld.Debug['v'] != 0 {
|
||||
fmt.Fprintf(&ld.Bso, "%5.2f datblk\n", obj.Cputime())
|
||||
}
|
||||
ld.Bflush(&ld.Bso)
|
||||
|
||||
ld.Cseek(int64(ld.Segdata.Fileoff))
|
||||
ld.Datblk(int64(ld.Segdata.Vaddr), int64(ld.Segdata.Filelen))
|
||||
|
||||
machlink = 0
|
||||
if ld.HEADTYPE == ld.Hdarwin {
|
||||
if ld.Debug['v'] != 0 {
|
||||
fmt.Fprintf(&ld.Bso, "%5.2f dwarf\n", obj.Cputime())
|
||||
}
|
||||
|
||||
if ld.Debug['w'] == 0 {
|
||||
dwarfoff = uint32(ld.Rnd(int64(uint64(ld.HEADR)+ld.Segtext.Length), int64(ld.INITRND)) + ld.Rnd(int64(ld.Segdata.Filelen), int64(ld.INITRND)))
|
||||
ld.Cseek(int64(dwarfoff))
|
||||
|
||||
ld.Segdwarf.Fileoff = uint64(ld.Cpos())
|
||||
ld.Dwarfemitdebugsections()
|
||||
ld.Segdwarf.Filelen = uint64(ld.Cpos()) - ld.Segdwarf.Fileoff
|
||||
}
|
||||
|
||||
machlink = uint32(ld.Domacholink())
|
||||
}
|
||||
|
||||
/* output symbol table */
|
||||
ld.Symsize = 0
|
||||
|
||||
ld.Lcsize = 0
|
||||
symo = 0
|
||||
if ld.Debug['s'] == 0 {
|
||||
// TODO: rationalize
|
||||
if ld.Debug['v'] != 0 {
|
||||
fmt.Fprintf(&ld.Bso, "%5.2f sym\n", obj.Cputime())
|
||||
}
|
||||
ld.Bflush(&ld.Bso)
|
||||
switch ld.HEADTYPE {
|
||||
default:
|
||||
if ld.Iself {
|
||||
symo = uint32(ld.Segdata.Fileoff + ld.Segdata.Filelen)
|
||||
symo = uint32(ld.Rnd(int64(symo), int64(ld.INITRND)))
|
||||
}
|
||||
|
||||
case ld.Hplan9:
|
||||
symo = uint32(ld.Segdata.Fileoff + ld.Segdata.Filelen)
|
||||
|
||||
case ld.Hdarwin:
|
||||
symo = uint32(ld.Rnd(int64(uint64(ld.HEADR)+ld.Segtext.Filelen), int64(ld.INITRND)) + ld.Rnd(int64(ld.Segdata.Filelen), int64(ld.INITRND)) + int64(machlink))
|
||||
}
|
||||
|
||||
ld.Cseek(int64(symo))
|
||||
switch ld.HEADTYPE {
|
||||
default:
|
||||
if ld.Iself {
|
||||
if ld.Debug['v'] != 0 {
|
||||
fmt.Fprintf(&ld.Bso, "%5.2f elfsym\n", obj.Cputime())
|
||||
}
|
||||
ld.Asmelfsym()
|
||||
ld.Cflush()
|
||||
ld.Cwrite(ld.Elfstrdat)
|
||||
|
||||
if ld.Debug['v'] != 0 {
|
||||
fmt.Fprintf(&ld.Bso, "%5.2f dwarf\n", obj.Cputime())
|
||||
}
|
||||
ld.Dwarfemitdebugsections()
|
||||
|
||||
if ld.Linkmode == ld.LinkExternal {
|
||||
ld.Elfemitreloc()
|
||||
}
|
||||
}
|
||||
|
||||
case ld.Hplan9:
|
||||
ld.Asmplan9sym()
|
||||
ld.Cflush()
|
||||
|
||||
sym = ld.Linklookup(ld.Ctxt, "pclntab", 0)
|
||||
if sym != nil {
|
||||
ld.Lcsize = int32(len(sym.P))
|
||||
for i = 0; int32(i) < ld.Lcsize; i++ {
|
||||
ld.Cput(uint8(sym.P[i]))
|
||||
}
|
||||
|
||||
ld.Cflush()
|
||||
}
|
||||
|
||||
case ld.Hdarwin:
|
||||
if ld.Linkmode == ld.LinkExternal {
|
||||
ld.Machoemitreloc()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ld.Ctxt.Cursym = nil
|
||||
if ld.Debug['v'] != 0 {
|
||||
fmt.Fprintf(&ld.Bso, "%5.2f header\n", obj.Cputime())
|
||||
}
|
||||
ld.Bflush(&ld.Bso)
|
||||
ld.Cseek(0)
|
||||
switch ld.HEADTYPE {
|
||||
default:
|
||||
case ld.Hplan9: /* plan 9 */
|
||||
ld.Thearch.Lput(0x647) /* magic */
|
||||
ld.Thearch.Lput(uint32(ld.Segtext.Filelen)) /* sizes */
|
||||
ld.Thearch.Lput(uint32(ld.Segdata.Filelen))
|
||||
ld.Thearch.Lput(uint32(ld.Segdata.Length - ld.Segdata.Filelen))
|
||||
ld.Thearch.Lput(uint32(ld.Symsize)) /* nsyms */
|
||||
ld.Thearch.Lput(uint32(ld.Entryvalue())) /* va of entry */
|
||||
ld.Thearch.Lput(0)
|
||||
ld.Thearch.Lput(uint32(ld.Lcsize))
|
||||
|
||||
case ld.Hlinux,
|
||||
ld.Hfreebsd,
|
||||
ld.Hnetbsd,
|
||||
ld.Hopenbsd,
|
||||
ld.Hnacl:
|
||||
ld.Asmbelf(int64(symo))
|
||||
|
||||
case ld.Hdarwin:
|
||||
ld.Asmbmacho()
|
||||
}
|
||||
|
||||
ld.Cflush()
|
||||
if ld.Debug['c'] != 0 {
|
||||
fmt.Printf("textsize=%d\n", ld.Segtext.Filelen)
|
||||
fmt.Printf("datsize=%d\n", ld.Segdata.Filelen)
|
||||
fmt.Printf("bsssize=%d\n", ld.Segdata.Length-ld.Segdata.Filelen)
|
||||
fmt.Printf("symsize=%d\n", ld.Symsize)
|
||||
fmt.Printf("lcsize=%d\n", ld.Lcsize)
|
||||
fmt.Printf("total=%d\n", ld.Segtext.Filelen+ld.Segdata.Length+uint64(ld.Symsize)+uint64(ld.Lcsize))
|
||||
}
|
||||
}
|
||||
78
src/cmd/new5l/l.go
Normal file
78
src/cmd/new5l/l.go
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
// Inferno utils/5l/asm.c
|
||||
// http://code.google.com/p/inferno-os/source/browse/utils/5l/asm.c
|
||||
//
|
||||
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
|
||||
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
|
||||
// Portions Copyright © 1997-1999 Vita Nuova Limited
|
||||
// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
|
||||
// Portions Copyright © 2004,2006 Bruce Ellis
|
||||
// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
|
||||
// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
|
||||
// Portions Copyright © 2009 The Go Authors. All rights reserved.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
package main
|
||||
|
||||
// Writing object files.
|
||||
|
||||
// Inferno utils/5l/l.h
|
||||
// http://code.google.com/p/inferno-os/source/browse/utils/5l/l.h
|
||||
//
|
||||
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
|
||||
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
|
||||
// Portions Copyright © 1997-1999 Vita Nuova Limited
|
||||
// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
|
||||
// Portions Copyright © 2004,2006 Bruce Ellis
|
||||
// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
|
||||
// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
|
||||
// Portions Copyright © 2009 The Go Authors. All rights reserved.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
const (
|
||||
thechar = '5'
|
||||
PtrSize = 4
|
||||
IntSize = 4
|
||||
RegSize = 4
|
||||
MaxAlign = 8
|
||||
FuncAlign = 4
|
||||
MINLC = 4
|
||||
)
|
||||
|
||||
/* Used by ../ld/dwarf.c */
|
||||
const (
|
||||
DWARFREGSP = 13
|
||||
)
|
||||
182
src/cmd/new5l/obj.go
Normal file
182
src/cmd/new5l/obj.go
Normal file
|
|
@ -0,0 +1,182 @@
|
|||
// Inferno utils/5l/obj.c
|
||||
// http://code.google.com/p/inferno-os/source/browse/utils/5l/obj.c
|
||||
//
|
||||
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
|
||||
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
|
||||
// Portions Copyright © 1997-1999 Vita Nuova Limited
|
||||
// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
|
||||
// Portions Copyright © 2004,2006 Bruce Ellis
|
||||
// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
|
||||
// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
|
||||
// Portions Copyright © 2009 The Go Authors. All rights reserved.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"cmd/internal/obj"
|
||||
"fmt"
|
||||
"log"
|
||||
)
|
||||
import "cmd/internal/ld"
|
||||
|
||||
// Reading object files.
|
||||
|
||||
func main() {
|
||||
linkarchinit()
|
||||
ld.Ldmain()
|
||||
}
|
||||
|
||||
func linkarchinit() {
|
||||
ld.Thestring = "arm"
|
||||
ld.Thelinkarch = &ld.Linkarm
|
||||
|
||||
ld.Thearch.Thechar = thechar
|
||||
ld.Thearch.Ptrsize = ld.Thelinkarch.Ptrsize
|
||||
ld.Thearch.Intsize = ld.Thelinkarch.Ptrsize
|
||||
ld.Thearch.Regsize = ld.Thelinkarch.Regsize
|
||||
ld.Thearch.Funcalign = FuncAlign
|
||||
ld.Thearch.Maxalign = MaxAlign
|
||||
ld.Thearch.Minlc = MINLC
|
||||
ld.Thearch.Dwarfregsp = DWARFREGSP
|
||||
|
||||
ld.Thearch.Adddynlib = adddynlib
|
||||
ld.Thearch.Adddynrel = adddynrel
|
||||
ld.Thearch.Adddynsym = adddynsym
|
||||
ld.Thearch.Archinit = archinit
|
||||
ld.Thearch.Archreloc = archreloc
|
||||
ld.Thearch.Archrelocvariant = archrelocvariant
|
||||
ld.Thearch.Asmb = asmb
|
||||
ld.Thearch.Elfreloc1 = elfreloc1
|
||||
ld.Thearch.Elfsetupplt = elfsetupplt
|
||||
ld.Thearch.Gentext = gentext
|
||||
ld.Thearch.Machoreloc1 = machoreloc1
|
||||
ld.Thearch.Lput = ld.Lputl
|
||||
ld.Thearch.Wput = ld.Wputl
|
||||
ld.Thearch.Vput = ld.Vputl
|
||||
|
||||
ld.Thearch.Linuxdynld = "/lib/ld-linux.so.3" // 2 for OABI, 3 for EABI
|
||||
ld.Thearch.Freebsddynld = "/usr/libexec/ld-elf.so.1"
|
||||
ld.Thearch.Openbsddynld = "XXX"
|
||||
ld.Thearch.Netbsddynld = "/libexec/ld.elf_so"
|
||||
ld.Thearch.Dragonflydynld = "XXX"
|
||||
ld.Thearch.Solarisdynld = "XXX"
|
||||
}
|
||||
|
||||
func archinit() {
|
||||
var s *ld.LSym
|
||||
|
||||
// getgoextlinkenabled is based on GO_EXTLINK_ENABLED when
|
||||
// Go was built; see ../../make.bash.
|
||||
if ld.Linkmode == ld.LinkAuto && obj.Getgoextlinkenabled() == "0" {
|
||||
ld.Linkmode = ld.LinkInternal
|
||||
}
|
||||
|
||||
switch ld.HEADTYPE {
|
||||
default:
|
||||
if ld.Linkmode == ld.LinkAuto {
|
||||
ld.Linkmode = ld.LinkInternal
|
||||
}
|
||||
if ld.Linkmode == ld.LinkExternal && obj.Getgoextlinkenabled() != "1" {
|
||||
log.Fatalf("cannot use -linkmode=external with -H %s", ld.Headstr(int(ld.HEADTYPE)))
|
||||
}
|
||||
|
||||
case ld.Hlinux,
|
||||
ld.Hfreebsd,
|
||||
ld.Hnacl,
|
||||
ld.Hdarwin:
|
||||
break
|
||||
}
|
||||
|
||||
switch ld.HEADTYPE {
|
||||
default:
|
||||
ld.Diag("unknown -H option")
|
||||
ld.Errorexit()
|
||||
fallthrough
|
||||
|
||||
case ld.Hplan9: /* plan 9 */
|
||||
ld.HEADR = 32
|
||||
|
||||
if ld.INITTEXT == -1 {
|
||||
ld.INITTEXT = 4128
|
||||
}
|
||||
if ld.INITDAT == -1 {
|
||||
ld.INITDAT = 0
|
||||
}
|
||||
if ld.INITRND == -1 {
|
||||
ld.INITRND = 4096
|
||||
}
|
||||
|
||||
case ld.Hlinux, /* arm elf */
|
||||
ld.Hfreebsd,
|
||||
ld.Hnetbsd:
|
||||
ld.Debug['d'] = 0
|
||||
// with dynamic linking
|
||||
ld.Elfinit()
|
||||
ld.HEADR = ld.ELFRESERVE
|
||||
if ld.INITTEXT == -1 {
|
||||
ld.INITTEXT = 0x10000 + int64(ld.HEADR)
|
||||
}
|
||||
if ld.INITDAT == -1 {
|
||||
ld.INITDAT = 0
|
||||
}
|
||||
if ld.INITRND == -1 {
|
||||
ld.INITRND = 4096
|
||||
}
|
||||
|
||||
case ld.Hnacl:
|
||||
ld.Elfinit()
|
||||
ld.HEADR = 0x10000
|
||||
ld.Funcalign = 16
|
||||
if ld.INITTEXT == -1 {
|
||||
ld.INITTEXT = 0x20000
|
||||
}
|
||||
if ld.INITDAT == -1 {
|
||||
ld.INITDAT = 0
|
||||
}
|
||||
if ld.INITRND == -1 {
|
||||
ld.INITRND = 0x10000
|
||||
}
|
||||
|
||||
case ld.Hdarwin: /* apple MACH */
|
||||
ld.Debug['w'] = 1 // disable DWARF generataion
|
||||
ld.Machoinit()
|
||||
ld.HEADR = ld.INITIAL_MACHO_HEADR
|
||||
if ld.INITTEXT == -1 {
|
||||
ld.INITTEXT = 4096 + int64(ld.HEADR)
|
||||
}
|
||||
if ld.INITDAT == -1 {
|
||||
ld.INITDAT = 0
|
||||
}
|
||||
if ld.INITRND == -1 {
|
||||
ld.INITRND = 4096
|
||||
}
|
||||
}
|
||||
|
||||
if ld.INITDAT != 0 && ld.INITRND != 0 {
|
||||
fmt.Printf("warning: -D0x%x is ignored because of -R0x%x\n", uint64(ld.INITDAT), uint32(ld.INITRND))
|
||||
}
|
||||
|
||||
// embed goarm to runtime.goarm
|
||||
s = ld.Linklookup(ld.Ctxt, "runtime.goarm", 0)
|
||||
|
||||
s.Type = ld.SRODATA
|
||||
ld.Adduint8(ld.Ctxt, s, uint8(ld.Ctxt.Goarm))
|
||||
}
|
||||
829
src/cmd/new6l/asm.go
Normal file
829
src/cmd/new6l/asm.go
Normal file
|
|
@ -0,0 +1,829 @@
|
|||
// Inferno utils/6l/asm.c
|
||||
// http://code.google.com/p/inferno-os/source/browse/utils/6l/asm.c
|
||||
//
|
||||
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
|
||||
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
|
||||
// Portions Copyright © 1997-1999 Vita Nuova Limited
|
||||
// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
|
||||
// Portions Copyright © 2004,2006 Bruce Ellis
|
||||
// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
|
||||
// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
|
||||
// Portions Copyright © 2009 The Go Authors. All rights reserved.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"cmd/internal/obj"
|
||||
"fmt"
|
||||
"log"
|
||||
)
|
||||
import "cmd/internal/ld"
|
||||
|
||||
func PADDR(x uint32) uint32 {
|
||||
return x &^ 0x80000000
|
||||
}
|
||||
|
||||
var zeroes string
|
||||
|
||||
func needlib(name string) int {
|
||||
var p string
|
||||
var s *ld.LSym
|
||||
|
||||
if name[0] == '\x00' {
|
||||
return 0
|
||||
}
|
||||
|
||||
/* reuse hash code in symbol table */
|
||||
p = fmt.Sprintf(".elfload.%s", name)
|
||||
|
||||
s = ld.Linklookup(ld.Ctxt, p, 0)
|
||||
|
||||
if s.Type == 0 {
|
||||
s.Type = 100 // avoid SDATA, etc.
|
||||
return 1
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
func gentext() {
|
||||
}
|
||||
|
||||
func adddynrela(rela *ld.LSym, s *ld.LSym, r *ld.Reloc) {
|
||||
ld.Addaddrplus(ld.Ctxt, rela, s, int64(r.Off))
|
||||
ld.Adduint64(ld.Ctxt, rela, ld.R_X86_64_RELATIVE)
|
||||
ld.Addaddrplus(ld.Ctxt, rela, r.Sym, r.Add) // Addend
|
||||
}
|
||||
|
||||
func adddynrel(s *ld.LSym, r *ld.Reloc) {
|
||||
var targ *ld.LSym
|
||||
var rela *ld.LSym
|
||||
var got *ld.LSym
|
||||
|
||||
targ = r.Sym
|
||||
ld.Ctxt.Cursym = s
|
||||
|
||||
switch r.Type {
|
||||
default:
|
||||
if r.Type >= 256 {
|
||||
ld.Diag("unexpected relocation type %d", r.Type)
|
||||
return
|
||||
}
|
||||
|
||||
// Handle relocations found in ELF object files.
|
||||
case 256 + ld.R_X86_64_PC32:
|
||||
if targ.Type == ld.SDYNIMPORT {
|
||||
ld.Diag("unexpected R_X86_64_PC32 relocation for dynamic symbol %s", targ.Name)
|
||||
}
|
||||
if targ.Type == 0 || targ.Type == ld.SXREF {
|
||||
ld.Diag("unknown symbol %s in pcrel", targ.Name)
|
||||
}
|
||||
r.Type = ld.R_PCREL
|
||||
r.Add += 4
|
||||
return
|
||||
|
||||
case 256 + ld.R_X86_64_PLT32:
|
||||
r.Type = ld.R_PCREL
|
||||
r.Add += 4
|
||||
if targ.Type == ld.SDYNIMPORT {
|
||||
addpltsym(targ)
|
||||
r.Sym = ld.Linklookup(ld.Ctxt, ".plt", 0)
|
||||
r.Add += int64(targ.Plt)
|
||||
}
|
||||
|
||||
return
|
||||
|
||||
case 256 + ld.R_X86_64_GOTPCREL:
|
||||
if targ.Type != ld.SDYNIMPORT {
|
||||
// have symbol
|
||||
if r.Off >= 2 && s.P[r.Off-2] == 0x8b {
|
||||
// turn MOVQ of GOT entry into LEAQ of symbol itself
|
||||
s.P[r.Off-2] = 0x8d
|
||||
|
||||
r.Type = ld.R_PCREL
|
||||
r.Add += 4
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// fall back to using GOT and hope for the best (CMOV*)
|
||||
// TODO: just needs relocation, no need to put in .dynsym
|
||||
addgotsym(targ)
|
||||
|
||||
r.Type = ld.R_PCREL
|
||||
r.Sym = ld.Linklookup(ld.Ctxt, ".got", 0)
|
||||
r.Add += 4
|
||||
r.Add += int64(targ.Got)
|
||||
return
|
||||
|
||||
case 256 + ld.R_X86_64_64:
|
||||
if targ.Type == ld.SDYNIMPORT {
|
||||
ld.Diag("unexpected R_X86_64_64 relocation for dynamic symbol %s", targ.Name)
|
||||
}
|
||||
r.Type = ld.R_ADDR
|
||||
return
|
||||
|
||||
// TODO: What is the difference between all these?
|
||||
// Handle relocations found in Mach-O object files.
|
||||
case 512 + ld.MACHO_X86_64_RELOC_UNSIGNED*2 + 0,
|
||||
512 + ld.MACHO_X86_64_RELOC_SIGNED*2 + 0,
|
||||
512 + ld.MACHO_X86_64_RELOC_BRANCH*2 + 0:
|
||||
r.Type = ld.R_ADDR
|
||||
|
||||
if targ.Type == ld.SDYNIMPORT {
|
||||
ld.Diag("unexpected reloc for dynamic symbol %s", targ.Name)
|
||||
}
|
||||
return
|
||||
|
||||
case 512 + ld.MACHO_X86_64_RELOC_BRANCH*2 + 1:
|
||||
if targ.Type == ld.SDYNIMPORT {
|
||||
addpltsym(targ)
|
||||
r.Sym = ld.Linklookup(ld.Ctxt, ".plt", 0)
|
||||
r.Add = int64(targ.Plt)
|
||||
r.Type = ld.R_PCREL
|
||||
return
|
||||
}
|
||||
fallthrough
|
||||
|
||||
// fall through
|
||||
case 512 + ld.MACHO_X86_64_RELOC_UNSIGNED*2 + 1,
|
||||
512 + ld.MACHO_X86_64_RELOC_SIGNED*2 + 1,
|
||||
512 + ld.MACHO_X86_64_RELOC_SIGNED_1*2 + 1,
|
||||
512 + ld.MACHO_X86_64_RELOC_SIGNED_2*2 + 1,
|
||||
512 + ld.MACHO_X86_64_RELOC_SIGNED_4*2 + 1:
|
||||
r.Type = ld.R_PCREL
|
||||
|
||||
if targ.Type == ld.SDYNIMPORT {
|
||||
ld.Diag("unexpected pc-relative reloc for dynamic symbol %s", targ.Name)
|
||||
}
|
||||
return
|
||||
|
||||
case 512 + ld.MACHO_X86_64_RELOC_GOT_LOAD*2 + 1:
|
||||
if targ.Type != ld.SDYNIMPORT {
|
||||
// have symbol
|
||||
// turn MOVQ of GOT entry into LEAQ of symbol itself
|
||||
if r.Off < 2 || s.P[r.Off-2] != 0x8b {
|
||||
ld.Diag("unexpected GOT_LOAD reloc for non-dynamic symbol %s", targ.Name)
|
||||
return
|
||||
}
|
||||
|
||||
s.P[r.Off-2] = 0x8d
|
||||
r.Type = ld.R_PCREL
|
||||
return
|
||||
}
|
||||
fallthrough
|
||||
|
||||
// fall through
|
||||
case 512 + ld.MACHO_X86_64_RELOC_GOT*2 + 1:
|
||||
if targ.Type != ld.SDYNIMPORT {
|
||||
ld.Diag("unexpected GOT reloc for non-dynamic symbol %s", targ.Name)
|
||||
}
|
||||
addgotsym(targ)
|
||||
r.Type = ld.R_PCREL
|
||||
r.Sym = ld.Linklookup(ld.Ctxt, ".got", 0)
|
||||
r.Add += int64(targ.Got)
|
||||
return
|
||||
}
|
||||
|
||||
// Handle references to ELF symbols from our own object files.
|
||||
if targ.Type != ld.SDYNIMPORT {
|
||||
return
|
||||
}
|
||||
|
||||
switch r.Type {
|
||||
case ld.R_CALL,
|
||||
ld.R_PCREL:
|
||||
addpltsym(targ)
|
||||
r.Sym = ld.Linklookup(ld.Ctxt, ".plt", 0)
|
||||
r.Add = int64(targ.Plt)
|
||||
return
|
||||
|
||||
case ld.R_ADDR:
|
||||
if s.Type == ld.STEXT && ld.Iself {
|
||||
// The code is asking for the address of an external
|
||||
// function. We provide it with the address of the
|
||||
// correspondent GOT symbol.
|
||||
addgotsym(targ)
|
||||
|
||||
r.Sym = ld.Linklookup(ld.Ctxt, ".got", 0)
|
||||
r.Add += int64(targ.Got)
|
||||
return
|
||||
}
|
||||
|
||||
if s.Type != ld.SDATA {
|
||||
break
|
||||
}
|
||||
if ld.Iself {
|
||||
adddynsym(ld.Ctxt, targ)
|
||||
rela = ld.Linklookup(ld.Ctxt, ".rela", 0)
|
||||
ld.Addaddrplus(ld.Ctxt, rela, s, int64(r.Off))
|
||||
if r.Siz == 8 {
|
||||
ld.Adduint64(ld.Ctxt, rela, ld.ELF64_R_INFO(uint32(targ.Dynid), ld.R_X86_64_64))
|
||||
} else {
|
||||
ld.Adduint64(ld.Ctxt, rela, ld.ELF64_R_INFO(uint32(targ.Dynid), ld.R_X86_64_32))
|
||||
}
|
||||
ld.Adduint64(ld.Ctxt, rela, uint64(r.Add))
|
||||
r.Type = 256 // ignore during relocsym
|
||||
return
|
||||
}
|
||||
|
||||
if ld.HEADTYPE == ld.Hdarwin && s.Size == int64(ld.Thearch.Ptrsize) && r.Off == 0 {
|
||||
// Mach-O relocations are a royal pain to lay out.
|
||||
// They use a compact stateful bytecode representation
|
||||
// that is too much bother to deal with.
|
||||
// Instead, interpret the C declaration
|
||||
// void *_Cvar_stderr = &stderr;
|
||||
// as making _Cvar_stderr the name of a GOT entry
|
||||
// for stderr. This is separate from the usual GOT entry,
|
||||
// just in case the C code assigns to the variable,
|
||||
// and of course it only works for single pointers,
|
||||
// but we only need to support cgo and that's all it needs.
|
||||
adddynsym(ld.Ctxt, targ)
|
||||
|
||||
got = ld.Linklookup(ld.Ctxt, ".got", 0)
|
||||
s.Type = got.Type | ld.SSUB
|
||||
s.Outer = got
|
||||
s.Sub = got.Sub
|
||||
got.Sub = s
|
||||
s.Value = got.Size
|
||||
ld.Adduint64(ld.Ctxt, got, 0)
|
||||
ld.Adduint32(ld.Ctxt, ld.Linklookup(ld.Ctxt, ".linkedit.got", 0), uint32(targ.Dynid))
|
||||
r.Type = 256 // ignore during relocsym
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
ld.Ctxt.Cursym = s
|
||||
ld.Diag("unsupported relocation for dynamic symbol %s (type=%d stype=%d)", targ.Name, r.Type, targ.Type)
|
||||
}
|
||||
|
||||
func elfreloc1(r *ld.Reloc, sectoff int64) int {
|
||||
var elfsym int32
|
||||
|
||||
ld.Thearch.Vput(uint64(sectoff))
|
||||
|
||||
elfsym = r.Xsym.Elfsym
|
||||
switch r.Type {
|
||||
default:
|
||||
return -1
|
||||
|
||||
case ld.R_ADDR:
|
||||
if r.Siz == 4 {
|
||||
ld.Thearch.Vput(ld.R_X86_64_32 | uint64(elfsym)<<32)
|
||||
} else if r.Siz == 8 {
|
||||
ld.Thearch.Vput(ld.R_X86_64_64 | uint64(elfsym)<<32)
|
||||
} else {
|
||||
return -1
|
||||
}
|
||||
|
||||
case ld.R_TLS_LE:
|
||||
if r.Siz == 4 {
|
||||
ld.Thearch.Vput(ld.R_X86_64_TPOFF32 | uint64(elfsym)<<32)
|
||||
} else {
|
||||
return -1
|
||||
}
|
||||
|
||||
case ld.R_CALL:
|
||||
if r.Siz == 4 {
|
||||
if r.Xsym.Type == ld.SDYNIMPORT {
|
||||
ld.Thearch.Vput(ld.R_X86_64_GOTPCREL | uint64(elfsym)<<32)
|
||||
} else {
|
||||
ld.Thearch.Vput(ld.R_X86_64_PC32 | uint64(elfsym)<<32)
|
||||
}
|
||||
} else {
|
||||
return -1
|
||||
}
|
||||
|
||||
case ld.R_PCREL:
|
||||
if r.Siz == 4 {
|
||||
ld.Thearch.Vput(ld.R_X86_64_PC32 | uint64(elfsym)<<32)
|
||||
} else {
|
||||
return -1
|
||||
}
|
||||
|
||||
case ld.R_TLS:
|
||||
if r.Siz == 4 {
|
||||
if ld.Flag_shared != 0 {
|
||||
ld.Thearch.Vput(ld.R_X86_64_GOTTPOFF | uint64(elfsym)<<32)
|
||||
} else {
|
||||
ld.Thearch.Vput(ld.R_X86_64_TPOFF32 | uint64(elfsym)<<32)
|
||||
}
|
||||
} else {
|
||||
return -1
|
||||
}
|
||||
}
|
||||
|
||||
ld.Thearch.Vput(uint64(r.Xadd))
|
||||
return 0
|
||||
}
|
||||
|
||||
func machoreloc1(r *ld.Reloc, sectoff int64) int {
|
||||
var v uint32
|
||||
var rs *ld.LSym
|
||||
|
||||
rs = r.Xsym
|
||||
|
||||
if rs.Type == ld.SHOSTOBJ || r.Type == ld.R_PCREL {
|
||||
if rs.Dynid < 0 {
|
||||
ld.Diag("reloc %d to non-macho symbol %s type=%d", r.Type, rs.Name, rs.Type)
|
||||
return -1
|
||||
}
|
||||
|
||||
v = uint32(rs.Dynid)
|
||||
v |= 1 << 27 // external relocation
|
||||
} else {
|
||||
v = uint32((rs.Sect.(*ld.Section)).Extnum)
|
||||
if v == 0 {
|
||||
ld.Diag("reloc %d to symbol %s in non-macho section %s type=%d", r.Type, rs.Name, (rs.Sect.(*ld.Section)).Name, rs.Type)
|
||||
return -1
|
||||
}
|
||||
}
|
||||
|
||||
switch r.Type {
|
||||
default:
|
||||
return -1
|
||||
|
||||
case ld.R_ADDR:
|
||||
v |= ld.MACHO_X86_64_RELOC_UNSIGNED << 28
|
||||
|
||||
case ld.R_CALL:
|
||||
v |= 1 << 24 // pc-relative bit
|
||||
v |= ld.MACHO_X86_64_RELOC_BRANCH << 28
|
||||
|
||||
// NOTE: Only works with 'external' relocation. Forced above.
|
||||
case ld.R_PCREL:
|
||||
v |= 1 << 24 // pc-relative bit
|
||||
v |= ld.MACHO_X86_64_RELOC_SIGNED << 28
|
||||
}
|
||||
|
||||
switch r.Siz {
|
||||
default:
|
||||
return -1
|
||||
|
||||
case 1:
|
||||
v |= 0 << 25
|
||||
|
||||
case 2:
|
||||
v |= 1 << 25
|
||||
|
||||
case 4:
|
||||
v |= 2 << 25
|
||||
|
||||
case 8:
|
||||
v |= 3 << 25
|
||||
}
|
||||
|
||||
ld.Thearch.Lput(uint32(sectoff))
|
||||
ld.Thearch.Lput(v)
|
||||
return 0
|
||||
}
|
||||
|
||||
func archreloc(r *ld.Reloc, s *ld.LSym, val *int64) int {
|
||||
return -1
|
||||
}
|
||||
|
||||
func archrelocvariant(r *ld.Reloc, s *ld.LSym, t int64) int64 {
|
||||
log.Fatalf("unexpected relocation variant")
|
||||
return t
|
||||
}
|
||||
|
||||
func elfsetupplt() {
|
||||
var plt *ld.LSym
|
||||
var got *ld.LSym
|
||||
|
||||
plt = ld.Linklookup(ld.Ctxt, ".plt", 0)
|
||||
got = ld.Linklookup(ld.Ctxt, ".got.plt", 0)
|
||||
if plt.Size == 0 {
|
||||
// pushq got+8(IP)
|
||||
ld.Adduint8(ld.Ctxt, plt, 0xff)
|
||||
|
||||
ld.Adduint8(ld.Ctxt, plt, 0x35)
|
||||
ld.Addpcrelplus(ld.Ctxt, plt, got, 8)
|
||||
|
||||
// jmpq got+16(IP)
|
||||
ld.Adduint8(ld.Ctxt, plt, 0xff)
|
||||
|
||||
ld.Adduint8(ld.Ctxt, plt, 0x25)
|
||||
ld.Addpcrelplus(ld.Ctxt, plt, got, 16)
|
||||
|
||||
// nopl 0(AX)
|
||||
ld.Adduint32(ld.Ctxt, plt, 0x00401f0f)
|
||||
|
||||
// assume got->size == 0 too
|
||||
ld.Addaddrplus(ld.Ctxt, got, ld.Linklookup(ld.Ctxt, ".dynamic", 0), 0)
|
||||
|
||||
ld.Adduint64(ld.Ctxt, got, 0)
|
||||
ld.Adduint64(ld.Ctxt, got, 0)
|
||||
}
|
||||
}
|
||||
|
||||
func addpltsym(s *ld.LSym) {
|
||||
if s.Plt >= 0 {
|
||||
return
|
||||
}
|
||||
|
||||
adddynsym(ld.Ctxt, s)
|
||||
|
||||
if ld.Iself {
|
||||
var plt *ld.LSym
|
||||
var got *ld.LSym
|
||||
var rela *ld.LSym
|
||||
|
||||
plt = ld.Linklookup(ld.Ctxt, ".plt", 0)
|
||||
got = ld.Linklookup(ld.Ctxt, ".got.plt", 0)
|
||||
rela = ld.Linklookup(ld.Ctxt, ".rela.plt", 0)
|
||||
if plt.Size == 0 {
|
||||
elfsetupplt()
|
||||
}
|
||||
|
||||
// jmpq *got+size(IP)
|
||||
ld.Adduint8(ld.Ctxt, plt, 0xff)
|
||||
|
||||
ld.Adduint8(ld.Ctxt, plt, 0x25)
|
||||
ld.Addpcrelplus(ld.Ctxt, plt, got, got.Size)
|
||||
|
||||
// add to got: pointer to current pos in plt
|
||||
ld.Addaddrplus(ld.Ctxt, got, plt, plt.Size)
|
||||
|
||||
// pushq $x
|
||||
ld.Adduint8(ld.Ctxt, plt, 0x68)
|
||||
|
||||
ld.Adduint32(ld.Ctxt, plt, uint32((got.Size-24-8)/8))
|
||||
|
||||
// jmpq .plt
|
||||
ld.Adduint8(ld.Ctxt, plt, 0xe9)
|
||||
|
||||
ld.Adduint32(ld.Ctxt, plt, uint32(-(plt.Size + 4)))
|
||||
|
||||
// rela
|
||||
ld.Addaddrplus(ld.Ctxt, rela, got, got.Size-8)
|
||||
|
||||
ld.Adduint64(ld.Ctxt, rela, ld.ELF64_R_INFO(uint32(s.Dynid), ld.R_X86_64_JMP_SLOT))
|
||||
ld.Adduint64(ld.Ctxt, rela, 0)
|
||||
|
||||
s.Plt = int32(plt.Size - 16)
|
||||
} else if ld.HEADTYPE == ld.Hdarwin {
|
||||
// To do lazy symbol lookup right, we're supposed
|
||||
// to tell the dynamic loader which library each
|
||||
// symbol comes from and format the link info
|
||||
// section just so. I'm too lazy (ha!) to do that
|
||||
// so for now we'll just use non-lazy pointers,
|
||||
// which don't need to be told which library to use.
|
||||
//
|
||||
// http://networkpx.blogspot.com/2009/09/about-lcdyldinfoonly-command.html
|
||||
// has details about what we're avoiding.
|
||||
|
||||
var plt *ld.LSym
|
||||
|
||||
addgotsym(s)
|
||||
plt = ld.Linklookup(ld.Ctxt, ".plt", 0)
|
||||
|
||||
ld.Adduint32(ld.Ctxt, ld.Linklookup(ld.Ctxt, ".linkedit.plt", 0), uint32(s.Dynid))
|
||||
|
||||
// jmpq *got+size(IP)
|
||||
s.Plt = int32(plt.Size)
|
||||
|
||||
ld.Adduint8(ld.Ctxt, plt, 0xff)
|
||||
ld.Adduint8(ld.Ctxt, plt, 0x25)
|
||||
ld.Addpcrelplus(ld.Ctxt, plt, ld.Linklookup(ld.Ctxt, ".got", 0), int64(s.Got))
|
||||
} else {
|
||||
ld.Diag("addpltsym: unsupported binary format")
|
||||
}
|
||||
}
|
||||
|
||||
func addgotsym(s *ld.LSym) {
|
||||
var got *ld.LSym
|
||||
var rela *ld.LSym
|
||||
|
||||
if s.Got >= 0 {
|
||||
return
|
||||
}
|
||||
|
||||
adddynsym(ld.Ctxt, s)
|
||||
got = ld.Linklookup(ld.Ctxt, ".got", 0)
|
||||
s.Got = int32(got.Size)
|
||||
ld.Adduint64(ld.Ctxt, got, 0)
|
||||
|
||||
if ld.Iself {
|
||||
rela = ld.Linklookup(ld.Ctxt, ".rela", 0)
|
||||
ld.Addaddrplus(ld.Ctxt, rela, got, int64(s.Got))
|
||||
ld.Adduint64(ld.Ctxt, rela, ld.ELF64_R_INFO(uint32(s.Dynid), ld.R_X86_64_GLOB_DAT))
|
||||
ld.Adduint64(ld.Ctxt, rela, 0)
|
||||
} else if ld.HEADTYPE == ld.Hdarwin {
|
||||
ld.Adduint32(ld.Ctxt, ld.Linklookup(ld.Ctxt, ".linkedit.got", 0), uint32(s.Dynid))
|
||||
} else {
|
||||
ld.Diag("addgotsym: unsupported binary format")
|
||||
}
|
||||
}
|
||||
|
||||
func adddynsym(ctxt *ld.Link, s *ld.LSym) {
|
||||
var d *ld.LSym
|
||||
var t int
|
||||
var name string
|
||||
|
||||
if s.Dynid >= 0 {
|
||||
return
|
||||
}
|
||||
|
||||
if ld.Iself {
|
||||
s.Dynid = int32(ld.Nelfsym)
|
||||
ld.Nelfsym++
|
||||
|
||||
d = ld.Linklookup(ctxt, ".dynsym", 0)
|
||||
|
||||
name = s.Extname
|
||||
ld.Adduint32(ctxt, d, uint32(ld.Addstring(ld.Linklookup(ctxt, ".dynstr", 0), name)))
|
||||
|
||||
/* type */
|
||||
t = ld.STB_GLOBAL << 4
|
||||
|
||||
if s.Cgoexport != 0 && s.Type&ld.SMASK == ld.STEXT {
|
||||
t |= ld.STT_FUNC
|
||||
} else {
|
||||
t |= ld.STT_OBJECT
|
||||
}
|
||||
ld.Adduint8(ctxt, d, uint8(t))
|
||||
|
||||
/* reserved */
|
||||
ld.Adduint8(ctxt, d, 0)
|
||||
|
||||
/* section where symbol is defined */
|
||||
if s.Type == ld.SDYNIMPORT {
|
||||
ld.Adduint16(ctxt, d, ld.SHN_UNDEF)
|
||||
} else {
|
||||
ld.Adduint16(ctxt, d, 1)
|
||||
}
|
||||
|
||||
/* value */
|
||||
if s.Type == ld.SDYNIMPORT {
|
||||
ld.Adduint64(ctxt, d, 0)
|
||||
} else {
|
||||
ld.Addaddr(ctxt, d, s)
|
||||
}
|
||||
|
||||
/* size of object */
|
||||
ld.Adduint64(ctxt, d, uint64(s.Size))
|
||||
|
||||
if s.Cgoexport&ld.CgoExportDynamic == 0 && s.Dynimplib != "" && needlib(s.Dynimplib) != 0 {
|
||||
ld.Elfwritedynent(ld.Linklookup(ctxt, ".dynamic", 0), ld.DT_NEEDED, uint64(ld.Addstring(ld.Linklookup(ctxt, ".dynstr", 0), s.Dynimplib)))
|
||||
}
|
||||
} else if ld.HEADTYPE == ld.Hdarwin {
|
||||
ld.Diag("adddynsym: missed symbol %s (%s)", s.Name, s.Extname)
|
||||
} else if ld.HEADTYPE == ld.Hwindows {
|
||||
} else // already taken care of
|
||||
{
|
||||
ld.Diag("adddynsym: unsupported binary format")
|
||||
}
|
||||
}
|
||||
|
||||
func adddynlib(lib string) {
|
||||
var s *ld.LSym
|
||||
|
||||
if needlib(lib) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
if ld.Iself {
|
||||
s = ld.Linklookup(ld.Ctxt, ".dynstr", 0)
|
||||
if s.Size == 0 {
|
||||
ld.Addstring(s, "")
|
||||
}
|
||||
ld.Elfwritedynent(ld.Linklookup(ld.Ctxt, ".dynamic", 0), ld.DT_NEEDED, uint64(ld.Addstring(s, lib)))
|
||||
} else if ld.HEADTYPE == ld.Hdarwin {
|
||||
ld.Machoadddynlib(lib)
|
||||
} else {
|
||||
ld.Diag("adddynlib: unsupported binary format")
|
||||
}
|
||||
}
|
||||
|
||||
func asmb() {
|
||||
var magic int32
|
||||
var i int
|
||||
var vl int64
|
||||
var symo int64
|
||||
var dwarfoff int64
|
||||
var machlink int64
|
||||
var sect *ld.Section
|
||||
var sym *ld.LSym
|
||||
|
||||
if ld.Debug['v'] != 0 {
|
||||
fmt.Fprintf(&ld.Bso, "%5.2f asmb\n", obj.Cputime())
|
||||
}
|
||||
ld.Bflush(&ld.Bso)
|
||||
|
||||
if ld.Debug['v'] != 0 {
|
||||
fmt.Fprintf(&ld.Bso, "%5.2f codeblk\n", obj.Cputime())
|
||||
}
|
||||
ld.Bflush(&ld.Bso)
|
||||
|
||||
if ld.Iself {
|
||||
ld.Asmbelfsetup()
|
||||
}
|
||||
|
||||
sect = ld.Segtext.Sect
|
||||
ld.Cseek(int64(sect.Vaddr - ld.Segtext.Vaddr + ld.Segtext.Fileoff))
|
||||
ld.Codeblk(int64(sect.Vaddr), int64(sect.Length))
|
||||
for sect = sect.Next; sect != nil; sect = sect.Next {
|
||||
ld.Cseek(int64(sect.Vaddr - ld.Segtext.Vaddr + ld.Segtext.Fileoff))
|
||||
ld.Datblk(int64(sect.Vaddr), int64(sect.Length))
|
||||
}
|
||||
|
||||
if ld.Segrodata.Filelen > 0 {
|
||||
if ld.Debug['v'] != 0 {
|
||||
fmt.Fprintf(&ld.Bso, "%5.2f rodatblk\n", obj.Cputime())
|
||||
}
|
||||
ld.Bflush(&ld.Bso)
|
||||
|
||||
ld.Cseek(int64(ld.Segrodata.Fileoff))
|
||||
ld.Datblk(int64(ld.Segrodata.Vaddr), int64(ld.Segrodata.Filelen))
|
||||
}
|
||||
|
||||
if ld.Debug['v'] != 0 {
|
||||
fmt.Fprintf(&ld.Bso, "%5.2f datblk\n", obj.Cputime())
|
||||
}
|
||||
ld.Bflush(&ld.Bso)
|
||||
|
||||
ld.Cseek(int64(ld.Segdata.Fileoff))
|
||||
ld.Datblk(int64(ld.Segdata.Vaddr), int64(ld.Segdata.Filelen))
|
||||
|
||||
machlink = 0
|
||||
if ld.HEADTYPE == ld.Hdarwin {
|
||||
if ld.Debug['v'] != 0 {
|
||||
fmt.Fprintf(&ld.Bso, "%5.2f dwarf\n", obj.Cputime())
|
||||
}
|
||||
|
||||
dwarfoff = ld.Rnd(int64(uint64(ld.HEADR)+ld.Segtext.Length), int64(ld.INITRND)) + ld.Rnd(int64(ld.Segdata.Filelen), int64(ld.INITRND))
|
||||
ld.Cseek(dwarfoff)
|
||||
|
||||
ld.Segdwarf.Fileoff = uint64(ld.Cpos())
|
||||
ld.Dwarfemitdebugsections()
|
||||
ld.Segdwarf.Filelen = uint64(ld.Cpos()) - ld.Segdwarf.Fileoff
|
||||
|
||||
machlink = ld.Domacholink()
|
||||
}
|
||||
|
||||
switch ld.HEADTYPE {
|
||||
default:
|
||||
ld.Diag("unknown header type %d", ld.HEADTYPE)
|
||||
fallthrough
|
||||
|
||||
case ld.Hplan9,
|
||||
ld.Helf:
|
||||
break
|
||||
|
||||
case ld.Hdarwin:
|
||||
ld.Debug['8'] = 1 /* 64-bit addresses */
|
||||
|
||||
case ld.Hlinux,
|
||||
ld.Hfreebsd,
|
||||
ld.Hnetbsd,
|
||||
ld.Hopenbsd,
|
||||
ld.Hdragonfly,
|
||||
ld.Hsolaris:
|
||||
ld.Debug['8'] = 1 /* 64-bit addresses */
|
||||
|
||||
case ld.Hnacl,
|
||||
ld.Hwindows:
|
||||
break
|
||||
}
|
||||
|
||||
ld.Symsize = 0
|
||||
ld.Spsize = 0
|
||||
ld.Lcsize = 0
|
||||
symo = 0
|
||||
if ld.Debug['s'] == 0 {
|
||||
if ld.Debug['v'] != 0 {
|
||||
fmt.Fprintf(&ld.Bso, "%5.2f sym\n", obj.Cputime())
|
||||
}
|
||||
ld.Bflush(&ld.Bso)
|
||||
switch ld.HEADTYPE {
|
||||
default:
|
||||
case ld.Hplan9,
|
||||
ld.Helf:
|
||||
ld.Debug['s'] = 1
|
||||
symo = int64(ld.Segdata.Fileoff + ld.Segdata.Filelen)
|
||||
|
||||
case ld.Hdarwin:
|
||||
symo = int64(ld.Segdata.Fileoff + uint64(ld.Rnd(int64(ld.Segdata.Filelen), int64(ld.INITRND))) + uint64(machlink))
|
||||
|
||||
case ld.Hlinux,
|
||||
ld.Hfreebsd,
|
||||
ld.Hnetbsd,
|
||||
ld.Hopenbsd,
|
||||
ld.Hdragonfly,
|
||||
ld.Hsolaris,
|
||||
ld.Hnacl:
|
||||
symo = int64(ld.Segdata.Fileoff + ld.Segdata.Filelen)
|
||||
symo = ld.Rnd(symo, int64(ld.INITRND))
|
||||
|
||||
case ld.Hwindows:
|
||||
symo = int64(ld.Segdata.Fileoff + ld.Segdata.Filelen)
|
||||
symo = ld.Rnd(symo, ld.PEFILEALIGN)
|
||||
}
|
||||
|
||||
ld.Cseek(symo)
|
||||
switch ld.HEADTYPE {
|
||||
default:
|
||||
if ld.Iself {
|
||||
ld.Cseek(symo)
|
||||
ld.Asmelfsym()
|
||||
ld.Cflush()
|
||||
ld.Cwrite(ld.Elfstrdat)
|
||||
|
||||
if ld.Debug['v'] != 0 {
|
||||
fmt.Fprintf(&ld.Bso, "%5.2f dwarf\n", obj.Cputime())
|
||||
}
|
||||
|
||||
ld.Dwarfemitdebugsections()
|
||||
|
||||
if ld.Linkmode == ld.LinkExternal {
|
||||
ld.Elfemitreloc()
|
||||
}
|
||||
}
|
||||
|
||||
case ld.Hplan9:
|
||||
ld.Asmplan9sym()
|
||||
ld.Cflush()
|
||||
|
||||
sym = ld.Linklookup(ld.Ctxt, "pclntab", 0)
|
||||
if sym != nil {
|
||||
ld.Lcsize = int32(len(sym.P))
|
||||
for i = 0; int32(i) < ld.Lcsize; i++ {
|
||||
ld.Cput(uint8(sym.P[i]))
|
||||
}
|
||||
|
||||
ld.Cflush()
|
||||
}
|
||||
|
||||
case ld.Hwindows:
|
||||
if ld.Debug['v'] != 0 {
|
||||
fmt.Fprintf(&ld.Bso, "%5.2f dwarf\n", obj.Cputime())
|
||||
}
|
||||
|
||||
ld.Dwarfemitdebugsections()
|
||||
|
||||
case ld.Hdarwin:
|
||||
if ld.Linkmode == ld.LinkExternal {
|
||||
ld.Machoemitreloc()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ld.Debug['v'] != 0 {
|
||||
fmt.Fprintf(&ld.Bso, "%5.2f headr\n", obj.Cputime())
|
||||
}
|
||||
ld.Bflush(&ld.Bso)
|
||||
ld.Cseek(0)
|
||||
switch ld.HEADTYPE {
|
||||
default:
|
||||
case ld.Hplan9: /* plan9 */
|
||||
magic = 4*26*26 + 7
|
||||
|
||||
magic |= 0x00008000 /* fat header */
|
||||
ld.Lputb(uint32(magic)) /* magic */
|
||||
ld.Lputb(uint32(ld.Segtext.Filelen)) /* sizes */
|
||||
ld.Lputb(uint32(ld.Segdata.Filelen))
|
||||
ld.Lputb(uint32(ld.Segdata.Length - ld.Segdata.Filelen))
|
||||
ld.Lputb(uint32(ld.Symsize)) /* nsyms */
|
||||
vl = ld.Entryvalue()
|
||||
ld.Lputb(PADDR(uint32(vl))) /* va of entry */
|
||||
ld.Lputb(uint32(ld.Spsize)) /* sp offsets */
|
||||
ld.Lputb(uint32(ld.Lcsize)) /* line offsets */
|
||||
ld.Vputb(uint64(vl)) /* va of entry */
|
||||
|
||||
case ld.Hdarwin:
|
||||
ld.Asmbmacho()
|
||||
|
||||
case ld.Hlinux,
|
||||
ld.Hfreebsd,
|
||||
ld.Hnetbsd,
|
||||
ld.Hopenbsd,
|
||||
ld.Hdragonfly,
|
||||
ld.Hsolaris,
|
||||
ld.Hnacl:
|
||||
ld.Asmbelf(symo)
|
||||
|
||||
case ld.Hwindows:
|
||||
ld.Asmbpe()
|
||||
}
|
||||
|
||||
ld.Cflush()
|
||||
}
|
||||
78
src/cmd/new6l/l.go
Normal file
78
src/cmd/new6l/l.go
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
// Inferno utils/6l/asm.c
|
||||
// http://code.google.com/p/inferno-os/source/browse/utils/6l/asm.c
|
||||
//
|
||||
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
|
||||
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
|
||||
// Portions Copyright © 1997-1999 Vita Nuova Limited
|
||||
// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
|
||||
// Portions Copyright © 2004,2006 Bruce Ellis
|
||||
// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
|
||||
// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
|
||||
// Portions Copyright © 2009 The Go Authors. All rights reserved.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
package main
|
||||
|
||||
// Writing object files.
|
||||
|
||||
// Inferno utils/6l/l.h
|
||||
// http://code.google.com/p/inferno-os/source/browse/utils/6l/l.h
|
||||
//
|
||||
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
|
||||
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
|
||||
// Portions Copyright © 1997-1999 Vita Nuova Limited
|
||||
// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
|
||||
// Portions Copyright © 2004,2006 Bruce Ellis
|
||||
// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
|
||||
// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
|
||||
// Portions Copyright © 2009 The Go Authors. All rights reserved.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
const (
|
||||
thechar = '6'
|
||||
MaxAlign = 32
|
||||
FuncAlign = 16
|
||||
)
|
||||
|
||||
const (
|
||||
MINLC = 1
|
||||
)
|
||||
|
||||
/* Used by ../ld/dwarf.c */
|
||||
const (
|
||||
DWARFREGSP = 7
|
||||
)
|
||||
215
src/cmd/new6l/obj.go
Normal file
215
src/cmd/new6l/obj.go
Normal file
|
|
@ -0,0 +1,215 @@
|
|||
// Inferno utils/6l/obj.c
|
||||
// http://code.google.com/p/inferno-os/source/browse/utils/6l/obj.c
|
||||
//
|
||||
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
|
||||
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
|
||||
// Portions Copyright © 1997-1999 Vita Nuova Limited
|
||||
// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
|
||||
// Portions Copyright © 2004,2006 Bruce Ellis
|
||||
// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
|
||||
// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
|
||||
// Portions Copyright © 2009 The Go Authors. All rights reserved.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"cmd/internal/obj"
|
||||
"fmt"
|
||||
"log"
|
||||
)
|
||||
import "cmd/internal/ld"
|
||||
|
||||
// Reading object files.
|
||||
|
||||
func main() {
|
||||
linkarchinit()
|
||||
ld.Ldmain()
|
||||
}
|
||||
|
||||
func linkarchinit() {
|
||||
ld.Thestring = "amd64"
|
||||
ld.Thelinkarch = &ld.Linkamd64
|
||||
if obj.Getgoarch() == "amd64p32" {
|
||||
ld.Thelinkarch = &ld.Linkamd64p32
|
||||
}
|
||||
|
||||
ld.Thearch.Thechar = thechar
|
||||
ld.Thearch.Ptrsize = ld.Thelinkarch.Ptrsize
|
||||
ld.Thearch.Intsize = ld.Thelinkarch.Ptrsize
|
||||
ld.Thearch.Regsize = ld.Thelinkarch.Regsize
|
||||
ld.Thearch.Funcalign = FuncAlign
|
||||
ld.Thearch.Maxalign = MaxAlign
|
||||
ld.Thearch.Minlc = MINLC
|
||||
ld.Thearch.Dwarfregsp = DWARFREGSP
|
||||
|
||||
ld.Thearch.Adddynlib = adddynlib
|
||||
ld.Thearch.Adddynrel = adddynrel
|
||||
ld.Thearch.Adddynsym = adddynsym
|
||||
ld.Thearch.Archinit = archinit
|
||||
ld.Thearch.Archreloc = archreloc
|
||||
ld.Thearch.Archrelocvariant = archrelocvariant
|
||||
ld.Thearch.Asmb = asmb
|
||||
ld.Thearch.Elfreloc1 = elfreloc1
|
||||
ld.Thearch.Elfsetupplt = elfsetupplt
|
||||
ld.Thearch.Gentext = gentext
|
||||
ld.Thearch.Machoreloc1 = machoreloc1
|
||||
ld.Thearch.Lput = ld.Lputl
|
||||
ld.Thearch.Wput = ld.Wputl
|
||||
ld.Thearch.Vput = ld.Vputl
|
||||
|
||||
ld.Thearch.Linuxdynld = "/lib64/ld-linux-x86-64.so.2"
|
||||
ld.Thearch.Freebsddynld = "/libexec/ld-elf.so.1"
|
||||
ld.Thearch.Openbsddynld = "/usr/libexec/ld.so"
|
||||
ld.Thearch.Netbsddynld = "/libexec/ld.elf_so"
|
||||
ld.Thearch.Dragonflydynld = "/usr/libexec/ld-elf.so.2"
|
||||
ld.Thearch.Solarisdynld = "/lib/amd64/ld.so.1"
|
||||
}
|
||||
|
||||
func archinit() {
|
||||
// getgoextlinkenabled is based on GO_EXTLINK_ENABLED when
|
||||
// Go was built; see ../../make.bash.
|
||||
if ld.Linkmode == ld.LinkAuto && obj.Getgoextlinkenabled() == "0" {
|
||||
ld.Linkmode = ld.LinkInternal
|
||||
}
|
||||
|
||||
if ld.Flag_shared != 0 {
|
||||
ld.Linkmode = ld.LinkExternal
|
||||
}
|
||||
|
||||
switch ld.HEADTYPE {
|
||||
default:
|
||||
if ld.Linkmode == ld.LinkAuto {
|
||||
ld.Linkmode = ld.LinkInternal
|
||||
}
|
||||
if ld.Linkmode == ld.LinkExternal && obj.Getgoextlinkenabled() != "1" {
|
||||
log.Fatalf("cannot use -linkmode=external with -H %s", ld.Headstr(int(ld.HEADTYPE)))
|
||||
}
|
||||
|
||||
case ld.Hdarwin,
|
||||
ld.Hdragonfly,
|
||||
ld.Hfreebsd,
|
||||
ld.Hlinux,
|
||||
ld.Hnacl,
|
||||
ld.Hnetbsd,
|
||||
ld.Hopenbsd,
|
||||
ld.Hsolaris:
|
||||
break
|
||||
}
|
||||
|
||||
switch ld.HEADTYPE {
|
||||
default:
|
||||
ld.Diag("unknown -H option")
|
||||
ld.Errorexit()
|
||||
fallthrough
|
||||
|
||||
case ld.Hplan9: /* plan 9 */
|
||||
ld.HEADR = 32 + 8
|
||||
|
||||
if ld.INITTEXT == -1 {
|
||||
ld.INITTEXT = 0x200000 + int64(ld.HEADR)
|
||||
}
|
||||
if ld.INITDAT == -1 {
|
||||
ld.INITDAT = 0
|
||||
}
|
||||
if ld.INITRND == -1 {
|
||||
ld.INITRND = 0x200000
|
||||
}
|
||||
|
||||
case ld.Helf: /* elf32 executable */
|
||||
ld.HEADR = int32(ld.Rnd(52+3*32, 16))
|
||||
|
||||
if ld.INITTEXT == -1 {
|
||||
ld.INITTEXT = 0x80110000
|
||||
}
|
||||
if ld.INITDAT == -1 {
|
||||
ld.INITDAT = 0
|
||||
}
|
||||
if ld.INITRND == -1 {
|
||||
ld.INITRND = 4096
|
||||
}
|
||||
|
||||
case ld.Hdarwin: /* apple MACH */
|
||||
ld.Machoinit()
|
||||
|
||||
ld.HEADR = ld.INITIAL_MACHO_HEADR
|
||||
if ld.INITRND == -1 {
|
||||
ld.INITRND = 4096
|
||||
}
|
||||
if ld.INITTEXT == -1 {
|
||||
ld.INITTEXT = 4096 + int64(ld.HEADR)
|
||||
}
|
||||
if ld.INITDAT == -1 {
|
||||
ld.INITDAT = 0
|
||||
}
|
||||
|
||||
case ld.Hlinux, /* elf64 executable */
|
||||
ld.Hfreebsd, /* freebsd */
|
||||
ld.Hnetbsd, /* netbsd */
|
||||
ld.Hopenbsd, /* openbsd */
|
||||
ld.Hdragonfly, /* dragonfly */
|
||||
ld.Hsolaris: /* solaris */
|
||||
ld.Elfinit()
|
||||
|
||||
ld.HEADR = ld.ELFRESERVE
|
||||
if ld.INITTEXT == -1 {
|
||||
ld.INITTEXT = (1 << 22) + int64(ld.HEADR)
|
||||
}
|
||||
if ld.INITDAT == -1 {
|
||||
ld.INITDAT = 0
|
||||
}
|
||||
if ld.INITRND == -1 {
|
||||
ld.INITRND = 4096
|
||||
}
|
||||
|
||||
case ld.Hnacl:
|
||||
ld.Elfinit()
|
||||
ld.Debug['w']++ // disable dwarf, which gets confused and is useless anyway
|
||||
ld.HEADR = 0x10000
|
||||
ld.Funcalign = 32
|
||||
if ld.INITTEXT == -1 {
|
||||
ld.INITTEXT = 0x20000
|
||||
}
|
||||
if ld.INITDAT == -1 {
|
||||
ld.INITDAT = 0
|
||||
}
|
||||
if ld.INITRND == -1 {
|
||||
ld.INITRND = 0x10000
|
||||
}
|
||||
|
||||
case ld.Hwindows: /* PE executable */
|
||||
ld.Peinit()
|
||||
|
||||
ld.HEADR = ld.PEFILEHEADR
|
||||
if ld.INITTEXT == -1 {
|
||||
ld.INITTEXT = ld.PEBASE + int64(ld.PESECTHEADR)
|
||||
}
|
||||
if ld.INITDAT == -1 {
|
||||
ld.INITDAT = 0
|
||||
}
|
||||
if ld.INITRND == -1 {
|
||||
ld.INITRND = ld.PESECTALIGN
|
||||
}
|
||||
}
|
||||
|
||||
if ld.INITDAT != 0 && ld.INITRND != 0 {
|
||||
fmt.Printf("warning: -D0x%x is ignored because of -R0x%x\n", uint64(ld.INITDAT), uint32(ld.INITRND))
|
||||
}
|
||||
}
|
||||
1
src/cmd/new6l/z.go
Normal file
1
src/cmd/new6l/z.go
Normal file
|
|
@ -0,0 +1 @@
|
|||
package main
|
||||
734
src/cmd/new8l/asm.go
Normal file
734
src/cmd/new8l/asm.go
Normal file
|
|
@ -0,0 +1,734 @@
|
|||
// Inferno utils/8l/asm.c
|
||||
// http://code.google.com/p/inferno-os/source/browse/utils/8l/asm.c
|
||||
//
|
||||
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
|
||||
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
|
||||
// Portions Copyright © 1997-1999 Vita Nuova Limited
|
||||
// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
|
||||
// Portions Copyright © 2004,2006 Bruce Ellis
|
||||
// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
|
||||
// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
|
||||
// Portions Copyright © 2009 The Go Authors. All rights reserved.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"cmd/internal/obj"
|
||||
"fmt"
|
||||
"log"
|
||||
)
|
||||
import "cmd/internal/ld"
|
||||
|
||||
func needlib(name string) int {
|
||||
var p string
|
||||
var s *ld.LSym
|
||||
|
||||
if name[0] == '\x00' {
|
||||
return 0
|
||||
}
|
||||
|
||||
/* reuse hash code in symbol table */
|
||||
p = fmt.Sprintf(".dynlib.%s", name)
|
||||
|
||||
s = ld.Linklookup(ld.Ctxt, p, 0)
|
||||
|
||||
if s.Type == 0 {
|
||||
s.Type = 100 // avoid SDATA, etc.
|
||||
return 1
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
func gentext() {
|
||||
}
|
||||
|
||||
func adddynrela(rela *ld.LSym, s *ld.LSym, r *ld.Reloc) {
|
||||
log.Fatalf("adddynrela not implemented")
|
||||
}
|
||||
|
||||
func adddynrel(s *ld.LSym, r *ld.Reloc) {
|
||||
var targ *ld.LSym
|
||||
var rel *ld.LSym
|
||||
var got *ld.LSym
|
||||
|
||||
targ = r.Sym
|
||||
ld.Ctxt.Cursym = s
|
||||
|
||||
switch r.Type {
|
||||
default:
|
||||
if r.Type >= 256 {
|
||||
ld.Diag("unexpected relocation type %d", r.Type)
|
||||
return
|
||||
}
|
||||
|
||||
// Handle relocations found in ELF object files.
|
||||
case 256 + ld.R_386_PC32:
|
||||
if targ.Type == ld.SDYNIMPORT {
|
||||
ld.Diag("unexpected R_386_PC32 relocation for dynamic symbol %s", targ.Name)
|
||||
}
|
||||
if targ.Type == 0 || targ.Type == ld.SXREF {
|
||||
ld.Diag("unknown symbol %s in pcrel", targ.Name)
|
||||
}
|
||||
r.Type = ld.R_PCREL
|
||||
r.Add += 4
|
||||
return
|
||||
|
||||
case 256 + ld.R_386_PLT32:
|
||||
r.Type = ld.R_PCREL
|
||||
r.Add += 4
|
||||
if targ.Type == ld.SDYNIMPORT {
|
||||
addpltsym(ld.Ctxt, targ)
|
||||
r.Sym = ld.Linklookup(ld.Ctxt, ".plt", 0)
|
||||
r.Add += int64(targ.Plt)
|
||||
}
|
||||
|
||||
return
|
||||
|
||||
case 256 + ld.R_386_GOT32:
|
||||
if targ.Type != ld.SDYNIMPORT {
|
||||
// have symbol
|
||||
if r.Off >= 2 && s.P[r.Off-2] == 0x8b {
|
||||
// turn MOVL of GOT entry into LEAL of symbol address, relative to GOT.
|
||||
s.P[r.Off-2] = 0x8d
|
||||
|
||||
r.Type = ld.R_GOTOFF
|
||||
return
|
||||
}
|
||||
|
||||
if r.Off >= 2 && s.P[r.Off-2] == 0xff && s.P[r.Off-1] == 0xb3 {
|
||||
// turn PUSHL of GOT entry into PUSHL of symbol itself.
|
||||
// use unnecessary SS prefix to keep instruction same length.
|
||||
s.P[r.Off-2] = 0x36
|
||||
|
||||
s.P[r.Off-1] = 0x68
|
||||
r.Type = ld.R_ADDR
|
||||
return
|
||||
}
|
||||
|
||||
ld.Diag("unexpected GOT reloc for non-dynamic symbol %s", targ.Name)
|
||||
return
|
||||
}
|
||||
|
||||
addgotsym(ld.Ctxt, targ)
|
||||
r.Type = ld.R_CONST // write r->add during relocsym
|
||||
r.Sym = nil
|
||||
r.Add += int64(targ.Got)
|
||||
return
|
||||
|
||||
case 256 + ld.R_386_GOTOFF:
|
||||
r.Type = ld.R_GOTOFF
|
||||
return
|
||||
|
||||
case 256 + ld.R_386_GOTPC:
|
||||
r.Type = ld.R_PCREL
|
||||
r.Sym = ld.Linklookup(ld.Ctxt, ".got", 0)
|
||||
r.Add += 4
|
||||
return
|
||||
|
||||
case 256 + ld.R_386_32:
|
||||
if targ.Type == ld.SDYNIMPORT {
|
||||
ld.Diag("unexpected R_386_32 relocation for dynamic symbol %s", targ.Name)
|
||||
}
|
||||
r.Type = ld.R_ADDR
|
||||
return
|
||||
|
||||
case 512 + ld.MACHO_GENERIC_RELOC_VANILLA*2 + 0:
|
||||
r.Type = ld.R_ADDR
|
||||
if targ.Type == ld.SDYNIMPORT {
|
||||
ld.Diag("unexpected reloc for dynamic symbol %s", targ.Name)
|
||||
}
|
||||
return
|
||||
|
||||
case 512 + ld.MACHO_GENERIC_RELOC_VANILLA*2 + 1:
|
||||
if targ.Type == ld.SDYNIMPORT {
|
||||
addpltsym(ld.Ctxt, targ)
|
||||
r.Sym = ld.Linklookup(ld.Ctxt, ".plt", 0)
|
||||
r.Add = int64(targ.Plt)
|
||||
r.Type = ld.R_PCREL
|
||||
return
|
||||
}
|
||||
|
||||
r.Type = ld.R_PCREL
|
||||
return
|
||||
|
||||
case 512 + ld.MACHO_FAKE_GOTPCREL:
|
||||
if targ.Type != ld.SDYNIMPORT {
|
||||
// have symbol
|
||||
// turn MOVL of GOT entry into LEAL of symbol itself
|
||||
if r.Off < 2 || s.P[r.Off-2] != 0x8b {
|
||||
ld.Diag("unexpected GOT reloc for non-dynamic symbol %s", targ.Name)
|
||||
return
|
||||
}
|
||||
|
||||
s.P[r.Off-2] = 0x8d
|
||||
r.Type = ld.R_PCREL
|
||||
return
|
||||
}
|
||||
|
||||
addgotsym(ld.Ctxt, targ)
|
||||
r.Sym = ld.Linklookup(ld.Ctxt, ".got", 0)
|
||||
r.Add += int64(targ.Got)
|
||||
r.Type = ld.R_PCREL
|
||||
return
|
||||
}
|
||||
|
||||
// Handle references to ELF symbols from our own object files.
|
||||
if targ.Type != ld.SDYNIMPORT {
|
||||
return
|
||||
}
|
||||
|
||||
switch r.Type {
|
||||
case ld.R_CALL,
|
||||
ld.R_PCREL:
|
||||
addpltsym(ld.Ctxt, targ)
|
||||
r.Sym = ld.Linklookup(ld.Ctxt, ".plt", 0)
|
||||
r.Add = int64(targ.Plt)
|
||||
return
|
||||
|
||||
case ld.R_ADDR:
|
||||
if s.Type != ld.SDATA {
|
||||
break
|
||||
}
|
||||
if ld.Iself {
|
||||
adddynsym(ld.Ctxt, targ)
|
||||
rel = ld.Linklookup(ld.Ctxt, ".rel", 0)
|
||||
ld.Addaddrplus(ld.Ctxt, rel, s, int64(r.Off))
|
||||
ld.Adduint32(ld.Ctxt, rel, ld.ELF32_R_INFO(uint32(targ.Dynid), ld.R_386_32))
|
||||
r.Type = ld.R_CONST // write r->add during relocsym
|
||||
r.Sym = nil
|
||||
return
|
||||
}
|
||||
|
||||
if ld.HEADTYPE == ld.Hdarwin && s.Size == PtrSize && r.Off == 0 {
|
||||
// Mach-O relocations are a royal pain to lay out.
|
||||
// They use a compact stateful bytecode representation
|
||||
// that is too much bother to deal with.
|
||||
// Instead, interpret the C declaration
|
||||
// void *_Cvar_stderr = &stderr;
|
||||
// as making _Cvar_stderr the name of a GOT entry
|
||||
// for stderr. This is separate from the usual GOT entry,
|
||||
// just in case the C code assigns to the variable,
|
||||
// and of course it only works for single pointers,
|
||||
// but we only need to support cgo and that's all it needs.
|
||||
adddynsym(ld.Ctxt, targ)
|
||||
|
||||
got = ld.Linklookup(ld.Ctxt, ".got", 0)
|
||||
s.Type = got.Type | ld.SSUB
|
||||
s.Outer = got
|
||||
s.Sub = got.Sub
|
||||
got.Sub = s
|
||||
s.Value = got.Size
|
||||
ld.Adduint32(ld.Ctxt, got, 0)
|
||||
ld.Adduint32(ld.Ctxt, ld.Linklookup(ld.Ctxt, ".linkedit.got", 0), uint32(targ.Dynid))
|
||||
r.Type = 256 // ignore during relocsym
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
ld.Ctxt.Cursym = s
|
||||
ld.Diag("unsupported relocation for dynamic symbol %s (type=%d stype=%d)", targ.Name, r.Type, targ.Type)
|
||||
}
|
||||
|
||||
func elfreloc1(r *ld.Reloc, sectoff int64) int {
|
||||
var elfsym int32
|
||||
|
||||
ld.Thearch.Lput(uint32(sectoff))
|
||||
|
||||
elfsym = r.Xsym.Elfsym
|
||||
switch r.Type {
|
||||
default:
|
||||
return -1
|
||||
|
||||
case ld.R_ADDR:
|
||||
if r.Siz == 4 {
|
||||
ld.Thearch.Lput(ld.R_386_32 | uint32(elfsym)<<8)
|
||||
} else {
|
||||
return -1
|
||||
}
|
||||
|
||||
case ld.R_CALL,
|
||||
ld.R_PCREL:
|
||||
if r.Siz == 4 {
|
||||
ld.Thearch.Lput(ld.R_386_PC32 | uint32(elfsym)<<8)
|
||||
} else {
|
||||
return -1
|
||||
}
|
||||
|
||||
case ld.R_TLS_LE,
|
||||
ld.R_TLS_IE:
|
||||
if r.Siz == 4 {
|
||||
ld.Thearch.Lput(ld.R_386_TLS_LE | uint32(elfsym)<<8)
|
||||
} else {
|
||||
return -1
|
||||
}
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
func machoreloc1(r *ld.Reloc, sectoff int64) int {
|
||||
var v uint32
|
||||
var rs *ld.LSym
|
||||
|
||||
rs = r.Xsym
|
||||
|
||||
if rs.Type == ld.SHOSTOBJ {
|
||||
if rs.Dynid < 0 {
|
||||
ld.Diag("reloc %d to non-macho symbol %s type=%d", r.Type, rs.Name, rs.Type)
|
||||
return -1
|
||||
}
|
||||
|
||||
v = uint32(rs.Dynid)
|
||||
v |= 1 << 27 // external relocation
|
||||
} else {
|
||||
v = uint32((rs.Sect.(*ld.Section)).Extnum)
|
||||
if v == 0 {
|
||||
ld.Diag("reloc %d to symbol %s in non-macho section %s type=%d", r.Type, rs.Name, (rs.Sect.(*ld.Section)).Name, rs.Type)
|
||||
return -1
|
||||
}
|
||||
}
|
||||
|
||||
switch r.Type {
|
||||
default:
|
||||
return -1
|
||||
|
||||
case ld.R_ADDR:
|
||||
v |= ld.MACHO_GENERIC_RELOC_VANILLA << 28
|
||||
|
||||
case ld.R_CALL,
|
||||
ld.R_PCREL:
|
||||
v |= 1 << 24 // pc-relative bit
|
||||
v |= ld.MACHO_GENERIC_RELOC_VANILLA << 28
|
||||
}
|
||||
|
||||
switch r.Siz {
|
||||
default:
|
||||
return -1
|
||||
|
||||
case 1:
|
||||
v |= 0 << 25
|
||||
|
||||
case 2:
|
||||
v |= 1 << 25
|
||||
|
||||
case 4:
|
||||
v |= 2 << 25
|
||||
|
||||
case 8:
|
||||
v |= 3 << 25
|
||||
}
|
||||
|
||||
ld.Thearch.Lput(uint32(sectoff))
|
||||
ld.Thearch.Lput(v)
|
||||
return 0
|
||||
}
|
||||
|
||||
func archreloc(r *ld.Reloc, s *ld.LSym, val *int64) int {
|
||||
if ld.Linkmode == ld.LinkExternal {
|
||||
return -1
|
||||
}
|
||||
switch r.Type {
|
||||
case ld.R_CONST:
|
||||
*val = r.Add
|
||||
return 0
|
||||
|
||||
case ld.R_GOTOFF:
|
||||
*val = ld.Symaddr(r.Sym) + r.Add - ld.Symaddr(ld.Linklookup(ld.Ctxt, ".got", 0))
|
||||
return 0
|
||||
}
|
||||
|
||||
return -1
|
||||
}
|
||||
|
||||
func archrelocvariant(r *ld.Reloc, s *ld.LSym, t int64) int64 {
|
||||
log.Fatalf("unexpected relocation variant")
|
||||
return t
|
||||
}
|
||||
|
||||
func elfsetupplt() {
|
||||
var plt *ld.LSym
|
||||
var got *ld.LSym
|
||||
|
||||
plt = ld.Linklookup(ld.Ctxt, ".plt", 0)
|
||||
got = ld.Linklookup(ld.Ctxt, ".got.plt", 0)
|
||||
if plt.Size == 0 {
|
||||
// pushl got+4
|
||||
ld.Adduint8(ld.Ctxt, plt, 0xff)
|
||||
|
||||
ld.Adduint8(ld.Ctxt, plt, 0x35)
|
||||
ld.Addaddrplus(ld.Ctxt, plt, got, 4)
|
||||
|
||||
// jmp *got+8
|
||||
ld.Adduint8(ld.Ctxt, plt, 0xff)
|
||||
|
||||
ld.Adduint8(ld.Ctxt, plt, 0x25)
|
||||
ld.Addaddrplus(ld.Ctxt, plt, got, 8)
|
||||
|
||||
// zero pad
|
||||
ld.Adduint32(ld.Ctxt, plt, 0)
|
||||
|
||||
// assume got->size == 0 too
|
||||
ld.Addaddrplus(ld.Ctxt, got, ld.Linklookup(ld.Ctxt, ".dynamic", 0), 0)
|
||||
|
||||
ld.Adduint32(ld.Ctxt, got, 0)
|
||||
ld.Adduint32(ld.Ctxt, got, 0)
|
||||
}
|
||||
}
|
||||
|
||||
func addpltsym(ctxt *ld.Link, s *ld.LSym) {
|
||||
var plt *ld.LSym
|
||||
var got *ld.LSym
|
||||
var rel *ld.LSym
|
||||
|
||||
if s.Plt >= 0 {
|
||||
return
|
||||
}
|
||||
|
||||
adddynsym(ctxt, s)
|
||||
|
||||
if ld.Iself {
|
||||
plt = ld.Linklookup(ctxt, ".plt", 0)
|
||||
got = ld.Linklookup(ctxt, ".got.plt", 0)
|
||||
rel = ld.Linklookup(ctxt, ".rel.plt", 0)
|
||||
if plt.Size == 0 {
|
||||
elfsetupplt()
|
||||
}
|
||||
|
||||
// jmpq *got+size
|
||||
ld.Adduint8(ctxt, plt, 0xff)
|
||||
|
||||
ld.Adduint8(ctxt, plt, 0x25)
|
||||
ld.Addaddrplus(ctxt, plt, got, got.Size)
|
||||
|
||||
// add to got: pointer to current pos in plt
|
||||
ld.Addaddrplus(ctxt, got, plt, plt.Size)
|
||||
|
||||
// pushl $x
|
||||
ld.Adduint8(ctxt, plt, 0x68)
|
||||
|
||||
ld.Adduint32(ctxt, plt, uint32(rel.Size))
|
||||
|
||||
// jmp .plt
|
||||
ld.Adduint8(ctxt, plt, 0xe9)
|
||||
|
||||
ld.Adduint32(ctxt, plt, uint32(-(plt.Size + 4)))
|
||||
|
||||
// rel
|
||||
ld.Addaddrplus(ctxt, rel, got, got.Size-4)
|
||||
|
||||
ld.Adduint32(ctxt, rel, ld.ELF32_R_INFO(uint32(s.Dynid), ld.R_386_JMP_SLOT))
|
||||
|
||||
s.Plt = int32(plt.Size - 16)
|
||||
} else if ld.HEADTYPE == ld.Hdarwin {
|
||||
// Same laziness as in 6l.
|
||||
|
||||
var plt *ld.LSym
|
||||
|
||||
plt = ld.Linklookup(ctxt, ".plt", 0)
|
||||
|
||||
addgotsym(ctxt, s)
|
||||
|
||||
ld.Adduint32(ctxt, ld.Linklookup(ctxt, ".linkedit.plt", 0), uint32(s.Dynid))
|
||||
|
||||
// jmpq *got+size(IP)
|
||||
s.Plt = int32(plt.Size)
|
||||
|
||||
ld.Adduint8(ctxt, plt, 0xff)
|
||||
ld.Adduint8(ctxt, plt, 0x25)
|
||||
ld.Addaddrplus(ctxt, plt, ld.Linklookup(ctxt, ".got", 0), int64(s.Got))
|
||||
} else {
|
||||
ld.Diag("addpltsym: unsupported binary format")
|
||||
}
|
||||
}
|
||||
|
||||
func addgotsym(ctxt *ld.Link, s *ld.LSym) {
|
||||
var got *ld.LSym
|
||||
var rel *ld.LSym
|
||||
|
||||
if s.Got >= 0 {
|
||||
return
|
||||
}
|
||||
|
||||
adddynsym(ctxt, s)
|
||||
got = ld.Linklookup(ctxt, ".got", 0)
|
||||
s.Got = int32(got.Size)
|
||||
ld.Adduint32(ctxt, got, 0)
|
||||
|
||||
if ld.Iself {
|
||||
rel = ld.Linklookup(ctxt, ".rel", 0)
|
||||
ld.Addaddrplus(ctxt, rel, got, int64(s.Got))
|
||||
ld.Adduint32(ctxt, rel, ld.ELF32_R_INFO(uint32(s.Dynid), ld.R_386_GLOB_DAT))
|
||||
} else if ld.HEADTYPE == ld.Hdarwin {
|
||||
ld.Adduint32(ctxt, ld.Linklookup(ctxt, ".linkedit.got", 0), uint32(s.Dynid))
|
||||
} else {
|
||||
ld.Diag("addgotsym: unsupported binary format")
|
||||
}
|
||||
}
|
||||
|
||||
func adddynsym(ctxt *ld.Link, s *ld.LSym) {
|
||||
var d *ld.LSym
|
||||
var t int
|
||||
var name string
|
||||
|
||||
if s.Dynid >= 0 {
|
||||
return
|
||||
}
|
||||
|
||||
if ld.Iself {
|
||||
s.Dynid = int32(ld.Nelfsym)
|
||||
ld.Nelfsym++
|
||||
|
||||
d = ld.Linklookup(ctxt, ".dynsym", 0)
|
||||
|
||||
/* name */
|
||||
name = s.Extname
|
||||
|
||||
ld.Adduint32(ctxt, d, uint32(ld.Addstring(ld.Linklookup(ctxt, ".dynstr", 0), name)))
|
||||
|
||||
/* value */
|
||||
if s.Type == ld.SDYNIMPORT {
|
||||
ld.Adduint32(ctxt, d, 0)
|
||||
} else {
|
||||
ld.Addaddr(ctxt, d, s)
|
||||
}
|
||||
|
||||
/* size */
|
||||
ld.Adduint32(ctxt, d, 0)
|
||||
|
||||
/* type */
|
||||
t = ld.STB_GLOBAL << 4
|
||||
|
||||
if s.Cgoexport != 0 && s.Type&ld.SMASK == ld.STEXT {
|
||||
t |= ld.STT_FUNC
|
||||
} else {
|
||||
t |= ld.STT_OBJECT
|
||||
}
|
||||
ld.Adduint8(ctxt, d, uint8(t))
|
||||
ld.Adduint8(ctxt, d, 0)
|
||||
|
||||
/* shndx */
|
||||
if s.Type == ld.SDYNIMPORT {
|
||||
ld.Adduint16(ctxt, d, ld.SHN_UNDEF)
|
||||
} else {
|
||||
ld.Adduint16(ctxt, d, 1)
|
||||
}
|
||||
} else if ld.HEADTYPE == ld.Hdarwin {
|
||||
ld.Diag("adddynsym: missed symbol %s (%s)", s.Name, s.Extname)
|
||||
} else if ld.HEADTYPE == ld.Hwindows {
|
||||
} else // already taken care of
|
||||
{
|
||||
ld.Diag("adddynsym: unsupported binary format")
|
||||
}
|
||||
}
|
||||
|
||||
func adddynlib(lib string) {
|
||||
var s *ld.LSym
|
||||
|
||||
if needlib(lib) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
if ld.Iself {
|
||||
s = ld.Linklookup(ld.Ctxt, ".dynstr", 0)
|
||||
if s.Size == 0 {
|
||||
ld.Addstring(s, "")
|
||||
}
|
||||
ld.Elfwritedynent(ld.Linklookup(ld.Ctxt, ".dynamic", 0), ld.DT_NEEDED, uint64(ld.Addstring(s, lib)))
|
||||
} else if ld.HEADTYPE == ld.Hdarwin {
|
||||
ld.Machoadddynlib(lib)
|
||||
} else if ld.HEADTYPE != ld.Hwindows {
|
||||
ld.Diag("adddynlib: unsupported binary format")
|
||||
}
|
||||
}
|
||||
|
||||
func asmb() {
|
||||
var magic int32
|
||||
var symo uint32
|
||||
var dwarfoff uint32
|
||||
var machlink uint32
|
||||
var sect *ld.Section
|
||||
var sym *ld.LSym
|
||||
var i int
|
||||
|
||||
if ld.Debug['v'] != 0 {
|
||||
fmt.Fprintf(&ld.Bso, "%5.2f asmb\n", obj.Cputime())
|
||||
}
|
||||
ld.Bflush(&ld.Bso)
|
||||
|
||||
if ld.Iself {
|
||||
ld.Asmbelfsetup()
|
||||
}
|
||||
|
||||
sect = ld.Segtext.Sect
|
||||
ld.Cseek(int64(sect.Vaddr - ld.Segtext.Vaddr + ld.Segtext.Fileoff))
|
||||
ld.Codeblk(int64(sect.Vaddr), int64(sect.Length))
|
||||
for sect = sect.Next; sect != nil; sect = sect.Next {
|
||||
ld.Cseek(int64(sect.Vaddr - ld.Segtext.Vaddr + ld.Segtext.Fileoff))
|
||||
ld.Datblk(int64(sect.Vaddr), int64(sect.Length))
|
||||
}
|
||||
|
||||
if ld.Segrodata.Filelen > 0 {
|
||||
if ld.Debug['v'] != 0 {
|
||||
fmt.Fprintf(&ld.Bso, "%5.2f rodatblk\n", obj.Cputime())
|
||||
}
|
||||
ld.Bflush(&ld.Bso)
|
||||
|
||||
ld.Cseek(int64(ld.Segrodata.Fileoff))
|
||||
ld.Datblk(int64(ld.Segrodata.Vaddr), int64(ld.Segrodata.Filelen))
|
||||
}
|
||||
|
||||
if ld.Debug['v'] != 0 {
|
||||
fmt.Fprintf(&ld.Bso, "%5.2f datblk\n", obj.Cputime())
|
||||
}
|
||||
ld.Bflush(&ld.Bso)
|
||||
|
||||
ld.Cseek(int64(ld.Segdata.Fileoff))
|
||||
ld.Datblk(int64(ld.Segdata.Vaddr), int64(ld.Segdata.Filelen))
|
||||
|
||||
machlink = 0
|
||||
if ld.HEADTYPE == ld.Hdarwin {
|
||||
if ld.Debug['v'] != 0 {
|
||||
fmt.Fprintf(&ld.Bso, "%5.2f dwarf\n", obj.Cputime())
|
||||
}
|
||||
|
||||
dwarfoff = uint32(ld.Rnd(int64(uint64(ld.HEADR)+ld.Segtext.Length), int64(ld.INITRND)) + ld.Rnd(int64(ld.Segdata.Filelen), int64(ld.INITRND)))
|
||||
ld.Cseek(int64(dwarfoff))
|
||||
|
||||
ld.Segdwarf.Fileoff = uint64(ld.Cpos())
|
||||
ld.Dwarfemitdebugsections()
|
||||
ld.Segdwarf.Filelen = uint64(ld.Cpos()) - ld.Segdwarf.Fileoff
|
||||
|
||||
machlink = uint32(ld.Domacholink())
|
||||
}
|
||||
|
||||
ld.Symsize = 0
|
||||
ld.Spsize = 0
|
||||
ld.Lcsize = 0
|
||||
symo = 0
|
||||
if ld.Debug['s'] == 0 {
|
||||
// TODO: rationalize
|
||||
if ld.Debug['v'] != 0 {
|
||||
fmt.Fprintf(&ld.Bso, "%5.2f sym\n", obj.Cputime())
|
||||
}
|
||||
ld.Bflush(&ld.Bso)
|
||||
switch ld.HEADTYPE {
|
||||
default:
|
||||
if ld.Iself {
|
||||
symo = uint32(ld.Segdata.Fileoff + ld.Segdata.Filelen)
|
||||
symo = uint32(ld.Rnd(int64(symo), int64(ld.INITRND)))
|
||||
}
|
||||
|
||||
case ld.Hplan9:
|
||||
symo = uint32(ld.Segdata.Fileoff + ld.Segdata.Filelen)
|
||||
|
||||
case ld.Hdarwin:
|
||||
symo = uint32(ld.Segdata.Fileoff + uint64(ld.Rnd(int64(ld.Segdata.Filelen), int64(ld.INITRND))) + uint64(machlink))
|
||||
|
||||
case ld.Hwindows:
|
||||
symo = uint32(ld.Segdata.Fileoff + ld.Segdata.Filelen)
|
||||
symo = uint32(ld.Rnd(int64(symo), ld.PEFILEALIGN))
|
||||
}
|
||||
|
||||
ld.Cseek(int64(symo))
|
||||
switch ld.HEADTYPE {
|
||||
default:
|
||||
if ld.Iself {
|
||||
if ld.Debug['v'] != 0 {
|
||||
fmt.Fprintf(&ld.Bso, "%5.2f elfsym\n", obj.Cputime())
|
||||
}
|
||||
ld.Asmelfsym()
|
||||
ld.Cflush()
|
||||
ld.Cwrite(ld.Elfstrdat)
|
||||
|
||||
if ld.Debug['v'] != 0 {
|
||||
fmt.Fprintf(&ld.Bso, "%5.2f dwarf\n", obj.Cputime())
|
||||
}
|
||||
ld.Dwarfemitdebugsections()
|
||||
|
||||
if ld.Linkmode == ld.LinkExternal {
|
||||
ld.Elfemitreloc()
|
||||
}
|
||||
}
|
||||
|
||||
case ld.Hplan9:
|
||||
ld.Asmplan9sym()
|
||||
ld.Cflush()
|
||||
|
||||
sym = ld.Linklookup(ld.Ctxt, "pclntab", 0)
|
||||
if sym != nil {
|
||||
ld.Lcsize = int32(len(sym.P))
|
||||
for i = 0; int32(i) < ld.Lcsize; i++ {
|
||||
ld.Cput(uint8(sym.P[i]))
|
||||
}
|
||||
|
||||
ld.Cflush()
|
||||
}
|
||||
|
||||
case ld.Hwindows:
|
||||
if ld.Debug['v'] != 0 {
|
||||
fmt.Fprintf(&ld.Bso, "%5.2f dwarf\n", obj.Cputime())
|
||||
}
|
||||
ld.Dwarfemitdebugsections()
|
||||
|
||||
case ld.Hdarwin:
|
||||
if ld.Linkmode == ld.LinkExternal {
|
||||
ld.Machoemitreloc()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ld.Debug['v'] != 0 {
|
||||
fmt.Fprintf(&ld.Bso, "%5.2f headr\n", obj.Cputime())
|
||||
}
|
||||
ld.Bflush(&ld.Bso)
|
||||
ld.Cseek(0)
|
||||
switch ld.HEADTYPE {
|
||||
default:
|
||||
case ld.Hplan9: /* plan9 */
|
||||
magic = 4*11*11 + 7
|
||||
|
||||
ld.Lputb(uint32(magic)) /* magic */
|
||||
ld.Lputb(uint32(ld.Segtext.Filelen)) /* sizes */
|
||||
ld.Lputb(uint32(ld.Segdata.Filelen))
|
||||
ld.Lputb(uint32(ld.Segdata.Length - ld.Segdata.Filelen))
|
||||
ld.Lputb(uint32(ld.Symsize)) /* nsyms */
|
||||
ld.Lputb(uint32(ld.Entryvalue())) /* va of entry */
|
||||
ld.Lputb(uint32(ld.Spsize)) /* sp offsets */
|
||||
ld.Lputb(uint32(ld.Lcsize)) /* line offsets */
|
||||
|
||||
case ld.Hdarwin:
|
||||
ld.Asmbmacho()
|
||||
|
||||
case ld.Hlinux,
|
||||
ld.Hfreebsd,
|
||||
ld.Hnetbsd,
|
||||
ld.Hopenbsd,
|
||||
ld.Hdragonfly,
|
||||
ld.Hnacl:
|
||||
ld.Asmbelf(int64(symo))
|
||||
|
||||
case ld.Hwindows:
|
||||
ld.Asmbpe()
|
||||
}
|
||||
|
||||
ld.Cflush()
|
||||
}
|
||||
78
src/cmd/new8l/l.go
Normal file
78
src/cmd/new8l/l.go
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
// Inferno utils/8l/asm.c
|
||||
// http://code.google.com/p/inferno-os/source/browse/utils/8l/asm.c
|
||||
//
|
||||
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
|
||||
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
|
||||
// Portions Copyright © 1997-1999 Vita Nuova Limited
|
||||
// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
|
||||
// Portions Copyright © 2004,2006 Bruce Ellis
|
||||
// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
|
||||
// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
|
||||
// Portions Copyright © 2009 The Go Authors. All rights reserved.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
package main
|
||||
|
||||
// Writing object files.
|
||||
|
||||
// Inferno utils/8l/l.h
|
||||
// http://code.google.com/p/inferno-os/source/browse/utils/8l/l.h
|
||||
//
|
||||
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
|
||||
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
|
||||
// Portions Copyright © 1997-1999 Vita Nuova Limited
|
||||
// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
|
||||
// Portions Copyright © 2004,2006 Bruce Ellis
|
||||
// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
|
||||
// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
|
||||
// Portions Copyright © 2009 The Go Authors. All rights reserved.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
const (
|
||||
thechar = '8'
|
||||
PtrSize = 4
|
||||
IntSize = 4
|
||||
RegSize = 4
|
||||
MaxAlign = 32
|
||||
FuncAlign = 16
|
||||
MINLC = 1
|
||||
)
|
||||
|
||||
/* Used by ../ld/dwarf.c */
|
||||
const (
|
||||
DWARFREGSP = 4
|
||||
)
|
||||
191
src/cmd/new8l/obj.go
Normal file
191
src/cmd/new8l/obj.go
Normal file
|
|
@ -0,0 +1,191 @@
|
|||
// Inferno utils/8l/obj.c
|
||||
// http://code.google.com/p/inferno-os/source/browse/utils/8l/obj.c
|
||||
//
|
||||
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
|
||||
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
|
||||
// Portions Copyright © 1997-1999 Vita Nuova Limited
|
||||
// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
|
||||
// Portions Copyright © 2004,2006 Bruce Ellis
|
||||
// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
|
||||
// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
|
||||
// Portions Copyright © 2009 The Go Authors. All rights reserved.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"cmd/internal/obj"
|
||||
"fmt"
|
||||
"log"
|
||||
)
|
||||
import "cmd/internal/ld"
|
||||
|
||||
// Reading object files.
|
||||
|
||||
func main() {
|
||||
linkarchinit()
|
||||
ld.Ldmain()
|
||||
}
|
||||
|
||||
func linkarchinit() {
|
||||
ld.Thestring = "386"
|
||||
ld.Thelinkarch = &ld.Link386
|
||||
|
||||
ld.Thearch.Thechar = thechar
|
||||
ld.Thearch.Ptrsize = ld.Thelinkarch.Ptrsize
|
||||
ld.Thearch.Intsize = ld.Thelinkarch.Ptrsize
|
||||
ld.Thearch.Regsize = ld.Thelinkarch.Regsize
|
||||
ld.Thearch.Funcalign = FuncAlign
|
||||
ld.Thearch.Maxalign = MaxAlign
|
||||
ld.Thearch.Minlc = MINLC
|
||||
ld.Thearch.Dwarfregsp = DWARFREGSP
|
||||
|
||||
ld.Thearch.Adddynlib = adddynlib
|
||||
ld.Thearch.Adddynrel = adddynrel
|
||||
ld.Thearch.Adddynsym = adddynsym
|
||||
ld.Thearch.Archinit = archinit
|
||||
ld.Thearch.Archreloc = archreloc
|
||||
ld.Thearch.Archrelocvariant = archrelocvariant
|
||||
ld.Thearch.Asmb = asmb
|
||||
ld.Thearch.Elfreloc1 = elfreloc1
|
||||
ld.Thearch.Elfsetupplt = elfsetupplt
|
||||
ld.Thearch.Gentext = gentext
|
||||
ld.Thearch.Machoreloc1 = machoreloc1
|
||||
ld.Thearch.Lput = ld.Lputl
|
||||
ld.Thearch.Wput = ld.Wputl
|
||||
ld.Thearch.Vput = ld.Vputl
|
||||
|
||||
ld.Thearch.Linuxdynld = "/lib/ld-linux.so.2"
|
||||
ld.Thearch.Freebsddynld = "/usr/libexec/ld-elf.so.1"
|
||||
ld.Thearch.Openbsddynld = "/usr/libexec/ld.so"
|
||||
ld.Thearch.Netbsddynld = "/usr/libexec/ld.elf_so"
|
||||
ld.Thearch.Dragonflydynld = "/usr/libexec/ld-elf.so.2"
|
||||
ld.Thearch.Solarisdynld = "/lib/ld.so.1"
|
||||
}
|
||||
|
||||
func archinit() {
|
||||
// getgoextlinkenabled is based on GO_EXTLINK_ENABLED when
|
||||
// Go was built; see ../../make.bash.
|
||||
if ld.Linkmode == ld.LinkAuto && obj.Getgoextlinkenabled() == "0" {
|
||||
ld.Linkmode = ld.LinkInternal
|
||||
}
|
||||
|
||||
switch ld.HEADTYPE {
|
||||
default:
|
||||
if ld.Linkmode == ld.LinkAuto {
|
||||
ld.Linkmode = ld.LinkInternal
|
||||
}
|
||||
if ld.Linkmode == ld.LinkExternal && obj.Getgoextlinkenabled() != "1" {
|
||||
log.Fatalf("cannot use -linkmode=external with -H %s", ld.Headstr(int(ld.HEADTYPE)))
|
||||
}
|
||||
|
||||
case ld.Hdarwin,
|
||||
ld.Hdragonfly,
|
||||
ld.Hfreebsd,
|
||||
ld.Hlinux,
|
||||
ld.Hnetbsd,
|
||||
ld.Hopenbsd:
|
||||
break
|
||||
}
|
||||
|
||||
switch ld.HEADTYPE {
|
||||
default:
|
||||
ld.Diag("unknown -H option")
|
||||
ld.Errorexit()
|
||||
fallthrough
|
||||
|
||||
case ld.Hplan9: /* plan 9 */
|
||||
ld.HEADR = 32
|
||||
|
||||
if ld.INITTEXT == -1 {
|
||||
ld.INITTEXT = 4096 + 32
|
||||
}
|
||||
if ld.INITDAT == -1 {
|
||||
ld.INITDAT = 0
|
||||
}
|
||||
if ld.INITRND == -1 {
|
||||
ld.INITRND = 4096
|
||||
}
|
||||
|
||||
case ld.Hdarwin: /* apple MACH */
|
||||
ld.Machoinit()
|
||||
|
||||
ld.HEADR = ld.INITIAL_MACHO_HEADR
|
||||
if ld.INITTEXT == -1 {
|
||||
ld.INITTEXT = 4096 + int64(ld.HEADR)
|
||||
}
|
||||
if ld.INITDAT == -1 {
|
||||
ld.INITDAT = 0
|
||||
}
|
||||
if ld.INITRND == -1 {
|
||||
ld.INITRND = 4096
|
||||
}
|
||||
|
||||
case ld.Hlinux, /* elf32 executable */
|
||||
ld.Hfreebsd,
|
||||
ld.Hnetbsd,
|
||||
ld.Hopenbsd,
|
||||
ld.Hdragonfly:
|
||||
ld.Elfinit()
|
||||
|
||||
ld.HEADR = ld.ELFRESERVE
|
||||
if ld.INITTEXT == -1 {
|
||||
ld.INITTEXT = 0x08048000 + int64(ld.HEADR)
|
||||
}
|
||||
if ld.INITDAT == -1 {
|
||||
ld.INITDAT = 0
|
||||
}
|
||||
if ld.INITRND == -1 {
|
||||
ld.INITRND = 4096
|
||||
}
|
||||
|
||||
case ld.Hnacl:
|
||||
ld.Elfinit()
|
||||
ld.HEADR = 0x10000
|
||||
ld.Funcalign = 32
|
||||
if ld.INITTEXT == -1 {
|
||||
ld.INITTEXT = 0x20000
|
||||
}
|
||||
if ld.INITDAT == -1 {
|
||||
ld.INITDAT = 0
|
||||
}
|
||||
if ld.INITRND == -1 {
|
||||
ld.INITRND = 0x10000
|
||||
}
|
||||
|
||||
case ld.Hwindows: /* PE executable */
|
||||
ld.Peinit()
|
||||
|
||||
ld.HEADR = ld.PEFILEHEADR
|
||||
if ld.INITTEXT == -1 {
|
||||
ld.INITTEXT = ld.PEBASE + int64(ld.PESECTHEADR)
|
||||
}
|
||||
if ld.INITDAT == -1 {
|
||||
ld.INITDAT = 0
|
||||
}
|
||||
if ld.INITRND == -1 {
|
||||
ld.INITRND = ld.PESECTALIGN
|
||||
}
|
||||
}
|
||||
|
||||
if ld.INITDAT != 0 && ld.INITRND != 0 {
|
||||
fmt.Printf("warning: -D0x%x is ignored because of -R0x%x\n", uint64(ld.INITDAT), uint32(ld.INITRND))
|
||||
}
|
||||
}
|
||||
851
src/cmd/new9l/asm.go
Normal file
851
src/cmd/new9l/asm.go
Normal file
|
|
@ -0,0 +1,851 @@
|
|||
// Inferno utils/5l/asm.c
|
||||
// http://code.google.com/p/inferno-os/source/browse/utils/5l/asm.c
|
||||
//
|
||||
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
|
||||
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
|
||||
// Portions Copyright © 1997-1999 Vita Nuova Limited
|
||||
// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
|
||||
// Portions Copyright © 2004,2006 Bruce Ellis
|
||||
// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
|
||||
// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
|
||||
// Portions Copyright © 2009 The Go Authors. All rights reserved.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"cmd/internal/obj"
|
||||
"fmt"
|
||||
"log"
|
||||
)
|
||||
import "cmd/internal/ld"
|
||||
|
||||
func needlib(name string) int {
|
||||
var p string
|
||||
var s *ld.LSym
|
||||
|
||||
if name[0] == '\x00' {
|
||||
return 0
|
||||
}
|
||||
|
||||
/* reuse hash code in symbol table */
|
||||
p = fmt.Sprintf(".dynlib.%s", name)
|
||||
|
||||
s = ld.Linklookup(ld.Ctxt, p, 0)
|
||||
|
||||
if s.Type == 0 {
|
||||
s.Type = 100 // avoid SDATA, etc.
|
||||
return 1
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
func gentext() {
|
||||
var s *ld.LSym
|
||||
var stub *ld.LSym
|
||||
var pprevtextp **ld.LSym
|
||||
var r *ld.Reloc
|
||||
var n string
|
||||
var o1 uint32
|
||||
var i int
|
||||
|
||||
// The ppc64 ABI PLT has similar concepts to other
|
||||
// architectures, but is laid out quite differently. When we
|
||||
// see an R_PPC64_REL24 relocation to a dynamic symbol
|
||||
// (indicating that the call needs to go through the PLT), we
|
||||
// generate up to three stubs and reserve a PLT slot.
|
||||
//
|
||||
// 1) The call site will be bl x; nop (where the relocation
|
||||
// applies to the bl). We rewrite this to bl x_stub; ld
|
||||
// r2,24(r1). The ld is necessary because x_stub will save
|
||||
// r2 (the TOC pointer) at 24(r1) (the "TOC save slot").
|
||||
//
|
||||
// 2) We reserve space for a pointer in the .plt section (once
|
||||
// per referenced dynamic function). .plt is a data
|
||||
// section filled solely by the dynamic linker (more like
|
||||
// .plt.got on other architectures). Initially, the
|
||||
// dynamic linker will fill each slot with a pointer to the
|
||||
// corresponding x@plt entry point.
|
||||
//
|
||||
// 3) We generate the "call stub" x_stub (once per dynamic
|
||||
// function/object file pair). This saves the TOC in the
|
||||
// TOC save slot, reads the function pointer from x's .plt
|
||||
// slot and calls it like any other global entry point
|
||||
// (including setting r12 to the function address).
|
||||
//
|
||||
// 4) We generate the "symbol resolver stub" x@plt (once per
|
||||
// dynamic function). This is solely a branch to the glink
|
||||
// resolver stub.
|
||||
//
|
||||
// 5) We generate the glink resolver stub (only once). This
|
||||
// computes which symbol resolver stub we came through and
|
||||
// invokes the dynamic resolver via a pointer provided by
|
||||
// the dynamic linker. This will patch up the .plt slot to
|
||||
// point directly at the function so future calls go
|
||||
// straight from the call stub to the real function, and
|
||||
// then call the function.
|
||||
|
||||
// NOTE: It's possible we could make ppc64 closer to other
|
||||
// architectures: ppc64's .plt is like .plt.got on other
|
||||
// platforms and ppc64's .glink is like .plt on other
|
||||
// platforms.
|
||||
|
||||
// Find all R_PPC64_REL24 relocations that reference dynamic
|
||||
// imports. Reserve PLT entries for these symbols and
|
||||
// generate call stubs. The call stubs need to live in .text,
|
||||
// which is why we need to do this pass this early.
|
||||
//
|
||||
// This assumes "case 1" from the ABI, where the caller needs
|
||||
// us to save and restore the TOC pointer.
|
||||
pprevtextp = &ld.Ctxt.Textp
|
||||
|
||||
for s = *pprevtextp; s != nil; (func() { pprevtextp = &s.Next; s = *pprevtextp })() {
|
||||
for i = range s.R {
|
||||
r = &s.R[i]
|
||||
if r.Type != 256+ld.R_PPC64_REL24 || r.Sym.Type != ld.SDYNIMPORT {
|
||||
continue
|
||||
}
|
||||
|
||||
// Reserve PLT entry and generate symbol
|
||||
// resolver
|
||||
addpltsym(ld.Ctxt, r.Sym)
|
||||
|
||||
// Generate call stub
|
||||
n = fmt.Sprintf("%s.%s", s.Name, r.Sym.Name)
|
||||
|
||||
stub = ld.Linklookup(ld.Ctxt, n, 0)
|
||||
stub.Reachable = stub.Reachable || s.Reachable
|
||||
if stub.Size == 0 {
|
||||
// Need outer to resolve .TOC.
|
||||
stub.Outer = s
|
||||
|
||||
// Link in to textp before s (we could
|
||||
// do it after, but would have to skip
|
||||
// the subsymbols)
|
||||
*pprevtextp = stub
|
||||
|
||||
stub.Next = s
|
||||
pprevtextp = &stub.Next
|
||||
|
||||
gencallstub(1, stub, r.Sym)
|
||||
}
|
||||
|
||||
// Update the relocation to use the call stub
|
||||
r.Sym = stub
|
||||
|
||||
// Restore TOC after bl. The compiler put a
|
||||
// nop here for us to overwrite.
|
||||
o1 = 0xe8410018 // ld r2,24(r1)
|
||||
ld.Ctxt.Arch.ByteOrder.PutUint32(s.P[r.Off:], o1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Construct a call stub in stub that calls symbol targ via its PLT
|
||||
// entry.
|
||||
func gencallstub(abicase int, stub *ld.LSym, targ *ld.LSym) {
|
||||
var plt *ld.LSym
|
||||
var r *ld.Reloc
|
||||
|
||||
if abicase != 1 {
|
||||
// If we see R_PPC64_TOCSAVE or R_PPC64_REL24_NOTOC
|
||||
// relocations, we'll need to implement cases 2 and 3.
|
||||
log.Fatalf("gencallstub only implements case 1 calls")
|
||||
}
|
||||
|
||||
plt = ld.Linklookup(ld.Ctxt, ".plt", 0)
|
||||
|
||||
stub.Type = ld.STEXT
|
||||
|
||||
// Save TOC pointer in TOC save slot
|
||||
ld.Adduint32(ld.Ctxt, stub, 0xf8410018) // std r2,24(r1)
|
||||
|
||||
// Load the function pointer from the PLT.
|
||||
r = ld.Addrel(stub)
|
||||
|
||||
r.Off = int32(stub.Size)
|
||||
r.Sym = plt
|
||||
r.Add = int64(targ.Plt)
|
||||
r.Siz = 2
|
||||
if ld.Ctxt.Arch.Endian == ld.BigEndian {
|
||||
r.Off += int32(r.Siz)
|
||||
}
|
||||
r.Type = ld.R_POWER_TOC
|
||||
r.Variant = ld.RV_POWER_HA
|
||||
ld.Adduint32(ld.Ctxt, stub, 0x3d820000) // addis r12,r2,targ@plt@toc@ha
|
||||
r = ld.Addrel(stub)
|
||||
r.Off = int32(stub.Size)
|
||||
r.Sym = plt
|
||||
r.Add = int64(targ.Plt)
|
||||
r.Siz = 2
|
||||
if ld.Ctxt.Arch.Endian == ld.BigEndian {
|
||||
r.Off += int32(r.Siz)
|
||||
}
|
||||
r.Type = ld.R_POWER_TOC
|
||||
r.Variant = ld.RV_POWER_LO
|
||||
ld.Adduint32(ld.Ctxt, stub, 0xe98c0000) // ld r12,targ@plt@toc@l(r12)
|
||||
|
||||
// Jump to the loaded pointer
|
||||
ld.Adduint32(ld.Ctxt, stub, 0x7d8903a6) // mtctr r12
|
||||
ld.Adduint32(ld.Ctxt, stub, 0x4e800420) // bctr
|
||||
}
|
||||
|
||||
func adddynrela(rel *ld.LSym, s *ld.LSym, r *ld.Reloc) {
|
||||
log.Fatalf("adddynrela not implemented")
|
||||
}
|
||||
|
||||
func adddynrel(s *ld.LSym, r *ld.Reloc) {
|
||||
var targ *ld.LSym
|
||||
var rela *ld.LSym
|
||||
|
||||
targ = r.Sym
|
||||
ld.Ctxt.Cursym = s
|
||||
|
||||
switch r.Type {
|
||||
default:
|
||||
if r.Type >= 256 {
|
||||
ld.Diag("unexpected relocation type %d", r.Type)
|
||||
return
|
||||
}
|
||||
|
||||
// Handle relocations found in ELF object files.
|
||||
case 256 + ld.R_PPC64_REL24:
|
||||
r.Type = ld.R_CALLPOWER
|
||||
|
||||
// This is a local call, so the caller isn't setting
|
||||
// up r12 and r2 is the same for the caller and
|
||||
// callee. Hence, we need to go to the local entry
|
||||
// point. (If we don't do this, the callee will try
|
||||
// to use r12 to compute r2.)
|
||||
r.Add += int64(r.Sym.Localentry) * 4
|
||||
|
||||
if targ.Type == ld.SDYNIMPORT {
|
||||
// Should have been handled in elfsetupplt
|
||||
ld.Diag("unexpected R_PPC64_REL24 for dyn import")
|
||||
}
|
||||
|
||||
return
|
||||
|
||||
case 256 + ld.R_PPC64_ADDR64:
|
||||
r.Type = ld.R_ADDR
|
||||
if targ.Type == ld.SDYNIMPORT {
|
||||
// These happen in .toc sections
|
||||
adddynsym(ld.Ctxt, targ)
|
||||
|
||||
rela = ld.Linklookup(ld.Ctxt, ".rela", 0)
|
||||
ld.Addaddrplus(ld.Ctxt, rela, s, int64(r.Off))
|
||||
ld.Adduint64(ld.Ctxt, rela, ld.ELF64_R_INFO(uint32(targ.Dynid), ld.R_PPC64_ADDR64))
|
||||
ld.Adduint64(ld.Ctxt, rela, uint64(r.Add))
|
||||
r.Type = 256 // ignore during relocsym
|
||||
}
|
||||
|
||||
return
|
||||
|
||||
case 256 + ld.R_PPC64_TOC16:
|
||||
r.Type = ld.R_POWER_TOC
|
||||
r.Variant = ld.RV_POWER_LO | ld.RV_CHECK_OVERFLOW
|
||||
return
|
||||
|
||||
case 256 + ld.R_PPC64_TOC16_LO:
|
||||
r.Type = ld.R_POWER_TOC
|
||||
r.Variant = ld.RV_POWER_LO
|
||||
return
|
||||
|
||||
case 256 + ld.R_PPC64_TOC16_HA:
|
||||
r.Type = ld.R_POWER_TOC
|
||||
r.Variant = ld.RV_POWER_HA | ld.RV_CHECK_OVERFLOW
|
||||
return
|
||||
|
||||
case 256 + ld.R_PPC64_TOC16_HI:
|
||||
r.Type = ld.R_POWER_TOC
|
||||
r.Variant = ld.RV_POWER_HI | ld.RV_CHECK_OVERFLOW
|
||||
return
|
||||
|
||||
case 256 + ld.R_PPC64_TOC16_DS:
|
||||
r.Type = ld.R_POWER_TOC
|
||||
r.Variant = ld.RV_POWER_DS | ld.RV_CHECK_OVERFLOW
|
||||
return
|
||||
|
||||
case 256 + ld.R_PPC64_TOC16_LO_DS:
|
||||
r.Type = ld.R_POWER_TOC
|
||||
r.Variant = ld.RV_POWER_DS
|
||||
return
|
||||
|
||||
case 256 + ld.R_PPC64_REL16_LO:
|
||||
r.Type = ld.R_PCREL
|
||||
r.Variant = ld.RV_POWER_LO
|
||||
r.Add += 2 // Compensate for relocation size of 2
|
||||
return
|
||||
|
||||
case 256 + ld.R_PPC64_REL16_HI:
|
||||
r.Type = ld.R_PCREL
|
||||
r.Variant = ld.RV_POWER_HI | ld.RV_CHECK_OVERFLOW
|
||||
r.Add += 2
|
||||
return
|
||||
|
||||
case 256 + ld.R_PPC64_REL16_HA:
|
||||
r.Type = ld.R_PCREL
|
||||
r.Variant = ld.RV_POWER_HA | ld.RV_CHECK_OVERFLOW
|
||||
r.Add += 2
|
||||
return
|
||||
}
|
||||
|
||||
// Handle references to ELF symbols from our own object files.
|
||||
if targ.Type != ld.SDYNIMPORT {
|
||||
return
|
||||
}
|
||||
|
||||
// TODO(austin): Translate our relocations to ELF
|
||||
|
||||
ld.Diag("unsupported relocation for dynamic symbol %s (type=%d stype=%d)", targ.Name, r.Type, targ.Type)
|
||||
}
|
||||
|
||||
func elfreloc1(r *ld.Reloc, sectoff int64) int {
|
||||
// TODO(minux)
|
||||
return -1
|
||||
}
|
||||
|
||||
func elfsetupplt() {
|
||||
var plt *ld.LSym
|
||||
|
||||
plt = ld.Linklookup(ld.Ctxt, ".plt", 0)
|
||||
if plt.Size == 0 {
|
||||
// The dynamic linker stores the address of the
|
||||
// dynamic resolver and the DSO identifier in the two
|
||||
// doublewords at the beginning of the .plt section
|
||||
// before the PLT array. Reserve space for these.
|
||||
plt.Size = 16
|
||||
}
|
||||
}
|
||||
|
||||
func machoreloc1(r *ld.Reloc, sectoff int64) int {
|
||||
return -1
|
||||
}
|
||||
|
||||
// Return the value of .TOC. for symbol s
|
||||
func symtoc(s *ld.LSym) int64 {
|
||||
var toc *ld.LSym
|
||||
|
||||
if s.Outer != nil {
|
||||
toc = ld.Linkrlookup(ld.Ctxt, ".TOC.", int(s.Outer.Version))
|
||||
} else {
|
||||
toc = ld.Linkrlookup(ld.Ctxt, ".TOC.", int(s.Version))
|
||||
}
|
||||
|
||||
if toc == nil {
|
||||
ld.Diag("TOC-relative relocation in object without .TOC.")
|
||||
return 0
|
||||
}
|
||||
|
||||
return toc.Value
|
||||
}
|
||||
|
||||
func archreloc(r *ld.Reloc, s *ld.LSym, val *int64) int {
|
||||
var o1 uint32
|
||||
var o2 uint32
|
||||
var t int64
|
||||
|
||||
if ld.Linkmode == ld.LinkExternal {
|
||||
// TODO(minux): translate R_ADDRPOWER and R_CALLPOWER into standard ELF relocations.
|
||||
// R_ADDRPOWER corresponds to R_PPC_ADDR16_HA and R_PPC_ADDR16_LO.
|
||||
// R_CALLPOWER corresponds to R_PPC_REL24.
|
||||
return -1
|
||||
}
|
||||
|
||||
switch r.Type {
|
||||
case ld.R_CONST:
|
||||
*val = r.Add
|
||||
return 0
|
||||
|
||||
case ld.R_GOTOFF:
|
||||
*val = ld.Symaddr(r.Sym) + r.Add - ld.Symaddr(ld.Linklookup(ld.Ctxt, ".got", 0))
|
||||
return 0
|
||||
|
||||
// r->add is two ppc64 instructions holding an immediate 32-bit constant.
|
||||
// We want to add r->sym's address to that constant.
|
||||
// The encoding of the immediate x<<16 + y,
|
||||
// where x is the low 16 bits of the first instruction and y is the low 16
|
||||
// bits of the second. Both x and y are signed (int16, not uint16).
|
||||
case ld.R_ADDRPOWER:
|
||||
o1 = uint32(r.Add >> 32)
|
||||
|
||||
o2 = uint32(r.Add)
|
||||
t = ld.Symaddr(r.Sym)
|
||||
if t < 0 {
|
||||
ld.Ctxt.Diag("relocation for %s is too big (>=2G): %d", s.Name, ld.Symaddr(r.Sym))
|
||||
}
|
||||
|
||||
t += ((int64(o1) & 0xffff) << 16) + (int64(int32(o2)) << 16 >> 16)
|
||||
if t&0x8000 != 0 {
|
||||
t += 0x10000
|
||||
}
|
||||
o1 = uint32(int64(o1&0xffff0000) | (t>>16)&0xffff)
|
||||
o2 = uint32(int64(o2&0xffff0000) | t&0xffff)
|
||||
|
||||
// when laid out, the instruction order must always be o1, o2.
|
||||
if ld.Ctxt.Arch.Endian == ld.BigEndian {
|
||||
*val = int64(o1)<<32 | int64(o2)
|
||||
} else {
|
||||
*val = int64(o2)<<32 | int64(o1)
|
||||
}
|
||||
return 0
|
||||
|
||||
// Bits 6 through 29 = (S + A - P) >> 2
|
||||
case ld.R_CALLPOWER:
|
||||
if ld.Ctxt.Arch.Endian == ld.BigEndian {
|
||||
o1 = ld.Be32(s.P[r.Off:])
|
||||
} else {
|
||||
o1 = ld.Le32(s.P[r.Off:])
|
||||
}
|
||||
|
||||
t = ld.Symaddr(r.Sym) + r.Add - (s.Value + int64(r.Off))
|
||||
if t&3 != 0 {
|
||||
ld.Ctxt.Diag("relocation for %s+%d is not aligned: %d", r.Sym.Name, r.Off, t)
|
||||
}
|
||||
if int64(int32(t<<6)>>6) != t {
|
||||
// TODO(austin) This can happen if text > 32M.
|
||||
// Add a call trampoline to .text in that case.
|
||||
ld.Ctxt.Diag("relocation for %s+%d is too big: %d", r.Sym.Name, r.Off, t)
|
||||
}
|
||||
|
||||
*val = int64(o1)&0xfc000003 | t&^0xfc000003
|
||||
return 0
|
||||
|
||||
case ld.R_POWER_TOC: // S + A - .TOC.
|
||||
*val = ld.Symaddr(r.Sym) + r.Add - symtoc(s)
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
return -1
|
||||
}
|
||||
|
||||
func archrelocvariant(r *ld.Reloc, s *ld.LSym, t int64) int64 {
|
||||
var o1 uint32
|
||||
switch r.Variant & ld.RV_TYPE_MASK {
|
||||
default:
|
||||
ld.Diag("unexpected relocation variant %d", r.Variant)
|
||||
fallthrough
|
||||
|
||||
case ld.RV_NONE:
|
||||
return t
|
||||
|
||||
case ld.RV_POWER_LO:
|
||||
if r.Variant&ld.RV_CHECK_OVERFLOW != 0 {
|
||||
// Whether to check for signed or unsigned
|
||||
// overflow depends on the instruction
|
||||
if ld.Ctxt.Arch.Endian == ld.BigEndian {
|
||||
o1 = ld.Be32(s.P[r.Off-2:])
|
||||
} else {
|
||||
o1 = ld.Le32(s.P[r.Off:])
|
||||
}
|
||||
switch o1 >> 26 {
|
||||
case 24, // ori
|
||||
26, // xori
|
||||
28: // andi
|
||||
if t>>16 != 0 {
|
||||
goto overflow
|
||||
}
|
||||
|
||||
default:
|
||||
if int64(int16(t)) != t {
|
||||
goto overflow
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return int64(int16(t))
|
||||
|
||||
case ld.RV_POWER_HA:
|
||||
t += 0x8000
|
||||
fallthrough
|
||||
|
||||
// Fallthrough
|
||||
case ld.RV_POWER_HI:
|
||||
t >>= 16
|
||||
|
||||
if r.Variant&ld.RV_CHECK_OVERFLOW != 0 {
|
||||
// Whether to check for signed or unsigned
|
||||
// overflow depends on the instruction
|
||||
if ld.Ctxt.Arch.Endian == ld.BigEndian {
|
||||
o1 = ld.Be32(s.P[r.Off-2:])
|
||||
} else {
|
||||
o1 = ld.Le32(s.P[r.Off:])
|
||||
}
|
||||
switch o1 >> 26 {
|
||||
case 25, // oris
|
||||
27, // xoris
|
||||
29: // andis
|
||||
if t>>16 != 0 {
|
||||
goto overflow
|
||||
}
|
||||
|
||||
default:
|
||||
if int64(int16(t)) != t {
|
||||
goto overflow
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return int64(int16(t))
|
||||
|
||||
case ld.RV_POWER_DS:
|
||||
if ld.Ctxt.Arch.Endian == ld.BigEndian {
|
||||
o1 = uint32(ld.Be16(s.P[r.Off:]))
|
||||
} else {
|
||||
o1 = uint32(ld.Le16(s.P[r.Off:]))
|
||||
}
|
||||
if t&3 != 0 {
|
||||
ld.Diag("relocation for %s+%d is not aligned: %d", r.Sym.Name, r.Off, t)
|
||||
}
|
||||
if (r.Variant&ld.RV_CHECK_OVERFLOW != 0) && int64(int16(t)) != t {
|
||||
goto overflow
|
||||
}
|
||||
return int64(o1)&0x3 | int64(int16(t))
|
||||
}
|
||||
|
||||
overflow:
|
||||
ld.Diag("relocation for %s+%d is too big: %d", r.Sym.Name, r.Off, t)
|
||||
return t
|
||||
}
|
||||
|
||||
func addpltsym(ctxt *ld.Link, s *ld.LSym) {
|
||||
if s.Plt >= 0 {
|
||||
return
|
||||
}
|
||||
|
||||
adddynsym(ctxt, s)
|
||||
|
||||
if ld.Iself {
|
||||
var plt *ld.LSym
|
||||
var rela *ld.LSym
|
||||
var glink *ld.LSym
|
||||
var r *ld.Reloc
|
||||
|
||||
plt = ld.Linklookup(ctxt, ".plt", 0)
|
||||
rela = ld.Linklookup(ctxt, ".rela.plt", 0)
|
||||
if plt.Size == 0 {
|
||||
elfsetupplt()
|
||||
}
|
||||
|
||||
// Create the glink resolver if necessary
|
||||
glink = ensureglinkresolver()
|
||||
|
||||
// Write symbol resolver stub (just a branch to the
|
||||
// glink resolver stub)
|
||||
r = ld.Addrel(glink)
|
||||
|
||||
r.Sym = glink
|
||||
r.Off = int32(glink.Size)
|
||||
r.Siz = 4
|
||||
r.Type = ld.R_CALLPOWER
|
||||
ld.Adduint32(ctxt, glink, 0x48000000) // b .glink
|
||||
|
||||
// In the ppc64 ABI, the dynamic linker is responsible
|
||||
// for writing the entire PLT. We just need to
|
||||
// reserve 8 bytes for each PLT entry and generate a
|
||||
// JMP_SLOT dynamic relocation for it.
|
||||
//
|
||||
// TODO(austin): ABI v1 is different
|
||||
s.Plt = int32(plt.Size)
|
||||
|
||||
plt.Size += 8
|
||||
|
||||
ld.Addaddrplus(ctxt, rela, plt, int64(s.Plt))
|
||||
ld.Adduint64(ctxt, rela, ld.ELF64_R_INFO(uint32(s.Dynid), ld.R_PPC64_JMP_SLOT))
|
||||
ld.Adduint64(ctxt, rela, 0)
|
||||
} else {
|
||||
ld.Diag("addpltsym: unsupported binary format")
|
||||
}
|
||||
}
|
||||
|
||||
// Generate the glink resolver stub if necessary and return the .glink section
|
||||
func ensureglinkresolver() *ld.LSym {
|
||||
var glink *ld.LSym
|
||||
var s *ld.LSym
|
||||
var r *ld.Reloc
|
||||
|
||||
glink = ld.Linklookup(ld.Ctxt, ".glink", 0)
|
||||
if glink.Size != 0 {
|
||||
return glink
|
||||
}
|
||||
|
||||
// This is essentially the resolver from the ppc64 ELF ABI.
|
||||
// At entry, r12 holds the address of the symbol resolver stub
|
||||
// for the target routine and the argument registers hold the
|
||||
// arguments for the target routine.
|
||||
//
|
||||
// This stub is PIC, so first get the PC of label 1 into r11.
|
||||
// Other things will be relative to this.
|
||||
ld.Adduint32(ld.Ctxt, glink, 0x7c0802a6) // mflr r0
|
||||
ld.Adduint32(ld.Ctxt, glink, 0x429f0005) // bcl 20,31,1f
|
||||
ld.Adduint32(ld.Ctxt, glink, 0x7d6802a6) // 1: mflr r11
|
||||
ld.Adduint32(ld.Ctxt, glink, 0x7c0803a6) // mtlf r0
|
||||
|
||||
// Compute the .plt array index from the entry point address.
|
||||
// Because this is PIC, everything is relative to label 1b (in
|
||||
// r11):
|
||||
// r0 = ((r12 - r11) - (res_0 - r11)) / 4 = (r12 - res_0) / 4
|
||||
ld.Adduint32(ld.Ctxt, glink, 0x3800ffd0) // li r0,-(res_0-1b)=-48
|
||||
ld.Adduint32(ld.Ctxt, glink, 0x7c006214) // add r0,r0,r12
|
||||
ld.Adduint32(ld.Ctxt, glink, 0x7c0b0050) // sub r0,r0,r11
|
||||
ld.Adduint32(ld.Ctxt, glink, 0x7800f082) // srdi r0,r0,2
|
||||
|
||||
// r11 = address of the first byte of the PLT
|
||||
r = ld.Addrel(glink)
|
||||
|
||||
r.Off = int32(glink.Size)
|
||||
r.Sym = ld.Linklookup(ld.Ctxt, ".plt", 0)
|
||||
r.Siz = 8
|
||||
r.Type = ld.R_ADDRPOWER
|
||||
|
||||
// addis r11,0,.plt@ha; addi r11,r11,.plt@l
|
||||
r.Add = 0x3d600000<<32 | 0x396b0000
|
||||
|
||||
glink.Size += 8
|
||||
|
||||
// Load r12 = dynamic resolver address and r11 = DSO
|
||||
// identifier from the first two doublewords of the PLT.
|
||||
ld.Adduint32(ld.Ctxt, glink, 0xe98b0000) // ld r12,0(r11)
|
||||
ld.Adduint32(ld.Ctxt, glink, 0xe96b0008) // ld r11,8(r11)
|
||||
|
||||
// Jump to the dynamic resolver
|
||||
ld.Adduint32(ld.Ctxt, glink, 0x7d8903a6) // mtctr r12
|
||||
ld.Adduint32(ld.Ctxt, glink, 0x4e800420) // bctr
|
||||
|
||||
// The symbol resolvers must immediately follow.
|
||||
// res_0:
|
||||
|
||||
// Add DT_PPC64_GLINK .dynamic entry, which points to 32 bytes
|
||||
// before the first symbol resolver stub.
|
||||
s = ld.Linklookup(ld.Ctxt, ".dynamic", 0)
|
||||
|
||||
ld.Elfwritedynentsymplus(s, ld.DT_PPC64_GLINK, glink, glink.Size-32)
|
||||
|
||||
return glink
|
||||
}
|
||||
|
||||
func adddynsym(ctxt *ld.Link, s *ld.LSym) {
|
||||
var d *ld.LSym
|
||||
var t int
|
||||
var name string
|
||||
|
||||
if s.Dynid >= 0 {
|
||||
return
|
||||
}
|
||||
|
||||
if ld.Iself {
|
||||
s.Dynid = int32(ld.Nelfsym)
|
||||
ld.Nelfsym++
|
||||
|
||||
d = ld.Linklookup(ctxt, ".dynsym", 0)
|
||||
|
||||
name = s.Extname
|
||||
ld.Adduint32(ctxt, d, uint32(ld.Addstring(ld.Linklookup(ctxt, ".dynstr", 0), name)))
|
||||
|
||||
/* type */
|
||||
t = ld.STB_GLOBAL << 4
|
||||
|
||||
if s.Cgoexport != 0 && s.Type&ld.SMASK == ld.STEXT {
|
||||
t |= ld.STT_FUNC
|
||||
} else {
|
||||
t |= ld.STT_OBJECT
|
||||
}
|
||||
ld.Adduint8(ctxt, d, uint8(t))
|
||||
|
||||
/* reserved */
|
||||
ld.Adduint8(ctxt, d, 0)
|
||||
|
||||
/* section where symbol is defined */
|
||||
if s.Type == ld.SDYNIMPORT {
|
||||
ld.Adduint16(ctxt, d, ld.SHN_UNDEF)
|
||||
} else {
|
||||
ld.Adduint16(ctxt, d, 1)
|
||||
}
|
||||
|
||||
/* value */
|
||||
if s.Type == ld.SDYNIMPORT {
|
||||
ld.Adduint64(ctxt, d, 0)
|
||||
} else {
|
||||
ld.Addaddr(ctxt, d, s)
|
||||
}
|
||||
|
||||
/* size of object */
|
||||
ld.Adduint64(ctxt, d, uint64(s.Size))
|
||||
} else {
|
||||
ld.Diag("adddynsym: unsupported binary format")
|
||||
}
|
||||
}
|
||||
|
||||
func adddynlib(lib string) {
|
||||
var s *ld.LSym
|
||||
|
||||
if needlib(lib) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
if ld.Iself {
|
||||
s = ld.Linklookup(ld.Ctxt, ".dynstr", 0)
|
||||
if s.Size == 0 {
|
||||
ld.Addstring(s, "")
|
||||
}
|
||||
ld.Elfwritedynent(ld.Linklookup(ld.Ctxt, ".dynamic", 0), ld.DT_NEEDED, uint64(ld.Addstring(s, lib)))
|
||||
} else {
|
||||
ld.Diag("adddynlib: unsupported binary format")
|
||||
}
|
||||
}
|
||||
|
||||
func asmb() {
|
||||
var symo uint32
|
||||
var sect *ld.Section
|
||||
var sym *ld.LSym
|
||||
var i int
|
||||
|
||||
if ld.Debug['v'] != 0 {
|
||||
fmt.Fprintf(&ld.Bso, "%5.2f asmb\n", obj.Cputime())
|
||||
}
|
||||
ld.Bflush(&ld.Bso)
|
||||
|
||||
if ld.Iself {
|
||||
ld.Asmbelfsetup()
|
||||
}
|
||||
|
||||
sect = ld.Segtext.Sect
|
||||
ld.Cseek(int64(sect.Vaddr - ld.Segtext.Vaddr + ld.Segtext.Fileoff))
|
||||
ld.Codeblk(int64(sect.Vaddr), int64(sect.Length))
|
||||
for sect = sect.Next; sect != nil; sect = sect.Next {
|
||||
ld.Cseek(int64(sect.Vaddr - ld.Segtext.Vaddr + ld.Segtext.Fileoff))
|
||||
ld.Datblk(int64(sect.Vaddr), int64(sect.Length))
|
||||
}
|
||||
|
||||
if ld.Segrodata.Filelen > 0 {
|
||||
if ld.Debug['v'] != 0 {
|
||||
fmt.Fprintf(&ld.Bso, "%5.2f rodatblk\n", obj.Cputime())
|
||||
}
|
||||
ld.Bflush(&ld.Bso)
|
||||
|
||||
ld.Cseek(int64(ld.Segrodata.Fileoff))
|
||||
ld.Datblk(int64(ld.Segrodata.Vaddr), int64(ld.Segrodata.Filelen))
|
||||
}
|
||||
|
||||
if ld.Debug['v'] != 0 {
|
||||
fmt.Fprintf(&ld.Bso, "%5.2f datblk\n", obj.Cputime())
|
||||
}
|
||||
ld.Bflush(&ld.Bso)
|
||||
|
||||
ld.Cseek(int64(ld.Segdata.Fileoff))
|
||||
ld.Datblk(int64(ld.Segdata.Vaddr), int64(ld.Segdata.Filelen))
|
||||
|
||||
/* output symbol table */
|
||||
ld.Symsize = 0
|
||||
|
||||
ld.Lcsize = 0
|
||||
symo = 0
|
||||
if ld.Debug['s'] == 0 {
|
||||
// TODO: rationalize
|
||||
if ld.Debug['v'] != 0 {
|
||||
fmt.Fprintf(&ld.Bso, "%5.2f sym\n", obj.Cputime())
|
||||
}
|
||||
ld.Bflush(&ld.Bso)
|
||||
switch ld.HEADTYPE {
|
||||
default:
|
||||
if ld.Iself {
|
||||
symo = uint32(ld.Segdata.Fileoff + ld.Segdata.Filelen)
|
||||
symo = uint32(ld.Rnd(int64(symo), int64(ld.INITRND)))
|
||||
}
|
||||
|
||||
case ld.Hplan9:
|
||||
symo = uint32(ld.Segdata.Fileoff + ld.Segdata.Filelen)
|
||||
}
|
||||
|
||||
ld.Cseek(int64(symo))
|
||||
switch ld.HEADTYPE {
|
||||
default:
|
||||
if ld.Iself {
|
||||
if ld.Debug['v'] != 0 {
|
||||
fmt.Fprintf(&ld.Bso, "%5.2f elfsym\n", obj.Cputime())
|
||||
}
|
||||
ld.Asmelfsym()
|
||||
ld.Cflush()
|
||||
ld.Cwrite(ld.Elfstrdat)
|
||||
|
||||
if ld.Debug['v'] != 0 {
|
||||
fmt.Fprintf(&ld.Bso, "%5.2f dwarf\n", obj.Cputime())
|
||||
}
|
||||
ld.Dwarfemitdebugsections()
|
||||
|
||||
if ld.Linkmode == ld.LinkExternal {
|
||||
ld.Elfemitreloc()
|
||||
}
|
||||
}
|
||||
|
||||
case ld.Hplan9:
|
||||
ld.Asmplan9sym()
|
||||
ld.Cflush()
|
||||
|
||||
sym = ld.Linklookup(ld.Ctxt, "pclntab", 0)
|
||||
if sym != nil {
|
||||
ld.Lcsize = int32(len(sym.P))
|
||||
for i = 0; int32(i) < ld.Lcsize; i++ {
|
||||
ld.Cput(uint8(sym.P[i]))
|
||||
}
|
||||
|
||||
ld.Cflush()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ld.Ctxt.Cursym = nil
|
||||
if ld.Debug['v'] != 0 {
|
||||
fmt.Fprintf(&ld.Bso, "%5.2f header\n", obj.Cputime())
|
||||
}
|
||||
ld.Bflush(&ld.Bso)
|
||||
ld.Cseek(0)
|
||||
switch ld.HEADTYPE {
|
||||
default:
|
||||
case ld.Hplan9: /* plan 9 */
|
||||
ld.Thearch.Lput(0x647) /* magic */
|
||||
ld.Thearch.Lput(uint32(ld.Segtext.Filelen)) /* sizes */
|
||||
ld.Thearch.Lput(uint32(ld.Segdata.Filelen))
|
||||
ld.Thearch.Lput(uint32(ld.Segdata.Length - ld.Segdata.Filelen))
|
||||
ld.Thearch.Lput(uint32(ld.Symsize)) /* nsyms */
|
||||
ld.Thearch.Lput(uint32(ld.Entryvalue())) /* va of entry */
|
||||
ld.Thearch.Lput(0)
|
||||
ld.Thearch.Lput(uint32(ld.Lcsize))
|
||||
|
||||
case ld.Hlinux,
|
||||
ld.Hfreebsd,
|
||||
ld.Hnetbsd,
|
||||
ld.Hopenbsd,
|
||||
ld.Hnacl:
|
||||
ld.Asmbelf(int64(symo))
|
||||
}
|
||||
|
||||
ld.Cflush()
|
||||
if ld.Debug['c'] != 0 {
|
||||
fmt.Printf("textsize=%d\n", ld.Segtext.Filelen)
|
||||
fmt.Printf("datsize=%d\n", ld.Segdata.Filelen)
|
||||
fmt.Printf("bsssize=%d\n", ld.Segdata.Length-ld.Segdata.Filelen)
|
||||
fmt.Printf("symsize=%d\n", ld.Symsize)
|
||||
fmt.Printf("lcsize=%d\n", ld.Lcsize)
|
||||
fmt.Printf("total=%d\n", ld.Segtext.Filelen+ld.Segdata.Length+uint64(ld.Symsize)+uint64(ld.Lcsize))
|
||||
}
|
||||
}
|
||||
77
src/cmd/new9l/l.go
Normal file
77
src/cmd/new9l/l.go
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
// Inferno utils/5l/asm.c
|
||||
// http://code.google.com/p/inferno-os/source/browse/utils/5l/asm.c
|
||||
//
|
||||
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
|
||||
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
|
||||
// Portions Copyright © 1997-1999 Vita Nuova Limited
|
||||
// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
|
||||
// Portions Copyright © 2004,2006 Bruce Ellis
|
||||
// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
|
||||
// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
|
||||
// Portions Copyright © 2009 The Go Authors. All rights reserved.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
package main
|
||||
|
||||
// Writing object files.
|
||||
|
||||
// cmd/9l/l.h from Vita Nuova.
|
||||
//
|
||||
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
|
||||
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
|
||||
// Portions Copyright © 1997-1999 Vita Nuova Limited
|
||||
// Portions Copyright © 2000-2008 Vita Nuova Holdings Limited (www.vitanuova.com)
|
||||
// Portions Copyright © 2004,2006 Bruce Ellis
|
||||
// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
|
||||
// Revisions Copyright © 2000-2008 Lucent Technologies Inc. and others
|
||||
// Portions Copyright © 2009 The Go Authors. All rights reserved.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
const (
|
||||
thechar = '9'
|
||||
PtrSize = 8
|
||||
IntSize = 8
|
||||
RegSize = 8
|
||||
MaxAlign = 32
|
||||
FuncAlign = 8
|
||||
MINLC = 4
|
||||
)
|
||||
|
||||
/* Used by ../ld/dwarf.c */
|
||||
const (
|
||||
DWARFREGSP = 1
|
||||
)
|
||||
165
src/cmd/new9l/obj.go
Normal file
165
src/cmd/new9l/obj.go
Normal file
|
|
@ -0,0 +1,165 @@
|
|||
// Inferno utils/5l/obj.c
|
||||
// http://code.google.com/p/inferno-os/source/browse/utils/5l/obj.c
|
||||
//
|
||||
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
|
||||
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
|
||||
// Portions Copyright © 1997-1999 Vita Nuova Limited
|
||||
// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
|
||||
// Portions Copyright © 2004,2006 Bruce Ellis
|
||||
// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
|
||||
// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
|
||||
// Portions Copyright © 2009 The Go Authors. All rights reserved.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"cmd/internal/obj"
|
||||
"fmt"
|
||||
"log"
|
||||
)
|
||||
import "cmd/internal/ld"
|
||||
|
||||
// Reading object files.
|
||||
|
||||
func main() {
|
||||
linkarchinit()
|
||||
ld.Ldmain()
|
||||
}
|
||||
|
||||
func linkarchinit() {
|
||||
ld.Thestring = obj.Getgoarch()
|
||||
if ld.Thestring == "ppc64le" {
|
||||
ld.Thelinkarch = &ld.Linkppc64le
|
||||
} else {
|
||||
ld.Thelinkarch = &ld.Linkppc64
|
||||
}
|
||||
|
||||
ld.Thearch.Thechar = thechar
|
||||
ld.Thearch.Ptrsize = ld.Thelinkarch.Ptrsize
|
||||
ld.Thearch.Intsize = ld.Thelinkarch.Ptrsize
|
||||
ld.Thearch.Regsize = ld.Thelinkarch.Regsize
|
||||
ld.Thearch.Funcalign = FuncAlign
|
||||
ld.Thearch.Maxalign = MaxAlign
|
||||
ld.Thearch.Minlc = MINLC
|
||||
ld.Thearch.Dwarfregsp = DWARFREGSP
|
||||
|
||||
ld.Thearch.Adddynlib = adddynlib
|
||||
ld.Thearch.Adddynrel = adddynrel
|
||||
ld.Thearch.Adddynsym = adddynsym
|
||||
ld.Thearch.Archinit = archinit
|
||||
ld.Thearch.Archreloc = archreloc
|
||||
ld.Thearch.Archrelocvariant = archrelocvariant
|
||||
ld.Thearch.Asmb = asmb
|
||||
ld.Thearch.Elfreloc1 = elfreloc1
|
||||
ld.Thearch.Elfsetupplt = elfsetupplt
|
||||
ld.Thearch.Gentext = gentext
|
||||
ld.Thearch.Machoreloc1 = machoreloc1
|
||||
if ld.Thelinkarch == &ld.Linkppc64le {
|
||||
ld.Thearch.Lput = ld.Lputl
|
||||
ld.Thearch.Wput = ld.Wputl
|
||||
ld.Thearch.Vput = ld.Vputl
|
||||
} else {
|
||||
ld.Thearch.Lput = ld.Lputb
|
||||
ld.Thearch.Wput = ld.Wputb
|
||||
ld.Thearch.Vput = ld.Vputb
|
||||
}
|
||||
|
||||
// TODO(austin): ABI v1 uses /usr/lib/ld.so.1
|
||||
ld.Thearch.Linuxdynld = "/lib64/ld64.so.1"
|
||||
|
||||
ld.Thearch.Freebsddynld = "XXX"
|
||||
ld.Thearch.Openbsddynld = "XXX"
|
||||
ld.Thearch.Netbsddynld = "XXX"
|
||||
ld.Thearch.Dragonflydynld = "XXX"
|
||||
ld.Thearch.Solarisdynld = "XXX"
|
||||
}
|
||||
|
||||
func archinit() {
|
||||
// getgoextlinkenabled is based on GO_EXTLINK_ENABLED when
|
||||
// Go was built; see ../../make.bash.
|
||||
if ld.Linkmode == ld.LinkAuto && obj.Getgoextlinkenabled() == "0" {
|
||||
ld.Linkmode = ld.LinkInternal
|
||||
}
|
||||
|
||||
switch ld.HEADTYPE {
|
||||
default:
|
||||
if ld.Linkmode == ld.LinkAuto {
|
||||
ld.Linkmode = ld.LinkInternal
|
||||
}
|
||||
if ld.Linkmode == ld.LinkExternal && obj.Getgoextlinkenabled() != "1" {
|
||||
log.Fatalf("cannot use -linkmode=external with -H %s", ld.Headstr(int(ld.HEADTYPE)))
|
||||
}
|
||||
}
|
||||
|
||||
switch ld.HEADTYPE {
|
||||
default:
|
||||
ld.Diag("unknown -H option")
|
||||
ld.Errorexit()
|
||||
fallthrough
|
||||
|
||||
case ld.Hplan9: /* plan 9 */
|
||||
ld.HEADR = 32
|
||||
|
||||
if ld.INITTEXT == -1 {
|
||||
ld.INITTEXT = 4128
|
||||
}
|
||||
if ld.INITDAT == -1 {
|
||||
ld.INITDAT = 0
|
||||
}
|
||||
if ld.INITRND == -1 {
|
||||
ld.INITRND = 4096
|
||||
}
|
||||
|
||||
case ld.Hlinux: /* ppc64 elf */
|
||||
if ld.Thestring == "ppc64" {
|
||||
ld.Debug['d'] = 1 // TODO(austin): ELF ABI v1 not supported yet
|
||||
}
|
||||
ld.Elfinit()
|
||||
ld.HEADR = ld.ELFRESERVE
|
||||
if ld.INITTEXT == -1 {
|
||||
ld.INITTEXT = 0x10000 + int64(ld.HEADR)
|
||||
}
|
||||
if ld.INITDAT == -1 {
|
||||
ld.INITDAT = 0
|
||||
}
|
||||
if ld.INITRND == -1 {
|
||||
ld.INITRND = 0x10000
|
||||
}
|
||||
|
||||
case ld.Hnacl:
|
||||
ld.Elfinit()
|
||||
ld.HEADR = 0x10000
|
||||
ld.Funcalign = 16
|
||||
if ld.INITTEXT == -1 {
|
||||
ld.INITTEXT = 0x20000
|
||||
}
|
||||
if ld.INITDAT == -1 {
|
||||
ld.INITDAT = 0
|
||||
}
|
||||
if ld.INITRND == -1 {
|
||||
ld.INITRND = 0x10000
|
||||
}
|
||||
}
|
||||
|
||||
if ld.INITDAT != 0 && ld.INITRND != 0 {
|
||||
fmt.Printf("warning: -D0x%x is ignored because of -R0x%x\n", uint64(ld.INITDAT), uint32(ld.INITRND))
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue