// ReadUInt32 reads a uint32 from r. func ReadUInt32(r io.Reader, byteOrder binary.ByteOrder) (uint32, error) { var buf [4]byte if _, err := io.ReadFull(r, buf[:]); err != nil { return 0, err } return byteOrder.Uint32(buf[:]), nil }
func NewNullFrame(data []byte, byteOrder binary.ByteOrder) (*NullFrame, error) { if len(data) < NULL_FRAME_HEADER_LENGTH { return nil, errors.New(fmt.Sprintf("required at least %d bytes of data.", NULL_FRAME_HEADER_LENGTH)) } return &NullFrame{byteOrder.Uint32(data), data[4:]}, nil }
func ReadFloat32(buf []byte, format byte, endianness binary.ByteOrder) float32 { encoding := format & EncodingMask if encoding == EncodingFloatingPoint { return math.Float32frombits(endianness.Uint32(buf)) } else { offset := 0 if endianness == binary.LittleEndian { offset = len(buf) - 1 } var neg byte = 0 if encoding == EncodingSignedInt && buf[offset]&(1<<7) != 0 { neg = 0xFF } tmp := []byte{neg, neg, neg, neg} if endianness == binary.BigEndian { copy(tmp[4-len(buf):], buf) } else { copy(tmp, buf) } sample := endianness.Uint32(tmp) div := math.Pow(2, float64(len(buf)*8-1)) if encoding == EncodingSignedInt { return float32(float64(int32(sample)) / div) } else { return float32(float64(sample)/div - 1.0) } } }
func (b *Buffer) ReadUint32(order binary.ByteOrder) (uint32, error) { if b.readPos >= len(b.Buf)-4 { return 0, io.EOF } u := order.Uint32(b.Buf[b.readPos:]) b.readPos += 4 return u, nil }
func newQosHistoryFromBytes(bin binary.ByteOrder, b []byte) (qosHistory, error) { if len(b) < 4+4 { return qosHistory{}, io.EOF } return qosHistory{ kind: bin.Uint32(b[0:]), depth: bin.Uint32(b[4:]), }, nil }
func timeFromBytes(order binary.ByteOrder, b []byte) (time.Time, error) { if len(b) < 8 { return timeInvalid, io.EOF } sec := int64(order.Uint32(b[0:])) frac := int64(order.Uint32(b[4:])) return time.Unix(sec, (frac*nanosPerSec)>>32).UTC(), nil }
func durationFromBytes(order binary.ByteOrder, b []byte) (time.Duration, error) { if len(b) < 8 { return time.Duration(0), io.EOF } sec := order.Uint32(b[0:]) nsec := order.Uint32(b[4:]) return time.Duration(sec*nanosPerSec + nsec), nil }
func makeGuid(b []byte, order binary.ByteOrder) Guid { g := Guid{ DataA: order.Uint32(b[:4]), DataB: order.Uint16(b[4:6]), DataC: order.Uint16(b[6:8]), DataD: [8]byte{}, } copy(g.DataD[:], b[8:]) return g }
func rvalSRational(in []byte, bo binary.ByteOrder) reflect.Value { denom := int64(int32(bo.Uint32(in[4:]))) if denom == 0 { // Prevent panics due to poorly written Rational fields with a // denominator of 0. Their usable value would likely be 0. return reflect.New(reflect.TypeOf(big.Rat{})) } numer := int64(int32(bo.Uint32(in))) return reflect.ValueOf(big.NewRat(numer, denom)) }
func newUDPv4LocFromBytes(bin binary.ByteOrder, b []byte) (locator, error) { if len(b) < 4+4+16 { return locator{}, io.EOF } return locator{ kind: int32(bin.Uint32(b[0:])), port: bin.Uint32(b[4:]), addr: net.IPv4(b[20], b[21], b[22], b[23]), // xxx: ipv6 support }, nil }
// Uint32 reads four bytes from the provided reader using a buffer from the // free list, converts it to a number using the provided byte order, and returns // the resulting uint32. func (l binaryFreeList) Uint32(r io.Reader, byteOrder binary.ByteOrder) (uint32, error) { buf := l.Borrow()[:4] if _, err := io.ReadFull(r, buf); err != nil { l.Return(buf) return 0, err } rv := byteOrder.Uint32(buf) l.Return(buf) return rv, nil }
func (p *paramListItem) valToString(bin binary.ByteOrder) (string, error) { if len(p.value) < 4 { return "", io.EOF } sz := int(bin.Uint32(p.value[0:])) if len(p.value) < 4+sz { return "", io.EOF } // encoded with null terminator, strip that out return string(p.value[4 : 4+sz-1]), nil }
func walksymtab(data []byte, ptrsz int, fn func(sym) error) error { var order binary.ByteOrder = binary.BigEndian var s sym p := data for len(p) >= 4 { // Symbol type, value. if len(p) < ptrsz { return &formatError{len(data), "unexpected EOF", nil} } // fixed-width value if ptrsz == 8 { s.value = order.Uint64(p[0:8]) p = p[8:] } else { s.value = uint64(order.Uint32(p[0:4])) p = p[4:] } var typ byte typ = p[0] & 0x7F s.typ = typ p = p[1:] // Name. var i int var nnul int for i = 0; i < len(p); i++ { if p[i] == 0 { nnul = 1 break } } switch typ { case 'z', 'Z': p = p[i+nnul:] for i = 0; i+2 <= len(p); i += 2 { if p[i] == 0 && p[i+1] == 0 { nnul = 2 break } } } if len(p) < i+nnul { return &formatError{len(data), "unexpected EOF", nil} } s.name = p[0:i] i += nnul p = p[i:] fn(s) } return nil }
// decodeTag assumes len(buf) >= 8 func decodeTag(buf []byte, bo binary.ByteOrder) tag { var t tag smallTag := bo.Uint32(buf[:]) t.dataType = dataType(smallTag) t.smallFormat = (smallTag >> 16) != 0 if t.smallFormat == true { t.nBytes = uint32(smallTag >> 16) } else { t.nBytes = bo.Uint32(buf[4:]) } return t }
func newQosReliabilityFromBytes(bin binary.ByteOrder, b []byte) (qosReliability, error) { if len(b) < 4+4+4 { return qosReliability{}, io.EOF } dur, err := durationFromBytes(bin, b[4:]) if err != nil { return qosReliability{}, err } return qosReliability{ kind: bin.Uint32(b[0:]), maxBlockingTime: dur, }, nil }
// Look for the attribute that indicates the object uses the hard-float ABI (a // file-level attribute with tag Tag_VFP_arch and value 1). Unfortunately the // format used means that we have to parse all of the file-level attributes to // find the one we are looking for. This format is slightly documented in "ELF // for the ARM Architecture" but mostly this is derived from reading the source // to gold and readelf. func parseArmAttributes(ctxt *Link, e binary.ByteOrder, data []byte) { // We assume the soft-float ABI unless we see a tag indicating otherwise. if ehdr.flags == 0x5000002 { ehdr.flags = 0x5000202 } if data[0] != 'A' { // TODO(dfc) should this be ctxt.Diag ? ctxt.Logf(".ARM.attributes has unexpected format %c\n", data[0]) return } data = data[1:] for len(data) != 0 { sectionlength := e.Uint32(data) sectiondata := data[4:sectionlength] data = data[sectionlength:] nulIndex := bytes.IndexByte(sectiondata, 0) if nulIndex < 0 { // TODO(dfc) should this be ctxt.Diag ? ctxt.Logf("corrupt .ARM.attributes (section name not NUL-terminated)\n") return } name := string(sectiondata[:nulIndex]) sectiondata = sectiondata[nulIndex+1:] if name != "aeabi" { continue } for len(sectiondata) != 0 { subsectiontag, sz := binary.Uvarint(sectiondata) subsectionsize := e.Uint32(sectiondata[sz:]) subsectiondata := sectiondata[sz+4 : subsectionsize] sectiondata = sectiondata[subsectionsize:] if subsectiontag == TagFile { attrList := elfAttributeList{data: subsectiondata} for !attrList.done() { attr := attrList.armAttr() if attr.tag == TagABIVFPArgs && attr.ival == 1 { ehdr.flags = 0x5000402 // has entry point, Version5 EABI, hard-float ABI } } if attrList.err != nil { // TODO(dfc) should this be ctxt.Diag ? ctxt.Logf("could not parse .ARM.attributes\n") } } } } }
func walksymtab(data []byte, fn func(sym) error) error { var order binary.ByteOrder = binary.BigEndian if bytes.HasPrefix(data, littleEndianSymtab) { data = data[6:] order = binary.LittleEndian } var s sym p := data for len(p) >= 6 { s.value = order.Uint32(p[0:4]) typ := p[4] if typ&0x80 == 0 { return &DecodingError{len(data) - len(p) + 4, "bad symbol type", typ} } typ &^= 0x80 s.typ = typ p = p[5:] var i int var nnul int for i = 0; i < len(p); i++ { if p[i] == 0 { nnul = 1 break } } switch typ { case 'z', 'Z': p = p[i+nnul:] for i = 0; i+2 <= len(p); i += 2 { if p[i] == 0 && p[i+1] == 0 { nnul = 2 break } } } if i+nnul+4 > len(p) { return &DecodingError{len(data), "unexpected EOF", nil} } s.name = p[0:i] i += nnul s.gotype = order.Uint32(p[i : i+4]) p = p[i+4:] fn(s) } return nil }
func newSimpleProtocol(n int, byteOrder binary.ByteOrder) *simpleProtocol { protocol := &simpleProtocol{ n: n, bo: byteOrder, } switch n { case 1: protocol.encodeHead = func(buffer []byte) { buffer[0] = byte(len(buffer) - n) } protocol.decodeHead = func(buffer []byte) int { return int(buffer[0]) } case 2: protocol.encodeHead = func(buffer []byte) { byteOrder.PutUint16(buffer, uint16(len(buffer)-n)) } protocol.decodeHead = func(buffer []byte) int { return int(byteOrder.Uint16(buffer)) } case 4: protocol.encodeHead = func(buffer []byte) { byteOrder.PutUint32(buffer, uint32(len(buffer)-n)) } protocol.decodeHead = func(buffer []byte) int { return int(byteOrder.Uint32(buffer)) } case 8: protocol.encodeHead = func(buffer []byte) { byteOrder.PutUint64(buffer, uint64(len(buffer)-n)) } protocol.decodeHead = func(buffer []byte) int { return int(byteOrder.Uint64(buffer)) } default: panic("unsupported packet head size") } return protocol }
func (*RawEncoding) Read(c *ClientConn, rect *Rectangle, r io.Reader) (Encoding, error) { bytesPerPixel := c.PixelFormat.BPP / 8 pixelBytes := make([]uint8, bytesPerPixel) var byteOrder binary.ByteOrder = binary.LittleEndian if c.PixelFormat.BigEndian { byteOrder = binary.BigEndian } colors := make([]Color, int(rect.Height)*int(rect.Width)) for y := uint16(0); y < rect.Height; y++ { for x := uint16(0); x < rect.Width; x++ { if _, err := io.ReadFull(r, pixelBytes); err != nil { return nil, err } var rawPixel uint32 if c.PixelFormat.BPP == 8 { rawPixel = uint32(pixelBytes[0]) } else if c.PixelFormat.BPP == 16 { rawPixel = uint32(byteOrder.Uint16(pixelBytes)) } else if c.PixelFormat.BPP == 32 { rawPixel = byteOrder.Uint32(pixelBytes) } color := &colors[int(y)*int(rect.Width)+int(x)] if c.PixelFormat.TrueColor { color.R = uint16((rawPixel >> c.PixelFormat.RedShift) & uint32(c.PixelFormat.RedMax)) color.G = uint16((rawPixel >> c.PixelFormat.GreenShift) & uint32(c.PixelFormat.GreenMax)) color.B = uint16((rawPixel >> c.PixelFormat.BlueShift) & uint32(c.PixelFormat.BlueMax)) } else { *color = c.ColorMap[rawPixel] } } } return &RawEncoding{colors}, nil }
// Decode decodes the leading bytes in src as a single instruction using // byte order ord. func Decode(src []byte, ord binary.ByteOrder) (inst Inst, err error) { if len(src) < 4 { return inst, errShort } if decoderCover == nil { decoderCover = make([]bool, len(instFormats)) } inst.Len = 4 // only 4-byte instructions are supported ui := ord.Uint32(src[:inst.Len]) inst.Enc = ui for i, iform := range instFormats { if ui&iform.Mask != iform.Value { continue } if ui&iform.DontCare != 0 { if debugDecode { log.Printf("Decode(%#x): unused bit is 1 for Op %s", ui, iform.Op) } // to match GNU objdump (libopcodes), we ignore don't care bits } for i, argfield := range iform.Args { if argfield == nil { break } inst.Args[i] = argfield.Parse(ui) } inst.Op = iform.Op if debugDecode { log.Printf("%#x: search entry %d", ui, i) continue } break } if inst.Op == 0 { return inst, errUnknown } return inst, nil }
// buildInputBig creates a byte-slice based on big-endian ordered input func buildInput(in input, order binary.ByteOrder) []byte { data := make([]byte, 0) d, _ := hex.DecodeString(in.tgId) data = append(data, d...) d, _ = hex.DecodeString(in.tpe) data = append(data, d...) d, _ = hex.DecodeString(in.nVals) data = append(data, d...) d, _ = hex.DecodeString(in.offset) data = append(data, d...) if in.val != "" { off := order.Uint32(d) for i := 0; i < int(off)-12; i++ { data = append(data, 0xFF) } d, _ = hex.DecodeString(in.val) data = append(data, d...) } return data }
func ldelf(f *Biobuf, pkg string, length int64, pn string) { if Debug['v'] != 0 { fmt.Fprintf(&Bso, "%5.2f ldelf %s\n", obj.Cputime(), pn) } Ctxt.Version++ base := int32(Boffset(f)) var add uint64 var e binary.ByteOrder var elfobj *ElfObj var err error var flag int var hdr *ElfHdrBytes var hdrbuf [64]uint8 var info uint64 var is64 int var j int var n int var name string var p []byte var r []Reloc var rela int var rp *Reloc var rsect *ElfSect var s *LSym var sect *ElfSect var sym ElfSym var symbols []*LSym if Bread(f, hdrbuf[:]) != len(hdrbuf) { goto bad } hdr = new(ElfHdrBytes) binary.Read(bytes.NewReader(hdrbuf[:]), binary.BigEndian, hdr) // only byte arrays; byte order doesn't matter if string(hdr.Ident[:4]) != "\x7FELF" { goto bad } switch hdr.Ident[5] { case ElfDataLsb: e = binary.LittleEndian case ElfDataMsb: e = binary.BigEndian default: goto bad } // read header elfobj = new(ElfObj) elfobj.e = e elfobj.f = f elfobj.base = int64(base) elfobj.length = length elfobj.name = pn is64 = 0 if hdr.Ident[4] == ElfClass64 { is64 = 1 hdr := new(ElfHdrBytes64) binary.Read(bytes.NewReader(hdrbuf[:]), binary.BigEndian, hdr) // only byte arrays; byte order doesn't matter elfobj.type_ = uint32(e.Uint16(hdr.Type[:])) elfobj.machine = uint32(e.Uint16(hdr.Machine[:])) elfobj.version = e.Uint32(hdr.Version[:]) elfobj.phoff = e.Uint64(hdr.Phoff[:]) elfobj.shoff = e.Uint64(hdr.Shoff[:]) elfobj.flags = e.Uint32(hdr.Flags[:]) elfobj.ehsize = uint32(e.Uint16(hdr.Ehsize[:])) elfobj.phentsize = uint32(e.Uint16(hdr.Phentsize[:])) elfobj.phnum = uint32(e.Uint16(hdr.Phnum[:])) elfobj.shentsize = uint32(e.Uint16(hdr.Shentsize[:])) elfobj.shnum = uint32(e.Uint16(hdr.Shnum[:])) elfobj.shstrndx = uint32(e.Uint16(hdr.Shstrndx[:])) } else { elfobj.type_ = uint32(e.Uint16(hdr.Type[:])) elfobj.machine = uint32(e.Uint16(hdr.Machine[:])) elfobj.version = e.Uint32(hdr.Version[:]) elfobj.entry = uint64(e.Uint32(hdr.Entry[:])) elfobj.phoff = uint64(e.Uint32(hdr.Phoff[:])) elfobj.shoff = uint64(e.Uint32(hdr.Shoff[:])) elfobj.flags = e.Uint32(hdr.Flags[:]) elfobj.ehsize = uint32(e.Uint16(hdr.Ehsize[:])) elfobj.phentsize = uint32(e.Uint16(hdr.Phentsize[:])) elfobj.phnum = uint32(e.Uint16(hdr.Phnum[:])) elfobj.shentsize = uint32(e.Uint16(hdr.Shentsize[:])) elfobj.shnum = uint32(e.Uint16(hdr.Shnum[:])) elfobj.shstrndx = uint32(e.Uint16(hdr.Shstrndx[:])) } elfobj.is64 = is64 if uint32(hdr.Ident[6]) != elfobj.version { goto bad } if e.Uint16(hdr.Type[:]) != ElfTypeRelocatable { Diag("%s: elf but not elf relocatable object", pn) return } switch Thearch.Thechar { default: Diag("%s: elf %s unimplemented", pn, Thestring) return case '5': if e != binary.LittleEndian || elfobj.machine != ElfMachArm || hdr.Ident[4] != ElfClass32 { Diag("%s: elf object but not arm", pn) return } case '6': if e != binary.LittleEndian || elfobj.machine != ElfMachAmd64 || hdr.Ident[4] != ElfClass64 { Diag("%s: elf object but not amd64", pn) return } case '7': if e != binary.LittleEndian || elfobj.machine != ElfMachArm64 || hdr.Ident[4] != ElfClass64 { Diag("%s: elf object but not arm64", pn) return } case '8': if e != binary.LittleEndian || elfobj.machine != ElfMach386 || hdr.Ident[4] != ElfClass32 { Diag("%s: elf object but not 386", pn) return } case '9': if elfobj.machine != ElfMachPower64 || hdr.Ident[4] != ElfClass64 { Diag("%s: elf object but not ppc64", pn) return } } // load section list into memory. elfobj.sect = make([]ElfSect, elfobj.shnum) elfobj.nsect = uint(elfobj.shnum) for i := 0; uint(i) < elfobj.nsect; i++ { if Bseek(f, int64(uint64(base)+elfobj.shoff+uint64(int64(i)*int64(elfobj.shentsize))), 0) < 0 { goto bad } sect = &elfobj.sect[i] if is64 != 0 { var b ElfSectBytes64 if err = binary.Read(f, e, &b); err != nil { goto bad } sect.nameoff = uint32(e.Uint32(b.Name[:])) sect.type_ = e.Uint32(b.Type[:]) sect.flags = e.Uint64(b.Flags[:]) sect.addr = e.Uint64(b.Addr[:]) sect.off = e.Uint64(b.Off[:]) sect.size = e.Uint64(b.Size[:]) sect.link = e.Uint32(b.Link[:]) sect.info = e.Uint32(b.Info[:]) sect.align = e.Uint64(b.Align[:]) sect.entsize = e.Uint64(b.Entsize[:]) } else { var b ElfSectBytes if err = binary.Read(f, e, &b); err != nil { goto bad } sect.nameoff = uint32(e.Uint32(b.Name[:])) sect.type_ = e.Uint32(b.Type[:]) sect.flags = uint64(e.Uint32(b.Flags[:])) sect.addr = uint64(e.Uint32(b.Addr[:])) sect.off = uint64(e.Uint32(b.Off[:])) sect.size = uint64(e.Uint32(b.Size[:])) sect.link = e.Uint32(b.Link[:]) sect.info = e.Uint32(b.Info[:]) sect.align = uint64(e.Uint32(b.Align[:])) sect.entsize = uint64(e.Uint32(b.Entsize[:])) } } // read section string table and translate names if elfobj.shstrndx >= uint32(elfobj.nsect) { err = fmt.Errorf("shstrndx out of range %d >= %d", elfobj.shstrndx, elfobj.nsect) goto bad } sect = &elfobj.sect[elfobj.shstrndx] if err = elfmap(elfobj, sect); err != nil { goto bad } for i := 0; uint(i) < elfobj.nsect; i++ { if elfobj.sect[i].nameoff != 0 { elfobj.sect[i].name = cstring(sect.base[elfobj.sect[i].nameoff:]) } } // load string table for symbols into memory. elfobj.symtab = section(elfobj, ".symtab") if elfobj.symtab == nil { // our work is done here - no symbols means nothing can refer to this file return } if elfobj.symtab.link <= 0 || elfobj.symtab.link >= uint32(elfobj.nsect) { Diag("%s: elf object has symbol table with invalid string table link", pn) return } elfobj.symstr = &elfobj.sect[elfobj.symtab.link] if is64 != 0 { elfobj.nsymtab = int(elfobj.symtab.size / ELF64SYMSIZE) } else { elfobj.nsymtab = int(elfobj.symtab.size / ELF32SYMSIZE) } if err = elfmap(elfobj, elfobj.symtab); err != nil { goto bad } if err = elfmap(elfobj, elfobj.symstr); err != nil { goto bad } // load text and data segments into memory. // they are not as small as the section lists, but we'll need // the memory anyway for the symbol images, so we might // as well use one large chunk. // create symbols for elfmapped sections for i := 0; uint(i) < elfobj.nsect; i++ { sect = &elfobj.sect[i] if (sect.type_ != ElfSectProgbits && sect.type_ != ElfSectNobits) || sect.flags&ElfSectFlagAlloc == 0 { continue } if sect.type_ != ElfSectNobits { if err = elfmap(elfobj, sect); err != nil { goto bad } } name = fmt.Sprintf("%s(%s)", pkg, sect.name) s = Linklookup(Ctxt, name, Ctxt.Version) switch int(sect.flags) & (ElfSectFlagAlloc | ElfSectFlagWrite | ElfSectFlagExec) { default: err = fmt.Errorf("unexpected flags for ELF section %s", sect.name) goto bad case ElfSectFlagAlloc: s.Type = SRODATA case ElfSectFlagAlloc + ElfSectFlagWrite: if sect.type_ == ElfSectNobits { s.Type = SNOPTRBSS } else { s.Type = SNOPTRDATA } case ElfSectFlagAlloc + ElfSectFlagExec: s.Type = STEXT } if sect.name == ".got" || sect.name == ".toc" { s.Type = SELFGOT } if sect.type_ == ElfSectProgbits { s.P = sect.base s.P = s.P[:sect.size] } s.Size = int64(sect.size) s.Align = int32(sect.align) sect.sym = s } // enter sub-symbols into symbol table. // symbol 0 is the null symbol. symbols = make([]*LSym, elfobj.nsymtab) if symbols == nil { Diag("out of memory") Errorexit() } for i := 1; i < elfobj.nsymtab; i++ { if err = readelfsym(elfobj, i, &sym, 1); err != nil { goto bad } symbols[i] = sym.sym if sym.type_ != ElfSymTypeFunc && sym.type_ != ElfSymTypeObject && sym.type_ != ElfSymTypeNone { continue } if sym.shndx == ElfSymShnCommon { s = sym.sym if uint64(s.Size) < sym.size { s.Size = int64(sym.size) } if s.Type == 0 || s.Type == SXREF { s.Type = SNOPTRBSS } continue } if uint(sym.shndx) >= elfobj.nsect || sym.shndx == 0 { continue } // even when we pass needSym == 1 to readelfsym, it might still return nil to skip some unwanted symbols if sym.sym == nil { continue } sect = &elfobj.sect[sym.shndx:][0] if sect.sym == nil { if strings.HasPrefix(sym.name, ".Linfo_string") { // clang does this continue } Diag("%s: sym#%d: ignoring %s in section %d (type %d)", pn, i, sym.name, sym.shndx, sym.type_) continue } s = sym.sym if s.Outer != nil { if s.Dupok != 0 { continue } Diag("%s: duplicate symbol reference: %s in both %s and %s", pn, s.Name, s.Outer.Name, sect.sym.Name) Errorexit() } s.Sub = sect.sym.Sub sect.sym.Sub = s s.Type = sect.sym.Type | s.Type&^SMASK | SSUB if s.Cgoexport&CgoExportDynamic == 0 { s.Dynimplib = "" // satisfy dynimport } s.Value = int64(sym.value) s.Size = int64(sym.size) s.Outer = sect.sym if sect.sym.Type == STEXT { if s.External != 0 && s.Dupok == 0 { Diag("%s: duplicate definition of %s", pn, s.Name) } s.External = 1 } if elfobj.machine == ElfMachPower64 { flag = int(sym.other) >> 5 if 2 <= flag && flag <= 6 { s.Localentry = 1 << uint(flag-2) } else if flag == 7 { Diag("%s: invalid sym.other 0x%x for %s", pn, sym.other, s.Name) } } } // Sort outer lists by address, adding to textp. // This keeps textp in increasing address order. for i := 0; uint(i) < elfobj.nsect; i++ { s = elfobj.sect[i].sym if s == nil { continue } if s.Sub != nil { s.Sub = listsort(s.Sub, valuecmp, listsubp) } if s.Type == STEXT { if s.Onlist != 0 { log.Fatalf("symbol %s listed multiple times", s.Name) } s.Onlist = 1 if Ctxt.Etextp != nil { Ctxt.Etextp.Next = s } else { Ctxt.Textp = s } Ctxt.Etextp = s for s = s.Sub; s != nil; s = s.Sub { if s.Onlist != 0 { log.Fatalf("symbol %s listed multiple times", s.Name) } s.Onlist = 1 Ctxt.Etextp.Next = s Ctxt.Etextp = s } } } // load relocations for i := 0; uint(i) < elfobj.nsect; i++ { rsect = &elfobj.sect[i] if rsect.type_ != ElfSectRela && rsect.type_ != ElfSectRel { continue } if rsect.info >= uint32(elfobj.nsect) || elfobj.sect[rsect.info].base == nil { continue } sect = &elfobj.sect[rsect.info] if err = elfmap(elfobj, rsect); err != nil { goto bad } rela = 0 if rsect.type_ == ElfSectRela { rela = 1 } n = int(rsect.size / uint64(4+4*is64) / uint64(2+rela)) r = make([]Reloc, n) p = rsect.base for j = 0; j < n; j++ { add = 0 rp = &r[j] if is64 != 0 { // 64-bit rel/rela rp.Off = int32(e.Uint64(p)) p = p[8:] info = e.Uint64(p) p = p[8:] if rela != 0 { add = e.Uint64(p) p = p[8:] } } else { // 32-bit rel/rela rp.Off = int32(e.Uint32(p)) p = p[4:] info = uint64(e.Uint32(p)) info = info>>8<<32 | info&0xff // convert to 64-bit info p = p[4:] if rela != 0 { add = uint64(e.Uint32(p)) p = p[4:] } } if info&0xffffffff == 0 { // skip R_*_NONE relocation j-- n-- continue } if info>>32 == 0 { // absolute relocation, don't bother reading the null symbol rp.Sym = nil } else { if err = readelfsym(elfobj, int(info>>32), &sym, 0); err != nil { goto bad } sym.sym = symbols[info>>32] if sym.sym == nil { err = fmt.Errorf("%s#%d: reloc of invalid sym #%d %s shndx=%d type=%d", sect.sym.Name, j, int(info>>32), sym.name, sym.shndx, sym.type_) goto bad } rp.Sym = sym.sym } rp.Type = int32(reltype(pn, int(uint32(info)), &rp.Siz)) if rela != 0 { rp.Add = int64(add) } else { // load addend from image if rp.Siz == 4 { rp.Add = int64(e.Uint32(sect.base[rp.Off:])) } else if rp.Siz == 8 { rp.Add = int64(e.Uint64(sect.base[rp.Off:])) } else { Diag("invalid rela size %d", rp.Siz) } } if rp.Siz == 2 { rp.Add = int64(int16(rp.Add)) } if rp.Siz == 4 { rp.Add = int64(int32(rp.Add)) } } //print("rel %s %d %d %s %#llx\n", sect->sym->name, rp->type, rp->siz, rp->sym->name, rp->add); sort.Sort(rbyoff(r[:n])) // just in case s = sect.sym s.R = r s.R = s.R[:n] } return bad: Diag("%s: malformed elf file: %v", pn, err) }
func (s Custom) Unpack(buf []byte, order binary.ByteOrder) ([]byte, error) { *s.A = int(order.Uint32(buf[0:4])) return buf[4:], nil }
func ldelf(ctxt *Link, f *bio.Reader, pkg string, length int64, pn string) { if ctxt.Debugvlog != 0 { ctxt.Logf("%5.2f ldelf %s\n", obj.Cputime(), pn) } localSymVersion := ctxt.Syms.IncVersion() base := f.Offset() var add uint64 var e binary.ByteOrder var elfobj *ElfObj var err error var flag int var hdr *ElfHdrBytes var hdrbuf [64]uint8 var info uint64 var is64 int var j int var n int var name string var p []byte var r []Reloc var rela int var rp *Reloc var rsect *ElfSect var s *Symbol var sect *ElfSect var sym ElfSym var symbols []*Symbol if _, err := io.ReadFull(f, hdrbuf[:]); err != nil { goto bad } hdr = new(ElfHdrBytes) binary.Read(bytes.NewReader(hdrbuf[:]), binary.BigEndian, hdr) // only byte arrays; byte order doesn't matter if string(hdr.Ident[:4]) != "\x7FELF" { goto bad } switch hdr.Ident[5] { case ElfDataLsb: e = binary.LittleEndian case ElfDataMsb: e = binary.BigEndian default: goto bad } // read header elfobj = new(ElfObj) elfobj.e = e elfobj.f = f elfobj.base = base elfobj.length = length elfobj.name = pn is64 = 0 if hdr.Ident[4] == ElfClass64 { is64 = 1 hdr := new(ElfHdrBytes64) binary.Read(bytes.NewReader(hdrbuf[:]), binary.BigEndian, hdr) // only byte arrays; byte order doesn't matter elfobj.type_ = uint32(e.Uint16(hdr.Type[:])) elfobj.machine = uint32(e.Uint16(hdr.Machine[:])) elfobj.version = e.Uint32(hdr.Version[:]) elfobj.phoff = e.Uint64(hdr.Phoff[:]) elfobj.shoff = e.Uint64(hdr.Shoff[:]) elfobj.flags = e.Uint32(hdr.Flags[:]) elfobj.ehsize = uint32(e.Uint16(hdr.Ehsize[:])) elfobj.phentsize = uint32(e.Uint16(hdr.Phentsize[:])) elfobj.phnum = uint32(e.Uint16(hdr.Phnum[:])) elfobj.shentsize = uint32(e.Uint16(hdr.Shentsize[:])) elfobj.shnum = uint32(e.Uint16(hdr.Shnum[:])) elfobj.shstrndx = uint32(e.Uint16(hdr.Shstrndx[:])) } else { elfobj.type_ = uint32(e.Uint16(hdr.Type[:])) elfobj.machine = uint32(e.Uint16(hdr.Machine[:])) elfobj.version = e.Uint32(hdr.Version[:]) elfobj.entry = uint64(e.Uint32(hdr.Entry[:])) elfobj.phoff = uint64(e.Uint32(hdr.Phoff[:])) elfobj.shoff = uint64(e.Uint32(hdr.Shoff[:])) elfobj.flags = e.Uint32(hdr.Flags[:]) elfobj.ehsize = uint32(e.Uint16(hdr.Ehsize[:])) elfobj.phentsize = uint32(e.Uint16(hdr.Phentsize[:])) elfobj.phnum = uint32(e.Uint16(hdr.Phnum[:])) elfobj.shentsize = uint32(e.Uint16(hdr.Shentsize[:])) elfobj.shnum = uint32(e.Uint16(hdr.Shnum[:])) elfobj.shstrndx = uint32(e.Uint16(hdr.Shstrndx[:])) } elfobj.is64 = is64 if uint32(hdr.Ident[6]) != elfobj.version { goto bad } if e.Uint16(hdr.Type[:]) != ElfTypeRelocatable { Errorf(nil, "%s: elf but not elf relocatable object", pn) return } switch SysArch.Family { default: Errorf(nil, "%s: elf %s unimplemented", pn, SysArch.Name) return case sys.MIPS64: if elfobj.machine != ElfMachMips || hdr.Ident[4] != ElfClass64 { Errorf(nil, "%s: elf object but not mips64", pn) return } case sys.ARM: if e != binary.LittleEndian || elfobj.machine != ElfMachArm || hdr.Ident[4] != ElfClass32 { Errorf(nil, "%s: elf object but not arm", pn) return } case sys.AMD64: if e != binary.LittleEndian || elfobj.machine != ElfMachAmd64 || hdr.Ident[4] != ElfClass64 { Errorf(nil, "%s: elf object but not amd64", pn) return } case sys.ARM64: if e != binary.LittleEndian || elfobj.machine != ElfMachArm64 || hdr.Ident[4] != ElfClass64 { Errorf(nil, "%s: elf object but not arm64", pn) return } case sys.I386: if e != binary.LittleEndian || elfobj.machine != ElfMach386 || hdr.Ident[4] != ElfClass32 { Errorf(nil, "%s: elf object but not 386", pn) return } case sys.PPC64: if elfobj.machine != ElfMachPower64 || hdr.Ident[4] != ElfClass64 { Errorf(nil, "%s: elf object but not ppc64", pn) return } case sys.S390X: if elfobj.machine != ElfMachS390 || hdr.Ident[4] != ElfClass64 { Errorf(nil, "%s: elf object but not s390x", pn) return } } // load section list into memory. elfobj.sect = make([]ElfSect, elfobj.shnum) elfobj.nsect = uint(elfobj.shnum) for i := 0; uint(i) < elfobj.nsect; i++ { if f.Seek(int64(uint64(base)+elfobj.shoff+uint64(int64(i)*int64(elfobj.shentsize))), 0) < 0 { goto bad } sect = &elfobj.sect[i] if is64 != 0 { var b ElfSectBytes64 if err = binary.Read(f, e, &b); err != nil { goto bad } sect.nameoff = e.Uint32(b.Name[:]) sect.type_ = e.Uint32(b.Type[:]) sect.flags = e.Uint64(b.Flags[:]) sect.addr = e.Uint64(b.Addr[:]) sect.off = e.Uint64(b.Off[:]) sect.size = e.Uint64(b.Size[:]) sect.link = e.Uint32(b.Link[:]) sect.info = e.Uint32(b.Info[:]) sect.align = e.Uint64(b.Align[:]) sect.entsize = e.Uint64(b.Entsize[:]) } else { var b ElfSectBytes if err = binary.Read(f, e, &b); err != nil { goto bad } sect.nameoff = e.Uint32(b.Name[:]) sect.type_ = e.Uint32(b.Type[:]) sect.flags = uint64(e.Uint32(b.Flags[:])) sect.addr = uint64(e.Uint32(b.Addr[:])) sect.off = uint64(e.Uint32(b.Off[:])) sect.size = uint64(e.Uint32(b.Size[:])) sect.link = e.Uint32(b.Link[:]) sect.info = e.Uint32(b.Info[:]) sect.align = uint64(e.Uint32(b.Align[:])) sect.entsize = uint64(e.Uint32(b.Entsize[:])) } } // read section string table and translate names if elfobj.shstrndx >= uint32(elfobj.nsect) { err = fmt.Errorf("shstrndx out of range %d >= %d", elfobj.shstrndx, elfobj.nsect) goto bad } sect = &elfobj.sect[elfobj.shstrndx] if err = elfmap(elfobj, sect); err != nil { goto bad } for i := 0; uint(i) < elfobj.nsect; i++ { if elfobj.sect[i].nameoff != 0 { elfobj.sect[i].name = cstring(sect.base[elfobj.sect[i].nameoff:]) } } // load string table for symbols into memory. elfobj.symtab = section(elfobj, ".symtab") if elfobj.symtab == nil { // our work is done here - no symbols means nothing can refer to this file return } if elfobj.symtab.link <= 0 || elfobj.symtab.link >= uint32(elfobj.nsect) { Errorf(nil, "%s: elf object has symbol table with invalid string table link", pn) return } elfobj.symstr = &elfobj.sect[elfobj.symtab.link] if is64 != 0 { elfobj.nsymtab = int(elfobj.symtab.size / ELF64SYMSIZE) } else { elfobj.nsymtab = int(elfobj.symtab.size / ELF32SYMSIZE) } if err = elfmap(elfobj, elfobj.symtab); err != nil { goto bad } if err = elfmap(elfobj, elfobj.symstr); err != nil { goto bad } // load text and data segments into memory. // they are not as small as the section lists, but we'll need // the memory anyway for the symbol images, so we might // as well use one large chunk. // create symbols for elfmapped sections for i := 0; uint(i) < elfobj.nsect; i++ { sect = &elfobj.sect[i] if sect.type_ == SHT_ARM_ATTRIBUTES && sect.name == ".ARM.attributes" { if err = elfmap(elfobj, sect); err != nil { goto bad } parseArmAttributes(ctxt, e, sect.base[:sect.size]) } if (sect.type_ != ElfSectProgbits && sect.type_ != ElfSectNobits) || sect.flags&ElfSectFlagAlloc == 0 { continue } if sect.type_ != ElfSectNobits { if err = elfmap(elfobj, sect); err != nil { goto bad } } name = fmt.Sprintf("%s(%s)", pkg, sect.name) s = ctxt.Syms.Lookup(name, localSymVersion) switch int(sect.flags) & (ElfSectFlagAlloc | ElfSectFlagWrite | ElfSectFlagExec) { default: err = fmt.Errorf("unexpected flags for ELF section %s", sect.name) goto bad case ElfSectFlagAlloc: s.Type = obj.SRODATA case ElfSectFlagAlloc + ElfSectFlagWrite: if sect.type_ == ElfSectNobits { s.Type = obj.SNOPTRBSS } else { s.Type = obj.SNOPTRDATA } case ElfSectFlagAlloc + ElfSectFlagExec: s.Type = obj.STEXT } if sect.name == ".got" || sect.name == ".toc" { s.Type = obj.SELFGOT } if sect.type_ == ElfSectProgbits { s.P = sect.base s.P = s.P[:sect.size] } s.Size = int64(sect.size) s.Align = int32(sect.align) sect.sym = s } // enter sub-symbols into symbol table. // symbol 0 is the null symbol. symbols = make([]*Symbol, elfobj.nsymtab) for i := 1; i < elfobj.nsymtab; i++ { if err = readelfsym(ctxt, elfobj, i, &sym, 1, localSymVersion); err != nil { goto bad } symbols[i] = sym.sym if sym.type_ != ElfSymTypeFunc && sym.type_ != ElfSymTypeObject && sym.type_ != ElfSymTypeNone { continue } if sym.shndx == ElfSymShnCommon { s = sym.sym if uint64(s.Size) < sym.size { s.Size = int64(sym.size) } if s.Type == 0 || s.Type == obj.SXREF { s.Type = obj.SNOPTRBSS } continue } if uint(sym.shndx) >= elfobj.nsect || sym.shndx == 0 { continue } // even when we pass needSym == 1 to readelfsym, it might still return nil to skip some unwanted symbols if sym.sym == nil { continue } sect = &elfobj.sect[sym.shndx] if sect.sym == nil { if strings.HasPrefix(sym.name, ".Linfo_string") { // clang does this continue } if sym.name == "" && sym.type_ == 0 && sect.name == ".debug_str" { // This reportedly happens with clang 3.7 on ARM. // See issue 13139. continue } if strings.HasPrefix(sym.name, ".LASF") { // gcc on s390x does this continue } Errorf(sym.sym, "%s: sym#%d: ignoring symbol in section %d (type %d)", pn, i, sym.shndx, sym.type_) continue } s = sym.sym if s.Outer != nil { if s.Attr.DuplicateOK() { continue } Exitf("%s: duplicate symbol reference: %s in both %s and %s", pn, s.Name, s.Outer.Name, sect.sym.Name) } s.Sub = sect.sym.Sub sect.sym.Sub = s s.Type = sect.sym.Type | s.Type&^obj.SMASK | obj.SSUB if !s.Attr.CgoExportDynamic() { s.Dynimplib = "" // satisfy dynimport } s.Value = int64(sym.value) s.Size = int64(sym.size) s.Outer = sect.sym if sect.sym.Type == obj.STEXT { if s.Attr.External() && !s.Attr.DuplicateOK() { Errorf(s, "%s: duplicate symbol definition", pn) } s.Attr |= AttrExternal } if elfobj.machine == ElfMachPower64 { flag = int(sym.other) >> 5 if 2 <= flag && flag <= 6 { s.Localentry = 1 << uint(flag-2) } else if flag == 7 { Errorf(s, "%s: invalid sym.other 0x%x", pn, sym.other) } } } // Sort outer lists by address, adding to textp. // This keeps textp in increasing address order. for i := 0; uint(i) < elfobj.nsect; i++ { s = elfobj.sect[i].sym if s == nil { continue } if s.Sub != nil { s.Sub = listsort(s.Sub) } if s.Type == obj.STEXT { if s.Attr.OnList() { log.Fatalf("symbol %s listed multiple times", s.Name) } s.Attr |= AttrOnList ctxt.Textp = append(ctxt.Textp, s) for s = s.Sub; s != nil; s = s.Sub { if s.Attr.OnList() { log.Fatalf("symbol %s listed multiple times", s.Name) } s.Attr |= AttrOnList ctxt.Textp = append(ctxt.Textp, s) } } } // load relocations for i := 0; uint(i) < elfobj.nsect; i++ { rsect = &elfobj.sect[i] if rsect.type_ != ElfSectRela && rsect.type_ != ElfSectRel { continue } if rsect.info >= uint32(elfobj.nsect) || elfobj.sect[rsect.info].base == nil { continue } sect = &elfobj.sect[rsect.info] if err = elfmap(elfobj, rsect); err != nil { goto bad } rela = 0 if rsect.type_ == ElfSectRela { rela = 1 } n = int(rsect.size / uint64(4+4*is64) / uint64(2+rela)) r = make([]Reloc, n) p = rsect.base for j = 0; j < n; j++ { add = 0 rp = &r[j] if is64 != 0 { // 64-bit rel/rela rp.Off = int32(e.Uint64(p)) p = p[8:] info = e.Uint64(p) p = p[8:] if rela != 0 { add = e.Uint64(p) p = p[8:] } } else { // 32-bit rel/rela rp.Off = int32(e.Uint32(p)) p = p[4:] info = uint64(e.Uint32(p)) info = info>>8<<32 | info&0xff // convert to 64-bit info p = p[4:] if rela != 0 { add = uint64(e.Uint32(p)) p = p[4:] } } if info&0xffffffff == 0 { // skip R_*_NONE relocation j-- n-- continue } if info>>32 == 0 { // absolute relocation, don't bother reading the null symbol rp.Sym = nil } else { if err = readelfsym(ctxt, elfobj, int(info>>32), &sym, 0, 0); err != nil { goto bad } sym.sym = symbols[info>>32] if sym.sym == nil { err = fmt.Errorf("%s#%d: reloc of invalid sym #%d %s shndx=%d type=%d", sect.sym.Name, j, int(info>>32), sym.name, sym.shndx, sym.type_) goto bad } rp.Sym = sym.sym } rp.Type = 256 + obj.RelocType(info) rp.Siz = relSize(ctxt, pn, uint32(info)) if rela != 0 { rp.Add = int64(add) } else { // load addend from image if rp.Siz == 4 { rp.Add = int64(e.Uint32(sect.base[rp.Off:])) } else if rp.Siz == 8 { rp.Add = int64(e.Uint64(sect.base[rp.Off:])) } else { Errorf(nil, "invalid rela size %d", rp.Siz) } } if rp.Siz == 2 { rp.Add = int64(int16(rp.Add)) } if rp.Siz == 4 { rp.Add = int64(int32(rp.Add)) } } //print("rel %s %d %d %s %#llx\n", sect->sym->name, rp->type, rp->siz, rp->sym->name, rp->add); sort.Sort(rbyoff(r[:n])) // just in case s = sect.sym s.R = r s.R = s.R[:n] } return bad: Errorf(nil, "%s: malformed elf file: %v", pn, err) }
// decodeNumeric decodes a simple stream of numeric or character data func decodeNumeric(de dataElement, bo binary.ByteOrder) (interface{}, error) { var b [8]byte var bs []byte if int(de.nBytes) > len(b) { bs = make([]byte, de.nBytes) } else { bs = b[:de.nBytes] } _, err := de.r.ReadAt(bs, 0) if err != nil { return nil, err } switch de.dataType { case miINT8: val := make([]int8, de.nBytes) for i, x := range bs { val[i] = int8(x) } return val, nil case miUINT8: val := make([]uint8, de.nBytes) copy(val, bs) return val, nil case miINT16: val := make([]int16, de.nBytes/2) for i := range bs { val[i] = int16(bo.Uint16(bs[2*i:])) } return val, nil case miUINT16: val := make([]uint16, de.nBytes/2) for i := range bs { val[i] = bo.Uint16(bs[2*i:]) } return val, nil case miINT32: val := make([]int32, de.nBytes/4) for i := range bs { val[i] = int32(bo.Uint32(bs[4*i:])) } return val, nil case miUINT32: val := make([]uint32, de.nBytes/4) for i := range bs { val[i] = bo.Uint32(bs[4*i:]) } return val, nil case miINT64: val := make([]int64, de.nBytes/8) for i := range bs { val[i] = int64(bo.Uint64(bs[8*i:])) } return val, nil case miUINT64: val := make([]uint64, de.nBytes/8) for i := range bs { val[i] = bo.Uint64(bs[8*i:]) } return val, nil case miSINGLE: val := make([]float32, de.nBytes/4) for i := range bs { val[i] = math.Float32frombits(bo.Uint32(bs[4*i:])) } return val, nil case miDOUBLE: val := make([]float64, de.nBytes/8) for i := range bs { val[i] = math.Float64frombits(bo.Uint64(bs[8*i:])) } return val, nil case miUTF8: return string(bs), nil case miUTF16: x := make([]uint16, de.nBytes/2) for i := range bs { x[i] = bo.Uint16(bs[2*i:]) } return string(utf16.Decode(x)), nil case miUTF32: runes := make([]rune, de.nBytes/4) for i := range runes { runes[i] = rune(bo.Uint32(bs[4*i:])) } return string(runes), nil } return nil, nil }
func ldmacho(f *bio.Reader, pkg string, length int64, pn string) { var err error var j int var is64 bool var secaddr uint64 var hdr [7 * 4]uint8 var cmdp []byte var dat []byte var ncmd uint32 var cmdsz uint32 var ty uint32 var sz uint32 var off uint32 var m *LdMachoObj var e binary.ByteOrder var sect *LdMachoSect var rel *LdMachoRel var rpi int var s *LSym var s1 *LSym var outer *LSym var c *LdMachoCmd var symtab *LdMachoSymtab var dsymtab *LdMachoDysymtab var sym *LdMachoSym var r []Reloc var rp *Reloc var name string Ctxt.IncVersion() base := f.Offset() if _, err := io.ReadFull(f, hdr[:]); err != nil { goto bad } if binary.BigEndian.Uint32(hdr[:])&^1 == 0xFEEDFACE { e = binary.BigEndian } else if binary.LittleEndian.Uint32(hdr[:])&^1 == 0xFEEDFACE { e = binary.LittleEndian } else { err = fmt.Errorf("bad magic - not mach-o file") goto bad } is64 = e.Uint32(hdr[:]) == 0xFEEDFACF ncmd = e.Uint32(hdr[4*4:]) cmdsz = e.Uint32(hdr[5*4:]) if ncmd > 0x10000 || cmdsz >= 0x01000000 { err = fmt.Errorf("implausible mach-o header ncmd=%d cmdsz=%d", ncmd, cmdsz) goto bad } if is64 { f.Seek(4, 1) // skip reserved word in header } m = new(LdMachoObj) m.f = f m.e = e m.cputype = uint(e.Uint32(hdr[1*4:])) m.subcputype = uint(e.Uint32(hdr[2*4:])) m.filetype = e.Uint32(hdr[3*4:]) m.ncmd = uint(ncmd) m.flags = e.Uint32(hdr[6*4:]) m.is64 = is64 m.base = base m.length = length m.name = pn switch SysArch.Family { default: Diag("%s: mach-o %s unimplemented", pn, SysArch.Name) return case sys.AMD64: if e != binary.LittleEndian || m.cputype != LdMachoCpuAmd64 { Diag("%s: mach-o object but not amd64", pn) return } case sys.I386: if e != binary.LittleEndian || m.cputype != LdMachoCpu386 { Diag("%s: mach-o object but not 386", pn) return } } m.cmd = make([]LdMachoCmd, ncmd) off = uint32(len(hdr)) cmdp = make([]byte, cmdsz) if _, err2 := io.ReadFull(f, cmdp); err2 != nil { err = fmt.Errorf("reading cmds: %v", err) goto bad } // read and parse load commands c = nil symtab = nil dsymtab = nil for i := 0; uint32(i) < ncmd; i++ { ty = e.Uint32(cmdp) sz = e.Uint32(cmdp[4:]) m.cmd[i].off = off unpackcmd(cmdp, m, &m.cmd[i], uint(ty), uint(sz)) cmdp = cmdp[sz:] off += sz if ty == LdMachoCmdSymtab { if symtab != nil { err = fmt.Errorf("multiple symbol tables") goto bad } symtab = &m.cmd[i].sym macholoadsym(m, symtab) } if ty == LdMachoCmdDysymtab { dsymtab = &m.cmd[i].dsym macholoaddsym(m, dsymtab) } if (is64 && ty == LdMachoCmdSegment64) || (!is64 && ty == LdMachoCmdSegment) { if c != nil { err = fmt.Errorf("multiple load commands") goto bad } c = &m.cmd[i] } } // load text and data segments into memory. // they are not as small as the load commands, but we'll need // the memory anyway for the symbol images, so we might // as well use one large chunk. if c == nil { err = fmt.Errorf("no load command") goto bad } if symtab == nil { // our work is done here - no symbols means nothing can refer to this file return } if int64(c.seg.fileoff+c.seg.filesz) >= length { err = fmt.Errorf("load segment out of range") goto bad } dat = make([]byte, c.seg.filesz) if f.Seek(m.base+int64(c.seg.fileoff), 0) < 0 { err = fmt.Errorf("cannot load object data: %v", err) goto bad } if _, err2 := io.ReadFull(f, dat); err2 != nil { err = fmt.Errorf("cannot load object data: %v", err) goto bad } for i := 0; uint32(i) < c.seg.nsect; i++ { sect = &c.seg.sect[i] if sect.segname != "__TEXT" && sect.segname != "__DATA" { continue } if sect.name == "__eh_frame" { continue } name = fmt.Sprintf("%s(%s/%s)", pkg, sect.segname, sect.name) s = Linklookup(Ctxt, name, Ctxt.Version) if s.Type != 0 { err = fmt.Errorf("duplicate %s/%s", sect.segname, sect.name) goto bad } if sect.flags&0xff == 1 { // S_ZEROFILL s.P = make([]byte, sect.size) } else { s.P = dat[sect.addr-c.seg.vmaddr:][:sect.size] } s.Size = int64(len(s.P)) if sect.segname == "__TEXT" { if sect.name == "__text" { s.Type = obj.STEXT } else { s.Type = obj.SRODATA } } else { if sect.name == "__bss" { s.Type = obj.SNOPTRBSS s.P = s.P[:0] } else { s.Type = obj.SNOPTRDATA } } sect.sym = s } // enter sub-symbols into symbol table. // have to guess sizes from next symbol. for i := 0; uint32(i) < symtab.nsym; i++ { sym = &symtab.sym[i] if sym.type_&N_STAB != 0 { continue } // TODO: check sym->type against outer->type. name = sym.name if name[0] == '_' && name[1] != '\x00' { name = name[1:] } v := 0 if sym.type_&N_EXT == 0 { v = Ctxt.Version } s = Linklookup(Ctxt, name, v) if sym.type_&N_EXT == 0 { s.Attr |= AttrDuplicateOK } sym.sym = s if sym.sectnum == 0 { // undefined continue } if uint32(sym.sectnum) > c.seg.nsect { err = fmt.Errorf("reference to invalid section %d", sym.sectnum) goto bad } sect = &c.seg.sect[sym.sectnum-1] outer = sect.sym if outer == nil { err = fmt.Errorf("reference to invalid section %s/%s", sect.segname, sect.name) continue } if s.Outer != nil { if s.Attr.DuplicateOK() { continue } Exitf("%s: duplicate symbol reference: %s in both %s and %s", pn, s.Name, s.Outer.Name, sect.sym.Name) } s.Type = outer.Type | obj.SSUB s.Sub = outer.Sub outer.Sub = s s.Outer = outer s.Value = int64(sym.value - sect.addr) if !s.Attr.CgoExportDynamic() { s.Dynimplib = "" // satisfy dynimport } if outer.Type == obj.STEXT { if s.Attr.External() && !s.Attr.DuplicateOK() { Diag("%s: duplicate definition of %s", pn, s.Name) } s.Attr |= AttrExternal } sym.sym = s } // Sort outer lists by address, adding to textp. // This keeps textp in increasing address order. for i := 0; uint32(i) < c.seg.nsect; i++ { sect = &c.seg.sect[i] s = sect.sym if s == nil { continue } if s.Sub != nil { s.Sub = listsort(s.Sub, valuecmp, listsubp) // assign sizes, now that we know symbols in sorted order. for s1 = s.Sub; s1 != nil; s1 = s1.Sub { if s1.Sub != nil { s1.Size = s1.Sub.Value - s1.Value } else { s1.Size = s.Value + s.Size - s1.Value } } } if s.Type == obj.STEXT { if s.Attr.OnList() { log.Fatalf("symbol %s listed multiple times", s.Name) } s.Attr |= AttrOnList Ctxt.Textp = append(Ctxt.Textp, s) for s1 = s.Sub; s1 != nil; s1 = s1.Sub { if s1.Attr.OnList() { log.Fatalf("symbol %s listed multiple times", s1.Name) } s1.Attr |= AttrOnList Ctxt.Textp = append(Ctxt.Textp, s1) } } } // load relocations for i := 0; uint32(i) < c.seg.nsect; i++ { sect = &c.seg.sect[i] s = sect.sym if s == nil { continue } macholoadrel(m, sect) if sect.rel == nil { continue } r = make([]Reloc, sect.nreloc) rpi = 0 Reloc: for j = 0; uint32(j) < sect.nreloc; j++ { rp = &r[rpi] rel = §.rel[j] if rel.scattered != 0 { if SysArch.Family != sys.I386 { // mach-o only uses scattered relocation on 32-bit platforms Diag("unexpected scattered relocation") continue } // on 386, rewrite scattered 4/1 relocation and some // scattered 2/1 relocation into the pseudo-pc-relative // reference that it is. // assume that the second in the pair is in this section // and use that as the pc-relative base. if uint32(j+1) >= sect.nreloc { err = fmt.Errorf("unsupported scattered relocation %d", int(rel.type_)) goto bad } if sect.rel[j+1].scattered == 0 || sect.rel[j+1].type_ != 1 || (rel.type_ != 4 && rel.type_ != 2) || uint64(sect.rel[j+1].value) < sect.addr || uint64(sect.rel[j+1].value) >= sect.addr+sect.size { err = fmt.Errorf("unsupported scattered relocation %d/%d", int(rel.type_), int(sect.rel[j+1].type_)) goto bad } rp.Siz = rel.length rp.Off = int32(rel.addr) // NOTE(rsc): I haven't worked out why (really when) // we should ignore the addend on a // scattered relocation, but it seems that the // common case is we ignore it. // It's likely that this is not strictly correct // and that the math should look something // like the non-scattered case below. rp.Add = 0 // want to make it pc-relative aka relative to rp->off+4 // but the scatter asks for relative to off = sect->rel[j+1].value - sect->addr. // adjust rp->add accordingly. rp.Type = obj.R_PCREL rp.Add += int64(uint64(int64(rp.Off)+4) - (uint64(sect.rel[j+1].value) - sect.addr)) // now consider the desired symbol. // find the section where it lives. var ks *LdMachoSect for k := 0; uint32(k) < c.seg.nsect; k++ { ks = &c.seg.sect[k] if ks.addr <= uint64(rel.value) && uint64(rel.value) < ks.addr+ks.size { if ks.sym != nil { rp.Sym = ks.sym rp.Add += int64(uint64(rel.value) - ks.addr) } else if ks.segname == "__IMPORT" && ks.name == "__pointers" { // handle reference to __IMPORT/__pointers. // how much worse can this get? // why are we supporting 386 on the mac anyway? rp.Type = 512 + MACHO_FAKE_GOTPCREL // figure out which pointer this is a reference to. k = int(uint64(ks.res1) + (uint64(rel.value)-ks.addr)/4) // load indirect table for __pointers // fetch symbol number if dsymtab == nil || k < 0 || uint32(k) >= dsymtab.nindirectsyms || dsymtab.indir == nil { err = fmt.Errorf("invalid scattered relocation: indirect symbol reference out of range") goto bad } k = int(dsymtab.indir[k]) if k < 0 || uint32(k) >= symtab.nsym { err = fmt.Errorf("invalid scattered relocation: symbol reference out of range") goto bad } rp.Sym = symtab.sym[k].sym } else { err = fmt.Errorf("unsupported scattered relocation: reference to %s/%s", ks.segname, ks.name) goto bad } rpi++ // skip #1 of 2 rel; continue skips #2 of 2. j++ continue Reloc } } err = fmt.Errorf("unsupported scattered relocation: invalid address %#x", rel.addr) goto bad } rp.Siz = rel.length rp.Type = 512 + (int32(rel.type_) << 1) + int32(rel.pcrel) rp.Off = int32(rel.addr) // Handle X86_64_RELOC_SIGNED referencing a section (rel->extrn == 0). if SysArch.Family == sys.AMD64 && rel.extrn == 0 && rel.type_ == 1 { // Calculate the addend as the offset into the section. // // The rip-relative offset stored in the object file is encoded // as follows: // // movsd 0x00000360(%rip),%xmm0 // // To get the absolute address of the value this rip-relative address is pointing // to, we must add the address of the next instruction to it. This is done by // taking the address of the relocation and adding 4 to it (since the rip-relative // offset can at most be 32 bits long). To calculate the offset into the section the // relocation is referencing, we subtract the vaddr of the start of the referenced // section found in the original object file. // // [For future reference, see Darwin's /usr/include/mach-o/x86_64/reloc.h] secaddr = c.seg.sect[rel.symnum-1].addr rp.Add = int64(uint64(int64(int32(e.Uint32(s.P[rp.Off:])))+int64(rp.Off)+4) - secaddr) } else { rp.Add = int64(int32(e.Uint32(s.P[rp.Off:]))) } // For i386 Mach-O PC-relative, the addend is written such that // it *is* the PC being subtracted. Use that to make // it match our version of PC-relative. if rel.pcrel != 0 && SysArch.Family == sys.I386 { rp.Add += int64(rp.Off) + int64(rp.Siz) } if rel.extrn == 0 { if rel.symnum < 1 || rel.symnum > c.seg.nsect { err = fmt.Errorf("invalid relocation: section reference out of range %d vs %d", rel.symnum, c.seg.nsect) goto bad } rp.Sym = c.seg.sect[rel.symnum-1].sym if rp.Sym == nil { err = fmt.Errorf("invalid relocation: %s", c.seg.sect[rel.symnum-1].name) goto bad } // References to symbols in other sections // include that information in the addend. // We only care about the delta from the // section base. if SysArch.Family == sys.I386 { rp.Add -= int64(c.seg.sect[rel.symnum-1].addr) } } else { if rel.symnum >= symtab.nsym { err = fmt.Errorf("invalid relocation: symbol reference out of range") goto bad } rp.Sym = symtab.sym[rel.symnum].sym } rpi++ } sort.Sort(rbyoff(r[:rpi])) s.R = r s.R = s.R[:rpi] } return bad: Diag("%s: malformed mach-o file: %v", pn, err) }
// Convert raw image data into a 2d array of 64-bit labels func (d *Data) convertTo64bit(geom dvid.Geometry, data []uint8, bytesPerVoxel, stride int) ([]byte, error) { nx := int(geom.Size().Value(0)) ny := int(geom.Size().Value(1)) numBytes := nx * ny * 8 data64 := make([]byte, numBytes, numBytes) var byteOrder binary.ByteOrder if geom.DataShape().ShapeDimensions() == 2 { byteOrder = binary.BigEndian // This is the default for PNG } else { byteOrder = binary.LittleEndian } switch bytesPerVoxel { case 1: dstI := 0 for y := 0; y < ny; y++ { srcI := y * stride for x := 0; x < nx; x++ { binary.LittleEndian.PutUint64(data64[dstI:dstI+8], uint64(data[srcI])) srcI++ dstI += 8 } } case 2: dstI := 0 for y := 0; y < ny; y++ { srcI := y * stride for x := 0; x < nx; x++ { value := byteOrder.Uint16(data[srcI : srcI+2]) binary.LittleEndian.PutUint64(data64[dstI:dstI+8], uint64(value)) srcI += 2 dstI += 8 } } case 4: dstI := 0 for y := 0; y < ny; y++ { srcI := y * stride for x := 0; x < nx; x++ { value := byteOrder.Uint32(data[srcI : srcI+4]) binary.LittleEndian.PutUint64(data64[dstI:dstI+8], uint64(value)) srcI += 4 dstI += 8 } } case 8: dstI := 0 for y := 0; y < ny; y++ { srcI := y * stride for x := 0; x < nx; x++ { value := byteOrder.Uint64(data[srcI : srcI+8]) binary.LittleEndian.PutUint64(data64[dstI:dstI+8], uint64(value)) srcI += 8 dstI += 8 } } default: return nil, fmt.Errorf("could not convert to 64-bit label given %d bytes/voxel", bytesPerVoxel) } return data64, nil }
// parseNotes returns the notes from a SHT_NOTE section or PT_NOTE segment. func parseNotes(reader io.Reader, alignment int, order binary.ByteOrder) ([]elfNote, error) { r := bufio.NewReader(reader) // padding returns the number of bytes required to pad the given size to an // alignment boundary. padding := func(size int) int { return ((size + (alignment - 1)) &^ (alignment - 1)) - size } var notes []elfNote for { noteHeader := make([]byte, 12) // 3 4-byte words if _, err := io.ReadFull(r, noteHeader); err == io.EOF { break } else if err != nil { return nil, err } namesz := order.Uint32(noteHeader[0:4]) descsz := order.Uint32(noteHeader[4:8]) typ := order.Uint32(noteHeader[8:12]) if uint64(namesz) > uint64(maxNoteSize) { return nil, fmt.Errorf("note name too long (%d bytes)", namesz) } var name string if namesz > 0 { // Documentation differs as to whether namesz is meant to include the // trailing zero, but everyone agrees that name is null-terminated. // So we'll just determine the actual length after the fact. var err error name, err = r.ReadString('\x00') if err == io.EOF { return nil, fmt.Errorf("missing note name (want %d bytes)", namesz) } else if err != nil { return nil, err } namesz = uint32(len(name)) name = name[:len(name)-1] } // Drop padding bytes until the desc field. for n := padding(len(noteHeader) + int(namesz)); n > 0; n-- { if _, err := r.ReadByte(); err == io.EOF { return nil, fmt.Errorf( "missing %d bytes of padding after note name", n) } else if err != nil { return nil, err } } if uint64(descsz) > uint64(maxNoteSize) { return nil, fmt.Errorf("note desc too long (%d bytes)", descsz) } desc := make([]byte, int(descsz)) if _, err := io.ReadFull(r, desc); err == io.EOF { return nil, fmt.Errorf("missing desc (want %d bytes)", len(desc)) } else if err != nil { return nil, err } notes = append(notes, elfNote{Name: name, Desc: desc, Type: typ}) // Drop padding bytes until the next note or the end of the section, // whichever comes first. for n := padding(len(desc)); n > 0; n-- { if _, err := r.ReadByte(); err == io.EOF { // We hit the end of the section before an alignment boundary. // This can happen if this section is at the end of the file or the next // section has a smaller alignment requirement. break } else if err != nil { return nil, err } } } return notes, nil }
func walksymtab(data []byte, fn func(sym) error) error { if len(data) == 0 { // missing symtab is okay return nil } var order binary.ByteOrder = binary.BigEndian newTable := false switch { case bytes.HasPrefix(data, oldLittleEndianSymtab): // Same as Go 1.0, but little endian. // Format was used during interim development between Go 1.0 and Go 1.1. // Should not be widespread, but easy to support. data = data[6:] order = binary.LittleEndian case bytes.HasPrefix(data, bigEndianSymtab): newTable = true case bytes.HasPrefix(data, littleEndianSymtab): newTable = true order = binary.LittleEndian } var ptrsz int if newTable { if len(data) < 8 { return &DecodingError{len(data), "unexpected EOF", nil} } ptrsz = int(data[7]) if ptrsz != 4 && ptrsz != 8 { return &DecodingError{7, "invalid pointer size", ptrsz} } data = data[8:] } var s sym p := data for len(p) >= 4 { var typ byte if newTable { // Symbol type, value, Go type. typ = p[0] & 0x3F wideValue := p[0]&0x40 != 0 goType := p[0]&0x80 != 0 if typ < 26 { typ += 'A' } else { typ += 'a' - 26 } s.typ = typ p = p[1:] if wideValue { if len(p) < ptrsz { return &DecodingError{len(data), "unexpected EOF", nil} } // fixed-width value if ptrsz == 8 { s.value = order.Uint64(p[0:8]) p = p[8:] } else { s.value = uint64(order.Uint32(p[0:4])) p = p[4:] } } else { // varint value s.value = 0 shift := uint(0) for len(p) > 0 && p[0]&0x80 != 0 { s.value |= uint64(p[0]&0x7F) << shift shift += 7 p = p[1:] } if len(p) == 0 { return &DecodingError{len(data), "unexpected EOF", nil} } s.value |= uint64(p[0]) << shift p = p[1:] } if goType { if len(p) < ptrsz { return &DecodingError{len(data), "unexpected EOF", nil} } // fixed-width go type if ptrsz == 8 { s.gotype = order.Uint64(p[0:8]) p = p[8:] } else { s.gotype = uint64(order.Uint32(p[0:4])) p = p[4:] } } } else { // Value, symbol type. s.value = uint64(order.Uint32(p[0:4])) if len(p) < 5 { return &DecodingError{len(data), "unexpected EOF", nil} } typ = p[4] if typ&0x80 == 0 { return &DecodingError{len(data) - len(p) + 4, "bad symbol type", typ} } typ &^= 0x80 s.typ = typ p = p[5:] } // Name. var i int var nnul int for i = 0; i < len(p); i++ { if p[i] == 0 { nnul = 1 break } } switch typ { case 'z', 'Z': p = p[i+nnul:] for i = 0; i+2 <= len(p); i += 2 { if p[i] == 0 && p[i+1] == 0 { nnul = 2 break } } } if len(p) < i+nnul { return &DecodingError{len(data), "unexpected EOF", nil} } s.name = p[0:i] i += nnul p = p[i:] if !newTable { if len(p) < 4 { return &DecodingError{len(data), "unexpected EOF", nil} } // Go type. s.gotype = uint64(order.Uint32(p[:4])) p = p[4:] } fn(s) } return nil }
func (s *Stream) readSectionHeaderBlockBody(headerData []byte) (header *SectionHeaderBlock, err error) { // // read byte-order magic, version and section length // bodyData, err := s.read(16) if err != nil { return nil, err } // // read byte-order magic // var byteOrder binary.ByteOrder if bodyData[0] == 0x1A && bodyData[1] == 0x2B && bodyData[2] == 0x3C && bodyData[3] == 0x4D { byteOrder = binary.BigEndian } else if bodyData[3] == 0x1A && bodyData[2] == 0x2B && bodyData[1] == 0x3C && bodyData[0] == 0x4D { byteOrder = binary.LittleEndian } else { return nil, errors.New("invalid byte order mark") } // // read other fields // versionMajor := byteOrder.Uint16(bodyData[4:6]) versionMinor := byteOrder.Uint16(bodyData[6:8]) sectionLength := int64(byteOrder.Uint64(bodyData[8:16])) // // Read options // totalLength := byteOrder.Uint32(headerData[4:8]) optsLen := totalLength - 28 rawOpts, err := s.readOptions(optsLen, byteOrder) if err != nil { return nil, err } opts, err := parseSectionHeaderOptions(rawOpts) if err != nil { return nil, err } // // Read last block total length // _, err = s.readExactly(4) if err != nil { return nil, err } retval := &SectionHeaderBlock{ totalLength: totalLength, ByteOrder: byteOrder, VersionMajor: versionMajor, VersionMinor: versionMinor, SectionLength: sectionLength, RawOptions: rawOpts, Options: opts, } s.sectionHeader = retval return retval, nil }