This is a simple container format that encapsulates multiple Mach-O files, each generally for a different architecture. XNU can execute these files just like single-arch Mach-Os and will pick the appropriate entry.
This page hosts a formal specification of macOS Mach-O multiarch ("fat") binary using Kaitai Struct. This specification can be automatically translated into a variety of programming languages to get a parsing library.
// Code generated by kaitai-struct-compiler from a .ksy source file. DO NOT EDIT.
import (
"github.com/kaitai-io/kaitai_struct_go_runtime/kaitai"
"bytes"
"io"
)
/**
* This is a simple container format that encapsulates multiple Mach-O files,
* each generally for a different architecture. XNU can execute these files just
* like single-arch Mach-Os and will pick the appropriate entry.
* @see <a href="https://opensource.apple.com/source/xnu/xnu-7195.121.3/EXTERNAL_HEADERS/mach-o/fat.h.auto.html">Source</a>
*/
type MachOFat struct {
Magic []byte
NumFatArch uint32
FatArchs []*MachOFat_FatArch
_io *kaitai.Stream
_root *MachOFat
_parent interface{}
}
func NewMachOFat() *MachOFat {
return &MachOFat{
}
}
func (this *MachOFat) Read(io *kaitai.Stream, parent interface{}, root *MachOFat) (err error) {
this._io = io
this._parent = parent
this._root = root
tmp1, err := this._io.ReadBytes(int(4))
if err != nil {
return err
}
tmp1 = tmp1
this.Magic = tmp1
if !(bytes.Equal(this.Magic, []uint8{202, 254, 186, 190})) {
return kaitai.NewValidationNotEqualError([]uint8{202, 254, 186, 190}, this.Magic, this._io, "/seq/0")
}
tmp2, err := this._io.ReadU4be()
if err != nil {
return err
}
this.NumFatArch = uint32(tmp2)
for i := 0; i < int(this.NumFatArch); i++ {
_ = i
tmp3 := NewMachOFat_FatArch()
err = tmp3.Read(this._io, this, this._root)
if err != nil {
return err
}
this.FatArchs = append(this.FatArchs, tmp3)
}
return err
}
type MachOFat_FatArch struct {
CpuType MachO_CpuType
CpuSubtype uint32
OfsObject uint32
LenObject uint32
Align uint32
_io *kaitai.Stream
_root *MachOFat
_parent *MachOFat
_raw_object []byte
_f_object bool
object *MachO
}
func NewMachOFat_FatArch() *MachOFat_FatArch {
return &MachOFat_FatArch{
}
}
func (this *MachOFat_FatArch) Read(io *kaitai.Stream, parent *MachOFat, root *MachOFat) (err error) {
this._io = io
this._parent = parent
this._root = root
tmp4, err := this._io.ReadU4be()
if err != nil {
return err
}
this.CpuType = MachO_CpuType(tmp4)
tmp5, err := this._io.ReadU4be()
if err != nil {
return err
}
this.CpuSubtype = uint32(tmp5)
tmp6, err := this._io.ReadU4be()
if err != nil {
return err
}
this.OfsObject = uint32(tmp6)
tmp7, err := this._io.ReadU4be()
if err != nil {
return err
}
this.LenObject = uint32(tmp7)
tmp8, err := this._io.ReadU4be()
if err != nil {
return err
}
this.Align = uint32(tmp8)
return err
}
func (this *MachOFat_FatArch) Object() (v *MachO, err error) {
if (this._f_object) {
return this.object, nil
}
_pos, err := this._io.Pos()
if err != nil {
return nil, err
}
_, err = this._io.Seek(int64(this.OfsObject), io.SeekStart)
if err != nil {
return nil, err
}
tmp9, err := this._io.ReadBytes(int(this.LenObject))
if err != nil {
return nil, err
}
tmp9 = tmp9
this._raw_object = tmp9
_io__raw_object := kaitai.NewStream(bytes.NewReader(this._raw_object))
tmp10 := NewMachO()
err = tmp10.Read(_io__raw_object, this, nil)
if err != nil {
return nil, err
}
this.object = tmp10
_, err = this._io.Seek(_pos, io.SeekStart)
if err != nil {
return nil, err
}
this._f_object = true
this._f_object = true
return this.object, nil
}