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"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
"unsafe"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TODO: error reporting detail
|
// TODO: error reporting detail
|
||||||
@ -296,14 +297,16 @@ func NewFile(r io.ReaderAt) (*File, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
f.Data = Data(ident[EI_DATA])
|
f.Data = Data(ident[EI_DATA])
|
||||||
|
var bo binary.ByteOrder
|
||||||
switch f.Data {
|
switch f.Data {
|
||||||
case ELFDATA2LSB:
|
case ELFDATA2LSB:
|
||||||
f.ByteOrder = binary.LittleEndian
|
bo = binary.LittleEndian
|
||||||
case ELFDATA2MSB:
|
case ELFDATA2MSB:
|
||||||
f.ByteOrder = binary.BigEndian
|
bo = binary.BigEndian
|
||||||
default:
|
default:
|
||||||
return nil, &FormatError{0, "unknown ELF data encoding", f.Data}
|
return nil, &FormatError{0, "unknown ELF data encoding", f.Data}
|
||||||
}
|
}
|
||||||
|
f.ByteOrder = bo
|
||||||
|
|
||||||
f.Version = Version(ident[EI_VERSION])
|
f.Version = Version(ident[EI_VERSION])
|
||||||
if f.Version != EV_CURRENT {
|
if f.Version != EV_CURRENT {
|
||||||
@ -320,43 +323,43 @@ func NewFile(r io.ReaderAt) (*File, error) {
|
|||||||
var shentsize, shnum, shstrndx int
|
var shentsize, shnum, shstrndx int
|
||||||
switch f.Class {
|
switch f.Class {
|
||||||
case ELFCLASS32:
|
case ELFCLASS32:
|
||||||
hdr := new(Header32)
|
var hdr Header32
|
||||||
sr.Seek(0, io.SeekStart)
|
data := make([]byte, unsafe.Sizeof(hdr))
|
||||||
if err := binary.Read(sr, f.ByteOrder, hdr); err != nil {
|
if _, err := sr.ReadAt(data, 0); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
f.Type = Type(hdr.Type)
|
f.Type = Type(bo.Uint16(data[unsafe.Offsetof(hdr.Type):]))
|
||||||
f.Machine = Machine(hdr.Machine)
|
f.Machine = Machine(bo.Uint16(data[unsafe.Offsetof(hdr.Machine):]))
|
||||||
f.Entry = uint64(hdr.Entry)
|
f.Entry = uint64(bo.Uint32(data[unsafe.Offsetof(hdr.Entry):]))
|
||||||
if v := Version(hdr.Version); v != f.Version {
|
if v := Version(bo.Uint32(data[unsafe.Offsetof(hdr.Version):])); v != f.Version {
|
||||||
return nil, &FormatError{0, "mismatched ELF version", v}
|
return nil, &FormatError{0, "mismatched ELF version", v}
|
||||||
}
|
}
|
||||||
phoff = int64(hdr.Phoff)
|
phoff = int64(bo.Uint32(data[unsafe.Offsetof(hdr.Phoff):]))
|
||||||
phentsize = int(hdr.Phentsize)
|
phentsize = int(bo.Uint16(data[unsafe.Offsetof(hdr.Phentsize):]))
|
||||||
phnum = int(hdr.Phnum)
|
phnum = int(bo.Uint16(data[unsafe.Offsetof(hdr.Phnum):]))
|
||||||
shoff = int64(hdr.Shoff)
|
shoff = int64(bo.Uint32(data[unsafe.Offsetof(hdr.Shoff):]))
|
||||||
shentsize = int(hdr.Shentsize)
|
shentsize = int(bo.Uint16(data[unsafe.Offsetof(hdr.Shentsize):]))
|
||||||
shnum = int(hdr.Shnum)
|
shnum = int(bo.Uint16(data[unsafe.Offsetof(hdr.Shnum):]))
|
||||||
shstrndx = int(hdr.Shstrndx)
|
shstrndx = int(bo.Uint16(data[unsafe.Offsetof(hdr.Shstrndx):]))
|
||||||
case ELFCLASS64:
|
case ELFCLASS64:
|
||||||
hdr := new(Header64)
|
var hdr Header64
|
||||||
sr.Seek(0, io.SeekStart)
|
data := make([]byte, unsafe.Sizeof(hdr))
|
||||||
if err := binary.Read(sr, f.ByteOrder, hdr); err != nil {
|
if _, err := sr.ReadAt(data, 0); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
f.Type = Type(hdr.Type)
|
f.Type = Type(bo.Uint16(data[unsafe.Offsetof(hdr.Type):]))
|
||||||
f.Machine = Machine(hdr.Machine)
|
f.Machine = Machine(bo.Uint16(data[unsafe.Offsetof(hdr.Machine):]))
|
||||||
f.Entry = hdr.Entry
|
f.Entry = bo.Uint64(data[unsafe.Offsetof(hdr.Entry):])
|
||||||
if v := Version(hdr.Version); v != f.Version {
|
if v := Version(bo.Uint32(data[unsafe.Offsetof(hdr.Version):])); v != f.Version {
|
||||||
return nil, &FormatError{0, "mismatched ELF version", v}
|
return nil, &FormatError{0, "mismatched ELF version", v}
|
||||||
}
|
}
|
||||||
phoff = int64(hdr.Phoff)
|
phoff = int64(bo.Uint64(data[unsafe.Offsetof(hdr.Phoff):]))
|
||||||
phentsize = int(hdr.Phentsize)
|
phentsize = int(bo.Uint16(data[unsafe.Offsetof(hdr.Phentsize):]))
|
||||||
phnum = int(hdr.Phnum)
|
phnum = int(bo.Uint16(data[unsafe.Offsetof(hdr.Phnum):]))
|
||||||
shoff = int64(hdr.Shoff)
|
shoff = int64(bo.Uint64(data[unsafe.Offsetof(hdr.Shoff):]))
|
||||||
shentsize = int(hdr.Shentsize)
|
shentsize = int(bo.Uint16(data[unsafe.Offsetof(hdr.Shentsize):]))
|
||||||
shnum = int(hdr.Shnum)
|
shnum = int(bo.Uint16(data[unsafe.Offsetof(hdr.Shnum):]))
|
||||||
shstrndx = int(hdr.Shstrndx)
|
shstrndx = int(bo.Uint16(data[unsafe.Offsetof(hdr.Shstrndx):]))
|
||||||
}
|
}
|
||||||
|
|
||||||
if shoff < 0 {
|
if shoff < 0 {
|
||||||
@ -389,47 +392,44 @@ func NewFile(r io.ReaderAt) (*File, error) {
|
|||||||
|
|
||||||
// Read program headers
|
// Read program headers
|
||||||
f.Progs = make([]*Prog, phnum)
|
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++ {
|
for i := 0; i < phnum; i++ {
|
||||||
off := phoff + int64(i)*int64(phentsize)
|
off := uintptr(i) * uintptr(phentsize)
|
||||||
sr.Seek(off, io.SeekStart)
|
|
||||||
p := new(Prog)
|
p := new(Prog)
|
||||||
switch f.Class {
|
switch f.Class {
|
||||||
case ELFCLASS32:
|
case ELFCLASS32:
|
||||||
ph := new(Prog32)
|
var ph Prog32
|
||||||
if err := binary.Read(sr, f.ByteOrder, ph); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
p.ProgHeader = ProgHeader{
|
p.ProgHeader = ProgHeader{
|
||||||
Type: ProgType(ph.Type),
|
Type: ProgType(bo.Uint32(phdata[off+unsafe.Offsetof(ph.Type):])),
|
||||||
Flags: ProgFlag(ph.Flags),
|
Flags: ProgFlag(bo.Uint32(phdata[off+unsafe.Offsetof(ph.Flags):])),
|
||||||
Off: uint64(ph.Off),
|
Off: uint64(bo.Uint32(phdata[off+unsafe.Offsetof(ph.Off):])),
|
||||||
Vaddr: uint64(ph.Vaddr),
|
Vaddr: uint64(bo.Uint32(phdata[off+unsafe.Offsetof(ph.Vaddr):])),
|
||||||
Paddr: uint64(ph.Paddr),
|
Paddr: uint64(bo.Uint32(phdata[off+unsafe.Offsetof(ph.Paddr):])),
|
||||||
Filesz: uint64(ph.Filesz),
|
Filesz: uint64(bo.Uint32(phdata[off+unsafe.Offsetof(ph.Filesz):])),
|
||||||
Memsz: uint64(ph.Memsz),
|
Memsz: uint64(bo.Uint32(phdata[off+unsafe.Offsetof(ph.Memsz):])),
|
||||||
Align: uint64(ph.Align),
|
Align: uint64(bo.Uint32(phdata[off+unsafe.Offsetof(ph.Align):])),
|
||||||
}
|
}
|
||||||
case ELFCLASS64:
|
case ELFCLASS64:
|
||||||
ph := new(Prog64)
|
var ph Prog64
|
||||||
if err := binary.Read(sr, f.ByteOrder, ph); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
p.ProgHeader = ProgHeader{
|
p.ProgHeader = ProgHeader{
|
||||||
Type: ProgType(ph.Type),
|
Type: ProgType(bo.Uint32(phdata[off+unsafe.Offsetof(ph.Type):])),
|
||||||
Flags: ProgFlag(ph.Flags),
|
Flags: ProgFlag(bo.Uint32(phdata[off+unsafe.Offsetof(ph.Flags):])),
|
||||||
Off: ph.Off,
|
Off: bo.Uint64(phdata[off+unsafe.Offsetof(ph.Off):]),
|
||||||
Vaddr: ph.Vaddr,
|
Vaddr: bo.Uint64(phdata[off+unsafe.Offsetof(ph.Vaddr):]),
|
||||||
Paddr: ph.Paddr,
|
Paddr: bo.Uint64(phdata[off+unsafe.Offsetof(ph.Paddr):]),
|
||||||
Filesz: ph.Filesz,
|
Filesz: bo.Uint64(phdata[off+unsafe.Offsetof(ph.Filesz):]),
|
||||||
Memsz: ph.Memsz,
|
Memsz: bo.Uint64(phdata[off+unsafe.Offsetof(ph.Memsz):]),
|
||||||
Align: ph.Align,
|
Align: bo.Uint64(phdata[off+unsafe.Offsetof(ph.Align):]),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if int64(p.Off) < 0 {
|
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 {
|
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.sr = io.NewSectionReader(r, int64(p.Off), int64(p.Filesz))
|
||||||
p.ReaderAt = p.sr
|
p.ReaderAt = p.sr
|
||||||
@ -446,7 +446,7 @@ func NewFile(r io.ReaderAt) (*File, error) {
|
|||||||
switch f.Class {
|
switch f.Class {
|
||||||
case ELFCLASS32:
|
case ELFCLASS32:
|
||||||
sh := new(Section32)
|
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
|
return nil, err
|
||||||
}
|
}
|
||||||
shnum = int(sh.Size)
|
shnum = int(sh.Size)
|
||||||
@ -454,7 +454,7 @@ func NewFile(r io.ReaderAt) (*File, error) {
|
|||||||
link = sh.Link
|
link = sh.Link
|
||||||
case ELFCLASS64:
|
case ELFCLASS64:
|
||||||
sh := new(Section64)
|
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
|
return nil, err
|
||||||
}
|
}
|
||||||
shnum = int(sh.Size)
|
shnum = int(sh.Size)
|
||||||
@ -493,51 +493,48 @@ func NewFile(r io.ReaderAt) (*File, error) {
|
|||||||
}
|
}
|
||||||
f.Sections = make([]*Section, 0, c)
|
f.Sections = make([]*Section, 0, c)
|
||||||
names := make([]uint32, 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++ {
|
for i := 0; i < shnum; i++ {
|
||||||
off := shoff + int64(i)*int64(shentsize)
|
off := uintptr(i) * uintptr(shentsize)
|
||||||
sr.Seek(off, io.SeekStart)
|
|
||||||
s := new(Section)
|
s := new(Section)
|
||||||
switch f.Class {
|
switch f.Class {
|
||||||
case ELFCLASS32:
|
case ELFCLASS32:
|
||||||
sh := new(Section32)
|
var sh Section32
|
||||||
if err := binary.Read(sr, f.ByteOrder, sh); err != nil {
|
names = append(names, bo.Uint32(shdata[off+unsafe.Offsetof(sh.Name):]))
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
names = append(names, sh.Name)
|
|
||||||
s.SectionHeader = SectionHeader{
|
s.SectionHeader = SectionHeader{
|
||||||
Type: SectionType(sh.Type),
|
Type: SectionType(bo.Uint32(shdata[off+unsafe.Offsetof(sh.Type):])),
|
||||||
Flags: SectionFlag(sh.Flags),
|
Flags: SectionFlag(bo.Uint32(shdata[off+unsafe.Offsetof(sh.Flags):])),
|
||||||
Addr: uint64(sh.Addr),
|
Addr: uint64(bo.Uint32(shdata[off+unsafe.Offsetof(sh.Addr):])),
|
||||||
Offset: uint64(sh.Off),
|
Offset: uint64(bo.Uint32(shdata[off+unsafe.Offsetof(sh.Off):])),
|
||||||
FileSize: uint64(sh.Size),
|
FileSize: uint64(bo.Uint32(shdata[off+unsafe.Offsetof(sh.Size):])),
|
||||||
Link: sh.Link,
|
Link: bo.Uint32(shdata[off+unsafe.Offsetof(sh.Link):]),
|
||||||
Info: sh.Info,
|
Info: bo.Uint32(shdata[off+unsafe.Offsetof(sh.Info):]),
|
||||||
Addralign: uint64(sh.Addralign),
|
Addralign: uint64(bo.Uint32(shdata[off+unsafe.Offsetof(sh.Addralign):])),
|
||||||
Entsize: uint64(sh.Entsize),
|
Entsize: uint64(bo.Uint32(shdata[off+unsafe.Offsetof(sh.Entsize):])),
|
||||||
}
|
}
|
||||||
case ELFCLASS64:
|
case ELFCLASS64:
|
||||||
sh := new(Section64)
|
var sh Section64
|
||||||
if err := binary.Read(sr, f.ByteOrder, sh); err != nil {
|
names = append(names, bo.Uint32(shdata[off+unsafe.Offsetof(sh.Name):]))
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
names = append(names, sh.Name)
|
|
||||||
s.SectionHeader = SectionHeader{
|
s.SectionHeader = SectionHeader{
|
||||||
Type: SectionType(sh.Type),
|
Type: SectionType(bo.Uint32(shdata[off+unsafe.Offsetof(sh.Type):])),
|
||||||
Flags: SectionFlag(sh.Flags),
|
Flags: SectionFlag(bo.Uint64(shdata[off+unsafe.Offsetof(sh.Flags):])),
|
||||||
Offset: sh.Off,
|
Offset: bo.Uint64(shdata[off+unsafe.Offsetof(sh.Off):]),
|
||||||
FileSize: sh.Size,
|
FileSize: bo.Uint64(shdata[off+unsafe.Offsetof(sh.Size):]),
|
||||||
Addr: sh.Addr,
|
Addr: bo.Uint64(shdata[off+unsafe.Offsetof(sh.Addr):]),
|
||||||
Link: sh.Link,
|
Link: bo.Uint32(shdata[off+unsafe.Offsetof(sh.Link):]),
|
||||||
Info: sh.Info,
|
Info: bo.Uint32(shdata[off+unsafe.Offsetof(sh.Info):]),
|
||||||
Addralign: sh.Addralign,
|
Addralign: bo.Uint64(shdata[off+unsafe.Offsetof(sh.Addralign):]),
|
||||||
Entsize: sh.Entsize,
|
Entsize: bo.Uint64(shdata[off+unsafe.Offsetof(sh.Entsize):]),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if int64(s.Offset) < 0 {
|
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 {
|
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))
|
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.
|
// Read the compression header.
|
||||||
switch f.Class {
|
switch f.Class {
|
||||||
case ELFCLASS32:
|
case ELFCLASS32:
|
||||||
ch := new(Chdr32)
|
var ch Chdr32
|
||||||
if err := binary.Read(s.sr, f.ByteOrder, ch); err != nil {
|
chdata := make([]byte, unsafe.Sizeof(ch))
|
||||||
|
if _, err := s.sr.ReadAt(chdata, 0); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
s.compressionType = CompressionType(ch.Type)
|
s.compressionType = CompressionType(bo.Uint32(chdata[unsafe.Offsetof(ch.Type):]))
|
||||||
s.Size = uint64(ch.Size)
|
s.Size = uint64(bo.Uint32(chdata[unsafe.Offsetof(ch.Size):]))
|
||||||
s.Addralign = uint64(ch.Addralign)
|
s.Addralign = uint64(bo.Uint32(chdata[unsafe.Offsetof(ch.Addralign):]))
|
||||||
s.compressionOffset = int64(binary.Size(ch))
|
s.compressionOffset = int64(unsafe.Sizeof(ch))
|
||||||
case ELFCLASS64:
|
case ELFCLASS64:
|
||||||
ch := new(Chdr64)
|
var ch Chdr64
|
||||||
if err := binary.Read(s.sr, f.ByteOrder, ch); err != nil {
|
chdata := make([]byte, unsafe.Sizeof(ch))
|
||||||
|
if _, err := s.sr.ReadAt(chdata, 0); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
s.compressionType = CompressionType(ch.Type)
|
s.compressionType = CompressionType(bo.Uint32(chdata[unsafe.Offsetof(ch.Type):]))
|
||||||
s.Size = ch.Size
|
s.Size = bo.Uint64(chdata[unsafe.Offsetof(ch.Size):])
|
||||||
s.Addralign = ch.Addralign
|
s.Addralign = bo.Uint64(chdata[unsafe.Offsetof(ch.Addralign):])
|
||||||
s.compressionOffset = int64(binary.Size(ch))
|
s.compressionOffset = int64(unsafe.Sizeof(ch))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user