mirror of
https://github.com/golang/go.git
synced 2025-05-18 05:44:35 +00:00
debug/elf: avoid using binary.Read() in NewFile()
With this change my test program that reads a tree of ELF files runs 1.71 ± 0.12 times faster without parallelism or 1.39 ± 0.06 times faster using 8 goroutines. Change-Id: I443d1a02736f16f5532ef28e1447c97aa87c7126 Reviewed-on: https://go-review.googlesource.com/c/go/+/571436 Auto-Submit: Ian Lance Taylor <iant@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Ian Lance Taylor <iant@google.com>
This commit is contained in:
parent
a29c30f620
commit
c9ed561db4
@ -27,6 +27,7 @@ import (
|
||||
"io"
|
||||
"os"
|
||||
"strings"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// TODO: error reporting detail
|
||||
@ -296,14 +297,16 @@ func NewFile(r io.ReaderAt) (*File, error) {
|
||||
}
|
||||
|
||||
f.Data = Data(ident[EI_DATA])
|
||||
var bo binary.ByteOrder
|
||||
switch f.Data {
|
||||
case ELFDATA2LSB:
|
||||
f.ByteOrder = binary.LittleEndian
|
||||
bo = binary.LittleEndian
|
||||
case ELFDATA2MSB:
|
||||
f.ByteOrder = binary.BigEndian
|
||||
bo = binary.BigEndian
|
||||
default:
|
||||
return nil, &FormatError{0, "unknown ELF data encoding", f.Data}
|
||||
}
|
||||
f.ByteOrder = bo
|
||||
|
||||
f.Version = Version(ident[EI_VERSION])
|
||||
if f.Version != EV_CURRENT {
|
||||
@ -320,43 +323,43 @@ func NewFile(r io.ReaderAt) (*File, error) {
|
||||
var shentsize, shnum, shstrndx int
|
||||
switch f.Class {
|
||||
case ELFCLASS32:
|
||||
hdr := new(Header32)
|
||||
sr.Seek(0, io.SeekStart)
|
||||
if err := binary.Read(sr, f.ByteOrder, hdr); err != nil {
|
||||
var hdr Header32
|
||||
data := make([]byte, unsafe.Sizeof(hdr))
|
||||
if _, err := sr.ReadAt(data, 0); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
f.Type = Type(hdr.Type)
|
||||
f.Machine = Machine(hdr.Machine)
|
||||
f.Entry = uint64(hdr.Entry)
|
||||
if v := Version(hdr.Version); v != f.Version {
|
||||
f.Type = Type(bo.Uint16(data[unsafe.Offsetof(hdr.Type):]))
|
||||
f.Machine = Machine(bo.Uint16(data[unsafe.Offsetof(hdr.Machine):]))
|
||||
f.Entry = uint64(bo.Uint32(data[unsafe.Offsetof(hdr.Entry):]))
|
||||
if v := Version(bo.Uint32(data[unsafe.Offsetof(hdr.Version):])); v != f.Version {
|
||||
return nil, &FormatError{0, "mismatched ELF version", v}
|
||||
}
|
||||
phoff = int64(hdr.Phoff)
|
||||
phentsize = int(hdr.Phentsize)
|
||||
phnum = int(hdr.Phnum)
|
||||
shoff = int64(hdr.Shoff)
|
||||
shentsize = int(hdr.Shentsize)
|
||||
shnum = int(hdr.Shnum)
|
||||
shstrndx = int(hdr.Shstrndx)
|
||||
phoff = int64(bo.Uint32(data[unsafe.Offsetof(hdr.Phoff):]))
|
||||
phentsize = int(bo.Uint16(data[unsafe.Offsetof(hdr.Phentsize):]))
|
||||
phnum = int(bo.Uint16(data[unsafe.Offsetof(hdr.Phnum):]))
|
||||
shoff = int64(bo.Uint32(data[unsafe.Offsetof(hdr.Shoff):]))
|
||||
shentsize = int(bo.Uint16(data[unsafe.Offsetof(hdr.Shentsize):]))
|
||||
shnum = int(bo.Uint16(data[unsafe.Offsetof(hdr.Shnum):]))
|
||||
shstrndx = int(bo.Uint16(data[unsafe.Offsetof(hdr.Shstrndx):]))
|
||||
case ELFCLASS64:
|
||||
hdr := new(Header64)
|
||||
sr.Seek(0, io.SeekStart)
|
||||
if err := binary.Read(sr, f.ByteOrder, hdr); err != nil {
|
||||
var hdr Header64
|
||||
data := make([]byte, unsafe.Sizeof(hdr))
|
||||
if _, err := sr.ReadAt(data, 0); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
f.Type = Type(hdr.Type)
|
||||
f.Machine = Machine(hdr.Machine)
|
||||
f.Entry = hdr.Entry
|
||||
if v := Version(hdr.Version); v != f.Version {
|
||||
f.Type = Type(bo.Uint16(data[unsafe.Offsetof(hdr.Type):]))
|
||||
f.Machine = Machine(bo.Uint16(data[unsafe.Offsetof(hdr.Machine):]))
|
||||
f.Entry = bo.Uint64(data[unsafe.Offsetof(hdr.Entry):])
|
||||
if v := Version(bo.Uint32(data[unsafe.Offsetof(hdr.Version):])); v != f.Version {
|
||||
return nil, &FormatError{0, "mismatched ELF version", v}
|
||||
}
|
||||
phoff = int64(hdr.Phoff)
|
||||
phentsize = int(hdr.Phentsize)
|
||||
phnum = int(hdr.Phnum)
|
||||
shoff = int64(hdr.Shoff)
|
||||
shentsize = int(hdr.Shentsize)
|
||||
shnum = int(hdr.Shnum)
|
||||
shstrndx = int(hdr.Shstrndx)
|
||||
phoff = int64(bo.Uint64(data[unsafe.Offsetof(hdr.Phoff):]))
|
||||
phentsize = int(bo.Uint16(data[unsafe.Offsetof(hdr.Phentsize):]))
|
||||
phnum = int(bo.Uint16(data[unsafe.Offsetof(hdr.Phnum):]))
|
||||
shoff = int64(bo.Uint64(data[unsafe.Offsetof(hdr.Shoff):]))
|
||||
shentsize = int(bo.Uint16(data[unsafe.Offsetof(hdr.Shentsize):]))
|
||||
shnum = int(bo.Uint16(data[unsafe.Offsetof(hdr.Shnum):]))
|
||||
shstrndx = int(bo.Uint16(data[unsafe.Offsetof(hdr.Shstrndx):]))
|
||||
}
|
||||
|
||||
if shoff < 0 {
|
||||
@ -389,47 +392,44 @@ func NewFile(r io.ReaderAt) (*File, error) {
|
||||
|
||||
// Read program headers
|
||||
f.Progs = make([]*Prog, phnum)
|
||||
phdata, err := saferio.ReadDataAt(sr, uint64(phnum)*uint64(phentsize), phoff)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for i := 0; i < phnum; i++ {
|
||||
off := phoff + int64(i)*int64(phentsize)
|
||||
sr.Seek(off, io.SeekStart)
|
||||
off := uintptr(i) * uintptr(phentsize)
|
||||
p := new(Prog)
|
||||
switch f.Class {
|
||||
case ELFCLASS32:
|
||||
ph := new(Prog32)
|
||||
if err := binary.Read(sr, f.ByteOrder, ph); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var ph Prog32
|
||||
p.ProgHeader = ProgHeader{
|
||||
Type: ProgType(ph.Type),
|
||||
Flags: ProgFlag(ph.Flags),
|
||||
Off: uint64(ph.Off),
|
||||
Vaddr: uint64(ph.Vaddr),
|
||||
Paddr: uint64(ph.Paddr),
|
||||
Filesz: uint64(ph.Filesz),
|
||||
Memsz: uint64(ph.Memsz),
|
||||
Align: uint64(ph.Align),
|
||||
Type: ProgType(bo.Uint32(phdata[off+unsafe.Offsetof(ph.Type):])),
|
||||
Flags: ProgFlag(bo.Uint32(phdata[off+unsafe.Offsetof(ph.Flags):])),
|
||||
Off: uint64(bo.Uint32(phdata[off+unsafe.Offsetof(ph.Off):])),
|
||||
Vaddr: uint64(bo.Uint32(phdata[off+unsafe.Offsetof(ph.Vaddr):])),
|
||||
Paddr: uint64(bo.Uint32(phdata[off+unsafe.Offsetof(ph.Paddr):])),
|
||||
Filesz: uint64(bo.Uint32(phdata[off+unsafe.Offsetof(ph.Filesz):])),
|
||||
Memsz: uint64(bo.Uint32(phdata[off+unsafe.Offsetof(ph.Memsz):])),
|
||||
Align: uint64(bo.Uint32(phdata[off+unsafe.Offsetof(ph.Align):])),
|
||||
}
|
||||
case ELFCLASS64:
|
||||
ph := new(Prog64)
|
||||
if err := binary.Read(sr, f.ByteOrder, ph); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var ph Prog64
|
||||
p.ProgHeader = ProgHeader{
|
||||
Type: ProgType(ph.Type),
|
||||
Flags: ProgFlag(ph.Flags),
|
||||
Off: ph.Off,
|
||||
Vaddr: ph.Vaddr,
|
||||
Paddr: ph.Paddr,
|
||||
Filesz: ph.Filesz,
|
||||
Memsz: ph.Memsz,
|
||||
Align: ph.Align,
|
||||
Type: ProgType(bo.Uint32(phdata[off+unsafe.Offsetof(ph.Type):])),
|
||||
Flags: ProgFlag(bo.Uint32(phdata[off+unsafe.Offsetof(ph.Flags):])),
|
||||
Off: bo.Uint64(phdata[off+unsafe.Offsetof(ph.Off):]),
|
||||
Vaddr: bo.Uint64(phdata[off+unsafe.Offsetof(ph.Vaddr):]),
|
||||
Paddr: bo.Uint64(phdata[off+unsafe.Offsetof(ph.Paddr):]),
|
||||
Filesz: bo.Uint64(phdata[off+unsafe.Offsetof(ph.Filesz):]),
|
||||
Memsz: bo.Uint64(phdata[off+unsafe.Offsetof(ph.Memsz):]),
|
||||
Align: bo.Uint64(phdata[off+unsafe.Offsetof(ph.Align):]),
|
||||
}
|
||||
}
|
||||
if int64(p.Off) < 0 {
|
||||
return nil, &FormatError{off, "invalid program header offset", p.Off}
|
||||
return nil, &FormatError{phoff + int64(off), "invalid program header offset", p.Off}
|
||||
}
|
||||
if int64(p.Filesz) < 0 {
|
||||
return nil, &FormatError{off, "invalid program header file size", p.Filesz}
|
||||
return nil, &FormatError{phoff + int64(off), "invalid program header file size", p.Filesz}
|
||||
}
|
||||
p.sr = io.NewSectionReader(r, int64(p.Off), int64(p.Filesz))
|
||||
p.ReaderAt = p.sr
|
||||
@ -446,7 +446,7 @@ func NewFile(r io.ReaderAt) (*File, error) {
|
||||
switch f.Class {
|
||||
case ELFCLASS32:
|
||||
sh := new(Section32)
|
||||
if err := binary.Read(sr, f.ByteOrder, sh); err != nil {
|
||||
if err := binary.Read(sr, bo, sh); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
shnum = int(sh.Size)
|
||||
@ -454,7 +454,7 @@ func NewFile(r io.ReaderAt) (*File, error) {
|
||||
link = sh.Link
|
||||
case ELFCLASS64:
|
||||
sh := new(Section64)
|
||||
if err := binary.Read(sr, f.ByteOrder, sh); err != nil {
|
||||
if err := binary.Read(sr, bo, sh); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
shnum = int(sh.Size)
|
||||
@ -493,51 +493,48 @@ func NewFile(r io.ReaderAt) (*File, error) {
|
||||
}
|
||||
f.Sections = make([]*Section, 0, c)
|
||||
names := make([]uint32, 0, c)
|
||||
shdata, err := saferio.ReadDataAt(sr, uint64(shnum)*uint64(shentsize), shoff)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for i := 0; i < shnum; i++ {
|
||||
off := shoff + int64(i)*int64(shentsize)
|
||||
sr.Seek(off, io.SeekStart)
|
||||
off := uintptr(i) * uintptr(shentsize)
|
||||
s := new(Section)
|
||||
switch f.Class {
|
||||
case ELFCLASS32:
|
||||
sh := new(Section32)
|
||||
if err := binary.Read(sr, f.ByteOrder, sh); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
names = append(names, sh.Name)
|
||||
var sh Section32
|
||||
names = append(names, bo.Uint32(shdata[off+unsafe.Offsetof(sh.Name):]))
|
||||
s.SectionHeader = SectionHeader{
|
||||
Type: SectionType(sh.Type),
|
||||
Flags: SectionFlag(sh.Flags),
|
||||
Addr: uint64(sh.Addr),
|
||||
Offset: uint64(sh.Off),
|
||||
FileSize: uint64(sh.Size),
|
||||
Link: sh.Link,
|
||||
Info: sh.Info,
|
||||
Addralign: uint64(sh.Addralign),
|
||||
Entsize: uint64(sh.Entsize),
|
||||
Type: SectionType(bo.Uint32(shdata[off+unsafe.Offsetof(sh.Type):])),
|
||||
Flags: SectionFlag(bo.Uint32(shdata[off+unsafe.Offsetof(sh.Flags):])),
|
||||
Addr: uint64(bo.Uint32(shdata[off+unsafe.Offsetof(sh.Addr):])),
|
||||
Offset: uint64(bo.Uint32(shdata[off+unsafe.Offsetof(sh.Off):])),
|
||||
FileSize: uint64(bo.Uint32(shdata[off+unsafe.Offsetof(sh.Size):])),
|
||||
Link: bo.Uint32(shdata[off+unsafe.Offsetof(sh.Link):]),
|
||||
Info: bo.Uint32(shdata[off+unsafe.Offsetof(sh.Info):]),
|
||||
Addralign: uint64(bo.Uint32(shdata[off+unsafe.Offsetof(sh.Addralign):])),
|
||||
Entsize: uint64(bo.Uint32(shdata[off+unsafe.Offsetof(sh.Entsize):])),
|
||||
}
|
||||
case ELFCLASS64:
|
||||
sh := new(Section64)
|
||||
if err := binary.Read(sr, f.ByteOrder, sh); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
names = append(names, sh.Name)
|
||||
var sh Section64
|
||||
names = append(names, bo.Uint32(shdata[off+unsafe.Offsetof(sh.Name):]))
|
||||
s.SectionHeader = SectionHeader{
|
||||
Type: SectionType(sh.Type),
|
||||
Flags: SectionFlag(sh.Flags),
|
||||
Offset: sh.Off,
|
||||
FileSize: sh.Size,
|
||||
Addr: sh.Addr,
|
||||
Link: sh.Link,
|
||||
Info: sh.Info,
|
||||
Addralign: sh.Addralign,
|
||||
Entsize: sh.Entsize,
|
||||
Type: SectionType(bo.Uint32(shdata[off+unsafe.Offsetof(sh.Type):])),
|
||||
Flags: SectionFlag(bo.Uint64(shdata[off+unsafe.Offsetof(sh.Flags):])),
|
||||
Offset: bo.Uint64(shdata[off+unsafe.Offsetof(sh.Off):]),
|
||||
FileSize: bo.Uint64(shdata[off+unsafe.Offsetof(sh.Size):]),
|
||||
Addr: bo.Uint64(shdata[off+unsafe.Offsetof(sh.Addr):]),
|
||||
Link: bo.Uint32(shdata[off+unsafe.Offsetof(sh.Link):]),
|
||||
Info: bo.Uint32(shdata[off+unsafe.Offsetof(sh.Info):]),
|
||||
Addralign: bo.Uint64(shdata[off+unsafe.Offsetof(sh.Addralign):]),
|
||||
Entsize: bo.Uint64(shdata[off+unsafe.Offsetof(sh.Entsize):]),
|
||||
}
|
||||
}
|
||||
if int64(s.Offset) < 0 {
|
||||
return nil, &FormatError{off, "invalid section offset", int64(s.Offset)}
|
||||
return nil, &FormatError{shoff + int64(off), "invalid section offset", int64(s.Offset)}
|
||||
}
|
||||
if int64(s.FileSize) < 0 {
|
||||
return nil, &FormatError{off, "invalid section size", int64(s.FileSize)}
|
||||
return nil, &FormatError{shoff + int64(off), "invalid section size", int64(s.FileSize)}
|
||||
}
|
||||
s.sr = io.NewSectionReader(r, int64(s.Offset), int64(s.FileSize))
|
||||
|
||||
@ -548,23 +545,25 @@ func NewFile(r io.ReaderAt) (*File, error) {
|
||||
// Read the compression header.
|
||||
switch f.Class {
|
||||
case ELFCLASS32:
|
||||
ch := new(Chdr32)
|
||||
if err := binary.Read(s.sr, f.ByteOrder, ch); err != nil {
|
||||
var ch Chdr32
|
||||
chdata := make([]byte, unsafe.Sizeof(ch))
|
||||
if _, err := s.sr.ReadAt(chdata, 0); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
s.compressionType = CompressionType(ch.Type)
|
||||
s.Size = uint64(ch.Size)
|
||||
s.Addralign = uint64(ch.Addralign)
|
||||
s.compressionOffset = int64(binary.Size(ch))
|
||||
s.compressionType = CompressionType(bo.Uint32(chdata[unsafe.Offsetof(ch.Type):]))
|
||||
s.Size = uint64(bo.Uint32(chdata[unsafe.Offsetof(ch.Size):]))
|
||||
s.Addralign = uint64(bo.Uint32(chdata[unsafe.Offsetof(ch.Addralign):]))
|
||||
s.compressionOffset = int64(unsafe.Sizeof(ch))
|
||||
case ELFCLASS64:
|
||||
ch := new(Chdr64)
|
||||
if err := binary.Read(s.sr, f.ByteOrder, ch); err != nil {
|
||||
var ch Chdr64
|
||||
chdata := make([]byte, unsafe.Sizeof(ch))
|
||||
if _, err := s.sr.ReadAt(chdata, 0); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
s.compressionType = CompressionType(ch.Type)
|
||||
s.Size = ch.Size
|
||||
s.Addralign = ch.Addralign
|
||||
s.compressionOffset = int64(binary.Size(ch))
|
||||
s.compressionType = CompressionType(bo.Uint32(chdata[unsafe.Offsetof(ch.Type):]))
|
||||
s.Size = bo.Uint64(chdata[unsafe.Offsetof(ch.Size):])
|
||||
s.Addralign = bo.Uint64(chdata[unsafe.Offsetof(ch.Addralign):])
|
||||
s.compressionOffset = int64(unsafe.Sizeof(ch))
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user