This commit is contained in:
parent
3ae47f93eb
commit
cc2e98ca49
26 changed files with 541 additions and 11 deletions
12
src/exe/Align.go
Normal file
12
src/exe/Align.go
Normal file
|
@ -0,0 +1,12 @@
|
|||
package exe
|
||||
|
||||
// Align calculates the next aligned address.
|
||||
func Align[T int | uint | int64 | uint64 | int32 | uint32](n T, alignment T) T {
|
||||
return (n + (alignment - 1)) & ^(alignment - 1)
|
||||
}
|
||||
|
||||
// AlignPad calculates the next aligned address and the padding needed.
|
||||
func AlignPad[T int | uint | int64 | uint64 | int32 | uint32](n T, alignment T) (T, T) {
|
||||
aligned := Align(n, alignment)
|
||||
return aligned, aligned - n
|
||||
}
|
7
src/exe/Discard.go
Normal file
7
src/exe/Discard.go
Normal file
|
@ -0,0 +1,7 @@
|
|||
package exe
|
||||
|
||||
// Discard implements a no-op WriteSeeker.
|
||||
type Discard struct{}
|
||||
|
||||
func (w *Discard) Write(_ []byte) (int, error) { return 0, nil }
|
||||
func (w *Discard) Seek(_ int64, _ int) (int64, error) { return 0, nil }
|
14
src/exe/Discard_test.go
Normal file
14
src/exe/Discard_test.go
Normal file
|
@ -0,0 +1,14 @@
|
|||
package exe_test
|
||||
|
||||
import (
|
||||
"io"
|
||||
"testing"
|
||||
|
||||
"git.urbach.dev/cli/q/src/exe"
|
||||
)
|
||||
|
||||
func TestDiscard(t *testing.T) {
|
||||
discard := exe.Discard{}
|
||||
discard.Write(nil)
|
||||
discard.Seek(0, io.SeekCurrent)
|
||||
}
|
42
src/exe/Executable.go
Normal file
42
src/exe/Executable.go
Normal file
|
@ -0,0 +1,42 @@
|
|||
package exe
|
||||
|
||||
// Executable is a generic definition of the binary that later gets translated to OS-specific formats.
|
||||
type Executable struct {
|
||||
Sections []*Section
|
||||
headerEnd int
|
||||
fileAlign int
|
||||
memoryAlign int
|
||||
}
|
||||
|
||||
// New creates a new executable.
|
||||
func New(headerEnd int, fileAlign int, memoryAlign int) *Executable {
|
||||
return &Executable{
|
||||
headerEnd: headerEnd,
|
||||
fileAlign: fileAlign,
|
||||
memoryAlign: memoryAlign,
|
||||
}
|
||||
}
|
||||
|
||||
// InitSections generates sections from raw byte slices.
|
||||
func (exe *Executable) InitSections(raw ...[]byte) {
|
||||
exe.Sections = make([]*Section, len(raw))
|
||||
|
||||
for i, data := range raw {
|
||||
exe.Sections[i] = &Section{Bytes: data}
|
||||
}
|
||||
|
||||
exe.Update()
|
||||
}
|
||||
|
||||
// Update recalculates all section offsets.
|
||||
func (exe *Executable) Update() {
|
||||
first := exe.Sections[0]
|
||||
first.FileOffset, first.Padding = AlignPad(exe.headerEnd, exe.fileAlign)
|
||||
first.MemoryOffset = Align(exe.headerEnd, exe.memoryAlign)
|
||||
|
||||
for i, section := range exe.Sections[1:] {
|
||||
previous := exe.Sections[i]
|
||||
section.FileOffset, section.Padding = AlignPad(previous.FileOffset+len(previous.Bytes), exe.fileAlign)
|
||||
section.MemoryOffset = Align(previous.MemoryOffset+len(previous.Bytes), exe.memoryAlign)
|
||||
}
|
||||
}
|
19
src/exe/Executable_test.go
Normal file
19
src/exe/Executable_test.go
Normal file
|
@ -0,0 +1,19 @@
|
|||
package exe_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"git.urbach.dev/cli/q/src/exe"
|
||||
"git.urbach.dev/go/assert"
|
||||
)
|
||||
|
||||
func TestExecutable(t *testing.T) {
|
||||
align := 0x1000
|
||||
x := exe.New(1, align, align)
|
||||
x.InitSections([]byte{1}, []byte{1})
|
||||
assert.Equal(t, len(x.Sections), 2)
|
||||
assert.Equal(t, x.Sections[0].Padding, align-1)
|
||||
assert.Equal(t, x.Sections[0].FileOffset, align)
|
||||
assert.Equal(t, x.Sections[1].Padding, align-1)
|
||||
assert.Equal(t, x.Sections[1].FileOffset, align*2)
|
||||
}
|
9
src/exe/Section.go
Normal file
9
src/exe/Section.go
Normal file
|
@ -0,0 +1,9 @@
|
|||
package exe
|
||||
|
||||
// Section represents some data within the executable that will also be loaded into memory.
|
||||
type Section struct {
|
||||
Bytes []byte
|
||||
FileOffset int
|
||||
Padding int
|
||||
MemoryOffset int
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue