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 := exe.New(elf.HeaderEnd, b.FileAlign(), b.MemoryAlign(), b.Congruent(), c.code, c.data, nil)
|
||||||
x.InitSections(c.code, c.data, nil)
|
|
||||||
dataSectionOffset := x.Sections[1].MemoryOffset - x.Sections[0].MemoryOffset
|
dataSectionOffset := x.Sections[1].MemoryOffset - x.Sections[0].MemoryOffset
|
||||||
|
|
||||||
for dataLabel, address := range dataLabels {
|
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
|
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.
|
// FileAlign returns the file alignment.
|
||||||
func (build *Build) FileAlign() int {
|
func (build *Build) FileAlign() int {
|
||||||
|
if build.OS == Linux {
|
||||||
|
return cacheLineSize
|
||||||
|
}
|
||||||
|
|
||||||
return build.MemoryAlign()
|
return build.MemoryAlign()
|
||||||
}
|
}
|
|
@ -4,7 +4,7 @@ package build
|
||||||
func (build *Build) MemoryAlign() int {
|
func (build *Build) MemoryAlign() int {
|
||||||
switch build.Arch {
|
switch build.Arch {
|
||||||
case ARM:
|
case ARM:
|
||||||
return 0x4000
|
return 0x10000
|
||||||
default:
|
default:
|
||||||
return 0x1000
|
return 0x1000
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,8 +18,7 @@ type ELF struct {
|
||||||
|
|
||||||
// Write writes the ELF64 format to the given writer.
|
// Write writes the ELF64 format to the given writer.
|
||||||
func Write(writer io.WriteSeeker, b *build.Build, codeBytes []byte, dataBytes []byte) {
|
func Write(writer io.WriteSeeker, b *build.Build, codeBytes []byte, dataBytes []byte) {
|
||||||
x := exe.New(HeaderEnd, b.FileAlign(), b.MemoryAlign())
|
x := exe.New(HeaderEnd, b.FileAlign(), b.MemoryAlign(), b.Congruent(), codeBytes, dataBytes)
|
||||||
x.InitSections(codeBytes, dataBytes)
|
|
||||||
code := x.Sections[0]
|
code := x.Sections[0]
|
||||||
data := x.Sections[1]
|
data := x.Sections[1]
|
||||||
|
|
||||||
|
|
|
@ -6,26 +6,25 @@ type Executable struct {
|
||||||
headerEnd int
|
headerEnd int
|
||||||
fileAlign int
|
fileAlign int
|
||||||
memoryAlign int
|
memoryAlign int
|
||||||
|
congruent bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// New creates a new executable.
|
// New creates a new executable.
|
||||||
func New(headerEnd int, fileAlign int, memoryAlign int) *Executable {
|
func New(headerEnd int, fileAlign int, memoryAlign int, congruent bool, raw ...[]byte) *Executable {
|
||||||
return &Executable{
|
exe := &Executable{
|
||||||
|
Sections: make([]*Section, len(raw)),
|
||||||
headerEnd: headerEnd,
|
headerEnd: headerEnd,
|
||||||
fileAlign: fileAlign,
|
fileAlign: fileAlign,
|
||||||
memoryAlign: memoryAlign,
|
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 {
|
for i, data := range raw {
|
||||||
exe.Sections[i] = &Section{Bytes: data}
|
exe.Sections[i] = &Section{Bytes: data}
|
||||||
}
|
}
|
||||||
|
|
||||||
exe.Update()
|
exe.Update()
|
||||||
|
return exe
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update recalculates all section offsets.
|
// Update recalculates all section offsets.
|
||||||
|
@ -34,9 +33,17 @@ func (exe *Executable) Update() {
|
||||||
first.FileOffset, first.Padding = AlignPad(exe.headerEnd, exe.fileAlign)
|
first.FileOffset, first.Padding = AlignPad(exe.headerEnd, exe.fileAlign)
|
||||||
first.MemoryOffset = Align(exe.headerEnd, exe.memoryAlign)
|
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:] {
|
for i, section := range exe.Sections[1:] {
|
||||||
previous := exe.Sections[i]
|
previous := exe.Sections[i]
|
||||||
section.FileOffset, section.Padding = AlignPad(previous.FileOffset+len(previous.Bytes), exe.fileAlign)
|
section.FileOffset, section.Padding = AlignPad(previous.FileOffset+len(previous.Bytes), exe.fileAlign)
|
||||||
section.MemoryOffset = Align(previous.MemoryOffset+len(previous.Bytes), exe.memoryAlign)
|
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"
|
"git.urbach.dev/go/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestExecutable(t *testing.T) {
|
func TestSimple(t *testing.T) {
|
||||||
align := 0x1000
|
align := 32
|
||||||
x := exe.New(1, align, align)
|
x := exe.New(1, align, align, false, []byte{1}, []byte{1})
|
||||||
x.InitSections([]byte{1}, []byte{1})
|
|
||||||
assert.Equal(t, len(x.Sections), 2)
|
assert.Equal(t, len(x.Sections), 2)
|
||||||
assert.Equal(t, x.Sections[0].Padding, align-1)
|
assert.Equal(t, x.Sections[0].Padding, align-1)
|
||||||
assert.Equal(t, x.Sections[0].FileOffset, align)
|
assert.Equal(t, x.Sections[0].FileOffset, align)
|
||||||
assert.Equal(t, x.Sections[1].Padding, align-1)
|
assert.Equal(t, x.Sections[1].Padding, align-1)
|
||||||
assert.Equal(t, x.Sections[1].FileOffset, align*2)
|
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.
|
// Write writes the Mach-O format to the given writer.
|
||||||
func Write(writer io.WriteSeeker, b *build.Build, codeBytes []byte, dataBytes []byte) {
|
func Write(writer io.WriteSeeker, b *build.Build, codeBytes []byte, dataBytes []byte) {
|
||||||
x := exe.New(HeaderEnd, b.FileAlign(), b.MemoryAlign())
|
x := exe.New(HeaderEnd, b.FileAlign(), b.MemoryAlign(), b.Congruent(), codeBytes, dataBytes)
|
||||||
x.InitSections(codeBytes, dataBytes)
|
|
||||||
code := x.Sections[0]
|
code := x.Sections[0]
|
||||||
data := x.Sections[1]
|
data := x.Sections[1]
|
||||||
arch, microArch := Arch(b.Arch)
|
arch, microArch := Arch(b.Arch)
|
||||||
|
|
|
@ -20,8 +20,7 @@ type EXE struct {
|
||||||
|
|
||||||
// Write writes the EXE file to the given writer.
|
// Write writes the EXE file to the given writer.
|
||||||
func Write(writer io.WriteSeeker, b *build.Build, codeBytes []byte, dataBytes []byte, libs dll.List) {
|
func Write(writer io.WriteSeeker, b *build.Build, codeBytes []byte, dataBytes []byte, libs dll.List) {
|
||||||
x := exe.New(HeaderEnd, b.FileAlign(), b.MemoryAlign())
|
x := exe.New(HeaderEnd, b.FileAlign(), b.MemoryAlign(), b.Congruent(), codeBytes, dataBytes, nil)
|
||||||
x.InitSections(codeBytes, dataBytes, nil)
|
|
||||||
code := x.Sections[0]
|
code := x.Sections[0]
|
||||||
data := x.Sections[1]
|
data := x.Sections[1]
|
||||||
imports := x.Sections[2]
|
imports := x.Sections[2]
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue