Commit daf5d414 authored by Andrew Gerrand's avatar Andrew Gerrand

[release-branch.go1.4] remove cmd/link

LGTM=dsymonds, minux
R=rsc, dsymonds, minux
CC=golang-codereviews
https://golang.org/cl/176910043
parent c1fc059b
// 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, "go.weak.") ||
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,
})
}
}
}
// autoConst defines the automatically generated constant symbols needed by p.
func (p *Prog) autoConst() {
for sym := range p.Missing {
switch {
case strings.HasPrefix(sym.Name, "go.weak."):
// weak symbol resolves to actual symbol if present, or else nil.
delete(p.Missing, sym)
targ := sym
targ.Name = sym.Name[len("go.weak."):]
var addr Addr
if s := p.Syms[targ]; s != nil {
addr = s.Addr
}
p.defineConst(sym.Name, addr)
}
}
}
// 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",
"testdata/autoweak.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 "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)
}
}
// TODO(rsc): Define full enumeration for relocation types.
const (
R_ADDR = 1
R_SIZE = 2
R_CALL = 3
R_CALLARM = 4
R_CALLIND = 5
R_CONST = 6
R_PCREL = 7
)
// 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 R_ADDR, R_CALLIND:
// ok
case R_PCREL, 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"
"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 http://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: 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()
p.autoConst()
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 6a -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 go.weak symbols.
TEXT start(SB),7,$0
MOVQ $autotab(SB),AX
MOVQ $autoptr(SB),AX
RET
// go.weak.sym should resolve to sym, because sym is in the binary.
DATA autotab+0(SB)/8, $go·weak·sym(SB)
DATA autotab+8(SB)/8, $sym(SB)
// go.weak.missingsym should resolve to 0, because missingsym is not in the binary.
DATA autotab+16(SB)/8, $go·weak·missingsym(SB)
DATA autotab+24(SB)/8, $0
// go.weak.deadsym should resolve to 0, because deadsym is discarded during dead code removal
DATA autotab+32(SB)/8, $go·weak·deadsym(SB)
DATA autotab+40(SB)/8, $0
GLOBL autotab(SB), $48
GLOBL sym(SB), $1
GLOBL deadsym(SB), $1
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 b0 10 00 00 00 00 00 00 |................|
00000090 00 00 00 00 00 00 00 00 b0 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 20 00 00 00 00 00 00 00 |. ...... .......|
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 20 20 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | ..............|
00000130 20 10 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | ...............|
*
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 20 20 00 00 00 00 00 00 90 00 00 00 00 00 00 00 | ..............|
00000180 20 10 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | ...............|
*
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 be 00 30 00 00 ba 0c 00 00 00 b8 |.......0........|
00001010 04 00 00 02 0f 05 31 ff b8 01 00 00 02 0f 05 c3 |......1.........|
00001020 fb ff ff ff 00 00 01 08 01 00 00 00 00 00 00 00 |................|
00001030 00 20 00 00 00 00 00 00 30 00 00 00 00 00 00 00 |. ......0.......|
00001040 20 20 00 00 00 00 00 00 80 00 00 00 00 00 00 00 | ..............|
00001050 00 20 00 00 00 00 00 00 58 00 00 00 00 00 00 80 |. ......X.......|
00001060 08 00 00 00 60 00 00 00 63 00 00 00 66 00 00 00 |....`...c...f...|
00001070 00 00 00 00 00 00 00 00 5f 72 74 30 5f 67 6f 00 |........_rt0_go.|
00001080 02 20 00 04 20 00 06 05 02 05 02 05 02 05 02 02 |. .. ...........|
00001090 02 02 02 05 02 02 02 01 00 00 00 00 00 00 00 00 |................|
000010a0 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