This commit is contained in:
parent
ca9595d1fb
commit
36f76170f5
9 changed files with 48 additions and 20 deletions
|
@ -59,8 +59,7 @@ func (a *Assembler) Compile(b *build.Build) (code []byte, data []byte, libs dll.
|
|||
}
|
||||
}
|
||||
|
||||
x := exe.New(elf.HeaderEnd, b.FileAlign(), b.MemoryAlign())
|
||||
x.InitSections(c.code, c.data, nil)
|
||||
x := exe.New(elf.HeaderEnd, b.FileAlign(), b.MemoryAlign(), b.Congruent(), c.code, c.data, nil)
|
||||
dataSectionOffset := x.Sections[1].MemoryOffset - x.Sections[0].MemoryOffset
|
||||
|
||||
for dataLabel, address := range dataLabels {
|
||||
|
|
6
src/build/Congruent.go
Normal file
6
src/build/Congruent.go
Normal file
|
@ -0,0 +1,6 @@
|
|||
package build
|
||||
|
||||
// Congruent returns true if the platform needs to force `virtual address % alignment == file offset % alignment`.
|
||||
func (build *Build) Congruent() bool {
|
||||
return build.OS == Linux
|
||||
}
|
|
@ -1,6 +1,13 @@
|
|||
package build
|
||||
|
||||
// cacheLineSize is the smallest unit of data that can be transferred between the RAM and the CPU cache.
|
||||
const cacheLineSize = 64
|
||||
|
||||
// FileAlign returns the file alignment.
|
||||
func (build *Build) FileAlign() int {
|
||||
if build.OS == Linux {
|
||||
return cacheLineSize
|
||||
}
|
||||
|
||||
return build.MemoryAlign()
|
||||
}
|
|
@ -4,7 +4,7 @@ package build
|
|||
func (build *Build) MemoryAlign() int {
|
||||
switch build.Arch {
|
||||
case ARM:
|
||||
return 0x4000
|
||||
return 0x10000
|
||||
default:
|
||||
return 0x1000
|
||||
}
|
||||
|
|
|
@ -18,8 +18,7 @@ type ELF struct {
|
|||
|
||||
// Write writes the ELF64 format to the given writer.
|
||||
func Write(writer io.WriteSeeker, b *build.Build, codeBytes []byte, dataBytes []byte) {
|
||||
x := exe.New(HeaderEnd, b.FileAlign(), b.MemoryAlign())
|
||||
x.InitSections(codeBytes, dataBytes)
|
||||
x := exe.New(HeaderEnd, b.FileAlign(), b.MemoryAlign(), b.Congruent(), codeBytes, dataBytes)
|
||||
code := x.Sections[0]
|
||||
data := x.Sections[1]
|
||||
|
||||
|
|
|
@ -6,26 +6,25 @@ type Executable struct {
|
|||
headerEnd int
|
||||
fileAlign int
|
||||
memoryAlign int
|
||||
congruent bool
|
||||
}
|
||||
|
||||
// New creates a new executable.
|
||||
func New(headerEnd int, fileAlign int, memoryAlign int) *Executable {
|
||||
return &Executable{
|
||||
func New(headerEnd int, fileAlign int, memoryAlign int, congruent bool, raw ...[]byte) *Executable {
|
||||
exe := &Executable{
|
||||
Sections: make([]*Section, len(raw)),
|
||||
headerEnd: headerEnd,
|
||||
fileAlign: fileAlign,
|
||||
memoryAlign: memoryAlign,
|
||||
congruent: congruent,
|
||||
}
|
||||
}
|
||||
|
||||
// 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()
|
||||
return exe
|
||||
}
|
||||
|
||||
// Update recalculates all section offsets.
|
||||
|
@ -34,9 +33,17 @@ func (exe *Executable) Update() {
|
|||
first.FileOffset, first.Padding = AlignPad(exe.headerEnd, exe.fileAlign)
|
||||
first.MemoryOffset = Align(exe.headerEnd, exe.memoryAlign)
|
||||
|
||||
if exe.congruent && exe.fileAlign != exe.memoryAlign {
|
||||
first.MemoryOffset += first.FileOffset % 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)
|
||||
|
||||
if exe.congruent && exe.fileAlign != exe.memoryAlign {
|
||||
section.MemoryOffset += section.FileOffset % exe.memoryAlign
|
||||
}
|
||||
}
|
||||
}
|
|
@ -7,13 +7,25 @@ import (
|
|||
"git.urbach.dev/go/assert"
|
||||
)
|
||||
|
||||
func TestExecutable(t *testing.T) {
|
||||
align := 0x1000
|
||||
x := exe.New(1, align, align)
|
||||
x.InitSections([]byte{1}, []byte{1})
|
||||
func TestSimple(t *testing.T) {
|
||||
align := 32
|
||||
x := exe.New(1, align, align, false, []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)
|
||||
}
|
||||
|
||||
func TestCongruent(t *testing.T) {
|
||||
fileAlign := 16
|
||||
memoryAlign := 32
|
||||
x := exe.New(1, fileAlign, memoryAlign, true, []byte{1}, []byte{1}, []byte{1})
|
||||
assert.Equal(t, len(x.Sections), 3)
|
||||
assert.Equal(t, x.Sections[0].FileOffset, fileAlign)
|
||||
assert.Equal(t, x.Sections[1].FileOffset, fileAlign*2)
|
||||
assert.Equal(t, x.Sections[2].FileOffset, fileAlign*3)
|
||||
assert.Equal(t, x.Sections[0].MemoryOffset, memoryAlign+(fileAlign%memoryAlign))
|
||||
assert.Equal(t, x.Sections[1].MemoryOffset, memoryAlign*2+(fileAlign*2%memoryAlign))
|
||||
assert.Equal(t, x.Sections[2].MemoryOffset, memoryAlign*3+(fileAlign*3%memoryAlign))
|
||||
}
|
|
@ -19,8 +19,7 @@ type MachO struct {
|
|||
|
||||
// Write writes the Mach-O format to the given writer.
|
||||
func Write(writer io.WriteSeeker, b *build.Build, codeBytes []byte, dataBytes []byte) {
|
||||
x := exe.New(HeaderEnd, b.FileAlign(), b.MemoryAlign())
|
||||
x.InitSections(codeBytes, dataBytes)
|
||||
x := exe.New(HeaderEnd, b.FileAlign(), b.MemoryAlign(), b.Congruent(), codeBytes, dataBytes)
|
||||
code := x.Sections[0]
|
||||
data := x.Sections[1]
|
||||
arch, microArch := Arch(b.Arch)
|
||||
|
|
|
@ -20,8 +20,7 @@ type EXE struct {
|
|||
|
||||
// Write writes the EXE file to the given writer.
|
||||
func Write(writer io.WriteSeeker, b *build.Build, codeBytes []byte, dataBytes []byte, libs dll.List) {
|
||||
x := exe.New(HeaderEnd, b.FileAlign(), b.MemoryAlign())
|
||||
x.InitSections(codeBytes, dataBytes, nil)
|
||||
x := exe.New(HeaderEnd, b.FileAlign(), b.MemoryAlign(), b.Congruent(), codeBytes, dataBytes, nil)
|
||||
code := x.Sections[0]
|
||||
data := x.Sections[1]
|
||||
imports := x.Sections[2]
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue