Improved alignment function
This commit is contained in:
parent
7092cb6626
commit
bec409dbd0
@ -1,3 +1,7 @@
|
|||||||
write(_ Int, _ Pointer, _ Int) -> Int {
|
write(_ Int, _ Pointer, _ Int) -> Int {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
exit(_ Int) {
|
||||||
|
return
|
||||||
|
}
|
@ -337,12 +337,11 @@ restart:
|
|||||||
}
|
}
|
||||||
|
|
||||||
data, dataLabels = a.Data.Finalize()
|
data, dataLabels = a.Data.Finalize()
|
||||||
|
dataStart := config.BaseAddress + config.CodeOffset + len(code)
|
||||||
dataStart := Address(config.BaseAddress) + config.CodeOffset + Address(len(code))
|
dataStart, _ = exe.Align(dataStart, config.Align)
|
||||||
dataStart += exe.Padding(dataStart, config.Align)
|
|
||||||
|
|
||||||
for _, pointer := range dataPointers {
|
for _, pointer := range dataPointers {
|
||||||
address := dataStart + pointer.Resolve()
|
address := Address(dataStart) + pointer.Resolve()
|
||||||
slice := code[pointer.Position : pointer.Position+4]
|
slice := code[pointer.Position : pointer.Position+4]
|
||||||
binary.LittleEndian.PutUint32(slice, uint32(address))
|
binary.LittleEndian.PutUint32(slice, uint32(address))
|
||||||
}
|
}
|
||||||
|
7
src/exe/Align.go
Normal file
7
src/exe/Align.go
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
package exe
|
||||||
|
|
||||||
|
// 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
|
||||||
|
}
|
@ -1,6 +0,0 @@
|
|||||||
package exe
|
|
||||||
|
|
||||||
// Padding calculates the padding needed to align `n` bytes with the specified alignment.
|
|
||||||
func Padding[T int | uint | int64 | uint64 | int32 | uint32](n T, align T) T {
|
|
||||||
return align - (n % align)
|
|
||||||
}
|
|
@ -21,10 +21,8 @@ func Write(writer io.Writer, code []byte, data []byte) {
|
|||||||
const HeaderEnd = HeaderSize + ProgramHeaderSize*2
|
const HeaderEnd = HeaderSize + ProgramHeaderSize*2
|
||||||
|
|
||||||
var (
|
var (
|
||||||
codePadding = exe.Padding(HeaderEnd, config.Align)
|
codeStart, codePadding = exe.Align(HeaderEnd, config.Align)
|
||||||
codeEnd = config.CodeOffset + len(code)
|
dataStart, dataPadding = exe.Align(codeStart+len(code), config.Align)
|
||||||
dataPadding = exe.Padding(codeEnd, config.Align)
|
|
||||||
dataStart = codeEnd + dataPadding
|
|
||||||
)
|
)
|
||||||
|
|
||||||
elf := &ELF{
|
elf := &ELF{
|
||||||
@ -74,11 +72,11 @@ 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{0}, codePadding))
|
writer.Write(bytes.Repeat([]byte{0x00}, codePadding))
|
||||||
writer.Write(code)
|
writer.Write(code)
|
||||||
|
|
||||||
if len(data) > 0 {
|
if len(data) > 0 {
|
||||||
writer.Write(bytes.Repeat([]byte{0}, dataPadding))
|
writer.Write(bytes.Repeat([]byte{0x00}, dataPadding))
|
||||||
writer.Write(data)
|
writer.Write(data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -26,10 +26,8 @@ func Write(writer io.Writer, code []byte, data []byte) {
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
codePadding = exe.Padding(HeaderEnd, config.Align)
|
codeStart, codePadding = exe.Align(HeaderEnd, config.Align)
|
||||||
codeEnd = config.CodeOffset + len(code)
|
dataStart, dataPadding = exe.Align(codeStart+len(code), config.Align)
|
||||||
dataPadding = exe.Padding(codeEnd, config.Align)
|
|
||||||
dataStart = codeEnd + dataPadding
|
|
||||||
)
|
)
|
||||||
|
|
||||||
m := &MachO{
|
m := &MachO{
|
||||||
@ -61,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(codeEnd),
|
SizeInMemory: uint64(codeStart + len(code)),
|
||||||
Offset: 0,
|
Offset: 0,
|
||||||
SizeInFile: uint64(codeEnd),
|
SizeInFile: uint64(codeStart + len(code)),
|
||||||
NumSections: 0,
|
NumSections: 0,
|
||||||
Flag: 0,
|
Flag: 0,
|
||||||
MaxProt: ProtReadable | ProtExecutable,
|
MaxProt: ProtReadable | ProtExecutable,
|
||||||
@ -119,8 +117,8 @@ func Write(writer io.Writer, code []byte, data []byte) {
|
|||||||
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{0}, int(codePadding)))
|
writer.Write(bytes.Repeat([]byte{0x00}, int(codePadding)))
|
||||||
writer.Write(code)
|
writer.Write(code)
|
||||||
writer.Write(bytes.Repeat([]byte{0}, int(dataPadding)))
|
writer.Write(bytes.Repeat([]byte{0x00}, int(dataPadding)))
|
||||||
writer.Write(data)
|
writer.Write(data)
|
||||||
}
|
}
|
||||||
|
@ -9,31 +9,36 @@ import (
|
|||||||
"git.akyoto.dev/cli/q/src/exe"
|
"git.akyoto.dev/cli/q/src/exe"
|
||||||
)
|
)
|
||||||
|
|
||||||
const NumSections = 2
|
|
||||||
|
|
||||||
// EXE is the portable executable format used on Windows.
|
// EXE is the portable executable format used on Windows.
|
||||||
type EXE struct {
|
type EXE struct {
|
||||||
DOSHeader
|
DOSHeader
|
||||||
NTHeader
|
NTHeader
|
||||||
OptionalHeader64
|
OptionalHeader64
|
||||||
Sections [NumSections]SectionHeader
|
Sections []SectionHeader
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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) {
|
func Write(writer io.Writer, code []byte, data []byte) {
|
||||||
const (
|
NumSections := 1
|
||||||
HeaderEnd = DOSHeaderSize + NTHeaderSize + OptionalHeader64Size + SectionHeaderSize*NumSections
|
|
||||||
)
|
if len(data) != 0 {
|
||||||
|
NumSections += 1
|
||||||
|
}
|
||||||
|
|
||||||
|
HeaderEnd := DOSHeaderSize + NTHeaderSize + OptionalHeader64Size + SectionHeaderSize*NumSections
|
||||||
|
|
||||||
var (
|
var (
|
||||||
codePadding = exe.Padding(HeaderEnd, config.Align)
|
codeStart, codePadding = exe.Align(HeaderEnd, config.Align)
|
||||||
codeEnd = config.CodeOffset + len(code)
|
dataStart, dataPadding = exe.Align(codeStart+len(code), config.Align)
|
||||||
dataPadding = exe.Padding(codeEnd, config.Align)
|
|
||||||
dataStart = codeEnd + dataPadding
|
|
||||||
)
|
)
|
||||||
|
|
||||||
imageSize := dataStart + len(data)
|
imageSize := codeStart + len(code)
|
||||||
imageSize += exe.Padding(imageSize, config.Align)
|
|
||||||
|
if len(data) != 0 {
|
||||||
|
imageSize = dataStart + len(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
imageSize, _ = exe.Align(imageSize, config.Align)
|
||||||
|
|
||||||
pe := &EXE{
|
pe := &EXE{
|
||||||
DOSHeader: DOSHeader{
|
DOSHeader: DOSHeader{
|
||||||
@ -43,7 +48,7 @@ func Write(writer io.Writer, code []byte, data []byte) {
|
|||||||
NTHeader: NTHeader{
|
NTHeader: NTHeader{
|
||||||
Signature: [4]byte{'P', 'E', 0, 0},
|
Signature: [4]byte{'P', 'E', 0, 0},
|
||||||
Machine: IMAGE_FILE_MACHINE_AMD64,
|
Machine: IMAGE_FILE_MACHINE_AMD64,
|
||||||
NumberOfSections: NumSections,
|
NumberOfSections: uint16(NumSections),
|
||||||
SizeOfOptionalHeader: OptionalHeader64Size,
|
SizeOfOptionalHeader: OptionalHeader64Size,
|
||||||
Characteristics: IMAGE_FILE_EXECUTABLE_IMAGE | IMAGE_FILE_LARGE_ADDRESS_AWARE,
|
Characteristics: IMAGE_FILE_EXECUTABLE_IMAGE | IMAGE_FILE_LARGE_ADDRESS_AWARE,
|
||||||
},
|
},
|
||||||
@ -61,7 +66,7 @@ func Write(writer io.Writer, code []byte, data []byte) {
|
|||||||
MajorSubsystemVersion: 0x06,
|
MajorSubsystemVersion: 0x06,
|
||||||
SizeOfImage: uint32(imageSize),
|
SizeOfImage: uint32(imageSize),
|
||||||
SizeOfHeaders: config.CodeOffset, // section bodies begin here
|
SizeOfHeaders: config.CodeOffset, // section bodies begin here
|
||||||
Subsystem: IMAGE_SUBSYSTEM_WINDOWS_GUI,
|
Subsystem: IMAGE_SUBSYSTEM_WINDOWS_CUI,
|
||||||
DllCharacteristics: IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA | IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE | IMAGE_DLLCHARACTERISTICS_NX_COMPAT | IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE,
|
DllCharacteristics: IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA | IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE | IMAGE_DLLCHARACTERISTICS_NX_COMPAT | IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE,
|
||||||
SizeOfStackReserve: 0x100000,
|
SizeOfStackReserve: 0x100000,
|
||||||
SizeOfStackCommit: 0x1000,
|
SizeOfStackCommit: 0x1000,
|
||||||
@ -87,7 +92,7 @@ func Write(writer io.Writer, code []byte, data []byte) {
|
|||||||
{VirtualAddress: 0, Size: 0},
|
{VirtualAddress: 0, Size: 0},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Sections: [NumSections]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)),
|
||||||
@ -110,10 +115,13 @@ func Write(writer io.Writer, code []byte, data []byte) {
|
|||||||
binary.Write(writer, binary.LittleEndian, &pe.DOSHeader)
|
binary.Write(writer, binary.LittleEndian, &pe.DOSHeader)
|
||||||
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[:NumSections])
|
||||||
|
|
||||||
writer.Write(bytes.Repeat([]byte{0}, int(codePadding)))
|
writer.Write(bytes.Repeat([]byte{0x00}, int(codePadding)))
|
||||||
writer.Write(code)
|
writer.Write(code)
|
||||||
writer.Write(bytes.Repeat([]byte{0}, int(dataPadding)))
|
|
||||||
|
if len(data) != 0 {
|
||||||
|
writer.Write(bytes.Repeat([]byte{0x00}, int(dataPadding)))
|
||||||
writer.Write(data)
|
writer.Write(data)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
@ -1,5 +1,10 @@
|
|||||||
## Portable Executable
|
## Portable Executable
|
||||||
|
|
||||||
|
## Notes
|
||||||
|
|
||||||
|
Unlike Linux, Windows does not ignore zero-length sections and will fail loading them because they don't exist within the file.
|
||||||
|
Adding a single byte to the section can fix this problem, but it's easier to just remove the section header entirely.
|
||||||
|
|
||||||
## Links
|
## Links
|
||||||
|
|
||||||
- https://learn.microsoft.com/en-us/previous-versions/ms809762(v=msdn.10)
|
- https://learn.microsoft.com/en-us/previous-versions/ms809762(v=msdn.10)
|
||||||
|
Loading…
Reference in New Issue
Block a user