aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/newlink/macho.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/newlink/macho.go')
-rw-r--r--src/cmd/newlink/macho.go380
1 files changed, 0 insertions, 380 deletions
diff --git a/src/cmd/newlink/macho.go b/src/cmd/newlink/macho.go
deleted file mode 100644
index 4e5524be9b..0000000000
--- a/src/cmd/newlink/macho.go
+++ /dev/null
@@ -1,380 +0,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.
-
-// 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
-}