Skip to content

Commit

Permalink
add EnsureROMContiguous
Browse files Browse the repository at this point in the history
  • Loading branch information
soypat committed Sep 22, 2024
1 parent 2cd831d commit 4f6fe99
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 4 deletions.
4 changes: 4 additions & 0 deletions cmd/picobin/elf.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,10 @@ func elfROM(f *elf.File, flags Flags) (ROM []byte, romAddr uint64, err error) {
if err != nil {
return nil, 0, err
}
err = elfutil.EnsureROMContiguous(f, uromStart, uromEnd)
if err != nil {
return nil, uromStart, err
}
romStart := int64(uromStart)
romSize := uromEnd - uromStart
if romSize > uint64(flags.readsize) {
Expand Down
38 changes: 34 additions & 4 deletions elfutil/elfutil.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"errors"
"fmt"
"io"
"math"
)

// SectionIsROM checks if the section is meant to exist on firmware.
Expand Down Expand Up @@ -33,12 +34,37 @@ func GetROMAddr(f *elf.File) (startAddr, endAddr uint64, err error) {
endAddr = endProg
}
}
if startAddr > endAddr {
if startAddr >= endAddr {
return 0, 0, errors.New("no ROM sections found")
} else if endAddr-startAddr > math.MaxInt {
return startAddr, endAddr, fmt.Errorf("ROM size overflows int %#x..%#x (%d)", startAddr, endAddr, endAddr-startAddr)
}
return startAddr, endAddr, nil
}

// EnsureROMContiguous checks ROM program memory is contiguously represented between startAddr and endAddr addresses and returns error if not contiguous.
func EnsureROMContiguous(f *elf.File, startAddr, endAddr uint64) error {
// TODO(soypat): maybe use a more elegant, non-brute approach... but really this is more than good enough for non-adversarial input. O(n) time for sorted inputs. O(n^2) for adversarial input. ELF is typically more or less sorted...
contiguousUpTo := startAddr
for c := 0; c < len(f.Progs); c++ {
for _, prog := range f.Progs {
pstart := prog.Paddr
pend := pstart + prog.Memsz
if !ProgIsROM(prog) || !aliases(contiguousUpTo, contiguousUpTo+1, pstart, pend) {
continue
}
contiguousUpTo = pend
if contiguousUpTo >= endAddr {
return nil
}
}
}
if contiguousUpTo == startAddr {
return errors.New("start address lower than ROM")
}
return fmt.Errorf("ROM memory not contiguous between %#x..%#x, only up to %#x", startAddr, endAddr, contiguousUpTo)
}

// ReadAt reads from the binary sections representing read-only-memory (ROM) starting at address addr.
func ReadAt(f *elf.File, b []byte, addr int64) (int, error) {
if addr < 0 {
Expand Down Expand Up @@ -76,7 +102,11 @@ func ReplaceSection(f *elf.File, sectionName string, newData []byte) error {
return nil
}

func aliases(start0, end0, start1, end1 int64) bool {
type integer interface {
~int | ~int64 | ~uint64
}

func aliases[T integer](start0, end0, start1, end1 T) bool {
return start0 < end1 && end0 > start1
}

Expand All @@ -87,14 +117,14 @@ func clear[E any](a []E) {
}
}

func max[T ~int | ~int64](a, b T) T {
func max[T integer](a, b T) T {
if a > b {
return a
}
return b
}

func min[T ~int | ~int64](a, b T) T {
func min[T integer](a, b T) T {
if a < b {
return a
}
Expand Down

0 comments on commit 4f6fe99

Please sign in to comment.