Commit fb880b8a authored by Russ Cox's avatar Russ Cox

cmd/newlink: delete

cmd/link is clearly the way forward.
The original rationale for cmd/newlink was that it would be a clean Go reimplementation.
But when push came to shove, cmd/link got converted from C instead,
and all the work on build modes and the like is in cmd/link now.
Cleaning up cmd/link is likely a much better plan.

This directory is something to delete from releases and the
testdata is something that breaks every time the .6 format changes.
Fix both problems by just deleting it outright.

Change-Id: Ib00fecda258ba685f1752725971182af9d4459eb
Reviewed-on: https://go-review.googlesource.com/20380
Run-TryBot: Russ Cox <rsc@golang.org>
Reviewed-by: default avatarBrad Fitzpatrick <bradfitz@golang.org>
Reviewed-by: default avatarIan Lance Taylor <iant@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
parent c4012b6b
......@@ -44,9 +44,6 @@ go src=..
gofmt_test.go
testdata
+
newlink
testdata
+
archive
tar
testdata
......
// Copyright 2014 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.
// Automatic symbol generation.
// TODO(rsc): Handle go.typelink, go.track symbols.
// TODO(rsc): Do not handle $f64. and $f32. symbols. Instead, generate those
// from the compiler and assemblers as dupok data, and then remove autoData below.
package main
import (
"cmd/internal/goobj"
"strconv"
"strings"
)
// linkerDefined lists the symbols supplied by other parts of the linker
// (runtime.go and layout.go).
var linkerDefined = map[string]bool{
"runtime.bss": true,
"runtime.data": true,
"runtime.ebss": true,
"runtime.edata": true,
"runtime.efunctab": true,
"runtime.end": true,
"runtime.enoptrbss": true,
"runtime.enoptrdata": true,
"runtime.erodata": true,
"runtime.etext": true,
"runtime.etypelink": true,
"runtime.functab": true,
"runtime.gcbss": true,
"runtime.gcdata": true,
"runtime.noptrbss": true,
"runtime.noptrdata": true,
"runtime.pclntab": true,
"runtime.rodata": true,
"runtime.text": true,
"runtime.typelink": true,
}
// isAuto reports whether sym is an automatically-generated data or constant symbol.
func (p *Prog) isAuto(sym goobj.SymID) bool {
return strings.HasPrefix(sym.Name, "$f64.") ||
strings.HasPrefix(sym.Name, "$f32.") ||
linkerDefined[sym.Name]
}
// autoData defines the automatically generated data symbols needed by p.
func (p *Prog) autoData() {
for sym := range p.Missing {
switch {
// Floating-point constants that need to be loaded from memory are
// written as $f64.{16 hex digits} or $f32.{8 hex digits}; the hex digits
// give the IEEE bit pattern of the constant. As far as the layout into
// memory is concerned, we interpret these as uint64 or uint32 constants.
case strings.HasPrefix(sym.Name, "$f64."), strings.HasPrefix(sym.Name, "$f32."):
size := 64
if sym.Name[2:4] == "32" {
size = 32
}
delete(p.Missing, sym)
fbits, err := strconv.ParseUint(sym.Name[len("$f64."):], 16, size)
if err != nil {
p.errorf("unexpected floating point symbol %s", sym)
continue
}
data := make([]byte, size/8)
if size == 64 {
p.byteorder.PutUint64(data, fbits)
} else {
p.byteorder.PutUint32(data, uint32(fbits))
}
p.addSym(&Sym{
Sym: &goobj.Sym{
SymID: sym,
Kind: goobj.SRODATA,
Size: size / 8,
},
Bytes: data,
})
}
}
}
// defineConst defines a new symbol with the given name and constant address.
func (p *Prog) defineConst(name string, addr Addr) {
sym := goobj.SymID{Name: name}
p.addSym(&Sym{
Sym: &goobj.Sym{
SymID: sym,
Kind: goobj.SCONST,
},
Package: nil,
Addr: addr,
})
}
// Copyright 2014 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.
// Test for auto-generated symbols.
// There is no test for $f64. and $f32. symbols, because those are
// not possible to write in the assembler syntax. Instead of changing
// the assembler to allow that, we plan to change the compilers
// not to generate such symbols (plain dupok data is sufficient).
package main
import (
"bytes"
"cmd/internal/goobj"
"testing"
)
// Each test case is an object file, generated from a corresponding .s file.
// The image of the autotab symbol should be a sequence of pairs of
// identical 8-byte sequences.
var autoTests = []string{
"testdata/autosection.6",
}
func TestAuto(t *testing.T) {
for _, obj := range autoTests {
p := Prog{GOOS: "darwin", GOARCH: "amd64", StartSym: "start"}
p.omitRuntime = true
p.Error = func(s string) { t.Error(s) }
var buf bytes.Buffer
p.link(&buf, obj)
if p.NumError > 0 {
continue // already reported
}
const name = "autotab"
sym := p.Syms[goobj.SymID{Name: name}]
if sym == nil {
t.Errorf("%s is missing %s symbol", obj, name)
return
}
if sym.Size == 0 {
return
}
seg := sym.Section.Segment
off := sym.Addr - seg.VirtAddr
data := seg.Data[off : off+Addr(sym.Size)]
if len(data)%16 != 0 {
t.Errorf("%s: %s.Size = %d, want multiple of 16", obj, name, len(data))
return
}
Data:
for i := 0; i < len(data); i += 16 {
have := p.byteorder.Uint64(data[i : i+8])
want := p.byteorder.Uint64(data[i+8 : i+16])
if have != want {
// Look for relocation so we can explain what went wrong.
for _, r := range sym.Reloc {
if r.Offset == i {
t.Errorf("%s: %s+%#x: %s: have %#x want %#x", obj, name, i, r.Sym, have, want)
continue Data
}
}
t.Errorf("%s: %s+%#x: have %#x want %#x", obj, name, i, have, want)
}
}
}
}
// Copyright 2014 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.
// Removal of dead code and data.
package main
import "cmd/internal/goobj"
// dead removes unreachable code and data from the program.
// It is basically a mark-sweep garbage collection: traverse all the
// symbols reachable from the entry (startSymID) and then delete
// the rest.
func (p *Prog) dead() {
p.Dead = make(map[goobj.SymID]bool)
reachable := make(map[goobj.SymID]bool)
p.walkDead(p.startSym, reachable)
for sym := range p.Syms {
if !reachable[sym] {
delete(p.Syms, sym)
p.Dead[sym] = true
}
}
for sym := range p.Missing {
if !reachable[sym] {
delete(p.Missing, sym)
p.Dead[sym] = true
}
}
p.SymOrder = removeDead(p.SymOrder, reachable)
for _, pkg := range p.Packages {
pkg.Syms = removeDead(pkg.Syms, reachable)
}
}
// walkDead traverses the symbols reachable from sym, adding them to reachable.
// The caller has verified that reachable[sym] = false.
func (p *Prog) walkDead(sym goobj.SymID, reachable map[goobj.SymID]bool) {
reachable[sym] = true
s := p.Syms[sym]
if s == nil {
return
}
for i := range s.Reloc {
r := &s.Reloc[i]
if !reachable[r.Sym] {
p.walkDead(r.Sym, reachable)
}
}
if s.Func != nil {
for _, fdata := range s.Func.FuncData {
if fdata.Sym.Name != "" && !reachable[fdata.Sym] {
p.walkDead(fdata.Sym, reachable)
}
}
}
}
// removeDead removes unreachable (dead) symbols from syms,
// returning a shortened slice using the same underlying array.
func removeDead(syms []*Sym, reachable map[goobj.SymID]bool) []*Sym {
keep := syms[:0]
for _, sym := range syms {
if reachable[sym.SymID] {
keep = append(keep, sym)
}
}
return keep
}
// Copyright 2014 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 main
import (
"cmd/internal/goobj"
"reflect"
"strings"
"testing"
)
// Each test case is an object file, generated from a corresponding .s file.
// The symbols in the object file with a dead_ prefix are the ones that
// should be removed from the program.
var deadTests = []string{
"testdata/dead.6",
}
func TestDead(t *testing.T) {
for _, obj := range deadTests {
p := Prog{GOOS: "darwin", GOARCH: "amd64", StartSym: "start"}
p.omitRuntime = true
p.Error = func(s string) { t.Error(s) }
p.init()
p.scan(obj)
if p.NumError > 0 {
continue // already reported
}
origSyms := copyMap(p.Syms)
origMissing := copyMap(p.Missing)
origSymOrder := copySlice(p.SymOrder)
origPkgSyms := copySlice(p.Packages["main"].Syms)
p.dead()
checkDeadMap(t, obj, "p.Syms", origSyms, p.Syms)
checkDeadMap(t, obj, "p.Missing", origMissing, p.Missing)
checkDeadSlice(t, obj, "p.SymOrder", origSymOrder, p.SymOrder)
checkDeadSlice(t, obj, `p.Packages["main"].Syms`, origPkgSyms, p.Packages["main"].Syms)
}
}
func copyMap(m interface{}) interface{} {
v := reflect.ValueOf(m)
out := reflect.MakeMap(v.Type())
for _, key := range v.MapKeys() {
out.SetMapIndex(key, v.MapIndex(key))
}
return out.Interface()
}
func checkDeadMap(t *testing.T, obj, name string, old, new interface{}) {
vold := reflect.ValueOf(old)
vnew := reflect.ValueOf(new)
for _, vid := range vold.MapKeys() {
id := vid.Interface().(goobj.SymID)
if strings.HasPrefix(id.Name, "dead_") {
if vnew.MapIndex(vid).IsValid() {
t.Errorf("%s: %s contains unnecessary symbol %s", obj, name, id)
}
} else {
if !vnew.MapIndex(vid).IsValid() {
t.Errorf("%s: %s is missing symbol %s", obj, name, id)
}
}
}
for _, vid := range vnew.MapKeys() {
id := vid.Interface().(goobj.SymID)
if !vold.MapIndex(vid).IsValid() {
t.Errorf("%s: %s contains unexpected symbol %s", obj, name, id)
}
}
}
func copySlice(x []*Sym) (out []*Sym) {
return append(out, x...)
}
func checkDeadSlice(t *testing.T, obj, name string, old, new []*Sym) {
for i, s := range old {
if strings.HasPrefix(s.Name, "dead_") {
continue
}
if len(new) == 0 {
t.Errorf("%s: %s is missing symbol %s\nhave%v\nwant%v", obj, name, s, new, old[i:])
return
}
if new[0].SymID != s.SymID {
t.Errorf("%s: %s is incorrect: have %s, want %s\nhave%v\nwant%v", obj, name, new[0].SymID, s.SymID, new, old[i:])
return
}
new = new[1:]
}
if len(new) > 0 {
t.Errorf("%s: %s has unexpected symbols: %v", obj, name, new)
}
}
// Copyright 2014 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.
// Generation of debug data structures (in the executable but not mapped at run time).
// See also runtime.go.
package main
func (p *Prog) debug() {
}
// Copyright 2014 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 main
import (
"encoding/hex"
"fmt"
"io/ioutil"
"regexp"
"strconv"
"strings"
"testing"
)
// mustParseHexdumpFile returns a block of data generated by
// parsing the hex dump in the named file.
// If the file cannot be read or does not contain a valid hex dump,
// mustParseHexdumpFile calls t.Fatal.
func mustParseHexdumpFile(t *testing.T, file string) []byte {
hex, err := ioutil.ReadFile(file)
if err != nil {
t.Fatal(err)
}
data, err := parseHexdump(string(hex))
if err != nil {
t.Fatal(err)
}
return data
}
// parseHexdump parses the hex dump in text, which should be the
// output of "hexdump -C" or Plan 9's "xd -b",
// and returns the original data used to produce the dump.
// It is meant to enable storing golden binary files as text, so that
// changes to the golden files can be seen during code reviews.
func parseHexdump(text string) ([]byte, error) {
var out []byte
for _, line := range strings.Split(text, "\n") {
if i := strings.Index(line, "|"); i >= 0 { // remove text dump
line = line[:i]
}
f := strings.Fields(line)
if len(f) > 1+16 {
return nil, fmt.Errorf("parsing hex dump: too many fields on line %q", line)
}
if len(f) == 0 || len(f) == 1 && f[0] == "*" { // all zeros block omitted
continue
}
addr64, err := strconv.ParseUint(f[0], 16, 0)
if err != nil {
return nil, fmt.Errorf("parsing hex dump: invalid address %q", f[0])
}
addr := int(addr64)
if len(out) < addr {
out = append(out, make([]byte, addr-len(out))...)
}
for _, x := range f[1:] {
val, err := strconv.ParseUint(x, 16, 8)
if err != nil {
return nil, fmt.Errorf("parsing hexdump: invalid hex byte %q", x)
}
out = append(out, byte(val))
}
}
return out, nil
}
func hexdump(data []byte) string {
text := hex.Dump(data) + fmt.Sprintf("%08x\n", len(data))
text = regexp.MustCompile(`\n([0-9a-f]+(\s+00){16}.*\n)+`).ReplaceAllString(text, "\n*\n")
return text
}
// Copyright 2014 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.
// Executable image layout - address assignment.
package main
import (
"cmd/internal/goobj"
)
// A layoutSection describes a single section to add to the
// final executable. Go binaries only have a fixed set of possible
// sections, and the symbol kind determines the section.
type layoutSection struct {
Segment string
Section string
Kind goobj.SymKind
Index int
}
// layout defines the layout of the generated Go executable.
// The order of entries here is the order in the executable.
// Entries with the same Segment name must be contiguous.
var layout = []layoutSection{
{Segment: "text", Section: "text", Kind: goobj.STEXT},
{Segment: "rodata", Section: "rodata", Kind: goobj.SRODATA},
{Segment: "rodata", Section: "functab", Kind: goobj.SPCLNTAB},
{Segment: "rodata", Section: "typelink", Kind: goobj.STYPELINK},
{Segment: "data", Section: "noptrdata", Kind: goobj.SNOPTRDATA},
{Segment: "data", Section: "data", Kind: goobj.SDATA},
{Segment: "data", Section: "bss", Kind: goobj.SBSS},
{Segment: "data", Section: "noptrbss", Kind: goobj.SNOPTRBSS},
// Later:
// {"rodata", "type", goobj.STYPE},
// {"rodata", "string", goobj.SSTRING},
// {"rodata", "gostring", goobj.SGOSTRING},
// {"rodata", "gofunc", goobj.SGOFUNC},
}
// layoutByKind maps from SymKind to an entry in layout.
var layoutByKind []*layoutSection
func init() {
// Build index from symbol type to layout entry.
max := 0
for _, sect := range layout {
if max <= int(sect.Kind) {
max = int(sect.Kind) + 1
}
}
layoutByKind = make([]*layoutSection, max)
for i := range layout {
sect := &layout[i]
layoutByKind[sect.Kind] = sect
sect.Index = i
}
}
// layout arranges symbols into sections and sections into segments,
// and then it assigns addresses to segments, sections, and symbols.
func (p *Prog) layout() {
sections := make([]*Section, len(layout))
// Assign symbols to sections using index, creating sections as needed.
// Could keep sections separated by type during input instead.
for _, sym := range p.SymOrder {
kind := sym.Kind
if kind < 0 || int(kind) >= len(layoutByKind) || layoutByKind[kind] == nil {
p.errorf("%s: unexpected symbol kind %v", sym.SymID, kind)
continue
}
lsect := layoutByKind[kind]
sect := sections[lsect.Index]
if sect == nil {
sect = &Section{
Name: lsect.Section,
Align: 1,
}
sections[lsect.Index] = sect
}
if sym.Data.Size > 0 || len(sym.Bytes) > 0 {
sect.InFile = true
}
sym.Section = sect
sect.Syms = append(sect.Syms, sym)
// TODO(rsc): Incorporate alignment information.
// First that information needs to be added to the object files.
//
// if sect.Align < Addr(sym.Align) {
// sect.Align = Addr(sym.Align)
// }
}
// Assign sections to segments, creating segments as needed.
var seg *Segment
for i, sect := range sections {
if sect == nil {
continue
}
segName := layout[i].Segment
// Special case: Mach-O does not support "rodata" segment,
// so store read-only data in text segment.
if p.GOOS == "darwin" && segName == "rodata" {
segName = "text"
}
if seg == nil || seg.Name != segName {
seg = &Segment{
Name: segName,
}
p.Segments = append(p.Segments, seg)
}
sect.Segment = seg
seg.Sections = append(seg.Sections, sect)
}
// Assign addresses.
// TODO(rsc): This choice needs to be informed by both
// the formatter and the target architecture.
// And maybe eventually a command line flag (sigh).
const segAlign = 4096
// TODO(rsc): Use a larger amount on most systems, which will let the
// compiler eliminate more nil checks.
if p.UnmappedSize == 0 {
p.UnmappedSize = segAlign
}
// TODO(rsc): addr := Addr(0) when generating a shared library or PIE.
addr := p.UnmappedSize
// Account for initial file header.
hdrVirt, hdrFile := p.formatter.headerSize(p)
addr += hdrVirt
// Assign addresses to segments, sections, symbols.
// Assign sizes to segments, sections.
startVirt := addr
startFile := hdrFile
for _, seg := range p.Segments {
addr = round(addr, segAlign)
seg.VirtAddr = addr
seg.FileOffset = startFile + seg.VirtAddr - startVirt
for _, sect := range seg.Sections {
addr = round(addr, sect.Align)
sect.VirtAddr = addr
for _, sym := range sect.Syms {
// TODO(rsc): Respect alignment once we have that information.
sym.Addr = addr
addr += Addr(sym.Size)
}
sect.Size = addr - sect.VirtAddr
if sect.InFile {
seg.FileSize = addr - seg.VirtAddr
}
}
seg.VirtSize = addr - seg.VirtAddr
}
// Define symbols for section names.
var progEnd Addr
for i, sect := range sections {
name := layout[i].Section
var start, end Addr
if sect != nil {
start = sect.VirtAddr
end = sect.VirtAddr + sect.Size
}
p.defineConst("runtime."+name, start)
p.defineConst("runtime.e"+name, end)
progEnd = end
}
p.defineConst("runtime.end", progEnd)
}
// Copyright 2014 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 main
import (
"bytes"
"strings"
"testing"
)
func TestLayout(t *testing.T) {
p := Prog{GOOS: "darwin", GOARCH: "amd64", StartSym: "text_start"}
p.omitRuntime = true
p.Error = func(s string) { t.Error(s) }
var buf bytes.Buffer
const obj = "testdata/layout.6"
p.link(&buf, obj)
if p.NumError > 0 {
return // already reported
}
if len(p.Dead) > 0 {
t.Errorf("%s: unexpected dead symbols %v", obj, p.Dead)
return
}
for _, sym := range p.SymOrder {
if p.isAuto(sym.SymID) {
continue
}
if sym.Section == nil {
t.Errorf("%s: symbol %s is missing section", obj, sym)
continue
}
i := strings.Index(sym.Name, "_")
if i < 0 {
t.Errorf("%s: unexpected symbol %s", obj, sym)
continue
}
if sym.Section.Name != sym.Name[:i] {
t.Errorf("%s: symbol %s in section %s, want %s", obj, sym, sym.Section.Name, sym.Name[:i])
}
}
}
// Copyright 2014 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 main
import (
"bytes"
"cmd/internal/goobj"
"io/ioutil"
"testing"
)
func TestLinkHello(t *testing.T) {
p := &Prog{
GOOS: "darwin",
GOARCH: "amd64",
Error: func(s string) { t.Error(s) },
StartSym: "_rt0_go",
}
var buf bytes.Buffer
p.link(&buf, "testdata/hello.6")
if p.NumError > 0 {
return
}
if p.Syms[goobj.SymID{"_rt0_go", 0}] == nil || p.Syms[goobj.SymID{"hello", 1}] == nil {
t.Errorf("Syms = %v, want at least [_rt0_go hello<1>]", p.Syms)
}
// uncomment to leave file behind for execution:
if false {
ioutil.WriteFile("a.out", buf.Bytes(), 0777)
}
checkGolden(t, buf.Bytes(), "testdata/link.hello.darwin.amd64")
}
// Copyright 2014 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.
// Loading of code and data fragments from package files into final image.
package main
import (
"cmd/internal/obj"
"os"
)
// load allocates segment images, populates them with data
// read from package files, and applies relocations to the data.
func (p *Prog) load() {
// TODO(rsc): mmap the output file and store the data directly.
// That will make writing the output file more efficient.
for _, seg := range p.Segments {
seg.Data = make([]byte, seg.FileSize)
}
for _, pkg := range p.Packages {
p.loadPackage(pkg)
}
}
// loadPackage loads and relocates data for all the
// symbols needed in the given package.
func (p *Prog) loadPackage(pkg *Package) {
if pkg.File == "" {
// This "package" contains internally generated symbols only.
// All such symbols have a sym.Bytes field holding the actual data
// (if any), plus relocations.
for _, sym := range pkg.Syms {
if sym.Bytes == nil {
continue
}
seg := sym.Section.Segment
off := sym.Addr - seg.VirtAddr
data := seg.Data[off : off+Addr(sym.Size)]
copy(data, sym.Bytes)
p.relocateSym(sym, data)
}
return
}
// Package stored in file.
f, err := os.Open(pkg.File)
if err != nil {
p.errorf("%v", err)
return
}
defer f.Close()
// TODO(rsc): Mmap file into memory.
for _, sym := range pkg.Syms {
if sym.Data.Size == 0 {
continue
}
// TODO(rsc): If not using mmap, at least coalesce nearby reads.
if sym.Section == nil {
p.errorf("internal error: missing section for %s", sym.Name)
}
seg := sym.Section.Segment
off := sym.Addr - seg.VirtAddr
if off >= Addr(len(seg.Data)) || off+Addr(sym.Data.Size) > Addr(len(seg.Data)) {
p.errorf("internal error: allocated space for %s too small: %d bytes for %d+%d (%d)", sym, len(seg.Data), off, sym.Data.Size, sym.Size)
}
data := seg.Data[off : off+Addr(sym.Data.Size)]
_, err := f.ReadAt(data, sym.Data.Offset)
if err != nil {
p.errorf("reading %v: %v", sym.SymID, err)
}
p.relocateSym(sym, data)
}
}
// relocateSym applies relocations to sym's data.
func (p *Prog) relocateSym(sym *Sym, data []byte) {
for i := range sym.Reloc {
r := &sym.Reloc[i]
targ := p.Syms[r.Sym]
if targ == nil {
p.errorf("%v: reference to undefined symbol %v", sym, r.Sym)
continue
}
val := targ.Addr + Addr(r.Add)
switch r.Type {
default:
p.errorf("%v: unknown relocation type %d", sym, r.Type)
case obj.R_ADDR, obj.R_CALLIND:
// ok
case obj.R_PCREL, obj.R_CALL:
val -= sym.Addr + Addr(r.Offset+r.Size)
}
frag := data[r.Offset : r.Offset+r.Size]
switch r.Size {
default:
p.errorf("%v: unknown relocation size %d", sym, r.Size)
case 4:
// TODO(rsc): Check for overflow?
p.byteorder.PutUint32(frag, uint32(val))
case 8:
p.byteorder.PutUint64(frag, uint64(val))
}
}
}
// Copyright 2014 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 (Darwin) object file writing.
package main
import (
"debug/macho"
"encoding/binary"
"io"
"strings"
)
// machoFormat is the implementation of formatter.
type machoFormat struct{}
// machoHeader and friends are data structures
// corresponding to the Mach-O file header
// to be written to disk.
const (
macho64Bit = 1 << 24
machoSubCPU386 = 3
)
// machoArch describes a Mach-O target architecture.
type machoArch struct {
CPU uint32
SubCPU uint32
}
// machoHeader is the Mach-O file header.
type machoHeader struct {
machoArch
FileType uint32
Loads []*machoLoad
Segments []*machoSegment
p *Prog // for reporting errors
}
// machoLoad is a Mach-O load command.
type machoLoad struct {
Type uint32
Data []uint32
}
// machoSegment is a Mach-O segment.
type machoSegment struct {
Name string
VirtAddr Addr
VirtSize Addr
FileOffset Addr
FileSize Addr
Prot1 uint32
Prot2 uint32
Flags uint32
Sections []*machoSection
}
// machoSection is a Mach-O section, inside a segment.
type machoSection struct {
Name string
Segment string
Addr Addr
Size Addr
Offset uint32
Align uint32
Reloc uint32
Nreloc uint32
Flags uint32
Res1 uint32
Res2 uint32
}
// layout positions the segments and sections in p
// to make room for the Mach-O file header.
// That is, it edits their VirtAddr fields to adjust for the presence
// of the Mach-O header at the beginning of the address space.
func (machoFormat) headerSize(p *Prog) (virt, file Addr) {
var h machoHeader
h.init(p)
size := Addr(h.size())
size = round(size, 4096)
p.HeaderSize = size
return size, size
}
// write writes p to w as a Mach-O executable.
// layout(p) must have already been called,
// and the number, sizes, and addresses of the segments
// and sections must not have been modified since the call.
func (machoFormat) write(w io.Writer, p *Prog) {
var h machoHeader
h.init(p)
off := Addr(0)
enc := h.encode()
w.Write(enc)
off += Addr(len(enc))
for _, seg := range p.Segments {
if seg.FileOffset < off {
h.p.errorf("mach-o error: invalid file offset")
}
w.Write(make([]byte, int(seg.FileOffset-off)))
if seg.FileSize != Addr(len(seg.Data)) {
h.p.errorf("mach-o error: invalid file size")
}
w.Write(seg.Data)
off = seg.FileOffset + Addr(len(seg.Data))
}
}
// Conversion of Prog to macho data structures.
// machoArches maps from GOARCH to machoArch.
var machoArches = map[string]machoArch{
"amd64": {
CPU: uint32(macho.CpuAmd64),
SubCPU: uint32(machoSubCPU386),
},
}
// init initializes the header h to describe p.
func (h *machoHeader) init(p *Prog) {
h.p = p
h.Segments = nil
h.Loads = nil
var ok bool
h.machoArch, ok = machoArches[p.GOARCH]
if !ok {
p.errorf("mach-o: unknown target GOARCH %q", p.GOARCH)
return
}
h.FileType = uint32(macho.TypeExec)
mseg := h.addSegment(p, "__PAGEZERO", nil)
mseg.VirtSize = p.UnmappedSize
for _, seg := range p.Segments {
h.addSegment(p, "__"+strings.ToUpper(seg.Name), seg)
}
var data []uint32
switch h.CPU {
default:
p.errorf("mach-o: unknown cpu %#x for GOARCH %q", h.CPU, p.GOARCH)
case uint32(macho.CpuAmd64):
data = make([]uint32, 2+42)
data[0] = 4 // thread type
data[1] = 42 // word count
data[2+32] = uint32(p.Entry) // RIP register, in two parts
data[2+32+1] = uint32(p.Entry >> 32)
}
h.Loads = append(h.Loads, &machoLoad{
Type: uint32(macho.LoadCmdUnixThread),
Data: data,
})
}
// addSegment adds to h a Mach-O segment like seg with the given name.
func (h *machoHeader) addSegment(p *Prog, name string, seg *Segment) *machoSegment {
mseg := &machoSegment{
Name: name,
}
h.Segments = append(h.Segments, mseg)
if seg == nil {
return mseg
}
mseg.VirtAddr = seg.VirtAddr
mseg.VirtSize = seg.VirtSize
mseg.FileOffset = round(seg.FileOffset, 4096)
mseg.FileSize = seg.FileSize
if name == "__TEXT" {
// Initially RWX, then just RX
mseg.Prot1 = 7
mseg.Prot2 = 5
// Text segment maps Mach-O header, needed by dynamic linker.
mseg.VirtAddr -= p.HeaderSize
mseg.VirtSize += p.HeaderSize
mseg.FileOffset -= p.HeaderSize
mseg.FileSize += p.HeaderSize
} else {
// RW
mseg.Prot1 = 3
mseg.Prot2 = 3
}
for _, sect := range seg.Sections {
h.addSection(mseg, seg, sect)
}
return mseg
}
// addSection adds to mseg a Mach-O section like sect, inside seg, with the given name.
func (h *machoHeader) addSection(mseg *machoSegment, seg *Segment, sect *Section) {
msect := &machoSection{
Name: "__" + sect.Name,
Segment: mseg.Name,
// Reloc: sect.RelocOffset,
// NumReloc: sect.RelocLen / 8,
Addr: sect.VirtAddr,
Size: sect.Size,
}
mseg.Sections = append(mseg.Sections, msect)
for 1<<msect.Align < sect.Align {
msect.Align++
}
if off := sect.VirtAddr - seg.VirtAddr; off < seg.FileSize {
// Data in file.
if sect.Size > seg.FileSize-off {
h.p.errorf("mach-o error: section crosses file boundary")
}
msect.Offset = uint32(seg.FileOffset + off)
} else {
// Zero filled.
msect.Flags |= 1
}
if sect.Name == "text" {
msect.Flags |= 0x400 // contains executable instructions
}
}
// A machoWriter helps write Mach-O headers.
// It is basically a buffer with some helper routines for writing integers.
type machoWriter struct {
dst []byte
tmp [8]byte
order binary.ByteOrder
is64 bool
p *Prog
}
// if64 returns x if w is writing a 64-bit object file; otherwise it returns y.
func (w *machoWriter) if64(x, y interface{}) interface{} {
if w.is64 {
return x
}
return y
}
// encode encodes each of the given arguments into the writer.
// It encodes uint32, []uint32, uint64, and []uint64 by writing each value
// in turn in the correct byte order for the output file.
// It encodes an Addr as a uint64 if writing a 64-bit output file, or else as a uint32.
// It encodes []byte and string by writing the raw bytes (no length prefix).
// It skips nil values in the args list.
func (w *machoWriter) encode(args ...interface{}) {
for _, arg := range args {
switch arg := arg.(type) {
default:
w.p.errorf("mach-o error: cannot encode %T", arg)
case nil:
// skip
case []byte:
w.dst = append(w.dst, arg...)
case string:
w.dst = append(w.dst, arg...)
case uint32:
w.order.PutUint32(w.tmp[:], arg)
w.dst = append(w.dst, w.tmp[:4]...)
case []uint32:
for _, x := range arg {
w.order.PutUint32(w.tmp[:], x)
w.dst = append(w.dst, w.tmp[:4]...)
}
case uint64:
w.order.PutUint64(w.tmp[:], arg)
w.dst = append(w.dst, w.tmp[:8]...)
case Addr:
if w.is64 {
w.order.PutUint64(w.tmp[:], uint64(arg))
w.dst = append(w.dst, w.tmp[:8]...)
} else {
if Addr(uint32(arg)) != arg {
w.p.errorf("mach-o error: truncating address %#x to uint32", arg)
}
w.order.PutUint32(w.tmp[:], uint32(arg))
w.dst = append(w.dst, w.tmp[:4]...)
}
}
}
}
// segmentSize returns the size of the encoding of seg in bytes.
func (w *machoWriter) segmentSize(seg *machoSegment) int {
if w.is64 {
return 18*4 + 20*4*len(seg.Sections)
}
return 14*4 + 22*4*len(seg.Sections)
}
// zeroPad returns the string s truncated or padded with NULs to n bytes.
func zeroPad(s string, n int) string {
if len(s) >= n {
return s[:n]
}
return s + strings.Repeat("\x00", n-len(s))
}
// size returns the encoded size of the header.
func (h *machoHeader) size() int {
// Could write separate code, but encoding is cheap; encode and throw it away.
return len(h.encode())
}
// encode returns the Mach-O encoding of the header.
func (h *machoHeader) encode() []byte {
w := &machoWriter{p: h.p}
w.is64 = h.CPU&macho64Bit != 0
w.order = w.p.byteorder
loadSize := 0
for _, seg := range h.Segments {
loadSize += w.segmentSize(seg)
}
for _, l := range h.Loads {
loadSize += 4 * (2 + len(l.Data))
}
w.encode(
w.if64(macho.Magic64, macho.Magic32),
uint32(h.CPU),
uint32(h.SubCPU),
uint32(h.FileType),
uint32(len(h.Loads)+len(h.Segments)),
uint32(loadSize),
uint32(1),
w.if64(uint32(0), nil),
)
for _, seg := range h.Segments {
w.encode(
w.if64(uint32(macho.LoadCmdSegment64), uint32(macho.LoadCmdSegment)),
uint32(w.segmentSize(seg)),
zeroPad(seg.Name, 16),
seg.VirtAddr,
seg.VirtSize,
seg.FileOffset,
seg.FileSize,
seg.Prot1,
seg.Prot2,
uint32(len(seg.Sections)),
seg.Flags,
)
for _, sect := range seg.Sections {
w.encode(
zeroPad(sect.Name, 16),
zeroPad(seg.Name, 16),
sect.Addr,
sect.Size,
sect.Offset,
sect.Align,
sect.Reloc,
sect.Nreloc,
sect.Flags,
sect.Res1,
sect.Res2,
w.if64(uint32(0), nil),
)
}
}
for _, load := range h.Loads {
w.encode(
load.Type,
uint32(4*(2+len(load.Data))),
load.Data,
)
}
return w.dst
}
// Copyright 2014 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 main
import (
"bytes"
"debug/macho"
"encoding/binary"
"fmt"
"io/ioutil"
"strings"
"testing"
)
// Test macho writing by checking that each generated prog can be written
// and then read back using debug/macho to get the same prog.
// Also check against golden testdata file.
var machoWriteTests = []struct {
name string
golden bool
prog *Prog
}{
// amd64 exit 9
{
name: "exit9",
golden: true,
prog: &Prog{
GOARCH: "amd64",
GOOS: "darwin",
UnmappedSize: 0x1000,
Entry: 0x1000,
Segments: []*Segment{
{
Name: "text",
VirtAddr: 0x1000,
VirtSize: 13,
FileOffset: 0,
FileSize: 13,
Data: []byte{
0xb8, 0x01, 0x00, 0x00, 0x02, // MOVL $0x2000001, AX
0xbf, 0x09, 0x00, 0x00, 0x00, // MOVL $9, DI
0x0f, 0x05, // SYSCALL
0xf4, // HLT
},
Sections: []*Section{
{
Name: "text",
VirtAddr: 0x1000,
Size: 13,
Align: 64,
},
},
},
},
},
},
// amd64 write hello world & exit 9
{
name: "hello",
golden: true,
prog: &Prog{
GOARCH: "amd64",
GOOS: "darwin",
UnmappedSize: 0x1000,
Entry: 0x1000,
Segments: []*Segment{
{
Name: "text",
VirtAddr: 0x1000,
VirtSize: 35,
FileOffset: 0,
FileSize: 35,
Data: []byte{
0xb8, 0x04, 0x00, 0x00, 0x02, // MOVL $0x2000001, AX
0xbf, 0x01, 0x00, 0x00, 0x00, // MOVL $1, DI
0xbe, 0x00, 0x30, 0x00, 0x00, // MOVL $0x3000, SI
0xba, 0x0c, 0x00, 0x00, 0x00, // MOVL $12, DX
0x0f, 0x05, // SYSCALL
0xb8, 0x01, 0x00, 0x00, 0x02, // MOVL $0x2000001, AX
0xbf, 0x09, 0x00, 0x00, 0x00, // MOVL $9, DI
0x0f, 0x05, // SYSCALL
0xf4, // HLT
},
Sections: []*Section{
{
Name: "text",
VirtAddr: 0x1000,
Size: 35,
Align: 64,
},
},
},
{
Name: "data",
VirtAddr: 0x2000,
VirtSize: 12,
FileOffset: 0x1000,
FileSize: 12,
Data: []byte("hello world\n"),
Sections: []*Section{
{
Name: "data",
VirtAddr: 0x2000,
Size: 12,
Align: 64,
},
},
},
},
},
},
// amd64 write hello world from rodata & exit 0
{
name: "helloro",
golden: true,
prog: &Prog{
GOARCH: "amd64",
GOOS: "darwin",
UnmappedSize: 0x1000,
Entry: 0x1000,
Segments: []*Segment{
{
Name: "text",
VirtAddr: 0x1000,
VirtSize: 0x100c,
FileOffset: 0,
FileSize: 0x100c,
Data: concat(
[]byte{
0xb8, 0x04, 0x00, 0x00, 0x02, // MOVL $0x2000001, AX
0xbf, 0x01, 0x00, 0x00, 0x00, // MOVL $1, DI
0xbe, 0x00, 0x30, 0x00, 0x00, // MOVL $0x3000, SI
0xba, 0x0c, 0x00, 0x00, 0x00, // MOVL $12, DX
0x0f, 0x05, // SYSCALL
0xb8, 0x01, 0x00, 0x00, 0x02, // MOVL $0x2000001, AX
0xbf, 0x00, 0x00, 0x00, 0x00, // MOVL $0, DI
0x0f, 0x05, // SYSCALL
0xf4, // HLT
},
make([]byte, 0x1000-35),
[]byte("hello world\n"),
),
Sections: []*Section{
{
Name: "text",
VirtAddr: 0x1000,
Size: 35,
Align: 64,
},
{
Name: "rodata",
VirtAddr: 0x2000,
Size: 12,
Align: 64,
},
},
},
},
},
},
}
func concat(xs ...[]byte) []byte {
var out []byte
for _, x := range xs {
out = append(out, x...)
}
return out
}
func TestMachoWrite(t *testing.T) {
for _, tt := range machoWriteTests {
name := tt.prog.GOARCH + "." + tt.name
prog := cloneProg(tt.prog)
prog.init()
var f machoFormat
vsize, fsize := f.headerSize(prog)
shiftProg(prog, vsize, fsize)
var buf bytes.Buffer
f.write(&buf, prog)
if false { // enable to debug
ioutil.WriteFile("a.out", buf.Bytes(), 0777)
}
read, err := machoRead(machoArches[tt.prog.GOARCH], buf.Bytes())
if err != nil {
t.Errorf("%s: reading mach-o output:\n\t%v", name, err)
continue
}
diffs := diffProg(read, prog)
if diffs != nil {
t.Errorf("%s: mismatched prog:\n\t%s", name, strings.Join(diffs, "\n\t"))
continue
}
if !tt.golden {
continue
}
checkGolden(t, buf.Bytes(), "testdata/macho."+name)
}
}
// machoRead reads the mach-o file in data and returns a corresponding prog.
func machoRead(arch machoArch, data []byte) (*Prog, error) {
f, err := macho.NewFile(bytes.NewReader(data))
if err != nil {
return nil, err
}
var errors []string
errorf := func(format string, args ...interface{}) {
errors = append(errors, fmt.Sprintf(format, args...))
}
magic := uint32(0xFEEDFACE)
if arch.CPU&macho64Bit != 0 {
magic |= 1
}
if f.Magic != magic {
errorf("header: Magic = %#x, want %#x", f.Magic, magic)
}
if f.Cpu != macho.CpuAmd64 {
errorf("header: CPU = %#x, want %#x", f.Cpu, macho.CpuAmd64)
}
if f.SubCpu != 3 {
errorf("header: SubCPU = %#x, want %#x", f.SubCpu, 3)
}
if f.Type != 2 {
errorf("header: FileType = %d, want %d", f.Type, 2)
}
if f.Flags != 1 {
errorf("header: Flags = %d, want %d", f.Flags, 1)
}
msects := f.Sections
var limit uint64
prog := new(Prog)
for _, load := range f.Loads {
switch load := load.(type) {
default:
errorf("unexpected macho load %T %x", load, load.Raw())
case macho.LoadBytes:
if len(load) < 8 || len(load)%4 != 0 {
errorf("unexpected load length %d", len(load))
continue
}
cmd := f.ByteOrder.Uint32(load)
switch macho.LoadCmd(cmd) {
default:
errorf("unexpected macho load cmd %s", macho.LoadCmd(cmd))
case macho.LoadCmdUnixThread:
data := make([]uint32, len(load[8:])/4)
binary.Read(bytes.NewReader(load[8:]), f.ByteOrder, data)
if len(data) != 44 {
errorf("macho thread len(data) = %d, want 42", len(data))
continue
}
if data[0] != 4 {
errorf("macho thread type = %d, want 4", data[0])
}
if data[1] != uint32(len(data))-2 {
errorf("macho thread desc len = %d, want %d", data[1], uint32(len(data))-2)
continue
}
for i, val := range data[2:] {
switch i {
default:
if val != 0 {
errorf("macho thread data[%d] = %#x, want 0", i, val)
}
case 32:
prog.Entry = Addr(val)
case 33:
prog.Entry |= Addr(val) << 32
}
}
}
case *macho.Segment:
if load.Addr < limit {
errorf("segments out of order: %q at %#x after %#x", load.Name, load.Addr, limit)
}
limit = load.Addr + load.Memsz
if load.Name == "__PAGEZERO" || load.Addr == 0 && load.Filesz == 0 {
if load.Name != "__PAGEZERO" {
errorf("segment with Addr=0, Filesz=0 is named %q, want %q", load.Name, "__PAGEZERO")
} else if load.Addr != 0 || load.Filesz != 0 {
errorf("segment %q has Addr=%#x, Filesz=%d, want Addr=%#x, Filesz=%d", load.Name, load.Addr, load.Filesz, 0, 0)
}
prog.UnmappedSize = Addr(load.Memsz)
continue
}
if !strings.HasPrefix(load.Name, "__") {
errorf("segment name %q does not begin with %q", load.Name, "__")
}
if strings.ToUpper(load.Name) != load.Name {
errorf("segment name %q is not all upper case", load.Name)
}
seg := &Segment{
Name: strings.ToLower(strings.TrimPrefix(load.Name, "__")),
VirtAddr: Addr(load.Addr),
VirtSize: Addr(load.Memsz),
FileOffset: Addr(load.Offset),
FileSize: Addr(load.Filesz),
}
prog.Segments = append(prog.Segments, seg)
data, err := load.Data()
if err != nil {
errorf("loading data from %q: %v", load.Name, err)
}
seg.Data = data
var maxprot, prot uint32
if load.Name == "__TEXT" {
maxprot, prot = 7, 5
} else {
maxprot, prot = 3, 3
}
if load.Maxprot != maxprot || load.Prot != prot {
errorf("segment %q protection is %d, %d, want %d, %d",
load.Name, load.Maxprot, load.Prot, maxprot, prot)
}
for len(msects) > 0 && msects[0].Addr < load.Addr+load.Memsz {
msect := msects[0]
msects = msects[1:]
if msect.Offset > 0 && prog.HeaderSize == 0 {
prog.HeaderSize = Addr(msect.Offset)
if seg.FileOffset != 0 {
errorf("initial segment %q does not map header", load.Name)
}
seg.VirtAddr += prog.HeaderSize
seg.VirtSize -= prog.HeaderSize
seg.FileOffset += prog.HeaderSize
seg.FileSize -= prog.HeaderSize
seg.Data = seg.Data[prog.HeaderSize:]
}
if msect.Addr < load.Addr {
errorf("section %q at address %#x is missing segment", msect.Name, msect.Addr)
continue
}
if !strings.HasPrefix(msect.Name, "__") {
errorf("section name %q does not begin with %q", msect.Name, "__")
}
if strings.ToLower(msect.Name) != msect.Name {
errorf("section name %q is not all lower case", msect.Name)
}
if msect.Seg != load.Name {
errorf("section %q is lists segment name %q, want %q",
msect.Name, msect.Seg, load.Name)
}
if uint64(msect.Offset) != uint64(load.Offset)+msect.Addr-load.Addr {
errorf("section %q file offset is %#x, want %#x",
msect.Name, msect.Offset, load.Offset+msect.Addr-load.Addr)
}
if msect.Reloff != 0 || msect.Nreloc != 0 {
errorf("section %q has reloff %d,%d, want %d,%d",
msect.Name, msect.Reloff, msect.Nreloc, 0, 0)
}
flags := uint32(0)
if msect.Name == "__text" {
flags = 0x400
}
if msect.Offset == 0 {
flags = 1
}
if msect.Flags != flags {
errorf("section %q flags = %#x, want %#x", msect.Name, msect.Flags, flags)
}
sect := &Section{
Name: strings.ToLower(strings.TrimPrefix(msect.Name, "__")),
VirtAddr: Addr(msect.Addr),
Size: Addr(msect.Size),
Align: 1 << msect.Align,
}
seg.Sections = append(seg.Sections, sect)
}
}
}
for _, msect := range msects {
errorf("section %q has no segment", msect.Name)
}
limit = 0
for _, msect := range f.Sections {
if msect.Addr < limit {
errorf("sections out of order: %q at %#x after %#x", msect.Name, msect.Addr, limit)
}
limit = msect.Addr + msect.Size
}
err = nil
if errors != nil {
err = fmt.Errorf("%s", strings.Join(errors, "\n\t"))
}
return prog, err
}
// Copyright 2014 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.
// Placeholder to keep build building.
package main
func main() {}
// Copyright 2014 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.
// Generation of runtime function information (pclntab).
package main
import (
"cmd/internal/goobj"
"cmd/internal/obj"
"encoding/binary"
"os"
"sort"
)
var zerofunc goobj.Func
// pclntab collects the runtime function data for each function that will
// be listed in the binary and builds a single table describing all functions.
// This table is used at run time for stack traces and to look up PC-specific
// information during garbage collection. The symbol created is named
// "pclntab" for historical reasons; the scope of the table has grown to
// include more than just PC/line number correspondences.
// The table format is documented at https://golang.org/s/go12symtab.
func (p *Prog) pclntab() {
// Count number of functions going into the binary,
// so that we can size the initial index correctly.
nfunc := 0
for _, sym := range p.SymOrder {
if sym.Kind != goobj.STEXT {
continue
}
nfunc++
}
// Table header.
buf := new(SymBuffer)
buf.Init(p)
buf.SetSize(8 + p.ptrsize)
off := 0
off = buf.Uint32(off, 0xfffffffb)
off = buf.Uint8(off, 0)
off = buf.Uint8(off, 0)
off = buf.Uint8(off, uint8(p.pcquantum))
off = buf.Uint8(off, uint8(p.ptrsize))
off = buf.Uint(off, uint64(nfunc), p.ptrsize)
indexOff := off
off += (nfunc*2 + 1) * p.ptrsize // function index, to be filled in
off += 4 // file table start offset, to be filled in
buf.SetSize(off)
// One-file cache for reading PCData tables from package files.
// TODO(rsc): Better I/O strategy.
var (
file *os.File
fname string
)
// Files gives the file numbering for source file names recorded
// in the binary.
files := make(map[string]int)
// Build the table, build the index, and build the file name numbering.
// The loop here must visit functions in the same order that they will
// be stored in the binary, or else binary search over the index will fail.
// The runtime checks that the index is sorted properly at program start time.
var lastSym *Sym
for _, sym := range p.SymOrder {
if sym.Kind != goobj.STEXT {
continue
}
lastSym = sym
// Treat no recorded function information same as all zeros.
f := sym.Func
if f == nil {
f = &zerofunc
}
// Open package file if needed, for reading PC data.
if fname != sym.Package.File {
if file != nil {
file.Close()
}
var err error
file, err = os.Open(sym.Package.File)
if err != nil {
p.errorf("%v: %v", sym, err)
return
}
fname = sym.Package.File
}
// off is the offset of the table entry where we're going to write
// the encoded form of Func.
// indexOff is the current position in the table index;
// we add an entry in the index pointing at off.
off = (buf.Size() + p.ptrsize - 1) &^ (p.ptrsize - 1)
indexOff = buf.Addr(indexOff, sym.SymID, 0)
indexOff = buf.Uint(indexOff, uint64(off), p.ptrsize)
// The Func encoding starts with a header giving offsets
// to data blobs, and then the data blobs themselves.
// end gives the current write position for the data blobs.
end := off + p.ptrsize + 3*4 + 5*4 + len(f.PCData)*4 + len(f.FuncData)*p.ptrsize
if len(f.FuncData) > 0 {
end += -end & (p.ptrsize - 1)
}
buf.SetSize(end)
// entry uintptr
// name int32
// args int32
// frame int32
//
// The frame recorded in the object file is
// the frame size used in an assembly listing, which does
// not include the caller PC on the stack.
// The frame size we want to list here is the delta from
// this function's SP to its caller's SP, which does include
// the caller PC. Add p.ptrsize to f.Frame to adjust.
// TODO(rsc): Record the same frame size in the object file.
off = buf.Addr(off, sym.SymID, 0)
off = buf.Uint32(off, uint32(addString(buf, sym.Name)))
off = buf.Uint32(off, uint32(f.Args))
off = buf.Uint32(off, uint32(f.Frame+p.ptrsize))
// pcdata
off = buf.Uint32(off, uint32(addPCTable(p, buf, file, f.PCSP)))
off = buf.Uint32(off, uint32(addPCFileTable(p, buf, file, f.PCFile, sym, files)))
off = buf.Uint32(off, uint32(addPCTable(p, buf, file, f.PCLine)))
off = buf.Uint32(off, uint32(len(f.PCData)))
off = buf.Uint32(off, uint32(len(f.FuncData)))
for _, pcdata := range f.PCData {
off = buf.Uint32(off, uint32(addPCTable(p, buf, file, pcdata)))
}
// funcdata
if len(f.FuncData) > 0 {
off += -off & (p.ptrsize - 1) // must be pointer-aligned
for _, funcdata := range f.FuncData {
if funcdata.Sym.Name == "" {
off = buf.Uint(off, uint64(funcdata.Offset), p.ptrsize)
} else {
off = buf.Addr(off, funcdata.Sym, funcdata.Offset)
}
}
}
if off != end {
p.errorf("internal error: invalid math in pclntab: off=%#x end=%#x", off, end)
break
}
}
if file != nil {
file.Close()
}
// Final entry of index is end PC of last function.
indexOff = buf.Addr(indexOff, lastSym.SymID, int64(lastSym.Size))
// Start file table.
// Function index is immediately followed by offset to file table.
off = (buf.Size() + p.ptrsize - 1) &^ (p.ptrsize - 1)
buf.Uint32(indexOff, uint32(off))
// File table is an array of uint32s.
// The first entry gives 1+n, the size of the array.
// The following n entries hold offsets to string data.
// File number n uses the string pointed at by entry n.
// File number 0 is invalid.
buf.SetSize(off + (1+len(files))*4)
buf.Uint32(off, uint32(1+len(files)))
var filestr []string
for file := range files {
filestr = append(filestr, file)
}
sort.Strings(filestr)
for _, file := range filestr {
id := files[file]
buf.Uint32(off+4*id, uint32(addString(buf, file)))
}
pclntab := &Sym{
Sym: &goobj.Sym{
SymID: goobj.SymID{Name: "runtime.pclntab"},
Kind: goobj.SPCLNTAB,
Size: buf.Size(),
Reloc: buf.Reloc(),
},
Bytes: buf.Bytes(),
}
p.addSym(pclntab)
}
// addString appends the string s to the buffer b.
// It returns the offset of the beginning of the string in the buffer.
func addString(b *SymBuffer, s string) int {
off := b.Size()
b.SetSize(off + len(s) + 1)
copy(b.data[off:], s)
return off
}
// addPCTable appends the PC-data table stored in the file f at the location loc
// to the symbol buffer b. It returns the offset of the beginning of the table
// in the buffer.
func addPCTable(p *Prog, b *SymBuffer, f *os.File, loc goobj.Data) int {
if loc.Size == 0 {
return 0
}
off := b.Size()
b.SetSize(off + int(loc.Size))
_, err := f.ReadAt(b.data[off:off+int(loc.Size)], loc.Offset)
if err != nil {
p.errorf("%v", err)
}
return off
}
// addPCFileTable is like addPCTable, but it renumbers the file names referred to by the table
// to use the global numbering maintained in the files map. It adds new files to the
// map as necessary.
func addPCFileTable(p *Prog, b *SymBuffer, f *os.File, loc goobj.Data, sym *Sym, files map[string]int) int {
if loc.Size == 0 {
return 0
}
off := b.Size()
src := make([]byte, loc.Size)
_, err := f.ReadAt(src, loc.Offset)
if err != nil {
p.errorf("%v", err)
return 0
}
filenum := make([]int, len(sym.Func.File))
for i, name := range sym.Func.File {
num := files[name]
if num == 0 {
num = len(files) + 1
files[name] = num
}
filenum[i] = num
}
var dst []byte
newval := int32(-1)
var it PCIter
for it.Init(p, src); !it.Done; it.Next() {
// value delta
oldval := it.Value
val := oldval
if oldval != -1 {
if oldval < 0 || int(oldval) >= len(filenum) {
p.errorf("%s: corrupt pc-file table", sym)
break
}
val = int32(filenum[oldval])
}
dv := val - newval
newval = val
uv := uint32(dv<<1) ^ uint32(dv>>31)
dst = appendVarint(dst, uv)
// pc delta
dst = appendVarint(dst, it.NextPC-it.PC)
}
if it.Corrupt {
p.errorf("%s: corrupt pc-file table", sym)
}
// terminating value delta
dst = appendVarint(dst, 0)
b.SetSize(off + len(dst))
copy(b.data[off:], dst)
return off
}
// A SymBuffer is a buffer for preparing the data image of a
// linker-generated symbol.
type SymBuffer struct {
data []byte
reloc []goobj.Reloc
order binary.ByteOrder
ptrsize int
}
// Init initializes the buffer for writing.
func (b *SymBuffer) Init(p *Prog) {
b.data = nil
b.reloc = nil
b.order = p.byteorder
b.ptrsize = p.ptrsize
}
// Bytes returns the buffer data.
func (b *SymBuffer) Bytes() []byte {
return b.data
}
// SetSize sets the buffer's data size to n bytes.
func (b *SymBuffer) SetSize(n int) {
for cap(b.data) < n {
b.data = append(b.data[:cap(b.data)], 0)
}
b.data = b.data[:n]
}
// Size returns the buffer's data size.
func (b *SymBuffer) Size() int {
return len(b.data)
}
// Reloc returns the buffered relocations.
func (b *SymBuffer) Reloc() []goobj.Reloc {
return b.reloc
}
// Uint8 sets the uint8 at offset off to v.
// It returns the offset just beyond v.
func (b *SymBuffer) Uint8(off int, v uint8) int {
b.data[off] = v
return off + 1
}
// Uint16 sets the uint16 at offset off to v.
// It returns the offset just beyond v.
func (b *SymBuffer) Uint16(off int, v uint16) int {
b.order.PutUint16(b.data[off:], v)
return off + 2
}
// Uint32 sets the uint32 at offset off to v.
// It returns the offset just beyond v.
func (b *SymBuffer) Uint32(off int, v uint32) int {
b.order.PutUint32(b.data[off:], v)
return off + 4
}
// Uint64 sets the uint64 at offset off to v.
// It returns the offset just beyond v.
func (b *SymBuffer) Uint64(off int, v uint64) int {
b.order.PutUint64(b.data[off:], v)
return off + 8
}
// Uint sets the size-byte unsigned integer at offset off to v.
// It returns the offset just beyond v.
func (b *SymBuffer) Uint(off int, v uint64, size int) int {
switch size {
case 1:
return b.Uint8(off, uint8(v))
case 2:
return b.Uint16(off, uint16(v))
case 4:
return b.Uint32(off, uint32(v))
case 8:
return b.Uint64(off, v)
}
panic("invalid use of SymBuffer.SetUint")
}
// Addr sets the pointer-sized address at offset off to refer
// to symoff bytes past the start of sym. It returns the offset
// just beyond the address.
func (b *SymBuffer) Addr(off int, sym goobj.SymID, symoff int64) int {
b.reloc = append(b.reloc, goobj.Reloc{
Offset: off,
Size: b.ptrsize,
Sym: sym,
Add: int(symoff),
Type: obj.R_ADDR,
})
return off + b.ptrsize
}
// A PCIter implements iteration over PC-data tables.
//
// var it PCIter
// for it.Init(p, data); !it.Done; it.Next() {
// it.Value holds from it.PC up to (but not including) it.NextPC
// }
// if it.Corrupt {
// data was malformed
// }
//
type PCIter struct {
PC uint32
NextPC uint32
Value int32
Done bool
Corrupt bool
p []byte
start bool
pcquantum uint32
}
// Init initializes the iteration.
// On return, if it.Done is true, the iteration is over.
// Otherwise it.Value applies in the pc range [it.PC, it.NextPC).
func (it *PCIter) Init(p *Prog, buf []byte) {
it.p = buf
it.PC = 0
it.NextPC = 0
it.Value = -1
it.start = true
it.pcquantum = uint32(p.pcquantum)
it.Done = false
it.Next()
}
// Next steps forward one entry in the table.
// On return, if it.Done is true, the iteration is over.
// Otherwise it.Value applies in the pc range [it.PC, it.NextPC).
func (it *PCIter) Next() {
it.PC = it.NextPC
if it.Done {
return
}
if len(it.p) == 0 {
it.Done = true
return
}
// value delta
uv, p, ok := decodeVarint(it.p)
if !ok {
it.Done = true
it.Corrupt = true
return
}
it.p = p
if uv == 0 && !it.start {
it.Done = true
return
}
it.start = false
sv := int32(uv>>1) ^ int32(uv<<31)>>31
it.Value += sv
// pc delta
uv, it.p, ok = decodeVarint(it.p)
if !ok {
it.Done = true
it.Corrupt = true
return
}
it.NextPC = it.PC + uv*it.pcquantum
}
// decodeVarint decodes an unsigned varint from p,
// reporting the value, the remainder of the data, and
// whether the decoding was successful.
func decodeVarint(p []byte) (v uint32, rest []byte, ok bool) {
for shift := uint(0); ; shift += 7 {
if len(p) == 0 {
return
}
c := uint32(p[0])
p = p[1:]
v |= (c & 0x7F) << shift
if c&0x80 == 0 {
break
}
}
return v, p, true
}
// appendVarint appends an unsigned varint encoding of v to p
// and returns the resulting slice.
func appendVarint(p []byte, v uint32) []byte {
for ; v >= 0x80; v >>= 7 {
p = append(p, byte(v)|0x80)
}
p = append(p, byte(v))
return p
}
// Copyright 2014 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 main
import (
"bytes"
"cmd/internal/goobj"
"fmt"
"math/rand"
"sort"
"strings"
"testing"
)
// Test of pcln table encoding.
// testdata/genpcln.go generates an assembly file with
// pseudorandom values for the data that pclntab stores.
// This test recomputes the same pseudorandom stream
// and checks that the final linked binary uses those values
// as well.
func TestPclntab(t *testing.T) {
p := &Prog{
GOOS: "darwin",
GOARCH: "amd64",
Error: func(s string) { t.Error(s) },
StartSym: "start",
omitRuntime: true,
}
var buf bytes.Buffer
p.link(&buf, "testdata/pclntab.6")
if p.NumError > 0 {
return
}
// The algorithm for computing values here must match
// the one in testdata/genpcln.go.
for f := 0; f < 3; f++ {
file := "input"
line := 1
rnd := rand.New(rand.NewSource(int64(f)))
args := rnd.Intn(100) * 8
frame := 32 + rnd.Intn(32)/8*8
size := 200 + rnd.Intn(100)*8
name := fmt.Sprintf("func%d", f)
r, off, fargs, fframe, ok := findFunc(t, p, name)
if !ok {
continue // error already printed
}
if fargs != args {
t.Errorf("%s: args=%d, want %d", name, fargs, args)
}
if fframe != frame+8 {
t.Errorf("%s: frame=%d, want %d", name, fframe, frame+8)
}
// Check FUNCDATA 1.
fdata, ok := loadFuncdata(t, r, name, off, 1)
if ok {
fsym := p.Syms[goobj.SymID{Name: fmt.Sprintf("funcdata%d", f)}]
if fsym == nil {
t.Errorf("funcdata%d is missing in binary", f)
} else if fdata != fsym.Addr {
t.Errorf("%s: funcdata 1 = %#x, want %#x", name, fdata, fsym.Addr)
}
}
// Walk code checking pcdata values.
spadj := 0
pcdata1 := -1
pcdata2 := -1
checkPCSP(t, r, name, off, 0, 0)
checkPCData(t, r, name, off, 0, 0, -1)
checkPCData(t, r, name, off, 0, 1, -1)
checkPCData(t, r, name, off, 0, 2, -1)
firstpc := 4
for i := 0; i < size; i++ {
pc := firstpc + i // skip SP adjustment to allocate frame
if i >= 0x100 && t.Failed() {
break
}
// Possible SP adjustment.
checkPCSP(t, r, name, off, pc, frame+spadj)
if rnd.Intn(100) == 0 {
checkPCFileLine(t, r, name, off, pc, file, line)
checkPCData(t, r, name, off, pc, 1, pcdata1)
checkPCData(t, r, name, off, pc, 2, pcdata2)
i += 1
pc = firstpc + i
checkPCFileLine(t, r, name, off, pc-1, file, line)
checkPCData(t, r, name, off, pc-1, 1, pcdata1)
checkPCData(t, r, name, off, pc-1, 2, pcdata2)
checkPCSP(t, r, name, off, pc-1, frame+spadj)
if spadj <= -32 || spadj < 32 && rnd.Intn(2) == 0 {
spadj += 8
} else {
spadj -= 8
}
checkPCSP(t, r, name, off, pc, frame+spadj)
}
// Possible PCFile change.
if rnd.Intn(100) == 0 {
file = fmt.Sprintf("file%d.s", rnd.Intn(10))
line = rnd.Intn(100) + 1
}
// Possible PCLine change.
if rnd.Intn(10) == 0 {
line = rnd.Intn(1000) + 1
}
// Possible PCData $1 change.
if rnd.Intn(100) == 0 {
pcdata1 = rnd.Intn(1000)
}
// Possible PCData $2 change.
if rnd.Intn(100) == 0 {
pcdata2 = rnd.Intn(1000)
}
if i == 0 {
checkPCFileLine(t, r, name, off, 0, file, line)
checkPCFileLine(t, r, name, off, pc-1, file, line)
}
checkPCFileLine(t, r, name, off, pc, file, line)
checkPCData(t, r, name, off, pc, 1, pcdata1)
checkPCData(t, r, name, off, pc, 2, pcdata2)
}
}
}
// findFunc finds the function information in the pclntab of p
// for the function with the given name.
// It returns a symbol reader for pclntab, the offset of the function information
// within that symbol, and the args and frame values read out of the information.
func findFunc(t *testing.T, p *Prog, name string) (r *SymReader, off, args, frame int, ok bool) {
tabsym := p.Syms[goobj.SymID{Name: "runtime.pclntab"}]
if tabsym == nil {
t.Errorf("pclntab is missing in binary")
return
}
r = new(SymReader)
r.Init(p, tabsym)
// pclntab must with 8-byte header
if r.Uint32(0) != 0xfffffffb || r.Uint8(4) != 0 || r.Uint8(5) != 0 || r.Uint8(6) != uint8(p.pcquantum) || r.Uint8(7) != uint8(p.ptrsize) {
t.Errorf("pclntab has incorrect header %.8x", r.data[:8])
return
}
sym := p.Syms[goobj.SymID{Name: name}]
if sym == nil {
t.Errorf("%s is missing in the binary", name)
return
}
// index is nfunc addr0 off0 addr1 off1 ... addr_nfunc (sentinel)
nfunc := int(r.Addr(8))
i := sort.Search(nfunc, func(i int) bool {
return r.Addr(8+p.ptrsize*(1+2*i)) >= sym.Addr
})
if entry := r.Addr(8 + p.ptrsize*(1+2*i)); entry != sym.Addr {
indexTab := make([]Addr, 2*nfunc+1)
for j := range indexTab {
indexTab[j] = r.Addr(8 + p.ptrsize*(1+j))
}
t.Errorf("pclntab is missing entry for %s (%#x): %#x", name, sym.Addr, indexTab)
return
}
off = int(r.Addr(8 + p.ptrsize*(1+2*i+1)))
// func description at off is
// entry addr
// nameoff uint32
// args uint32
// frame uint32
// pcspoff uint32
// pcfileoff uint32
// pclineoff uint32
// npcdata uint32
// nfuncdata uint32
// pcdata npcdata*uint32
// funcdata nfuncdata*addr
//
if entry := r.Addr(off); entry != sym.Addr {
t.Errorf("pclntab inconsistent: entry for %s addr=%#x has entry=%#x", name, sym.Addr, entry)
return
}
nameoff := int(r.Uint32(off + p.ptrsize))
args = int(r.Uint32(off + p.ptrsize + 1*4))
frame = int(r.Uint32(off + p.ptrsize + 2*4))
fname := r.String(nameoff)
if fname != name {
t.Errorf("pclntab inconsistent: entry for %s addr=%#x has name %q", name, sym.Addr, fname)
}
ok = true // off, args, frame are usable
return
}
// loadFuncdata returns the funcdata #fnum value
// loaded from the function information for name.
func loadFuncdata(t *testing.T, r *SymReader, name string, off int, fnum int) (Addr, bool) {
npcdata := int(r.Uint32(off + r.p.ptrsize + 6*4))
nfuncdata := int(r.Uint32(off + r.p.ptrsize + 7*4))
if fnum >= nfuncdata {
t.Errorf("pclntab(%s): no funcdata %d (only < %d)", name, fnum, nfuncdata)
return 0, false
}
fdataoff := off + r.p.ptrsize + (8+npcdata)*4 + fnum*r.p.ptrsize
fdataoff += fdataoff & 4
return r.Addr(fdataoff), true
}
// checkPCSP checks that the PCSP table in the function information at off
// lists spadj as the sp delta for pc.
func checkPCSP(t *testing.T, r *SymReader, name string, off, pc, spadj int) {
pcoff := r.Uint32(off + r.p.ptrsize + 3*4)
pcval, ok := readPCData(t, r, name, "PCSP", pcoff, pc)
if !ok {
return
}
if pcval != spadj {
t.Errorf("pclntab(%s): at pc=+%#x, pcsp=%d, want %d", name, pc, pcval, spadj)
}
}
// checkPCSP checks that the PCFile and PCLine tables in the function information at off
// list file, line as the file name and line number for pc.
func checkPCFileLine(t *testing.T, r *SymReader, name string, off, pc int, file string, line int) {
pcfileoff := r.Uint32(off + r.p.ptrsize + 4*4)
pclineoff := r.Uint32(off + r.p.ptrsize + 5*4)
pcfilenum, ok1 := readPCData(t, r, name, "PCFile", pcfileoff, pc)
pcline, ok2 := readPCData(t, r, name, "PCLine", pclineoff, pc)
if !ok1 || !ok2 {
return
}
nfunc := int(r.Addr(8))
filetaboff := r.Uint32(8 + r.p.ptrsize*2*(nfunc+1))
nfile := int(r.Uint32(int(filetaboff)))
if pcfilenum <= 0 || pcfilenum >= nfile {
t.Errorf("pclntab(%s): at pc=+%#x, filenum=%d (invalid; nfile=%d)", name, pc, pcfilenum, nfile)
}
pcfile := r.String(int(r.Uint32(int(filetaboff) + pcfilenum*4)))
if !strings.HasSuffix(pcfile, file) {
t.Errorf("pclntab(%s): at pc=+%#x, file=%q, want %q", name, pc, pcfile, file)
}
if pcline != line {
t.Errorf("pclntab(%s): at pc=+%#x, line=%d, want %d", name, pc, pcline, line)
}
}
// checkPCData checks that the PCData#pnum table in the function information at off
// list val as the value for pc.
func checkPCData(t *testing.T, r *SymReader, name string, off, pc, pnum, val int) {
pcoff := r.Uint32(off + r.p.ptrsize + (8+pnum)*4)
pcval, ok := readPCData(t, r, name, fmt.Sprintf("PCData#%d", pnum), pcoff, pc)
if !ok {
return
}
if pcval != val {
t.Errorf("pclntab(%s): at pc=+%#x, pcdata#%d=%d, want %d", name, pc, pnum, pcval, val)
}
}
// readPCData reads the PCData table offset off
// to obtain and return the value associated with pc.
func readPCData(t *testing.T, r *SymReader, name, pcdataname string, pcoff uint32, pc int) (int, bool) {
// "If pcsp, pcfile, pcln, or any of the pcdata offsets is zero,
// that table is considered missing, and all PCs take value -1."
if pcoff == 0 {
return -1, true
}
var it PCIter
for it.Init(r.p, r.data[pcoff:]); !it.Done; it.Next() {
if it.PC <= uint32(pc) && uint32(pc) < it.NextPC {
return int(it.Value), true
}
}
if it.Corrupt {
t.Errorf("pclntab(%s): %s: corrupt pcdata table", name, pcdataname)
}
return 0, false
}
// A SymReader provides typed access to the data for a symbol.
type SymReader struct {
p *Prog
data []byte
}
func (r *SymReader) Init(p *Prog, sym *Sym) {
seg := sym.Section.Segment
off := sym.Addr - seg.VirtAddr
data := seg.Data[off : off+Addr(sym.Size)]
r.p = p
r.data = data
}
func (r *SymReader) Uint8(off int) uint8 {
return r.data[off]
}
func (r *SymReader) Uint16(off int) uint16 {
return r.p.byteorder.Uint16(r.data[off:])
}
func (r *SymReader) Uint32(off int) uint32 {
return r.p.byteorder.Uint32(r.data[off:])
}
func (r *SymReader) Uint64(off int) uint64 {
return r.p.byteorder.Uint64(r.data[off:])
}
func (r *SymReader) Addr(off int) Addr {
if r.p.ptrsize == 4 {
return Addr(r.Uint32(off))
}
return Addr(r.Uint64(off))
}
func (r *SymReader) String(off int) string {
end := off
for r.data[end] != '\x00' {
end++
}
return string(r.data[off:end])
}
// Copyright 2014 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 main
import (
"cmd/internal/goobj"
"encoding/binary"
"fmt"
"go/build"
"io"
"os"
"runtime"
)
// A Prog holds state for constructing an executable (program) image.
//
// The usual sequence of operations on a Prog is:
//
// p.init()
// p.scan(file)
// p.dead()
// p.runtime()
// p.layout()
// p.load()
// p.debug()
// p.write(w)
//
// p.init is in this file. The rest of the methods are in files
// named for the method. The convenience method p.link runs
// this sequence.
//
type Prog struct {
// Context
GOOS string // target operating system
GOARCH string // target architecture
Format string // desired file format ("elf", "macho", ...)
Error func(string) // called to report an error (if set)
NumError int // number of errors printed
StartSym string
// Derived context
arch
formatter formatter
startSym goobj.SymID
pkgdir string
omitRuntime bool // do not load runtime package
// Input
Packages map[string]*Package // loaded packages, by import path
Syms map[goobj.SymID]*Sym // defined symbols, by symbol ID
Missing map[goobj.SymID]bool // missing symbols
Dead map[goobj.SymID]bool // symbols removed as dead
SymOrder []*Sym // order syms were scanned
MaxVersion int // max SymID.Version, for generating fresh symbol IDs
// Output
UnmappedSize Addr // size of unmapped region at address 0
HeaderSize Addr // size of object file header
Entry Addr // virtual address where execution begins
Segments []*Segment // loaded memory segments
}
// An arch describes architecture-dependent settings.
type arch struct {
byteorder binary.ByteOrder
ptrsize int
pcquantum int
}
// A formatter takes care of the details of generating a particular
// kind of executable file.
type formatter interface {
// headerSize returns the footprint of the header for p
// in both virtual address space and file bytes.
// The footprint does not include any bytes stored at the
// end of the file.
headerSize(p *Prog) (virt, file Addr)
// write writes the executable file for p to w.
write(w io.Writer, p *Prog)
}
// An Addr represents a virtual memory address, a file address, or a size.
// It must be a uint64, not a uintptr, so that a 32-bit linker can still generate a 64-bit binary.
// It must be unsigned in order to link programs placed at very large start addresses.
// Math involving Addrs must be checked carefully not to require negative numbers.
type Addr uint64
// A Package is a Go package loaded from a file.
type Package struct {
*goobj.Package // table of contents
File string // file name for reopening
Syms []*Sym // symbols defined by this package
}
// A Sym is a symbol defined in a loaded package.
type Sym struct {
*goobj.Sym // symbol metadata from package file
Package *Package // package defining symbol
Section *Section // section where symbol is placed in output program
Addr Addr // virtual address of symbol in output program
Bytes []byte // symbol data, for internally defined symbols
}
// A Segment is a loaded memory segment.
// A Prog is expected to have segments named "text" and optionally "data",
// in that order, before any other segments.
type Segment struct {
Name string // name of segment: "text", "data", ...
VirtAddr Addr // virtual memory address of segment base
VirtSize Addr // size of segment in memory
FileOffset Addr // file offset of segment base
FileSize Addr // size of segment in file; can be less than VirtSize
Sections []*Section // sections inside segment
Data []byte // raw data of segment image
}
// A Section is part of a loaded memory segment.
type Section struct {
Name string // name of section: "text", "rodata", "noptrbss", and so on
VirtAddr Addr // virtual memory address of section base
Size Addr // size of section in memory
Align Addr // required alignment
InFile bool // section has image data in file (like data, unlike bss)
Syms []*Sym // symbols stored in section
Segment *Segment // segment containing section
}
func (p *Prog) errorf(format string, args ...interface{}) {
if p.Error != nil {
p.Error(fmt.Sprintf(format, args...))
} else {
fmt.Fprintf(os.Stderr, format+"\n", args...)
}
p.NumError++
}
// link is the one-stop convenience method for running a link.
// It writes to w the object file generated from using mainFile as the main package.
func (p *Prog) link(w io.Writer, mainFile string) {
p.init()
p.scan(mainFile)
if p.NumError > 0 {
return
}
p.dead()
p.runtime()
p.autoData()
p.layout()
if p.NumError > 0 {
return
}
p.load()
if p.NumError > 0 {
return
}
p.debug()
if p.NumError > 0 {
return
}
p.write(w)
}
// init initializes p for use by the other methods.
func (p *Prog) init() {
// Set default context if not overridden.
if p.GOOS == "" {
p.GOOS = build.Default.GOOS
}
if p.GOARCH == "" {
p.GOARCH = build.Default.GOARCH
}
if p.Format == "" {
p.Format = goosFormat[p.GOOS]
if p.Format == "" {
p.errorf("no default file format for GOOS %q", p.GOOS)
return
}
}
if p.StartSym == "" {
p.StartSym = fmt.Sprintf("_rt0_%s_%s", p.GOARCH, p.GOOS)
}
// Derive internal context.
p.formatter = formatters[p.Format]
if p.formatter == nil {
p.errorf("unknown output file format %q", p.Format)
return
}
p.startSym = goobj.SymID{Name: p.StartSym}
arch, ok := arches[p.GOARCH]
if !ok {
p.errorf("unknown GOOS %q", p.GOOS)
return
}
p.arch = arch
p.pkgdir = fmt.Sprintf("%s/pkg/%s_%s", runtime.GOROOT(), p.GOOS, p.GOARCH)
}
// goosFormat records the default format for each known GOOS value.
var goosFormat = map[string]string{
"darwin": "darwin",
}
// formatters records the format implementation for each known format value.
var formatters = map[string]formatter{
"darwin": machoFormat{},
}
var arches = map[string]arch{
"amd64": {
byteorder: binary.LittleEndian,
ptrsize: 8,
pcquantum: 1,
},
}
// Copyright 2014 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 main
import (
"bytes"
"fmt"
"io/ioutil"
"testing"
)
// shiftProg adjusts the addresses in p.
// It adds vdelta to all virtual addresses and fdelta to all file offsets.
func shiftProg(p *Prog, vdelta Addr, fdelta Addr) {
p.Entry += vdelta
for _, seg := range p.Segments {
seg.FileOffset += fdelta
seg.VirtAddr += vdelta
for _, sect := range seg.Sections {
sect.VirtAddr += vdelta
for _, sym := range sect.Syms {
sym.Addr += vdelta
}
}
}
}
// diffProg returns a list of differences between p and q,
// assuming p is being checked and q is the correct answer.
func diffProg(p, q *Prog) []string {
var errors []string
if p.UnmappedSize != q.UnmappedSize {
errors = append(errors, fmt.Sprintf("p.UnmappedSize = %#x, want %#x", p.UnmappedSize, q.UnmappedSize))
}
if p.HeaderSize != q.HeaderSize {
errors = append(errors, fmt.Sprintf("p.HeaderSize = %#x, want %#x", p.HeaderSize, q.HeaderSize))
}
if p.Entry != q.Entry {
errors = append(errors, fmt.Sprintf("p.Entry = %#x, want %#x", p.Entry, q.Entry))
}
for i := 0; i < len(p.Segments) || i < len(q.Segments); i++ {
if i >= len(p.Segments) {
errors = append(errors, fmt.Sprintf("p missing segment %q", q.Segments[i].Name))
continue
}
if i >= len(q.Segments) {
errors = append(errors, fmt.Sprintf("p has extra segment %q", p.Segments[i].Name))
continue
}
pseg := p.Segments[i]
qseg := q.Segments[i]
if pseg.Name != qseg.Name {
errors = append(errors, fmt.Sprintf("segment %d Name = %q, want %q", i, pseg.Name, qseg.Name))
continue // probably out of sync
}
if pseg.VirtAddr != qseg.VirtAddr {
errors = append(errors, fmt.Sprintf("segment %q VirtAddr = %#x, want %#x", pseg.Name, pseg.VirtAddr, qseg.VirtAddr))
}
if pseg.VirtSize != qseg.VirtSize {
errors = append(errors, fmt.Sprintf("segment %q VirtSize = %#x, want %#x", pseg.Name, pseg.VirtSize, qseg.VirtSize))
}
if pseg.FileOffset != qseg.FileOffset {
errors = append(errors, fmt.Sprintf("segment %q FileOffset = %#x, want %#x", pseg.Name, pseg.FileOffset, qseg.FileOffset))
}
if pseg.FileSize != qseg.FileSize {
errors = append(errors, fmt.Sprintf("segment %q FileSize = %#x, want %#x", pseg.Name, pseg.FileSize, qseg.FileSize))
}
if len(pseg.Data) != len(qseg.Data) {
errors = append(errors, fmt.Sprintf("segment %q len(Data) = %d, want %d", pseg.Name, len(pseg.Data), len(qseg.Data)))
} else if !bytes.Equal(pseg.Data, qseg.Data) {
errors = append(errors, fmt.Sprintf("segment %q Data mismatch:\n\thave %x\n\twant %x", pseg.Name, pseg.Data, qseg.Data))
}
for j := 0; j < len(pseg.Sections) || j < len(qseg.Sections); j++ {
if j >= len(pseg.Sections) {
errors = append(errors, fmt.Sprintf("segment %q missing section %q", pseg.Name, qseg.Sections[i].Name))
continue
}
if j >= len(qseg.Sections) {
errors = append(errors, fmt.Sprintf("segment %q has extra section %q", pseg.Name, pseg.Sections[i].Name))
continue
}
psect := pseg.Sections[j]
qsect := qseg.Sections[j]
if psect.Name != qsect.Name {
errors = append(errors, fmt.Sprintf("segment %q, section %d Name = %q, want %q", pseg.Name, j, psect.Name, qsect.Name))
continue // probably out of sync
}
if psect.VirtAddr != qsect.VirtAddr {
errors = append(errors, fmt.Sprintf("segment %q section %q VirtAddr = %#x, want %#x", pseg.Name, psect.Name, psect.VirtAddr, qsect.VirtAddr))
}
if psect.Size != qsect.Size {
errors = append(errors, fmt.Sprintf("segment %q section %q Size = %#x, want %#x", pseg.Name, psect.Name, psect.Size, qsect.Size))
}
if psect.Align != qsect.Align {
errors = append(errors, fmt.Sprintf("segment %q section %q Align = %#x, want %#x", pseg.Name, psect.Name, psect.Align, qsect.Align))
}
}
}
return errors
}
// cloneProg returns a deep copy of p.
func cloneProg(p *Prog) *Prog {
q := new(Prog)
*q = *p
q.Segments = make([]*Segment, len(p.Segments))
for i, seg := range p.Segments {
q.Segments[i] = cloneSegment(seg)
}
return q
}
// cloneSegment returns a deep copy of seg.
func cloneSegment(seg *Segment) *Segment {
t := new(Segment)
*t = *seg
t.Sections = make([]*Section, len(seg.Sections))
for i, sect := range seg.Sections {
t.Sections[i] = cloneSection(sect)
}
t.Data = make([]byte, len(seg.Data))
copy(t.Data, seg.Data)
return t
}
// cloneSection returns a deep copy of section.
func cloneSection(sect *Section) *Section {
// At the moment, there's nothing we need to make a deep copy of.
t := new(Section)
*t = *sect
return t
}
const saveMismatch = true
// checkGolden checks that data matches the named file.
// If not, it reports the error to the test.
func checkGolden(t *testing.T, data []byte, name string) {
golden := mustParseHexdumpFile(t, name)
if !bytes.Equal(data, golden) {
if saveMismatch {
ioutil.WriteFile(name+".raw", data, 0666)
ioutil.WriteFile(name+".hex", []byte(hexdump(data)), 0666)
}
// TODO(rsc): A better diff would be nice, as needed.
i := 0
for i < len(data) && i < len(golden) && data[i] == golden[i] {
i++
}
if i >= len(data) {
t.Errorf("%s: output file shorter than expected: have %d bytes, want %d", name, len(data), len(golden))
} else if i >= len(golden) {
t.Errorf("%s: output file larger than expected: have %d bytes, want %d", name, len(data), len(golden))
} else {
t.Errorf("%s: output file differs at byte %d: have %#02x, want %#02x", name, i, data[i], golden[i])
}
}
}
// Copyright 2014 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.
// Generation of runtime-accessible data structures.
// See also debug.go.
package main
import "cmd/internal/goobj"
func (p *Prog) runtime() {
p.pclntab()
// TODO: Implement garbage collection data.
p.addSym(&Sym{
Sym: &goobj.Sym{
SymID: goobj.SymID{Name: "runtime.gcdata"},
Kind: goobj.SRODATA,
},
})
p.addSym(&Sym{
Sym: &goobj.Sym{
SymID: goobj.SymID{Name: "runtime.gcbss"},
Kind: goobj.SRODATA,
},
})
}
// Copyright 2014 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.
// Initial scan of packages making up a program.
// TODO(rsc): Rename goobj.SymID.Version to StaticID to avoid confusion with the ELF meaning of version.
// TODO(rsc): Fix file format so that SBSS/SNOPTRBSS with data is listed as SDATA/SNOPTRDATA.
// TODO(rsc): Parallelize scan to overlap file i/o where possible.
package main
import (
"cmd/internal/goobj"
"os"
"sort"
"strings"
)
// scan scans all packages making up the program, starting with package main defined in mainfile.
func (p *Prog) scan(mainfile string) {
p.initScan()
p.scanFile("main", mainfile)
if len(p.Missing) > 0 && !p.omitRuntime {
p.scanImport("runtime")
}
var missing []string
for sym := range p.Missing {
if !p.isAuto(sym) {
missing = append(missing, sym.String())
}
}
if missing != nil {
sort.Strings(missing)
for _, sym := range missing {
p.errorf("undefined: %s", sym)
}
}
// TODO(rsc): Walk import graph to diagnose cycles.
}
// initScan initializes the Prog fields needed by scan.
func (p *Prog) initScan() {
p.Packages = make(map[string]*Package)
p.Syms = make(map[goobj.SymID]*Sym)
p.Missing = make(map[goobj.SymID]bool)
p.Missing[p.startSym] = true
}
// scanFile reads file to learn about the package with the given import path.
func (p *Prog) scanFile(pkgpath string, file string) {
pkg := &Package{
File: file,
}
p.Packages[pkgpath] = pkg
f, err := os.Open(file)
if err != nil {
p.errorf("%v", err)
return
}
gp, err := goobj.Parse(f, pkgpath)
f.Close()
if err != nil {
p.errorf("reading %s: %v", file, err)
return
}
// TODO(rsc): Change cmd/internal/goobj to record package name as gp.Name.
// TODO(rsc): If pkgpath == "main", check that gp.Name == "main".
pkg.Package = gp
for _, gs := range gp.Syms {
// TODO(rsc): Fix file format instead of this workaround.
if gs.Data.Size > 0 {
switch gs.Kind {
case goobj.SBSS:
gs.Kind = goobj.SDATA
case goobj.SNOPTRBSS:
gs.Kind = goobj.SNOPTRDATA
}
}
if gs.Version != 0 {
gs.Version += p.MaxVersion
}
for i := range gs.Reloc {
r := &gs.Reloc[i]
if r.Sym.Version != 0 {
r.Sym.Version += p.MaxVersion
}
if p.Syms[r.Sym] == nil {
p.Missing[r.Sym] = true
}
}
if gs.Func != nil {
for i := range gs.Func.FuncData {
fdata := &gs.Func.FuncData[i]
if fdata.Sym.Name != "" {
if fdata.Sym.Version != 0 {
fdata.Sym.Version += p.MaxVersion
}
if p.Syms[fdata.Sym] == nil {
p.Missing[fdata.Sym] = true
}
}
}
}
if old := p.Syms[gs.SymID]; old != nil {
// Duplicate definition of symbol. Is it okay?
// TODO(rsc): Write test for this code.
switch {
// If both symbols are BSS (no data), take max of sizes
// but otherwise ignore second symbol.
case old.Data.Size == 0 && gs.Data.Size == 0:
if old.Size < gs.Size {
old.Size = gs.Size
}
continue
// If one is in BSS and one is not, use the one that is not.
case old.Data.Size > 0 && gs.Data.Size == 0:
continue
case gs.Data.Size > 0 && old.Data.Size == 0:
break // install gs as new symbol below
// If either is marked as DupOK, we can keep either one.
// Keep the one that we saw first.
case old.DupOK || gs.DupOK:
continue
// Otherwise, there's an actual conflict:
default:
p.errorf("symbol %s defined in both %s and %s %v %v", gs.SymID, old.Package.File, file, old.Data, gs.Data)
continue
}
}
s := &Sym{
Sym: gs,
Package: pkg,
}
p.addSym(s)
delete(p.Missing, gs.SymID)
if s.Data.Size > int64(s.Size) {
p.errorf("%s: initialized data larger than symbol (%d > %d)", s, s.Data.Size, s.Size)
}
}
p.MaxVersion += pkg.MaxVersion
for i, pkgpath := range pkg.Imports {
// TODO(rsc): Fix file format to drop .a from recorded import path.
pkgpath = strings.TrimSuffix(pkgpath, ".a")
pkg.Imports[i] = pkgpath
p.scanImport(pkgpath)
}
}
func (p *Prog) addSym(s *Sym) {
pkg := s.Package
if pkg == nil {
pkg = p.Packages[""]
if pkg == nil {
pkg = &Package{}
p.Packages[""] = pkg
}
s.Package = pkg
}
pkg.Syms = append(pkg.Syms, s)
p.Syms[s.SymID] = s
p.SymOrder = append(p.SymOrder, s)
}
// scanImport finds the object file for the given import path and then scans it.
func (p *Prog) scanImport(pkgpath string) {
if p.Packages[pkgpath] != nil {
return // already loaded
}
// TODO(rsc): Implement correct search to find file.
p.scanFile(pkgpath, p.pkgdir+"/"+pkgpath+".a")
}
ALL=\
autosection.6\
autoweak.6\
dead.6\
hello.6\
layout.6\
pclntab.6\
all: $(ALL)
%.6: %.s
GOARCH=amd64 GOOS=darwin go tool asm -o $*.6 -I $(shell go env GOROOT)/pkg/include -trimpath=$(shell pwd) $*.s
pclntab.s: genpcln.go
go run genpcln.go >pclntab.s
// Copyright 2014 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.
// Test of section-named symbols.
#include "textflag.h"
TEXT start(SB),7,$0
MOVQ $autotab(SB),AX
MOVQ $autoptr(SB),AX
RET
GLOBL zero(SB), $8
GLOBL zeronoptr(SB), NOPTR, $16
// text
DATA autotab+0x00(SB)/8, $runtime·text(SB)
DATA autotab+0x08(SB)/8, $start(SB)
DATA autotab+0x10(SB)/8, $runtime·etext(SB)
DATA autotab+0x18(SB)/8, $start+16(SB)
// data
DATA autotab+0x20(SB)/8, $runtime·data(SB)
DATA autotab+0x28(SB)/8, $autotab(SB)
DATA autotab+0x30(SB)/8, $runtime·edata(SB)
DATA autotab+0x38(SB)/8, $nonzero+4(SB)
// bss
DATA autotab+0x40(SB)/8, $runtime·bss(SB)
DATA autotab+0x48(SB)/8, $zero(SB)
DATA autotab+0x50(SB)/8, $runtime·ebss(SB)
DATA autotab+0x58(SB)/8, $zero+8(SB)
// noptrdata
DATA autotab+0x60(SB)/8, $runtime·noptrdata(SB)
DATA autotab+0x68(SB)/8, $nonzeronoptr(SB)
DATA autotab+0x70(SB)/8, $runtime·enoptrdata(SB)
DATA autotab+0x78(SB)/8, $nonzeronoptr+8(SB)
// noptrbss
DATA autotab+0x80(SB)/8, $runtime·noptrbss(SB)
DATA autotab+0x88(SB)/8, $zeronoptr(SB)
DATA autotab+0x90(SB)/8, $runtime·enoptrbss(SB)
DATA autotab+0x98(SB)/8, $zeronoptr+16(SB)
// end
DATA autotab+0xa0(SB)/8, $runtime·end(SB)
DATA autotab+0xa8(SB)/8, $zeronoptr+16(SB)
GLOBL autotab(SB), $0xb0
DATA nonzero(SB)/4, $1
GLOBL nonzero(SB), $4
DATA nonzeronoptr(SB)/8, $2
GLOBL nonzeronoptr(SB), NOPTR, $8
GLOBL autoptr(SB), $0
// Copyright 2014 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.
// Test of dead code removal.
// Symbols with names beginning with dead_ should be discarded.
// Others should be kept.
TEXT start(SB),7,$0 // start symbol
MOVQ $data1<>(SB), AX
CALL text1(SB)
MOVQ $text2(SB), BX
RET
TEXT text1(SB),7,$0
FUNCDATA $1, funcdata+4(SB)
RET
TEXT text2(SB),7,$0
MOVQ $runtime·edata(SB),BX
RET
DATA data1<>+0(SB)/8, $data2(SB)
DATA data1<>+8(SB)/8, $data3(SB)
GLOBL data1<>(SB), $16
GLOBL data2(SB), $1
GLOBL data3(SB), $1
GLOBL funcdata(SB), $8
TEXT dead_start(SB),7,$0
MOVQ $dead_data1(SB), AX
CALL dead_text1(SB)
MOVQ $dead_text2(SB), BX
RET
TEXT dead_text1(SB),7,$0
FUNCDATA $1, dead_funcdata+4(SB)
RET
TEXT dead_text2(SB),7,$0
RET
DATA dead_data1+0(SB)/8, $dead_data2(SB)
DATA dead_data1+8(SB)/8, $dead_data3(SB)
GLOBL dead_data1(SB), $16
GLOBL dead_data2(SB), $1
GLOBL dead_data3(SB), $1
GLOBL dead_funcdata(SB), $8
// Copyright 2014 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 program generates a .s file using a pseudorandom
// value stream for the runtime function data.
// The pclntab test checks that the linked copy
// still has the same pseudorandom value stream.
package main
import (
"fmt"
"math/rand"
)
func main() {
fmt.Printf("// generated by genpcln.go; do not edit\n\n")
for f := 0; f < 3; f++ {
r := rand.New(rand.NewSource(int64(f)))
file := "input"
line := 1
args := r.Intn(100) * 8
frame := 32 + r.Intn(32)/8*8
fmt.Printf("#line %d %q\n", line, file)
fmt.Printf("TEXT func%d(SB),7,$%d-%d\n", f, frame, args)
fmt.Printf("\tFUNCDATA $1, funcdata%d(SB)\n", f)
fmt.Printf("#line %d %q\n", line, file)
size := 200 + r.Intn(100)*8
spadj := 0
flushed := 0
firstpc := 4
flush := func(i int) {
for i-flushed >= 10 {
fmt.Printf("#line %d %q\n", line, file)
fmt.Printf("/*%#04x*/\tMOVQ $0x123456789, AX\n", firstpc+flushed)
flushed += 10
}
for i-flushed >= 5 {
fmt.Printf("#line %d %q\n", line, file)
fmt.Printf("/*%#04x*/\tMOVL $0x1234567, AX\n", firstpc+flushed)
flushed += 5
}
for i-flushed > 0 {
fmt.Printf("#line %d %q\n", line, file)
fmt.Printf("/*%#04x*/\tBYTE $0\n", firstpc+flushed)
flushed++
}
}
for i := 0; i < size; i++ {
// Possible SP adjustment.
if r.Intn(100) == 0 {
flush(i)
fmt.Printf("#line %d %q\n", line, file)
if spadj <= -32 || spadj < 32 && r.Intn(2) == 0 {
spadj += 8
fmt.Printf("/*%#04x*/\tPUSHQ AX\n", firstpc+i)
} else {
spadj -= 8
fmt.Printf("/*%#04x*/\tPOPQ AX\n", firstpc+i)
}
i += 1
flushed = i
}
// Possible PCFile change.
if r.Intn(100) == 0 {
flush(i)
file = fmt.Sprintf("file%d.s", r.Intn(10))
line = r.Intn(100) + 1
}
// Possible PCLine change.
if r.Intn(10) == 0 {
flush(i)
line = r.Intn(1000) + 1
}
// Possible PCData $1 change.
if r.Intn(100) == 0 {
flush(i)
fmt.Printf("/*%6s*/\tPCDATA $1, $%d\n", "", r.Intn(1000))
}
// Possible PCData $2 change.
if r.Intn(100) == 0 {
flush(i)
fmt.Printf("/*%6s*/\tPCDATA $2, $%d\n", "", r.Intn(1000))
}
}
flush(size)
for spadj < 0 {
fmt.Printf("\tPUSHQ AX\n")
spadj += 8
}
for spadj > 0 {
fmt.Printf("\tPOPQ AX\n")
spadj -= 8
}
fmt.Printf("\tRET\n")
fmt.Printf("\n")
fmt.Printf("GLOBL funcdata%d(SB), $16\n", f)
}
fmt.Printf("\nTEXT start(SB),7,$0\n")
for f := 0; f < 3; f++ {
fmt.Printf("\tCALL func%d(SB)\n", f)
}
fmt.Printf("\tMOVQ $runtime·pclntab(SB), AX\n")
fmt.Printf("\n\tRET\n")
}
TEXT _rt0_go(SB),7,$0
MOVL $1, DI
MOVL $hello<>(SB), SI
MOVL $12, DX
MOVL $0x2000004, AX
SYSCALL
MOVL $0, DI
MOVL $0x2000001, AX
SYSCALL
RET
DATA hello<>+0(SB)/4, $"hell"
DATA hello<>+4(SB)/4, $"o wo"
DATA hello<>+8(SB)/4, $"rld\n"
GLOBL hello<>(SB), $12
// Copyright 2014 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.
// Test of section assignment in layout.go.
// Each symbol should end up in the section named by the symbol name prefix (up to the underscore).
#include "textflag.h"
TEXT text_start(SB),7,$0
MOVQ $rodata_sym(SB), AX
MOVQ $noptrdata_sym(SB), AX
MOVQ $data_sym(SB), AX
MOVQ $bss_sym(SB), AX
MOVQ $noptrbss_sym(SB), AX
RET
DATA rodata_sym(SB)/4, $1
GLOBL rodata_sym(SB), RODATA, $4
DATA noptrdata_sym(SB)/4, $1
GLOBL noptrdata_sym(SB), NOPTR, $4
DATA data_sym(SB)/4, $1
GLOBL data_sym(SB), $4
GLOBL bss_sym(SB), $4
GLOBL noptrbss_sym(SB), NOPTR, $4
00000000 cf fa ed fe 07 00 00 01 03 00 00 00 02 00 00 00 |................|
00000010 04 00 00 00 d0 02 00 00 01 00 00 00 00 00 00 00 |................|
00000020 19 00 00 00 48 00 00 00 5f 5f 50 41 47 45 5a 45 |....H...__PAGEZE|
00000030 52 4f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |RO..............|
00000040 00 10 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
*
00000060 00 00 00 00 00 00 00 00 19 00 00 00 38 01 00 00 |............8...|
00000070 5f 5f 54 45 58 54 00 00 00 00 00 00 00 00 00 00 |__TEXT..........|
00000080 00 10 00 00 00 00 00 00 c0 10 00 00 00 00 00 00 |................|
00000090 00 00 00 00 00 00 00 00 c0 10 00 00 00 00 00 00 |................|
000000a0 07 00 00 00 05 00 00 00 03 00 00 00 00 00 00 00 |................|
000000b0 5f 5f 74 65 78 74 00 00 00 00 00 00 00 00 00 00 |__text..........|
000000c0 5f 5f 54 45 58 54 00 00 00 00 00 00 00 00 00 00 |__TEXT..........|
000000d0 00 20 00 00 00 00 00 00 30 00 00 00 00 00 00 00 |. ......0.......|
000000e0 00 10 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
000000f0 00 04 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000100 5f 5f 72 6f 64 61 74 61 00 00 00 00 00 00 00 00 |__rodata........|
00000110 5f 5f 54 45 58 54 00 00 00 00 00 00 00 00 00 00 |__TEXT..........|
00000120 30 20 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |0 ..............|
00000130 30 10 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |0...............|
*
00000150 5f 5f 66 75 6e 63 74 61 62 00 00 00 00 00 00 00 |__functab.......|
00000160 5f 5f 54 45 58 54 00 00 00 00 00 00 00 00 00 00 |__TEXT..........|
00000170 30 20 00 00 00 00 00 00 90 00 00 00 00 00 00 00 |0 ..............|
00000180 30 10 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |0...............|
*
000001a0 19 00 00 00 98 00 00 00 5f 5f 44 41 54 41 00 00 |........__DATA..|
000001b0 00 00 00 00 00 00 00 00 00 30 00 00 00 00 00 00 |.........0......|
000001c0 0c 00 00 00 00 00 00 00 00 20 00 00 00 00 00 00 |......... ......|
000001d0 0c 00 00 00 00 00 00 00 03 00 00 00 03 00 00 00 |................|
000001e0 01 00 00 00 00 00 00 00 5f 5f 64 61 74 61 00 00 |........__data..|
000001f0 00 00 00 00 00 00 00 00 5f 5f 44 41 54 41 00 00 |........__DATA..|
00000200 00 00 00 00 00 00 00 00 00 30 00 00 00 00 00 00 |.........0......|
00000210 0c 00 00 00 00 00 00 00 00 20 00 00 00 00 00 00 |......... ......|
*
00000230 00 00 00 00 00 00 00 00 05 00 00 00 b8 00 00 00 |................|
00000240 04 00 00 00 2a 00 00 00 00 00 00 00 00 00 00 00 |....*...........|
*
000002c0 00 00 00 00 00 00 00 00 00 20 00 00 00 00 00 00 |......... ......|
*
00001000 bf 01 00 00 00 8d 35 f5 0f 00 00 ba 0c 00 00 00 |......5.........|
00001010 b8 04 00 00 02 0f 05 31 ff b8 01 00 00 02 0f 05 |.......1........|
00001020 c3 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00001030 fb ff ff ff 00 00 01 08 01 00 00 00 00 00 00 00 |................|
00001040 00 20 00 00 00 00 00 00 30 00 00 00 00 00 00 00 |. ......0.......|
00001050 30 20 00 00 00 00 00 00 80 00 00 00 00 00 00 00 |0 ..............|
00001060 00 20 00 00 00 00 00 00 58 00 00 00 00 00 00 80 |. ......X.......|
00001070 08 00 00 00 60 00 00 00 63 00 00 00 66 00 00 00 |....`...c...f...|
00001080 00 00 00 00 00 00 00 00 5f 72 74 30 5f 67 6f 00 |........_rt0_go.|
00001090 02 30 00 04 30 00 06 05 02 06 02 05 02 05 02 02 |.0..0...........|
000010a0 02 02 02 05 02 02 02 10 00 00 00 00 00 00 00 00 |................|
000010b0 02 00 00 00 88 00 00 00 68 65 6c 6c 6f 2e 73 00 |........hello.s.|
*
00002000 68 65 6c 6c 6f 20 77 6f 72 6c 64 0a |hello world.|
0000200c
00000000 cf fa ed fe 07 00 00 01 03 00 00 00 02 00 00 00 |................|
00000010 03 00 00 00 98 01 00 00 01 00 00 00 00 00 00 00 |................|
00000020 19 00 00 00 48 00 00 00 5f 5f 50 41 47 45 5a 45 |....H...__PAGEZE|
00000030 52 4f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |RO..............|
00000040 00 10 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000050 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000060 00 00 00 00 00 00 00 00 19 00 00 00 98 00 00 00 |................|
00000070 5f 5f 54 45 58 54 00 00 00 00 00 00 00 00 00 00 |__TEXT..........|
00000080 00 10 00 00 00 00 00 00 0d 10 00 00 00 00 00 00 |................|
00000090 00 00 00 00 00 00 00 00 0d 10 00 00 00 00 00 00 |................|
000000a0 07 00 00 00 05 00 00 00 01 00 00 00 00 00 00 00 |................|
000000b0 5f 5f 74 65 78 74 00 00 00 00 00 00 00 00 00 00 |__text..........|
000000c0 5f 5f 54 45 58 54 00 00 00 00 00 00 00 00 00 00 |__TEXT..........|
000000d0 00 20 00 00 00 00 00 00 0d 00 00 00 00 00 00 00 |. ..............|
000000e0 00 10 00 00 06 00 00 00 00 00 00 00 00 00 00 00 |................|
000000f0 00 04 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000100 05 00 00 00 b8 00 00 00 04 00 00 00 2a 00 00 00 |............*...|
00000110 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
*
00000190 00 20 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |. ..............|
000001a0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
*
00001000 b8 01 00 00 02 bf 09 00 00 00 0f 05 f4 |.............|
0000100d
00000000 cf fa ed fe 07 00 00 01 03 00 00 00 02 00 00 00 |................|
00000010 04 00 00 00 30 02 00 00 01 00 00 00 00 00 00 00 |....0...........|
00000020 19 00 00 00 48 00 00 00 5f 5f 50 41 47 45 5a 45 |....H...__PAGEZE|
00000030 52 4f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |RO..............|
00000040 00 10 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000050 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000060 00 00 00 00 00 00 00 00 19 00 00 00 98 00 00 00 |................|
00000070 5f 5f 54 45 58 54 00 00 00 00 00 00 00 00 00 00 |__TEXT..........|
00000080 00 10 00 00 00 00 00 00 23 10 00 00 00 00 00 00 |........#.......|
00000090 00 00 00 00 00 00 00 00 23 10 00 00 00 00 00 00 |........#.......|
000000a0 07 00 00 00 05 00 00 00 01 00 00 00 00 00 00 00 |................|
000000b0 5f 5f 74 65 78 74 00 00 00 00 00 00 00 00 00 00 |__text..........|
000000c0 5f 5f 54 45 58 54 00 00 00 00 00 00 00 00 00 00 |__TEXT..........|
000000d0 00 20 00 00 00 00 00 00 23 00 00 00 00 00 00 00 |. ......#.......|
000000e0 00 10 00 00 06 00 00 00 00 00 00 00 00 00 00 00 |................|
000000f0 00 04 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000100 19 00 00 00 98 00 00 00 5f 5f 44 41 54 41 00 00 |........__DATA..|
00000110 00 00 00 00 00 00 00 00 00 30 00 00 00 00 00 00 |.........0......|
00000120 0c 00 00 00 00 00 00 00 00 20 00 00 00 00 00 00 |......... ......|
00000130 0c 00 00 00 00 00 00 00 03 00 00 00 03 00 00 00 |................|
00000140 01 00 00 00 00 00 00 00 5f 5f 64 61 74 61 00 00 |........__data..|
00000150 00 00 00 00 00 00 00 00 5f 5f 44 41 54 41 00 00 |........__DATA..|
00000160 00 00 00 00 00 00 00 00 00 30 00 00 00 00 00 00 |.........0......|
00000170 0c 00 00 00 00 00 00 00 00 20 00 00 06 00 00 00 |......... ......|
00000180 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000190 00 00 00 00 00 00 00 00 05 00 00 00 b8 00 00 00 |................|
000001a0 04 00 00 00 2a 00 00 00 00 00 00 00 00 00 00 00 |....*...........|
000001b0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
*
00000220 00 00 00 00 00 00 00 00 00 20 00 00 00 00 00 00 |......... ......|
00000230 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
*
00001000 b8 04 00 00 02 bf 01 00 00 00 be 00 30 00 00 ba |............0...|
00001010 0c 00 00 00 0f 05 b8 01 00 00 02 bf 09 00 00 00 |................|
00001020 0f 05 f4 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00001030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
*
00002000 68 65 6c 6c 6f 20 77 6f 72 6c 64 0a |hello world.|
0000200c
00000000 cf fa ed fe 07 00 00 01 03 00 00 00 02 00 00 00 |................|
00000010 03 00 00 00 e8 01 00 00 01 00 00 00 00 00 00 00 |................|
00000020 19 00 00 00 48 00 00 00 5f 5f 50 41 47 45 5a 45 |....H...__PAGEZE|
00000030 52 4f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |RO..............|
00000040 00 10 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000050 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000060 00 00 00 00 00 00 00 00 19 00 00 00 e8 00 00 00 |................|
00000070 5f 5f 54 45 58 54 00 00 00 00 00 00 00 00 00 00 |__TEXT..........|
00000080 00 10 00 00 00 00 00 00 0c 20 00 00 00 00 00 00 |......... ......|
00000090 00 00 00 00 00 00 00 00 0c 20 00 00 00 00 00 00 |......... ......|
000000a0 07 00 00 00 05 00 00 00 02 00 00 00 00 00 00 00 |................|
000000b0 5f 5f 74 65 78 74 00 00 00 00 00 00 00 00 00 00 |__text..........|
000000c0 5f 5f 54 45 58 54 00 00 00 00 00 00 00 00 00 00 |__TEXT..........|
000000d0 00 20 00 00 00 00 00 00 23 00 00 00 00 00 00 00 |. ......#.......|
000000e0 00 10 00 00 06 00 00 00 00 00 00 00 00 00 00 00 |................|
000000f0 00 04 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000100 5f 5f 72 6f 64 61 74 61 00 00 00 00 00 00 00 00 |__rodata........|
00000110 5f 5f 54 45 58 54 00 00 00 00 00 00 00 00 00 00 |__TEXT..........|
00000120 00 30 00 00 00 00 00 00 0c 00 00 00 00 00 00 00 |.0..............|
00000130 00 20 00 00 06 00 00 00 00 00 00 00 00 00 00 00 |. ..............|
00000140 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000150 05 00 00 00 b8 00 00 00 04 00 00 00 2a 00 00 00 |............*...|
00000160 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
*
000001e0 00 20 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |. ..............|
000001f0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
*
00001000 b8 04 00 00 02 bf 01 00 00 00 be 00 30 00 00 ba |............0...|
00001010 0c 00 00 00 0f 05 b8 01 00 00 02 bf 00 00 00 00 |................|
00001020 0f 05 f4 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00001030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
*
00002000 68 65 6c 6c 6f 20 77 6f 72 6c 64 0a |hello world.|
0000200c
// generated by genpcln.go; do not edit
#line 1 "input"
TEXT func0(SB),7,$48-592
FUNCDATA $1, funcdata0(SB)
#line 1 "input"
#line 1 "input"
/*0x0004*/ MOVL $0x1234567, AX
#line 1 "input"
/*0x0009*/ BYTE $0
/* */ PCDATA $1, $110
#line 1 "input"
/*0x000a*/ BYTE $0
#line 1 "input"
/*0x000b*/ BYTE $0
/* */ PCDATA $1, $422
#line 1 "input"
/*0x000c*/ BYTE $0
#line 1 "input"
/*0x000d*/ BYTE $0
#line 1 "input"
/*0x000e*/ POPQ AX
#line 1 "input"
/*0x000f*/ MOVL $0x1234567, AX
#line 1 "input"
/*0x0014*/ BYTE $0
#line 1 "input"
/*0x0015*/ BYTE $0
#line 1 "input"
/*0x0016*/ BYTE $0
#line 542 "input"
/*0x0017*/ BYTE $0
#line 960 "input"
/*0x0018*/ MOVL $0x1234567, AX
#line 960 "input"
/*0x001d*/ BYTE $0
#line 960 "input"
/*0x001e*/ PUSHQ AX
#line 960 "input"
/*0x001f*/ BYTE $0
#line 960 "input"
/*0x0020*/ BYTE $0
#line 594 "input"
/*0x0021*/ BYTE $0
#line 671 "input"
/*0x0022*/ MOVL $0x1234567, AX
#line 671 "input"
/*0x0027*/ BYTE $0
#line 671 "input"
/*0x0028*/ BYTE $0
#line 230 "input"
/*0x0029*/ BYTE $0
#line 230 "input"
/*0x002a*/ BYTE $0
#line 413 "input"
/*0x002b*/ BYTE $0
#line 413 "input"
/*0x002c*/ BYTE $0
#line 413 "input"
/*0x002d*/ BYTE $0
#line 729 "input"
/*0x002e*/ BYTE $0
#line 729 "input"
/*0x002f*/ BYTE $0
#line 729 "input"
/*0x0030*/ BYTE $0
#line 948 "input"
/*0x0031*/ BYTE $0
#line 11 "input"
/*0x0032*/ MOVQ $0x123456789, AX
#line 11 "input"
/*0x003c*/ MOVL $0x1234567, AX
#line 11 "input"
/*0x0041*/ BYTE $0
#line 11 "input"
/*0x0042*/ BYTE $0
#line 11 "input"
/*0x0043*/ POPQ AX
/* */ PCDATA $2, $342
#line 11 "input"
/*0x0044*/ MOVQ $0x123456789, AX
#line 11 "input"
/*0x004e*/ MOVQ $0x123456789, AX
#line 11 "input"
/*0x0058*/ MOVL $0x1234567, AX
#line 11 "input"
/*0x005d*/ BYTE $0
#line 11 "input"
/*0x005e*/ BYTE $0
#line 70 "input"
/*0x005f*/ BYTE $0
#line 70 "input"
/*0x0060*/ BYTE $0
#line 70 "input"
/*0x0061*/ BYTE $0
#line 18 "input"
/*0x0062*/ MOVQ $0x123456789, AX
#line 18 "input"
/*0x006c*/ MOVL $0x1234567, AX
#line 18 "input"
/*0x0071*/ BYTE $0
#line 814 "input"
/*0x0072*/ BYTE $0
#line 814 "input"
/*0x0073*/ PUSHQ AX
#line 763 "input"
/*0x0074*/ BYTE $0
#line 763 "input"
/*0x0075*/ BYTE $0
#line 763 "input"
/*0x0076*/ BYTE $0
#line 530 "input"
/*0x0077*/ BYTE $0
#line 530 "input"
/*0x0078*/ BYTE $0
#line 530 "input"
/*0x0079*/ BYTE $0
#line 530 "input"
/*0x007a*/ BYTE $0
#line 985 "input"
/*0x007b*/ BYTE $0
#line 985 "input"
/*0x007c*/ BYTE $0
#line 985 "input"
/*0x007d*/ BYTE $0
#line 985 "input"
/*0x007e*/ PUSHQ AX
#line 985 "input"
/*0x007f*/ MOVL $0x1234567, AX
#line 958 "input"
/*0x0084*/ BYTE $0
#line 368 "input"
/*0x0085*/ MOVQ $0x123456789, AX
#line 368 "input"
/*0x008f*/ MOVL $0x1234567, AX
#line 368 "input"
/*0x0094*/ BYTE $0
#line 368 "input"
/*0x0095*/ BYTE $0
#line 368 "input"
/*0x0096*/ BYTE $0
#line 368 "input"
/*0x0097*/ BYTE $0
#line 75 "file0.s"
/*0x0098*/ BYTE $0
#line 75 "file0.s"
/*0x0099*/ BYTE $0
#line 75 "file0.s"
/*0x009a*/ BYTE $0
#line 75 "file0.s"
/*0x009b*/ BYTE $0
#line 588 "file0.s"
/*0x009c*/ MOVQ $0x123456789, AX
#line 187 "file0.s"
/*0x00a6*/ MOVQ $0x123456789, AX
#line 187 "file0.s"
/*0x00b0*/ BYTE $0
#line 202 "file0.s"
/*0x00b1*/ MOVL $0x1234567, AX
#line 202 "file0.s"
/*0x00b6*/ BYTE $0
#line 887 "file0.s"
/*0x00b7*/ MOVL $0x1234567, AX
#line 887 "file0.s"
/*0x00bc*/ BYTE $0
#line 887 "file0.s"
/*0x00bd*/ BYTE $0
#line 480 "file0.s"
/*0x00be*/ MOVL $0x1234567, AX
#line 480 "file0.s"
/*0x00c3*/ BYTE $0
#line 40 "file8.s"
/*0x00c4*/ BYTE $0
#line 17 "file0.s"
/*0x00c5*/ MOVQ $0x123456789, AX
#line 17 "file0.s"
/*0x00cf*/ BYTE $0
#line 17 "file0.s"
/*0x00d0*/ BYTE $0
#line 17 "file0.s"
/*0x00d1*/ BYTE $0
#line 17 "file0.s"
/*0x00d2*/ BYTE $0
#line 436 "file0.s"
/*0x00d3*/ MOVL $0x1234567, AX
#line 436 "file0.s"
/*0x00d8*/ BYTE $0
#line 436 "file0.s"
/*0x00d9*/ BYTE $0
#line 346 "file0.s"
/*0x00da*/ BYTE $0
#line 346 "file0.s"
/*0x00db*/ BYTE $0
#line 346 "file0.s"
/*0x00dc*/ BYTE $0
#line 812 "file0.s"
/*0x00dd*/ BYTE $0
#line 812 "file0.s"
/*0x00de*/ BYTE $0
#line 812 "file0.s"
/*0x00df*/ BYTE $0
#line 812 "file0.s"
/*0x00e0*/ BYTE $0
#line 94 "file1.s"
/*0x00e1*/ BYTE $0
#line 94 "file1.s"
/*0x00e2*/ BYTE $0
#line 165 "file1.s"
/*0x00e3*/ MOVL $0x1234567, AX
#line 165 "file1.s"
/*0x00e8*/ BYTE $0
#line 456 "file1.s"
/*0x00e9*/ BYTE $0
#line 810 "file1.s"
/*0x00ea*/ BYTE $0
#line 722 "file1.s"
/*0x00eb*/ BYTE $0
#line 722 "file1.s"
/*0x00ec*/ BYTE $0
#line 722 "file1.s"
/*0x00ed*/ BYTE $0
#line 722 "file1.s"
/*0x00ee*/ BYTE $0
#line 722 "file1.s"
/*0x00ef*/ PUSHQ AX
#line 722 "file1.s"
/*0x00f0*/ BYTE $0
#line 722 "file1.s"
/*0x00f1*/ BYTE $0
#line 722 "file1.s"
/*0x00f2*/ BYTE $0
#line 722 "file1.s"
/*0x00f3*/ BYTE $0
/* */ PCDATA $2, $246
#line 722 "file1.s"
/*0x00f4*/ MOVQ $0x123456789, AX
#line 722 "file1.s"
/*0x00fe*/ MOVQ $0x123456789, AX
#line 722 "file1.s"
/*0x0108*/ MOVL $0x1234567, AX
#line 722 "file1.s"
/*0x010d*/ BYTE $0
#line 722 "file1.s"
/*0x010e*/ BYTE $0
#line 497 "file1.s"
/*0x010f*/ MOVQ $0x123456789, AX
#line 497 "file1.s"
/*0x0119*/ MOVQ $0x123456789, AX
#line 497 "file1.s"
/*0x0123*/ MOVQ $0x123456789, AX
#line 497 "file1.s"
/*0x012d*/ MOVL $0x1234567, AX
#line 497 "file1.s"
/*0x0132*/ BYTE $0
#line 686 "file1.s"
/*0x0133*/ BYTE $0
#line 686 "file1.s"
/*0x0134*/ BYTE $0
#line 248 "file1.s"
/*0x0135*/ BYTE $0
#line 248 "file1.s"
/*0x0136*/ BYTE $0
#line 248 "file1.s"
/*0x0137*/ BYTE $0
#line 248 "file1.s"
/*0x0138*/ BYTE $0
#line 307 "file1.s"
/*0x0139*/ BYTE $0
#line 220 "file1.s"
/*0x013a*/ MOVL $0x1234567, AX
#line 220 "file1.s"
/*0x013f*/ BYTE $0
#line 220 "file1.s"
/*0x0140*/ BYTE $0
#line 467 "file1.s"
/*0x0141*/ MOVQ $0x123456789, AX
#line 467 "file1.s"
/*0x014b*/ BYTE $0
#line 467 "file1.s"
/*0x014c*/ BYTE $0
#line 467 "file1.s"
/*0x014d*/ BYTE $0
#line 467 "file1.s"
/*0x014e*/ BYTE $0
#line 786 "file1.s"
/*0x014f*/ MOVL $0x1234567, AX
#line 251 "file1.s"
/*0x0154*/ BYTE $0
/* */ PCDATA $2, $64
#line 251 "file1.s"
/*0x0155*/ BYTE $0
#line 251 "file1.s"
/*0x0156*/ BYTE $0
#line 251 "file1.s"
/*0x0157*/ BYTE $0
#line 618 "file1.s"
/*0x0158*/ MOVQ $0x123456789, AX
/* */ PCDATA $1, $686
#line 618 "file1.s"
/*0x0162*/ BYTE $0
#line 618 "file1.s"
/*0x0163*/ BYTE $0
#line 618 "file1.s"
/*0x0164*/ BYTE $0
#line 618 "file1.s"
/*0x0165*/ PUSHQ AX
/* */ PCDATA $2, $915
#line 618 "file1.s"
/*0x0166*/ BYTE $0
#line 618 "file1.s"
/*0x0167*/ BYTE $0
#line 618 "file1.s"
/*0x0168*/ BYTE $0
#line 618 "file1.s"
/*0x0169*/ BYTE $0
#line 230 "file1.s"
/*0x016a*/ BYTE $0
#line 823 "file1.s"
/*0x016b*/ BYTE $0
#line 145 "file1.s"
/*0x016c*/ MOVQ $0x123456789, AX
#line 145 "file1.s"
/*0x0176*/ BYTE $0
#line 145 "file1.s"
/*0x0177*/ BYTE $0
#line 675 "file1.s"
/*0x0178*/ BYTE $0
#line 62 "file9.s"
/*0x0179*/ BYTE $0
/* */ PCDATA $2, $768
#line 62 "file9.s"
/*0x017a*/ BYTE $0
#line 62 "file9.s"
/*0x017b*/ BYTE $0
#line 29 "file9.s"
/*0x017c*/ BYTE $0
#line 29 "file9.s"
/*0x017d*/ BYTE $0
#line 29 "file9.s"
/*0x017e*/ BYTE $0
#line 29 "file9.s"
/*0x017f*/ BYTE $0
#line 65 "file4.s"
/*0x0180*/ BYTE $0
#line 77 "file3.s"
/*0x0181*/ MOVL $0x1234567, AX
#line 77 "file3.s"
/*0x0186*/ BYTE $0
#line 77 "file3.s"
/*0x0187*/ BYTE $0
#line 77 "file3.s"
/*0x0188*/ BYTE $0
#line 307 "file3.s"
/*0x0189*/ MOVQ $0x123456789, AX
#line 307 "file3.s"
/*0x0193*/ BYTE $0
#line 654 "file3.s"
/*0x0194*/ BYTE $0
#line 654 "file3.s"
/*0x0195*/ BYTE $0
#line 115 "file3.s"
/*0x0196*/ MOVL $0x1234567, AX
#line 115 "file3.s"
/*0x019b*/ BYTE $0
#line 115 "file3.s"
/*0x019c*/ BYTE $0
#line 115 "file3.s"
/*0x019d*/ BYTE $0
#line 115 "file3.s"
/*0x019e*/ BYTE $0
#line 154 "file3.s"
/*0x019f*/ MOVQ $0x123456789, AX
#line 166 "file3.s"
/*0x01a9*/ BYTE $0
#line 166 "file3.s"
/*0x01aa*/ BYTE $0
#line 166 "file3.s"
/*0x01ab*/ BYTE $0
/* */ PCDATA $1, $523
#line 166 "file3.s"
/*0x01ac*/ MOVL $0x1234567, AX
#line 166 "file3.s"
/*0x01b1*/ BYTE $0
#line 779 "file3.s"
/*0x01b2*/ BYTE $0
#line 779 "file3.s"
/*0x01b3*/ BYTE $0
#line 515 "file3.s"
/*0x01b4*/ BYTE $0
#line 515 "file3.s"
/*0x01b5*/ BYTE $0
#line 369 "file3.s"
/*0x01b6*/ MOVL $0x1234567, AX
#line 369 "file3.s"
/*0x01bb*/ BYTE $0
#line 369 "file3.s"
/*0x01bc*/ BYTE $0
#line 369 "file3.s"
/*0x01bd*/ BYTE $0
#line 680 "file3.s"
/*0x01be*/ BYTE $0
#line 680 "file3.s"
/*0x01bf*/ BYTE $0
#line 680 "file3.s"
/*0x01c0*/ BYTE $0
#line 680 "file3.s"
/*0x01c1*/ BYTE $0
#line 131 "file3.s"
/*0x01c2*/ MOVQ $0x123456789, AX
#line 131 "file3.s"
/*0x01cc*/ BYTE $0
#line 131 "file3.s"
/*0x01cd*/ BYTE $0
#line 131 "file3.s"
/*0x01ce*/ BYTE $0
#line 131 "file3.s"
/*0x01cf*/ BYTE $0
#line 848 "file3.s"
/*0x01d0*/ BYTE $0
#line 848 "file3.s"
/*0x01d1*/ BYTE $0
#line 848 "file3.s"
/*0x01d2*/ POPQ AX
#line 848 "file3.s"
/*0x01d3*/ BYTE $0
#line 848 "file3.s"
/*0x01d4*/ BYTE $0
#line 848 "file3.s"
/*0x01d5*/ BYTE $0
/* */ PCDATA $1, $86
#line 848 "file3.s"
/*0x01d6*/ MOVL $0x1234567, AX
#line 438 "file3.s"
/*0x01db*/ MOVQ $0x123456789, AX
#line 438 "file3.s"
/*0x01e5*/ MOVL $0x1234567, AX
#line 5 "file3.s"
/*0x01ea*/ BYTE $0
#line 5 "file3.s"
/*0x01eb*/ BYTE $0
#line 531 "file3.s"
/*0x01ec*/ MOVQ $0x123456789, AX
#line 531 "file3.s"
/*0x01f6*/ MOVQ $0x123456789, AX
#line 531 "file3.s"
/*0x0200*/ MOVQ $0x123456789, AX
#line 531 "file3.s"
/*0x020a*/ MOVL $0x1234567, AX
#line 863 "file3.s"
/*0x020f*/ BYTE $0
#line 733 "file3.s"
/*0x0210*/ MOVQ $0x123456789, AX
#line 166 "file3.s"
/*0x021a*/ MOVQ $0x123456789, AX
#line 166 "file3.s"
/*0x0224*/ BYTE $0
#line 166 "file3.s"
/*0x0225*/ BYTE $0
#line 166 "file3.s"
/*0x0226*/ BYTE $0
#line 166 "file3.s"
/*0x0227*/ BYTE $0
#line 54 "file3.s"
/*0x0228*/ MOVQ $0x123456789, AX
#line 54 "file3.s"
/*0x0232*/ BYTE $0
#line 54 "file3.s"
/*0x0233*/ BYTE $0
#line 54 "file3.s"
/*0x0234*/ BYTE $0
#line 20 "file4.s"
/*0x0235*/ BYTE $0
#line 20 "file4.s"
/*0x0236*/ BYTE $0
#line 546 "file4.s"
/*0x0237*/ BYTE $0
#line 546 "file4.s"
/*0x0238*/ BYTE $0
#line 74 "file4.s"
/*0x0239*/ BYTE $0
#line 31 "file4.s"
/*0x023a*/ BYTE $0
#line 31 "file4.s"
/*0x023b*/ BYTE $0
#line 31 "file4.s"
/*0x023c*/ BYTE $0
#line 31 "file4.s"
/*0x023d*/ BYTE $0
#line 834 "file4.s"
/*0x023e*/ BYTE $0
#line 834 "file4.s"
/*0x023f*/ BYTE $0
#line 519 "file4.s"
/*0x0240*/ MOVL $0x1234567, AX
#line 342 "file4.s"
/*0x0245*/ BYTE $0
#line 342 "file4.s"
/*0x0246*/ BYTE $0
#line 342 "file4.s"
/*0x0247*/ BYTE $0
#line 458 "file4.s"
/*0x0248*/ BYTE $0
#line 458 "file4.s"
/*0x0249*/ BYTE $0
#line 458 "file4.s"
/*0x024a*/ BYTE $0
#line 458 "file4.s"
/*0x024b*/ BYTE $0
#line 13 "file9.s"
/*0x024c*/ BYTE $0
#line 13 "file9.s"
/*0x024d*/ BYTE $0
#line 13 "file9.s"
/*0x024e*/ BYTE $0
#line 365 "file9.s"
/*0x024f*/ BYTE $0
#line 749 "file9.s"
/*0x0250*/ MOVL $0x1234567, AX
#line 749 "file9.s"
/*0x0255*/ BYTE $0
#line 749 "file9.s"
/*0x0256*/ BYTE $0
#line 41 "file0.s"
/*0x0257*/ MOVL $0x1234567, AX
#line 41 "file0.s"
/*0x025c*/ BYTE $0
#line 41 "file0.s"
/*0x025d*/ BYTE $0
#line 41 "file0.s"
/*0x025e*/ BYTE $0
#line 869 "file0.s"
/*0x025f*/ BYTE $0
#line 881 "file0.s"
/*0x0260*/ MOVQ $0x123456789, AX
#line 881 "file0.s"
/*0x026a*/ MOVQ $0x123456789, AX
POPQ AX
POPQ AX
RET
GLOBL funcdata0(SB), $16
#line 1 "input"
TEXT func1(SB),7,$40-648
FUNCDATA $1, funcdata1(SB)
#line 1 "input"
#line 1 "input"
/*0x0004*/ BYTE $0
#line 12 "file4.s"
/*0x0005*/ MOVL $0x1234567, AX
#line 12 "file4.s"
/*0x000a*/ BYTE $0
#line 12 "file4.s"
/*0x000b*/ BYTE $0
#line 12 "file4.s"
/*0x000c*/ BYTE $0
/* */ PCDATA $2, $705
#line 12 "file4.s"
/*0x000d*/ MOVQ $0x123456789, AX
#line 12 "file4.s"
/*0x0017*/ BYTE $0
#line 633 "file4.s"
/*0x0018*/ MOVQ $0x123456789, AX
#line 633 "file4.s"
/*0x0022*/ MOVL $0x1234567, AX
#line 633 "file4.s"
/*0x0027*/ POPQ AX
#line 633 "file4.s"
/*0x0028*/ BYTE $0
#line 633 "file4.s"
/*0x0029*/ BYTE $0
#line 633 "file4.s"
/*0x002a*/ BYTE $0
#line 633 "file4.s"
/*0x002b*/ PUSHQ AX
#line 633 "file4.s"
/*0x002c*/ MOVL $0x1234567, AX
#line 997 "file4.s"
/*0x0031*/ BYTE $0
#line 997 "file4.s"
/*0x0032*/ BYTE $0
#line 997 "file4.s"
/*0x0033*/ BYTE $0
#line 997 "file4.s"
/*0x0034*/ BYTE $0
#line 997 "file4.s"
/*0x0035*/ POPQ AX
#line 997 "file4.s"
/*0x0036*/ BYTE $0
#line 997 "file4.s"
/*0x0037*/ BYTE $0
#line 1 "file4.s"
/*0x0038*/ MOVQ $0x123456789, AX
#line 1 "file4.s"
/*0x0042*/ MOVQ $0x123456789, AX
#line 1 "file4.s"
/*0x004c*/ MOVQ $0x123456789, AX
#line 1 "file4.s"
/*0x0056*/ MOVQ $0x123456789, AX
#line 1 "file4.s"
/*0x0060*/ BYTE $0
#line 922 "file4.s"
/*0x0061*/ BYTE $0
#line 375 "file4.s"
/*0x0062*/ MOVL $0x1234567, AX
/* */ PCDATA $1, $51
#line 31 "file4.s"
/*0x0067*/ MOVQ $0x123456789, AX
#line 31 "file4.s"
/*0x0071*/ BYTE $0
#line 620 "file4.s"
/*0x0072*/ MOVL $0x1234567, AX
#line 620 "file4.s"
/*0x0077*/ BYTE $0
#line 695 "file4.s"
/*0x0078*/ MOVL $0x1234567, AX
#line 799 "file4.s"
/*0x007d*/ MOVL $0x1234567, AX
#line 41 "file4.s"
/*0x0082*/ BYTE $0
#line 795 "file4.s"
/*0x0083*/ MOVL $0x1234567, AX
#line 908 "file4.s"
/*0x0088*/ BYTE $0
#line 905 "file4.s"
/*0x0089*/ BYTE $0
#line 905 "file4.s"
/*0x008a*/ BYTE $0
#line 905 "file4.s"
/*0x008b*/ BYTE $0
#line 905 "file4.s"
/*0x008c*/ BYTE $0
#line 861 "file4.s"
/*0x008d*/ MOVL $0x1234567, AX
#line 861 "file4.s"
/*0x0092*/ BYTE $0
#line 861 "file4.s"
/*0x0093*/ BYTE $0
#line 861 "file4.s"
/*0x0094*/ BYTE $0
#line 861 "file4.s"
/*0x0095*/ BYTE $0
/* */ PCDATA $1, $192
#line 861 "file4.s"
/*0x0096*/ MOVQ $0x123456789, AX
/* */ PCDATA $1, $60
#line 861 "file4.s"
/*0x00a0*/ MOVL $0x1234567, AX
#line 861 "file4.s"
/*0x00a5*/ BYTE $0
#line 861 "file4.s"
/*0x00a6*/ BYTE $0
#line 56 "file6.s"
/*0x00a7*/ MOVQ $0x123456789, AX
#line 56 "file6.s"
/*0x00b1*/ BYTE $0
#line 56 "file6.s"
/*0x00b2*/ BYTE $0
#line 56 "file6.s"
/*0x00b3*/ BYTE $0
#line 204 "file6.s"
/*0x00b4*/ BYTE $0
#line 204 "file6.s"
/*0x00b5*/ BYTE $0
#line 204 "file6.s"
/*0x00b6*/ BYTE $0
#line 204 "file6.s"
/*0x00b7*/ BYTE $0
#line 979 "file6.s"
/*0x00b8*/ MOVL $0x1234567, AX
#line 979 "file6.s"
/*0x00bd*/ BYTE $0
#line 979 "file6.s"
/*0x00be*/ BYTE $0
#line 979 "file6.s"
/*0x00bf*/ BYTE $0
#line 58 "file6.s"
/*0x00c0*/ MOVL $0x1234567, AX
#line 238 "file6.s"
/*0x00c5*/ MOVL $0x1234567, AX
#line 238 "file6.s"
/*0x00ca*/ BYTE $0
#line 238 "file6.s"
/*0x00cb*/ BYTE $0
#line 699 "file2.s"
/*0x00cc*/ MOVQ $0x123456789, AX
#line 699 "file2.s"
/*0x00d6*/ BYTE $0
#line 699 "file2.s"
/*0x00d7*/ BYTE $0
#line 514 "file2.s"
/*0x00d8*/ MOVL $0x1234567, AX
#line 514 "file2.s"
/*0x00dd*/ BYTE $0
#line 514 "file2.s"
/*0x00de*/ BYTE $0
#line 108 "file2.s"
/*0x00df*/ MOVQ $0x123456789, AX
#line 108 "file2.s"
/*0x00e9*/ MOVQ $0x123456789, AX
#line 108 "file2.s"
/*0x00f3*/ MOVL $0x1234567, AX
#line 108 "file2.s"
/*0x00f8*/ BYTE $0
#line 108 "file2.s"
/*0x00f9*/ BYTE $0
#line 918 "file2.s"
/*0x00fa*/ BYTE $0
#line 918 "file2.s"
/*0x00fb*/ BYTE $0
#line 785 "file2.s"
/*0x00fc*/ BYTE $0
#line 3 "file5.s"
/*0x00fd*/ BYTE $0
#line 918 "file5.s"
/*0x00fe*/ BYTE $0
#line 918 "file5.s"
/*0x00ff*/ BYTE $0
#line 670 "file5.s"
/*0x0100*/ MOVL $0x1234567, AX
#line 670 "file5.s"
/*0x0105*/ BYTE $0
#line 720 "file5.s"
/*0x0106*/ BYTE $0
#line 384 "file5.s"
/*0x0107*/ MOVQ $0x123456789, AX
#line 384 "file5.s"
/*0x0111*/ MOVQ $0x123456789, AX
#line 384 "file5.s"
/*0x011b*/ MOVQ $0x123456789, AX
#line 384 "file5.s"
/*0x0125*/ BYTE $0
#line 384 "file5.s"
/*0x0126*/ BYTE $0
#line 263 "file5.s"
/*0x0127*/ BYTE $0
#line 750 "file5.s"
/*0x0128*/ MOVL $0x1234567, AX
#line 750 "file5.s"
/*0x012d*/ BYTE $0
#line 679 "file5.s"
/*0x012e*/ MOVL $0x1234567, AX
#line 679 "file5.s"
/*0x0133*/ BYTE $0
#line 679 "file5.s"
/*0x0134*/ BYTE $0
#line 679 "file5.s"
/*0x0135*/ BYTE $0
#line 679 "file5.s"
/*0x0136*/ POPQ AX
#line 171 "file5.s"
/*0x0137*/ MOVL $0x1234567, AX
#line 171 "file5.s"
/*0x013c*/ BYTE $0
#line 34 "file2.s"
/*0x013d*/ BYTE $0
#line 34 "file2.s"
/*0x013e*/ BYTE $0
#line 34 "file2.s"
/*0x013f*/ BYTE $0
#line 732 "file2.s"
/*0x0140*/ BYTE $0
#line 732 "file2.s"
/*0x0141*/ PUSHQ AX
#line 485 "file2.s"
/*0x0142*/ BYTE $0
#line 485 "file2.s"
/*0x0143*/ BYTE $0
#line 485 "file2.s"
/*0x0144*/ BYTE $0
#line 222 "file2.s"
/*0x0145*/ BYTE $0
#line 222 "file2.s"
/*0x0146*/ BYTE $0
/* */ PCDATA $1, $462
#line 222 "file2.s"
/*0x0147*/ MOVQ $0x123456789, AX
#line 222 "file2.s"
/*0x0151*/ MOVL $0x1234567, AX
#line 222 "file2.s"
/*0x0156*/ BYTE $0
#line 677 "file2.s"
/*0x0157*/ BYTE $0
#line 117 "file2.s"
/*0x0158*/ MOVL $0x1234567, AX
#line 117 "file2.s"
/*0x015d*/ BYTE $0
#line 117 "file2.s"
/*0x015e*/ BYTE $0
#line 361 "file2.s"
/*0x015f*/ MOVL $0x1234567, AX
#line 590 "file2.s"
/*0x0164*/ BYTE $0
#line 590 "file2.s"
/*0x0165*/ BYTE $0
#line 58 "file2.s"
/*0x0166*/ MOVL $0x1234567, AX
#line 58 "file2.s"
/*0x016b*/ BYTE $0
#line 58 "file2.s"
/*0x016c*/ BYTE $0
#line 58 "file2.s"
/*0x016d*/ BYTE $0
#line 58 "file2.s"
/*0x016e*/ BYTE $0
#line 983 "file2.s"
/*0x016f*/ BYTE $0
#line 983 "file2.s"
/*0x0170*/ BYTE $0
#line 983 "file2.s"
/*0x0171*/ BYTE $0
#line 983 "file2.s"
/*0x0172*/ BYTE $0
#line 727 "file2.s"
/*0x0173*/ MOVL $0x1234567, AX
#line 450 "file2.s"
/*0x0178*/ BYTE $0
#line 450 "file2.s"
/*0x0179*/ BYTE $0
#line 450 "file2.s"
/*0x017a*/ BYTE $0
#line 450 "file2.s"
/*0x017b*/ BYTE $0
#line 334 "file2.s"
/*0x017c*/ BYTE $0
#line 334 "file2.s"
/*0x017d*/ BYTE $0
#line 334 "file2.s"
/*0x017e*/ BYTE $0
#line 334 "file2.s"
/*0x017f*/ BYTE $0
#line 465 "file2.s"
/*0x0180*/ MOVL $0x1234567, AX
/* */ PCDATA $1, $518
#line 465 "file2.s"
/*0x0185*/ MOVL $0x1234567, AX
#line 465 "file2.s"
/*0x018a*/ BYTE $0
#line 465 "file2.s"
/*0x018b*/ BYTE $0
#line 465 "file2.s"
/*0x018c*/ BYTE $0
#line 465 "file2.s"
/*0x018d*/ BYTE $0
#line 682 "file2.s"
/*0x018e*/ MOVL $0x1234567, AX
#line 682 "file2.s"
/*0x0193*/ BYTE $0
#line 682 "file2.s"
/*0x0194*/ BYTE $0
#line 846 "file2.s"
/*0x0195*/ MOVQ $0x123456789, AX
#line 846 "file2.s"
/*0x019f*/ BYTE $0
#line 846 "file2.s"
/*0x01a0*/ BYTE $0
#line 846 "file2.s"
/*0x01a1*/ POPQ AX
#line 846 "file2.s"
/*0x01a2*/ BYTE $0
#line 846 "file2.s"
/*0x01a3*/ BYTE $0
#line 49 "file2.s"
/*0x01a4*/ BYTE $0
#line 49 "file2.s"
/*0x01a5*/ BYTE $0
#line 49 "file2.s"
/*0x01a6*/ BYTE $0
#line 726 "file2.s"
/*0x01a7*/ MOVQ $0x123456789, AX
#line 726 "file2.s"
/*0x01b1*/ MOVL $0x1234567, AX
#line 726 "file2.s"
/*0x01b6*/ BYTE $0
#line 726 "file2.s"
/*0x01b7*/ BYTE $0
#line 726 "file2.s"
/*0x01b8*/ BYTE $0
#line 726 "file2.s"
/*0x01b9*/ PUSHQ AX
#line 726 "file2.s"
/*0x01ba*/ BYTE $0
#line 726 "file2.s"
/*0x01bb*/ BYTE $0
#line 726 "file2.s"
/*0x01bc*/ BYTE $0
#line 726 "file2.s"
/*0x01bd*/ BYTE $0
#line 13 "file1.s"
/*0x01be*/ BYTE $0
#line 13 "file1.s"
/*0x01bf*/ BYTE $0
#line 13 "file1.s"
/*0x01c0*/ BYTE $0
#line 827 "file1.s"
/*0x01c1*/ MOVL $0x1234567, AX
#line 827 "file1.s"
/*0x01c6*/ BYTE $0
#line 827 "file1.s"
/*0x01c7*/ BYTE $0
#line 827 "file1.s"
/*0x01c8*/ BYTE $0
#line 827 "file1.s"
/*0x01c9*/ BYTE $0
#line 783 "file1.s"
/*0x01ca*/ BYTE $0
#line 783 "file1.s"
/*0x01cb*/ BYTE $0
#line 783 "file1.s"
/*0x01cc*/ BYTE $0
#line 783 "file1.s"
/*0x01cd*/ BYTE $0
#line 367 "file1.s"
/*0x01ce*/ MOVQ $0x123456789, AX
#line 367 "file1.s"
/*0x01d8*/ MOVL $0x1234567, AX
#line 367 "file1.s"
/*0x01dd*/ BYTE $0
#line 367 "file1.s"
/*0x01de*/ BYTE $0
#line 367 "file1.s"
/*0x01df*/ BYTE $0
#line 367 "file1.s"
/*0x01e0*/ BYTE $0
#line 581 "file1.s"
/*0x01e1*/ BYTE $0
#line 581 "file1.s"
/*0x01e2*/ BYTE $0
#line 581 "file1.s"
/*0x01e3*/ BYTE $0
#line 638 "file1.s"
/*0x01e4*/ MOVQ $0x123456789, AX
#line 638 "file1.s"
/*0x01ee*/ MOVL $0x1234567, AX
#line 638 "file1.s"
/*0x01f3*/ BYTE $0
#line 638 "file1.s"
/*0x01f4*/ BYTE $0
#line 638 "file1.s"
/*0x01f5*/ BYTE $0
#line 359 "file1.s"
/*0x01f6*/ BYTE $0
#line 449 "file1.s"
/*0x01f7*/ BYTE $0
#line 449 "file1.s"
/*0x01f8*/ BYTE $0
#line 449 "file1.s"
/*0x01f9*/ BYTE $0
#line 298 "file1.s"
/*0x01fa*/ BYTE $0
#line 298 "file1.s"
/*0x01fb*/ BYTE $0
#line 257 "file1.s"
/*0x01fc*/ BYTE $0
#line 257 "file1.s"
/*0x01fd*/ BYTE $0
#line 257 "file1.s"
/*0x01fe*/ BYTE $0
#line 512 "file1.s"
/*0x01ff*/ MOVL $0x1234567, AX
#line 512 "file1.s"
/*0x0204*/ BYTE $0
#line 512 "file1.s"
/*0x0205*/ BYTE $0
#line 617 "file1.s"
/*0x0206*/ MOVL $0x1234567, AX
#line 478 "file1.s"
/*0x020b*/ BYTE $0
/* */ PCDATA $2, $351
#line 478 "file1.s"
/*0x020c*/ BYTE $0
#line 958 "file1.s"
/*0x020d*/ BYTE $0
#line 958 "file1.s"
/*0x020e*/ BYTE $0
#line 958 "file1.s"
/*0x020f*/ BYTE $0
#line 958 "file1.s"
/*0x0210*/ BYTE $0
#line 371 "file1.s"
/*0x0211*/ MOVQ $0x123456789, AX
#line 371 "file1.s"
/*0x021b*/ BYTE $0
#line 371 "file1.s"
/*0x021c*/ BYTE $0
#line 56 "file3.s"
/*0x021d*/ MOVL $0x1234567, AX
#line 56 "file3.s"
/*0x0222*/ BYTE $0
#line 56 "file3.s"
/*0x0223*/ BYTE $0
#line 56 "file9.s"
/*0x0224*/ MOVQ $0x123456789, AX
#line 56 "file9.s"
/*0x022e*/ BYTE $0
#line 56 "file9.s"
/*0x022f*/ BYTE $0
#line 56 "file9.s"
/*0x0230*/ BYTE $0
#line 56 "file9.s"
/*0x0231*/ BYTE $0
#line 684 "file9.s"
/*0x0232*/ MOVQ $0x123456789, AX
#line 684 "file9.s"
/*0x023c*/ BYTE $0
#line 684 "file9.s"
/*0x023d*/ POPQ AX
#line 407 "file9.s"
/*0x023e*/ MOVL $0x1234567, AX
#line 407 "file9.s"
/*0x0243*/ BYTE $0
PUSHQ AX
PUSHQ AX
RET
GLOBL funcdata1(SB), $16
#line 1 "input"
TEXT func2(SB),7,$40-688
FUNCDATA $1, funcdata2(SB)
#line 1 "input"
#line 1 "input"
/*0x0004*/ BYTE $0
#line 860 "input"
/*0x0005*/ BYTE $0
#line 860 "input"
/*0x0006*/ BYTE $0
#line 860 "input"
/*0x0007*/ BYTE $0
#line 860 "input"
/*0x0008*/ BYTE $0
#line 85 "input"
/*0x0009*/ BYTE $0
#line 85 "input"
/*0x000a*/ BYTE $0
#line 355 "input"
/*0x000b*/ MOVQ $0x123456789, AX
#line 355 "input"
/*0x0015*/ MOVL $0x1234567, AX
#line 355 "input"
/*0x001a*/ BYTE $0
#line 355 "input"
/*0x001b*/ BYTE $0
#line 355 "input"
/*0x001c*/ BYTE $0
#line 840 "input"
/*0x001d*/ MOVL $0x1234567, AX
#line 840 "input"
/*0x0022*/ BYTE $0
#line 294 "input"
/*0x0023*/ MOVQ $0x123456789, AX
#line 294 "input"
/*0x002d*/ MOVQ $0x123456789, AX
#line 294 "input"
/*0x0037*/ MOVQ $0x123456789, AX
#line 294 "input"
/*0x0041*/ BYTE $0
#line 294 "input"
/*0x0042*/ BYTE $0
#line 294 "input"
/*0x0043*/ BYTE $0
#line 294 "input"
/*0x0044*/ BYTE $0
/* */ PCDATA $1, $385
#line 294 "input"
/*0x0045*/ BYTE $0
#line 294 "input"
/*0x0046*/ BYTE $0
#line 294 "input"
/*0x0047*/ BYTE $0
#line 81 "file9.s"
/*0x0048*/ MOVL $0x1234567, AX
#line 81 "file9.s"
/*0x004d*/ BYTE $0
#line 81 "file9.s"
/*0x004e*/ BYTE $0
#line 81 "file9.s"
/*0x004f*/ POPQ AX
#line 81 "file9.s"
/*0x0050*/ MOVL $0x1234567, AX
#line 81 "file9.s"
/*0x0055*/ BYTE $0
/* */ PCDATA $1, $701
#line 81 "file9.s"
/*0x0056*/ MOVL $0x1234567, AX
#line 81 "file9.s"
/*0x005b*/ BYTE $0
#line 81 "file9.s"
/*0x005c*/ BYTE $0
#line 81 "file9.s"
/*0x005d*/ BYTE $0
#line 81 "file9.s"
/*0x005e*/ BYTE $0
#line 290 "file9.s"
/*0x005f*/ BYTE $0
#line 290 "file9.s"
/*0x0060*/ BYTE $0
#line 290 "file9.s"
/*0x0061*/ BYTE $0
#line 197 "file9.s"
/*0x0062*/ MOVL $0x1234567, AX
#line 197 "file9.s"
/*0x0067*/ BYTE $0
#line 608 "file9.s"
/*0x0068*/ MOVQ $0x123456789, AX
#line 608 "file9.s"
/*0x0072*/ MOVQ $0x123456789, AX
#line 608 "file9.s"
/*0x007c*/ BYTE $0
/* */ PCDATA $1, $562
#line 608 "file9.s"
/*0x007d*/ BYTE $0
#line 608 "file9.s"
/*0x007e*/ BYTE $0
#line 189 "file9.s"
/*0x007f*/ MOVL $0x1234567, AX
#line 189 "file9.s"
/*0x0084*/ BYTE $0
#line 189 "file9.s"
/*0x0085*/ BYTE $0
#line 189 "file9.s"
/*0x0086*/ BYTE $0
#line 189 "file9.s"
/*0x0087*/ BYTE $0
#line 472 "file9.s"
/*0x0088*/ MOVL $0x1234567, AX
#line 472 "file9.s"
/*0x008d*/ BYTE $0
#line 472 "file9.s"
/*0x008e*/ BYTE $0
#line 472 "file9.s"
/*0x008f*/ PUSHQ AX
#line 472 "file9.s"
/*0x0090*/ MOVQ $0x123456789, AX
#line 472 "file9.s"
/*0x009a*/ MOVL $0x1234567, AX
#line 472 "file9.s"
/*0x009f*/ BYTE $0
#line 472 "file9.s"
/*0x00a0*/ BYTE $0
#line 472 "file9.s"
/*0x00a1*/ BYTE $0
#line 472 "file9.s"
/*0x00a2*/ BYTE $0
#line 148 "file9.s"
/*0x00a3*/ MOVQ $0x123456789, AX
#line 148 "file9.s"
/*0x00ad*/ BYTE $0
#line 148 "file9.s"
/*0x00ae*/ BYTE $0
#line 148 "file9.s"
/*0x00af*/ BYTE $0
#line 148 "file9.s"
/*0x00b0*/ BYTE $0
#line 562 "file9.s"
/*0x00b1*/ MOVL $0x1234567, AX
#line 562 "file9.s"
/*0x00b6*/ BYTE $0
#line 562 "file9.s"
/*0x00b7*/ PUSHQ AX
#line 562 "file9.s"
/*0x00b8*/ BYTE $0
#line 532 "file9.s"
/*0x00b9*/ MOVQ $0x123456789, AX
#line 532 "file9.s"
/*0x00c3*/ MOVQ $0x123456789, AX
#line 282 "file9.s"
/*0x00cd*/ BYTE $0
#line 282 "file9.s"
/*0x00ce*/ BYTE $0
#line 282 "file9.s"
/*0x00cf*/ BYTE $0
/* */ PCDATA $2, $861
#line 282 "file9.s"
/*0x00d0*/ BYTE $0
#line 282 "file9.s"
/*0x00d1*/ BYTE $0
/* */ PCDATA $2, $310
#line 282 "file9.s"
/*0x00d2*/ BYTE $0
#line 416 "file9.s"
/*0x00d3*/ MOVQ $0x123456789, AX
#line 416 "file9.s"
/*0x00dd*/ MOVL $0x1234567, AX
#line 780 "file9.s"
/*0x00e2*/ BYTE $0
#line 780 "file9.s"
/*0x00e3*/ BYTE $0
#line 765 "file9.s"
/*0x00e4*/ MOVL $0x1234567, AX
#line 523 "file9.s"
/*0x00e9*/ BYTE $0
#line 523 "file9.s"
/*0x00ea*/ BYTE $0
#line 523 "file9.s"
/*0x00eb*/ BYTE $0
#line 733 "file9.s"
/*0x00ec*/ MOVQ $0x123456789, AX
#line 378 "file9.s"
/*0x00f6*/ BYTE $0
#line 378 "file9.s"
/*0x00f7*/ BYTE $0
#line 378 "file9.s"
/*0x00f8*/ BYTE $0
#line 378 "file9.s"
/*0x00f9*/ BYTE $0
#line 540 "file9.s"
/*0x00fa*/ BYTE $0
#line 540 "file9.s"
/*0x00fb*/ BYTE $0
#line 57 "file9.s"
/*0x00fc*/ BYTE $0
#line 57 "file9.s"
/*0x00fd*/ BYTE $0
#line 57 "file9.s"
/*0x00fe*/ BYTE $0
#line 417 "file9.s"
/*0x00ff*/ BYTE $0
/* */ PCDATA $1, $932
#line 417 "file9.s"
/*0x0100*/ BYTE $0
#line 417 "file9.s"
/*0x0101*/ BYTE $0
#line 417 "file9.s"
/*0x0102*/ BYTE $0
#line 417 "file9.s"
/*0x0103*/ BYTE $0
#line 713 "file9.s"
/*0x0104*/ MOVL $0x1234567, AX
#line 610 "file0.s"
/*0x0109*/ MOVQ $0x123456789, AX
#line 610 "file0.s"
/*0x0113*/ MOVL $0x1234567, AX
#line 610 "file0.s"
/*0x0118*/ BYTE $0
#line 787 "file0.s"
/*0x0119*/ MOVQ $0x123456789, AX
#line 829 "file0.s"
/*0x0123*/ BYTE $0
#line 829 "file0.s"
/*0x0124*/ BYTE $0
#line 829 "file0.s"
/*0x0125*/ BYTE $0
#line 849 "file0.s"
/*0x0126*/ BYTE $0
#line 849 "file0.s"
/*0x0127*/ BYTE $0
#line 849 "file0.s"
/*0x0128*/ BYTE $0
/* */ PCDATA $2, $356
#line 849 "file0.s"
/*0x0129*/ BYTE $0
#line 849 "file0.s"
/*0x012a*/ BYTE $0
#line 88 "file0.s"
/*0x012b*/ MOVL $0x1234567, AX
#line 88 "file0.s"
/*0x0130*/ BYTE $0
#line 88 "file0.s"
/*0x0131*/ BYTE $0
#line 88 "file0.s"
/*0x0132*/ BYTE $0
#line 684 "file0.s"
/*0x0133*/ BYTE $0
#line 684 "file0.s"
/*0x0134*/ BYTE $0
#line 684 "file0.s"
/*0x0135*/ BYTE $0
#line 684 "file0.s"
/*0x0136*/ BYTE $0
#line 238 "file0.s"
/*0x0137*/ BYTE $0
#line 238 "file0.s"
/*0x0138*/ BYTE $0
#line 238 "file0.s"
/*0x0139*/ PUSHQ AX
#line 238 "file0.s"
/*0x013a*/ BYTE $0
#line 238 "file0.s"
/*0x013b*/ BYTE $0
#line 603 "file0.s"
/*0x013c*/ BYTE $0
#line 981 "file0.s"
/*0x013d*/ BYTE $0
#line 981 "file0.s"
/*0x013e*/ POPQ AX
#line 616 "file0.s"
/*0x013f*/ BYTE $0
#line 616 "file0.s"
/*0x0140*/ BYTE $0
#line 616 "file0.s"
/*0x0141*/ BYTE $0
#line 616 "file0.s"
/*0x0142*/ BYTE $0
#line 716 "file0.s"
/*0x0143*/ MOVL $0x1234567, AX
#line 716 "file0.s"
/*0x0148*/ BYTE $0
#line 716 "file0.s"
/*0x0149*/ BYTE $0
#line 34 "file0.s"
/*0x014a*/ BYTE $0
#line 34 "file0.s"
/*0x014b*/ BYTE $0
#line 34 "file0.s"
/*0x014c*/ BYTE $0
#line 90 "file0.s"
/*0x014d*/ MOVL $0x1234567, AX
#line 316 "file0.s"
/*0x0152*/ MOVQ $0x123456789, AX
#line 230 "file0.s"
/*0x015c*/ MOVQ $0x123456789, AX
#line 799 "file0.s"
/*0x0166*/ MOVQ $0x123456789, AX
#line 799 "file0.s"
/*0x0170*/ BYTE $0
#line 799 "file0.s"
/*0x0171*/ BYTE $0
/* */ PCDATA $1, $247
#line 799 "file0.s"
/*0x0172*/ BYTE $0
#line 799 "file0.s"
/*0x0173*/ BYTE $0
#line 799 "file0.s"
/*0x0174*/ BYTE $0
#line 655 "file0.s"
/*0x0175*/ MOVL $0x1234567, AX
#line 655 "file0.s"
/*0x017a*/ BYTE $0
#line 551 "file0.s"
/*0x017b*/ BYTE $0
#line 551 "file0.s"
/*0x017c*/ BYTE $0
#line 271 "file0.s"
/*0x017d*/ MOVQ $0x123456789, AX
#line 271 "file0.s"
/*0x0187*/ MOVQ $0x123456789, AX
#line 271 "file0.s"
/*0x0191*/ MOVL $0x1234567, AX
#line 271 "file0.s"
/*0x0196*/ BYTE $0
#line 271 "file0.s"
/*0x0197*/ BYTE $0
#line 271 "file0.s"
/*0x0198*/ BYTE $0
#line 233 "file0.s"
/*0x0199*/ MOVL $0x1234567, AX
#line 233 "file0.s"
/*0x019e*/ BYTE $0
#line 233 "file0.s"
/*0x019f*/ BYTE $0
#line 233 "file0.s"
/*0x01a0*/ BYTE $0
#line 233 "file0.s"
/*0x01a1*/ BYTE $0
#line 738 "file0.s"
/*0x01a2*/ MOVL $0x1234567, AX
#line 738 "file0.s"
/*0x01a7*/ BYTE $0
#line 800 "file0.s"
/*0x01a8*/ BYTE $0
#line 800 "file0.s"
/*0x01a9*/ BYTE $0
#line 646 "file0.s"
/*0x01aa*/ MOVQ $0x123456789, AX
#line 646 "file0.s"
/*0x01b4*/ BYTE $0
#line 646 "file0.s"
/*0x01b5*/ BYTE $0
#line 646 "file0.s"
/*0x01b6*/ BYTE $0
#line 709 "file0.s"
/*0x01b7*/ BYTE $0
#line 709 "file0.s"
/*0x01b8*/ BYTE $0
#line 709 "file0.s"
/*0x01b9*/ BYTE $0
#line 709 "file0.s"
/*0x01ba*/ BYTE $0
#line 296 "file0.s"
/*0x01bb*/ BYTE $0
#line 296 "file0.s"
/*0x01bc*/ BYTE $0
#line 296 "file0.s"
/*0x01bd*/ BYTE $0
#line 71 "file0.s"
/*0x01be*/ BYTE $0
#line 71 "file0.s"
/*0x01bf*/ BYTE $0
#line 71 "file0.s"
/*0x01c0*/ BYTE $0
#line 7 "file2.s"
/*0x01c1*/ BYTE $0
#line 747 "file2.s"
/*0x01c2*/ BYTE $0
#line 177 "file2.s"
/*0x01c3*/ MOVQ $0x123456789, AX
#line 177 "file2.s"
/*0x01cd*/ MOVQ $0x123456789, AX
#line 177 "file2.s"
/*0x01d7*/ MOVL $0x1234567, AX
#line 177 "file2.s"
/*0x01dc*/ BYTE $0
#line 177 "file2.s"
/*0x01dd*/ BYTE $0
#line 177 "file2.s"
/*0x01de*/ BYTE $0
#line 72 "file2.s"
/*0x01df*/ BYTE $0
#line 215 "file2.s"
/*0x01e0*/ MOVL $0x1234567, AX
#line 215 "file2.s"
/*0x01e5*/ BYTE $0
#line 215 "file2.s"
/*0x01e6*/ BYTE $0
#line 215 "file2.s"
/*0x01e7*/ BYTE $0
#line 946 "file2.s"
/*0x01e8*/ BYTE $0
#line 946 "file2.s"
/*0x01e9*/ BYTE $0
#line 946 "file2.s"
/*0x01ea*/ BYTE $0
#line 946 "file2.s"
/*0x01eb*/ BYTE $0
#line 263 "file2.s"
/*0x01ec*/ MOVL $0x1234567, AX
#line 263 "file2.s"
/*0x01f1*/ BYTE $0
#line 897 "file2.s"
/*0x01f2*/ MOVQ $0x123456789, AX
#line 897 "file2.s"
/*0x01fc*/ MOVQ $0x123456789, AX
#line 897 "file2.s"
/*0x0206*/ BYTE $0
#line 897 "file2.s"
/*0x0207*/ BYTE $0
#line 897 "file2.s"
/*0x0208*/ BYTE $0
#line 229 "file2.s"
/*0x0209*/ BYTE $0
#line 229 "file2.s"
/*0x020a*/ BYTE $0
#line 229 "file2.s"
/*0x020b*/ BYTE $0
#line 229 "file2.s"
/*0x020c*/ BYTE $0
/* */ PCDATA $1, $7
#line 229 "file2.s"
/*0x020d*/ MOVL $0x1234567, AX
#line 229 "file2.s"
/*0x0212*/ BYTE $0
#line 353 "file2.s"
/*0x0213*/ BYTE $0
#line 353 "file2.s"
/*0x0214*/ BYTE $0
#line 353 "file2.s"
/*0x0215*/ BYTE $0
#line 353 "file2.s"
/*0x0216*/ BYTE $0
#line 852 "file2.s"
/*0x0217*/ BYTE $0
#line 852 "file2.s"
/*0x0218*/ BYTE $0
#line 852 "file2.s"
/*0x0219*/ BYTE $0
#line 852 "file2.s"
/*0x021a*/ BYTE $0
#line 852 "file2.s"
/*0x021b*/ PUSHQ AX
#line 852 "file2.s"
/*0x021c*/ BYTE $0
#line 852 "file2.s"
/*0x021d*/ BYTE $0
#line 852 "file2.s"
/*0x021e*/ BYTE $0
#line 904 "file2.s"
/*0x021f*/ MOVQ $0x123456789, AX
#line 904 "file2.s"
/*0x0229*/ BYTE $0
#line 904 "file2.s"
/*0x022a*/ BYTE $0
#line 882 "file2.s"
/*0x022b*/ BYTE $0
#line 905 "file2.s"
/*0x022c*/ BYTE $0
#line 410 "file2.s"
/*0x022d*/ MOVQ $0x123456789, AX
#line 410 "file2.s"
/*0x0237*/ BYTE $0
#line 410 "file2.s"
/*0x0238*/ BYTE $0
#line 410 "file2.s"
/*0x0239*/ POPQ AX
#line 410 "file2.s"
/*0x023a*/ BYTE $0
#line 410 "file2.s"
/*0x023b*/ BYTE $0
#line 410 "file2.s"
/*0x023c*/ BYTE $0
/* */ PCDATA $2, $173
#line 410 "file2.s"
/*0x023d*/ MOVL $0x1234567, AX
#line 410 "file2.s"
/*0x0242*/ BYTE $0
/* */ PCDATA $1, $396
#line 410 "file2.s"
/*0x0243*/ BYTE $0
#line 410 "file2.s"
/*0x0244*/ BYTE $0
#line 666 "file2.s"
/*0x0245*/ BYTE $0
#line 129 "file2.s"
/*0x0246*/ MOVQ $0x123456789, AX
#line 129 "file2.s"
/*0x0250*/ BYTE $0
#line 391 "file2.s"
/*0x0251*/ BYTE $0
#line 696 "file2.s"
/*0x0252*/ MOVL $0x1234567, AX
#line 940 "file2.s"
/*0x0257*/ BYTE $0
#line 940 "file2.s"
/*0x0258*/ BYTE $0
#line 606 "file2.s"
/*0x0259*/ MOVL $0x1234567, AX
#line 606 "file2.s"
/*0x025e*/ BYTE $0
#line 648 "file2.s"
/*0x025f*/ MOVQ $0x123456789, AX
#line 648 "file2.s"
/*0x0269*/ BYTE $0
#line 648 "file2.s"
/*0x026a*/ BYTE $0
/* */ PCDATA $2, $84
#line 648 "file2.s"
/*0x026b*/ MOVQ $0x123456789, AX
#line 648 "file2.s"
/*0x0275*/ MOVQ $0x123456789, AX
#line 648 "file2.s"
/*0x027f*/ MOVQ $0x123456789, AX
#line 648 "file2.s"
/*0x0289*/ MOVQ $0x123456789, AX
#line 648 "file2.s"
/*0x0293*/ MOVQ $0x123456789, AX
#line 648 "file2.s"
/*0x029d*/ MOVL $0x1234567, AX
#line 648 "file2.s"
/*0x02a2*/ PUSHQ AX
#line 648 "file2.s"
/*0x02a3*/ MOVL $0x1234567, AX
#line 648 "file2.s"
/*0x02a8*/ BYTE $0
#line 648 "file2.s"
/*0x02a9*/ BYTE $0
#line 648 "file2.s"
/*0x02aa*/ BYTE $0
#line 648 "file2.s"
/*0x02ab*/ BYTE $0
#line 449 "file2.s"
/*0x02ac*/ MOVQ $0x123456789, AX
#line 449 "file2.s"
/*0x02b6*/ MOVL $0x1234567, AX
#line 284 "file2.s"
/*0x02bb*/ BYTE $0
#line 284 "file2.s"
/*0x02bc*/ BYTE $0
#line 284 "file2.s"
/*0x02bd*/ BYTE $0
#line 284 "file2.s"
/*0x02be*/ BYTE $0
#line 26 "file2.s"
/*0x02bf*/ MOVQ $0x123456789, AX
#line 26 "file2.s"
/*0x02c9*/ MOVL $0x1234567, AX
#line 26 "file2.s"
/*0x02ce*/ BYTE $0
#line 26 "file2.s"
/*0x02cf*/ BYTE $0
#line 26 "file2.s"
/*0x02d0*/ BYTE $0
#line 605 "file2.s"
/*0x02d1*/ MOVL $0x1234567, AX
#line 605 "file2.s"
/*0x02d6*/ BYTE $0
#line 605 "file2.s"
/*0x02d7*/ BYTE $0
#line 605 "file2.s"
/*0x02d8*/ BYTE $0
#line 593 "file2.s"
/*0x02d9*/ MOVL $0x1234567, AX
#line 541 "file2.s"
/*0x02de*/ MOVL $0x1234567, AX
#line 541 "file2.s"
/*0x02e3*/ BYTE $0
#line 541 "file2.s"
/*0x02e4*/ BYTE $0
#line 181 "file2.s"
/*0x02e5*/ MOVQ $0x123456789, AX
#line 181 "file2.s"
/*0x02ef*/ BYTE $0
#line 907 "file2.s"
/*0x02f0*/ MOVQ $0x123456789, AX
#line 704 "file2.s"
/*0x02fa*/ MOVQ $0x123456789, AX
#line 704 "file2.s"
/*0x0304*/ MOVQ $0x123456789, AX
#line 704 "file2.s"
/*0x030e*/ MOVL $0x1234567, AX
#line 704 "file2.s"
/*0x0313*/ BYTE $0
#line 704 "file2.s"
/*0x0314*/ BYTE $0
#line 704 "file2.s"
/*0x0315*/ BYTE $0
#line 704 "file2.s"
/*0x0316*/ BYTE $0
#line 859 "file2.s"
/*0x0317*/ MOVL $0x1234567, AX
#line 407 "file2.s"
/*0x031c*/ BYTE $0
#line 407 "file2.s"
/*0x031d*/ BYTE $0
/* */ PCDATA $2, $569
#line 407 "file2.s"
/*0x031e*/ MOVL $0x1234567, AX
#line 407 "file2.s"
/*0x0323*/ BYTE $0
#line 407 "file2.s"
/*0x0324*/ BYTE $0
#line 407 "file2.s"
/*0x0325*/ BYTE $0
/* */ PCDATA $1, $937
#line 407 "file2.s"
/*0x0326*/ MOVL $0x1234567, AX
#line 407 "file2.s"
/*0x032b*/ BYTE $0
#line 774 "file2.s"
/*0x032c*/ MOVQ $0x123456789, AX
#line 774 "file2.s"
/*0x0336*/ BYTE $0
#line 547 "file2.s"
/*0x0337*/ BYTE $0
#line 547 "file2.s"
/*0x0338*/ BYTE $0
#line 547 "file2.s"
/*0x0339*/ BYTE $0
#line 547 "file2.s"
/*0x033a*/ PUSHQ AX
#line 547 "file2.s"
/*0x033b*/ MOVL $0x1234567, AX
#line 427 "file2.s"
/*0x0340*/ MOVL $0x1234567, AX
/* */ PCDATA $1, $462
#line 427 "file2.s"
/*0x0345*/ MOVQ $0x123456789, AX
#line 427 "file2.s"
/*0x034f*/ MOVL $0x1234567, AX
#line 427 "file2.s"
/*0x0354*/ BYTE $0
#line 427 "file2.s"
/*0x0355*/ BYTE $0
#line 427 "file2.s"
/*0x0356*/ BYTE $0
#line 427 "file2.s"
/*0x0357*/ BYTE $0
/* */ PCDATA $2, $303
#line 427 "file2.s"
/*0x0358*/ MOVQ $0x123456789, AX
#line 427 "file2.s"
/*0x0362*/ BYTE $0
#line 427 "file2.s"
/*0x0363*/ BYTE $0
#line 708 "file2.s"
/*0x0364*/ BYTE $0
#line 708 "file2.s"
/*0x0365*/ BYTE $0
#line 708 "file2.s"
/*0x0366*/ BYTE $0
#line 708 "file2.s"
/*0x0367*/ BYTE $0
#line 218 "file2.s"
/*0x0368*/ MOVL $0x1234567, AX
#line 44 "file2.s"
/*0x036d*/ BYTE $0
#line 915 "file2.s"
/*0x036e*/ BYTE $0
#line 915 "file2.s"
/*0x036f*/ BYTE $0
#line 915 "file2.s"
/*0x0370*/ BYTE $0
#line 915 "file2.s"
/*0x0371*/ BYTE $0
#line 122 "file2.s"
/*0x0372*/ MOVQ $0x123456789, AX
#line 122 "file2.s"
/*0x037c*/ MOVL $0x1234567, AX
#line 122 "file2.s"
/*0x0381*/ BYTE $0
#line 122 "file2.s"
/*0x0382*/ BYTE $0
#line 266 "file2.s"
/*0x0383*/ BYTE $0
#line 266 "file2.s"
/*0x0384*/ BYTE $0
#line 368 "file2.s"
/*0x0385*/ BYTE $0
#line 368 "file2.s"
/*0x0386*/ BYTE $0
#line 368 "file2.s"
/*0x0387*/ BYTE $0
#line 368 "file2.s"
/*0x0388*/ BYTE $0
#line 775 "file2.s"
/*0x0389*/ BYTE $0
#line 10 "file8.s"
/*0x038a*/ BYTE $0
#line 10 "file8.s"
/*0x038b*/ BYTE $0
#line 422 "file8.s"
/*0x038c*/ MOVL $0x1234567, AX
#line 422 "file8.s"
/*0x0391*/ BYTE $0
#line 613 "file8.s"
/*0x0392*/ BYTE $0
#line 613 "file8.s"
/*0x0393*/ BYTE $0
#line 613 "file8.s"
/*0x0394*/ BYTE $0
#line 697 "file8.s"
/*0x0395*/ MOVQ $0x123456789, AX
#line 697 "file8.s"
/*0x039f*/ MOVQ $0x123456789, AX
#line 697 "file8.s"
/*0x03a9*/ BYTE $0
#line 697 "file8.s"
/*0x03aa*/ BYTE $0
#line 697 "file8.s"
/*0x03ab*/ BYTE $0
POPQ AX
POPQ AX
POPQ AX
RET
GLOBL funcdata2(SB), $16
TEXT start(SB),7,$0
CALL func0(SB)
CALL func1(SB)
CALL func2(SB)
MOVQ $runtime·pclntab(SB), AX
RET
// Copyright 2014 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 main
// round returns size rounded up to the next multiple of align;
// align must be a power of two.
func round(size, align Addr) Addr {
return (size + align - 1) &^ (align - 1)
}
// Copyright 2014 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.
// Writing of executable and (for hostlink mode) object files.
package main
import "io"
func (p *Prog) write(w io.Writer) {
p.Entry = p.Syms[p.startSym].Addr
p.formatter.write(w, p)
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment