aboutsummaryrefslogtreecommitdiff
path: root/src/debug
diff options
context:
space:
mode:
authorPeter Collingbourne <pcc@google.com>2024-03-12 20:01:40 -0700
committerGopher Robot <gobot@golang.org>2024-03-15 05:04:31 +0000
commitc9ed561db438ba413ba8cfac0c292a615bda45a8 (patch)
treee5d6a80819553212333128598f56dab1fbe2336e /src/debug
parenta29c30f620bdf5eba16263ed53d3efa01961d615 (diff)
downloadgo-c9ed561db438ba413ba8cfac0c292a615bda45a8.tar.gz
go-c9ed561db438ba413ba8cfac0c292a615bda45a8.zip
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>
Diffstat (limited to 'src/debug')
-rw-r--r--src/debug/elf/file.go207
1 files changed, 103 insertions, 104 deletions
diff --git a/src/debug/elf/file.go b/src/debug/elf/file.go
index 7228447c21..6b4de0c56e 100644
--- a/src/debug/elf/file.go
+++ b/src/debug/elf/file.go
@@ -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))
}
}