Added exe package to manage sections

This commit is contained in:
2025-03-08 22:14:24 +01:00
parent 919d94e0f4
commit b67f3b0977
16 changed files with 207 additions and 134 deletions

View File

@ -3,7 +3,7 @@ package asmc
import ( import (
"git.urbach.dev/cli/q/src/config" "git.urbach.dev/cli/q/src/config"
"git.urbach.dev/cli/q/src/elf" "git.urbach.dev/cli/q/src/elf"
"git.urbach.dev/cli/q/src/fs" "git.urbach.dev/cli/q/src/exe"
"git.urbach.dev/cli/q/src/macho" "git.urbach.dev/cli/q/src/macho"
"git.urbach.dev/cli/q/src/pe" "git.urbach.dev/cli/q/src/pe"
) )
@ -21,6 +21,5 @@ func codeOffset() Address {
headerEnd = pe.HeaderEnd headerEnd = pe.HeaderEnd
} }
offset, _ := fs.Align(headerEnd, config.Align) return exe.Align(headerEnd, config.FileAlign)
return offset
} }

View File

@ -13,4 +13,5 @@ type compiler struct {
dlls dll.List dlls dll.List
codeStart Address codeStart Address
dataStart Address dataStart Address
importsStart Address
} }

View File

@ -8,15 +8,15 @@ import (
) )
func (c *compiler) dllCall(x asm.Instruction) { func (c *compiler) dllCall(x asm.Instruction) {
size := 4
c.code = x86.CallAt(c.code, 0x00_00_00_00) c.code = x86.CallAt(c.code, 0x00_00_00_00)
position := len(c.code) - size next := Address(len(c.code))
position := next - 4
label := x.Data.(*asm.Label) label := x.Data.(*asm.Label)
pointer := &pointer{ pointer := &pointer{
Position: Address(position), Position: Address(position),
OpSize: 2, OpSize: 2,
Size: uint8(size), Size: 4,
} }
pointer.Resolve = func() Address { pointer.Resolve = func() Address {
@ -29,7 +29,9 @@ func (c *compiler) dllCall(x asm.Instruction) {
panic("unknown DLL function " + label.Name) panic("unknown DLL function " + label.Name)
} }
return Address(index * 8) destination := c.importsStart + Address(index*8)
from := c.codeStart + next
return destination - from
} }
c.dllPointers = append(c.dllPointers, pointer) c.dllPointers = append(c.dllPointers, pointer)

View File

@ -6,7 +6,7 @@ import (
"slices" "slices"
"git.urbach.dev/cli/q/src/config" "git.urbach.dev/cli/q/src/config"
"git.urbach.dev/cli/q/src/fs" "git.urbach.dev/cli/q/src/exe"
"git.urbach.dev/cli/q/src/sizeof" "git.urbach.dev/cli/q/src/sizeof"
) )
@ -77,7 +77,9 @@ restart:
} }
} }
c.dataStart, _ = fs.Align(c.codeStart+Address(len(c.code)), config.Align) sections := exe.MakeSections(int(codeOffset()), c.code, c.data, nil)
data := sections[1]
c.dataStart = Address(data.MemoryOffset)
for _, pointer := range c.dataPointers { for _, pointer := range c.dataPointers {
address := pointer.Resolve() address := pointer.Resolve()
@ -86,14 +88,13 @@ restart:
} }
if config.TargetOS == config.Windows { if config.TargetOS == config.Windows {
importsStart, _ := fs.Align(c.dataStart+Address(len(c.data)), config.Align) imports := sections[2]
c.importsStart = Address(imports.MemoryOffset)
for _, pointer := range c.dllPointers { for _, pointer := range c.dllPointers {
destination := importsStart + pointer.Resolve() address := pointer.Resolve()
from := c.codeStart + pointer.Position + Address(pointer.Size) slice := c.code[pointer.Position : pointer.Position+Address(pointer.Size)]
offset := destination - from binary.LittleEndian.PutUint32(slice, uint32(address))
slice := c.code[pointer.Position : pointer.Position+4]
binary.LittleEndian.PutUint32(slice, uint32(offset))
} }
} }
} }

View File

@ -7,6 +7,9 @@ const (
// The base address is the virtual address for our ELF file. // The base address is the virtual address for our ELF file.
BaseAddress = 0x40 * MinAddress BaseAddress = 0x40 * MinAddress
// Align is the alignment of the sections and it must be a multiple of the page size. // FileAlign is the alignment of the sections in the file.
Align = 0x1000 FileAlign = 0x4000
// MemoryAlign is the alignment of the sections in memory and it must be a multiple of the page size.
MemoryAlign = 0x4000
) )

View File

@ -6,7 +6,7 @@ import (
"io" "io"
"git.urbach.dev/cli/q/src/config" "git.urbach.dev/cli/q/src/config"
"git.urbach.dev/cli/q/src/fs" "git.urbach.dev/cli/q/src/exe"
) )
const HeaderEnd = HeaderSize + ProgramHeaderSize*2 const HeaderEnd = HeaderSize + ProgramHeaderSize*2
@ -21,19 +21,11 @@ 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.Writer, code []byte, data []byte) { func Write(writer io.Writer, codeBytes []byte, dataBytes []byte) {
var ( sections := exe.MakeSections(HeaderEnd, codeBytes, dataBytes)
codeStart, codePadding = fs.Align(HeaderEnd, config.Align) code := sections[0]
dataStart, dataPadding = fs.Align(codeStart+len(code), config.Align) data := sections[1]
arch int16 arch := cpu()
)
switch config.TargetArch {
case config.ARM:
arch = ArchitectureARM64
case config.X86:
arch = ArchitectureAMD64
}
elf := &ELF{ elf := &ELF{
Header: Header{ Header: Header{
@ -46,7 +38,7 @@ func Write(writer io.Writer, code []byte, data []byte) {
Type: TypeExecutable, Type: TypeExecutable,
Architecture: arch, Architecture: arch,
FileVersion: 1, FileVersion: 1,
EntryPointInMemory: int64(config.BaseAddress + codeStart), EntryPointInMemory: int64(config.BaseAddress + code.MemoryOffset),
ProgramHeaderOffset: HeaderSize, ProgramHeaderOffset: HeaderSize,
SectionHeaderOffset: 0, SectionHeaderOffset: 0,
Flags: 0, Flags: 0,
@ -58,24 +50,22 @@ func Write(writer io.Writer, code []byte, data []byte) {
SectionNameStringTableIndex: 0, SectionNameStringTableIndex: 0,
}, },
CodeHeader: ProgramHeader{ CodeHeader: ProgramHeader{
Type: ProgramTypeLOAD, Type: ProgramTypeLOAD,
Flags: ProgramFlagsExecutable | ProgramFlagsReadable, Flags: ProgramFlagsExecutable | ProgramFlagsReadable,
Offset: int64(codeStart), Offset: int64(code.FileOffset),
VirtualAddress: int64(config.BaseAddress + codeStart), VirtualAddress: int64(config.BaseAddress + code.MemoryOffset),
PhysicalAddress: int64(config.BaseAddress + codeStart), SizeInFile: int64(len(code.Bytes)),
SizeInFile: int64(len(code)), SizeInMemory: int64(len(code.Bytes)),
SizeInMemory: int64(len(code)), Align: config.MemoryAlign,
Align: config.Align,
}, },
DataHeader: ProgramHeader{ DataHeader: ProgramHeader{
Type: ProgramTypeLOAD, Type: ProgramTypeLOAD,
Flags: ProgramFlagsReadable, Flags: ProgramFlagsReadable,
Offset: int64(dataStart), Offset: int64(data.FileOffset),
VirtualAddress: int64(config.BaseAddress + dataStart), VirtualAddress: int64(config.BaseAddress + data.MemoryOffset),
PhysicalAddress: int64(config.BaseAddress + dataStart), SizeInFile: int64(len(data.Bytes)),
SizeInFile: int64(len(data)), SizeInMemory: int64(len(data.Bytes)),
SizeInMemory: int64(len(data)), Align: config.MemoryAlign,
Align: config.Align,
}, },
} }
@ -86,10 +76,10 @@ func Write(writer io.Writer, code []byte, data []byte) {
binary.Write(writer, binary.LittleEndian, &elf.Header) binary.Write(writer, binary.LittleEndian, &elf.Header)
binary.Write(writer, binary.LittleEndian, &elf.CodeHeader) binary.Write(writer, binary.LittleEndian, &elf.CodeHeader)
binary.Write(writer, binary.LittleEndian, &elf.DataHeader) binary.Write(writer, binary.LittleEndian, &elf.DataHeader)
writer.Write(bytes.Repeat([]byte{0x00}, codePadding)) writer.Write(bytes.Repeat([]byte{0x00}, code.Padding))
writer.Write(code) writer.Write(code.Bytes)
writer.Write(bytes.Repeat([]byte{0x00}, dataPadding)) writer.Write(bytes.Repeat([]byte{0x00}, data.Padding))
writer.Write(data) writer.Write(data.Bytes)
if config.Sections { if config.Sections {
writer.Write(elf.StringTable) writer.Write(elf.StringTable)

15
src/elf/cpu.go Normal file
View File

@ -0,0 +1,15 @@
package elf
import "git.urbach.dev/cli/q/src/config"
// cpu returns the CPU architecture used in the ELF header.
func cpu() int16 {
switch config.TargetArch {
case config.ARM:
return ArchitectureARM64
case config.X86:
return ArchitectureAMD64
default:
panic("unknown architecture")
}
}

12
src/exe/Align.go Normal file
View 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
}

31
src/exe/Executable.go Normal file
View File

@ -0,0 +1,31 @@
package exe
import "git.urbach.dev/cli/q/src/config"
// Executable is a generic definition of the binary that later gets translated to OS-specific formats.
type Executable []*Section
// MakeSections creates new sections.
func MakeSections(headerEnd int, raw ...[]byte) Executable {
sections := make(Executable, len(raw))
for i, data := range raw {
sections[i] = &Section{Bytes: data}
}
sections.Update(headerEnd)
return sections
}
// Update recalculates all section offsets.
func (sections Executable) Update(headerEnd int) {
first := sections[0]
first.FileOffset, first.Padding = AlignPad(headerEnd, config.FileAlign)
first.MemoryOffset = Align(headerEnd, config.MemoryAlign)
for i, section := range sections[1:] {
previous := sections[i]
section.FileOffset, section.Padding = AlignPad(previous.FileOffset+len(previous.Bytes), config.FileAlign)
section.MemoryOffset = Align(previous.MemoryOffset+len(previous.Bytes), config.MemoryAlign)
}
}

9
src/exe/Section.go Normal file
View 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
}

View File

@ -1,7 +0,0 @@
package fs
// Align calculates the next aligned address and the padding needed.
func Align[T int | uint | int64 | uint64 | int32 | uint32](n T, alignment T) (T, T) {
aligned := (n + (alignment - 1)) & ^(alignment - 1)
return aligned, aligned - n
}

View File

@ -6,7 +6,7 @@ import (
"io" "io"
"git.urbach.dev/cli/q/src/config" "git.urbach.dev/cli/q/src/config"
"git.urbach.dev/cli/q/src/fs" "git.urbach.dev/cli/q/src/exe"
) )
const ( const (
@ -24,22 +24,11 @@ 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.Writer, code []byte, data []byte) { func Write(writer io.Writer, codeBytes []byte, dataBytes []byte) {
var ( sections := exe.MakeSections(HeaderEnd, codeBytes, dataBytes)
codeStart, codePadding = fs.Align(HeaderEnd, config.Align) code := sections[0]
dataStart, dataPadding = fs.Align(codeStart+len(code), config.Align) data := sections[1]
arch CPU arch, microArch := cpu()
microArch uint32
)
switch config.TargetArch {
case config.ARM:
arch = CPU_ARM_64
microArch = CPU_SUBTYPE_ARM64_ALL | 0x80000000
case config.X86:
arch = CPU_X86_64
microArch = CPU_SUBTYPE_X86_64_ALL | 0x80000000
}
m := &MachO{ m := &MachO{
Header: Header{ Header: Header{
@ -70,9 +59,9 @@ func Write(writer io.Writer, code []byte, data []byte) {
Length: Segment64Size, Length: Segment64Size,
Name: [16]byte{'_', '_', 'T', 'E', 'X', 'T'}, Name: [16]byte{'_', '_', 'T', 'E', 'X', 'T'},
Address: config.BaseAddress, Address: config.BaseAddress,
SizeInMemory: uint64(codeStart + len(code)), SizeInMemory: uint64(code.MemoryOffset + len(code.Bytes)),
Offset: 0, Offset: 0,
SizeInFile: uint64(codeStart + len(code)), SizeInFile: uint64(code.FileOffset + len(code.Bytes)),
NumSections: 0, NumSections: 0,
Flag: 0, Flag: 0,
MaxProt: ProtReadable | ProtExecutable, MaxProt: ProtReadable | ProtExecutable,
@ -82,10 +71,10 @@ func Write(writer io.Writer, code []byte, data []byte) {
LoadCommand: LcSegment64, LoadCommand: LcSegment64,
Length: Segment64Size, Length: Segment64Size,
Name: [16]byte{'_', '_', 'D', 'A', 'T', 'A'}, Name: [16]byte{'_', '_', 'D', 'A', 'T', 'A'},
Address: uint64(config.BaseAddress + dataStart), Address: uint64(config.BaseAddress + data.MemoryOffset),
SizeInMemory: uint64(len(data)), SizeInMemory: uint64(len(data.Bytes)),
Offset: uint64(dataStart), Offset: uint64(data.FileOffset),
SizeInFile: uint64(len(data)), SizeInFile: uint64(len(data.Bytes)),
NumSections: 0, NumSections: 0,
Flag: 0, Flag: 0,
MaxProt: ProtReadable, MaxProt: ProtReadable,
@ -113,7 +102,7 @@ func Write(writer io.Writer, code []byte, data []byte) {
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
uint32(config.BaseAddress + codeStart), 0, uint32(config.BaseAddress + code.MemoryOffset), 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
@ -127,8 +116,8 @@ func Write(writer io.Writer, code []byte, data []byte) {
binary.Write(writer, binary.LittleEndian, &m.CodeHeader) binary.Write(writer, binary.LittleEndian, &m.CodeHeader)
binary.Write(writer, binary.LittleEndian, &m.DataHeader) binary.Write(writer, binary.LittleEndian, &m.DataHeader)
binary.Write(writer, binary.LittleEndian, &m.UnixThread) binary.Write(writer, binary.LittleEndian, &m.UnixThread)
writer.Write(bytes.Repeat([]byte{0x00}, codePadding)) writer.Write(bytes.Repeat([]byte{0x00}, code.Padding))
writer.Write(code) writer.Write(code.Bytes)
writer.Write(bytes.Repeat([]byte{0x00}, dataPadding)) writer.Write(bytes.Repeat([]byte{0x00}, data.Padding))
writer.Write(data) writer.Write(data.Bytes)
} }

15
src/macho/cpu.go Normal file
View File

@ -0,0 +1,15 @@
package macho
import "git.urbach.dev/cli/q/src/config"
// cpu returns the CPU architecture used in the Mach-O header.
func cpu() (CPU, uint32) {
switch config.TargetArch {
case config.ARM:
return CPU_ARM_64, CPU_SUBTYPE_ARM64_ALL | 0x80000000
case config.X86:
return CPU_X86_64, CPU_SUBTYPE_X86_64_ALL | 0x80000000
default:
panic("unknown architecture")
}
}

View File

@ -7,7 +7,7 @@ import (
"git.urbach.dev/cli/q/src/config" "git.urbach.dev/cli/q/src/config"
"git.urbach.dev/cli/q/src/dll" "git.urbach.dev/cli/q/src/dll"
"git.urbach.dev/cli/q/src/fs" "git.urbach.dev/cli/q/src/exe"
) )
const ( const (
@ -24,31 +24,30 @@ 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.Writer, code []byte, data []byte, dlls dll.List) { func Write(writer io.Writer, codeBytes []byte, dataBytes []byte, dlls dll.List) {
var ( var (
codeStart, codePadding = fs.Align(HeaderEnd, config.Align) sections = exe.MakeSections(HeaderEnd, codeBytes, dataBytes, nil)
dataStart, dataPadding = fs.Align(codeStart+len(code), config.Align) code = sections[0]
importsStart, importsPadding = fs.Align(dataStart+len(data), config.Align) data = sections[1]
subSystem = IMAGE_SUBSYSTEM_WINDOWS_CUI imports = sections[2]
imports, dllData, dllImports, dllDataStart = importLibraries(dlls, importsStart) subSystem = IMAGE_SUBSYSTEM_WINDOWS_CUI
importDirectoryStart = dllDataStart + len(dllData) arch = cpu()
importDirectorySize = DLLImportSize * len(dllImports)
importSectionSize = len(imports)*8 + len(dllData) + importDirectorySize
imageSize, _ = fs.Align(importsStart+importSectionSize, config.Align)
arch uint16
) )
importsData, dllData, dllImports, dllDataStart := importLibraries(dlls, imports.FileOffset)
buffer := bytes.Buffer{}
binary.Write(&buffer, binary.LittleEndian, &importsData)
binary.Write(&buffer, binary.LittleEndian, &dllData)
binary.Write(&buffer, binary.LittleEndian, &dllImports)
imports.Bytes = buffer.Bytes()
importDirectoryStart := dllDataStart + len(dllData)
importDirectorySize := DLLImportSize * len(dllImports)
imageSize := exe.Align(imports.MemoryOffset+len(imports.Bytes), config.MemoryAlign)
if dlls.Contains("user32") { if dlls.Contains("user32") {
subSystem = IMAGE_SUBSYSTEM_WINDOWS_GUI subSystem = IMAGE_SUBSYSTEM_WINDOWS_GUI
} }
switch config.TargetArch {
case config.ARM:
arch = IMAGE_FILE_MACHINE_ARM64
case config.X86:
arch = IMAGE_FILE_MACHINE_AMD64
}
pe := &EXE{ pe := &EXE{
DOSHeader: DOSHeader{ DOSHeader: DOSHeader{
Magic: [4]byte{'M', 'Z', 0, 0}, Magic: [4]byte{'M', 'Z', 0, 0},
@ -68,14 +67,14 @@ func Write(writer io.Writer, code []byte, data []byte, dlls dll.List) {
Magic: 0x020B, // PE32+ / 64-bit executable Magic: 0x020B, // PE32+ / 64-bit executable
MajorLinkerVersion: 0x0E, MajorLinkerVersion: 0x0E,
MinorLinkerVersion: 0x16, MinorLinkerVersion: 0x16,
SizeOfCode: uint32(len(code)), SizeOfCode: uint32(len(code.Bytes)),
SizeOfInitializedData: 0, SizeOfInitializedData: 0,
SizeOfUninitializedData: 0, SizeOfUninitializedData: 0,
AddressOfEntryPoint: uint32(codeStart), AddressOfEntryPoint: uint32(code.MemoryOffset),
BaseOfCode: uint32(codeStart), BaseOfCode: uint32(code.MemoryOffset),
ImageBase: config.BaseAddress, ImageBase: config.BaseAddress,
SectionAlignment: config.Align, // power of 2, must be greater than or equal to FileAlignment SectionAlignment: config.MemoryAlign, // power of 2, must be greater than or equal to FileAlignment
FileAlignment: config.Align, // power of 2 FileAlignment: config.FileAlign, // power of 2
MajorOperatingSystemVersion: 0x06, MajorOperatingSystemVersion: 0x06,
MinorOperatingSystemVersion: 0, MinorOperatingSystemVersion: 0,
MajorImageVersion: 0, MajorImageVersion: 0,
@ -83,8 +82,8 @@ func Write(writer io.Writer, code []byte, data []byte, dlls dll.List) {
MajorSubsystemVersion: 0x06, MajorSubsystemVersion: 0x06,
MinorSubsystemVersion: 0, MinorSubsystemVersion: 0,
Win32VersionValue: 0, Win32VersionValue: 0,
SizeOfImage: uint32(imageSize), SizeOfImage: uint32(imageSize), // a multiple of SectionAlignment
SizeOfHeaders: uint32(codeStart), // section bodies begin here SizeOfHeaders: uint32(code.FileOffset), // section bodies begin here
CheckSum: 0, CheckSum: 0,
Subsystem: uint16(subSystem), Subsystem: uint16(subSystem),
DllCharacteristics: IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA | IMAGE_DLLCHARACTERISTICS_NX_COMPAT | IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE, // IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE DllCharacteristics: IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA | IMAGE_DLLCHARACTERISTICS_NX_COMPAT | IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE, // IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE
@ -107,7 +106,7 @@ func Write(writer io.Writer, code []byte, data []byte, dlls dll.List) {
{VirtualAddress: 0, Size: 0}, {VirtualAddress: 0, Size: 0},
{VirtualAddress: 0, Size: 0}, {VirtualAddress: 0, Size: 0},
{VirtualAddress: 0, Size: 0}, {VirtualAddress: 0, Size: 0},
{VirtualAddress: uint32(importsStart), Size: uint32(len(imports) * 8)}, // RVA of the import address table {VirtualAddress: uint32(imports.MemoryOffset), Size: uint32(len(importsData) * 8)}, // RVA of the import address table
{VirtualAddress: 0, Size: 0}, {VirtualAddress: 0, Size: 0},
{VirtualAddress: 0, Size: 0}, {VirtualAddress: 0, Size: 0},
{VirtualAddress: 0, Size: 0}, {VirtualAddress: 0, Size: 0},
@ -116,26 +115,26 @@ func Write(writer io.Writer, code []byte, data []byte, dlls dll.List) {
Sections: []SectionHeader{ Sections: []SectionHeader{
{ {
Name: [8]byte{'.', 't', 'e', 'x', 't'}, Name: [8]byte{'.', 't', 'e', 'x', 't'},
VirtualSize: uint32(len(code)), VirtualSize: uint32(len(code.Bytes)),
VirtualAddress: uint32(codeStart), VirtualAddress: uint32(code.MemoryOffset),
RawSize: uint32(len(code)), // must be a multiple of FileAlignment RawSize: uint32(len(code.Bytes)), // must be a multiple of FileAlignment
RawAddress: uint32(codeStart), // must be a multiple of FileAlignment RawAddress: uint32(code.FileOffset), // must be a multiple of FileAlignment
Characteristics: IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ, Characteristics: IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ,
}, },
{ {
Name: [8]byte{'.', 'r', 'd', 'a', 't', 'a'}, Name: [8]byte{'.', 'r', 'd', 'a', 't', 'a'},
VirtualSize: uint32(len(data)), VirtualSize: uint32(len(data.Bytes)),
VirtualAddress: uint32(dataStart), VirtualAddress: uint32(data.MemoryOffset),
RawSize: uint32(len(data)), RawSize: uint32(len(data.Bytes)),
RawAddress: uint32(dataStart), RawAddress: uint32(data.FileOffset),
Characteristics: IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ, Characteristics: IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ,
}, },
{ {
Name: [8]byte{'.', 'i', 'd', 'a', 't', 'a'}, Name: [8]byte{'.', 'i', 'd', 'a', 't', 'a'},
VirtualSize: uint32(importSectionSize), VirtualSize: uint32(len(imports.Bytes)),
VirtualAddress: uint32(importsStart), VirtualAddress: uint32(imports.MemoryOffset),
RawSize: uint32(importSectionSize), RawSize: uint32(len(imports.Bytes)),
RawAddress: uint32(importsStart), RawAddress: uint32(imports.FileOffset),
Characteristics: IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ, Characteristics: IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ,
}, },
}, },
@ -145,12 +144,10 @@ func Write(writer io.Writer, code []byte, data []byte, dlls dll.List) {
binary.Write(writer, binary.LittleEndian, &pe.NTHeader) binary.Write(writer, binary.LittleEndian, &pe.NTHeader)
binary.Write(writer, binary.LittleEndian, &pe.OptionalHeader64) binary.Write(writer, binary.LittleEndian, &pe.OptionalHeader64)
binary.Write(writer, binary.LittleEndian, &pe.Sections) binary.Write(writer, binary.LittleEndian, &pe.Sections)
writer.Write(bytes.Repeat([]byte{0x00}, codePadding)) writer.Write(bytes.Repeat([]byte{0x00}, code.Padding))
writer.Write(code) writer.Write(code.Bytes)
writer.Write(bytes.Repeat([]byte{0x00}, dataPadding)) writer.Write(bytes.Repeat([]byte{0x00}, data.Padding))
writer.Write(data) writer.Write(data.Bytes)
writer.Write(bytes.Repeat([]byte{0x00}, importsPadding)) writer.Write(bytes.Repeat([]byte{0x00}, imports.Padding))
binary.Write(writer, binary.LittleEndian, &imports) writer.Write(imports.Bytes)
binary.Write(writer, binary.LittleEndian, &dllData)
binary.Write(writer, binary.LittleEndian, &dllImports)
} }

15
src/pe/cpu.go Normal file
View File

@ -0,0 +1,15 @@
package pe
import "git.urbach.dev/cli/q/src/config"
// cpu returns the CPU architecture used in the PE header.
func cpu() uint16 {
switch config.TargetArch {
case config.ARM:
return IMAGE_FILE_MACHINE_ARM64
case config.X86:
return IMAGE_FILE_MACHINE_AMD64
default:
panic("unknown architecture")
}
}

View File

@ -13,6 +13,7 @@
- [data](data) - Data container that can re-use existing data (e.g. the `Hello` in `Hello World`) - [data](data) - Data container that can re-use existing data (e.g. the `Hello` in `Hello World`)
- [dll](dll) - DLL support for Windows systems (w.i.p.) - [dll](dll) - DLL support for Windows systems (w.i.p.)
- [elf](elf) - ELF format for Linux executables - [elf](elf) - ELF format for Linux executables
- [exe](exe) - Generic executable format to calculate section offsets
- [errors](errors) - Error types - [errors](errors) - Error types
- [eval](eval) - Evaluates expressions - [eval](eval) - Evaluates expressions
- [expression](expression) - Expression parser generating trees with the `Parse` function - [expression](expression) - Expression parser generating trees with the `Parse` function