Improved section offset calculation

This commit is contained in:
Eduard Urbach 2025-01-20 13:51:47 +01:00
parent e2a6a31d8e
commit 4b7c9f387d
Signed by: akyoto
GPG Key ID: C874F672B1AF20C0
7 changed files with 56 additions and 38 deletions

2
go.mod
View File

@ -7,4 +7,4 @@ require (
git.akyoto.dev/go/color v0.1.1
)
require golang.org/x/sys v0.24.0 // indirect
require golang.org/x/sys v0.29.0 // indirect

4
go.sum
View File

@ -2,5 +2,5 @@ git.akyoto.dev/go/assert v0.1.3 h1:QwCUbmG4aZYsNk/OuRBz1zWVKmGlDUHhOnnDBfn8Qw8=
git.akyoto.dev/go/assert v0.1.3/go.mod h1:0GzMaM0eURuDwtGkJJkCsI7r2aUKr+5GmWNTFPgDocM=
git.akyoto.dev/go/color v0.1.1 h1:mMAoMIwLBPNy7ocRSxdsCFs7onPC3GfDEiJErCneqRE=
git.akyoto.dev/go/color v0.1.1/go.mod h1:ywOjoD0O0sk6bIn92uAJf7mErlEFCuQInL84y4Lqi3Q=
golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg=
golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU=
golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=

View File

@ -8,7 +8,10 @@ import (
"git.akyoto.dev/cli/q/src/config"
"git.akyoto.dev/cli/q/src/dll"
"git.akyoto.dev/cli/q/src/elf"
"git.akyoto.dev/cli/q/src/fs"
"git.akyoto.dev/cli/q/src/macho"
"git.akyoto.dev/cli/q/src/pe"
"git.akyoto.dev/cli/q/src/sizeof"
"git.akyoto.dev/cli/q/src/x64"
)
@ -370,21 +373,40 @@ restart:
}
}
headerEnd := Address(0)
switch config.TargetOS {
case "linux":
headerEnd = elf.HeaderEnd
case "macos":
headerEnd = macho.HeaderEnd
case "windows":
headerEnd = pe.HeaderEnd
}
codeStart, _ := fs.Align(headerEnd, config.Align)
dataStart, _ := fs.Align(codeStart+Address(len(code)), config.Align)
data, dataLabels = a.Data.Finalize()
dataStart := config.BaseAddress + config.CodeOffset + len(code)
dataStart, _ = fs.Align(dataStart, config.Align)
for _, pointer := range dataPointers {
address := Address(dataStart) + pointer.Resolve()
address := config.BaseAddress + Address(dataStart) + pointer.Resolve()
slice := code[pointer.Position : pointer.Position+4]
binary.LittleEndian.PutUint32(slice, uint32(address))
}
for _, pointer := range dllPointers {
destination := Address(0x3000) + pointer.Resolve()
address := destination - Address(config.CodeOffset+pointer.Position+Address(pointer.Size))
slice := code[pointer.Position : pointer.Position+4]
binary.LittleEndian.PutUint32(slice, uint32(address))
if config.TargetOS == "windows" {
if len(data) == 0 {
data = []byte{0}
}
importsStart, _ := fs.Align(dataStart+Address(len(data)), config.Align)
for _, pointer := range dllPointers {
destination := Address(importsStart) + pointer.Resolve()
delta := destination - Address(codeStart+pointer.Position+Address(pointer.Size))
slice := code[pointer.Position : pointer.Position+4]
binary.LittleEndian.PutUint32(slice, uint32(delta))
}
}
return code, data

View File

@ -9,11 +9,8 @@ const (
// The base address is the virtual address for our ELF file.
BaseAddress = 0x40 * MinAddress
// Align decides the alignment of the sections and it must be a multiple of the page size.
// Align is the alignment of the sections and it must be a multiple of the page size.
Align = 0x1000
// The code offset is the offset of the executable machine code within the file.
CodeOffset = Align
)
var (

View File

@ -9,6 +9,8 @@ import (
"git.akyoto.dev/cli/q/src/fs"
)
const HeaderEnd = HeaderSize + ProgramHeaderSize*2
// ELF represents an ELF file.
type ELF struct {
Header
@ -18,8 +20,6 @@ type ELF struct {
// Write writes the ELF64 format to the given writer.
func Write(writer io.Writer, code []byte, data []byte) {
const HeaderEnd = HeaderSize + ProgramHeaderSize*2
var (
codeStart, codePadding = fs.Align(HeaderEnd, config.Align)
dataStart, dataPadding = fs.Align(codeStart+len(code), config.Align)
@ -36,7 +36,7 @@ func Write(writer io.Writer, code []byte, data []byte) {
Type: TypeExecutable,
Architecture: ArchitectureAMD64,
FileVersion: 1,
EntryPointInMemory: config.BaseAddress + config.CodeOffset,
EntryPointInMemory: int64(config.BaseAddress + codeStart),
ProgramHeaderOffset: HeaderSize,
SectionHeaderOffset: 0,
Flags: 0,
@ -50,9 +50,9 @@ func Write(writer io.Writer, code []byte, data []byte) {
CodeHeader: ProgramHeader{
Type: ProgramTypeLOAD,
Flags: ProgramFlagsExecutable | ProgramFlagsReadable,
Offset: config.CodeOffset,
VirtualAddress: config.BaseAddress + config.CodeOffset,
PhysicalAddress: config.BaseAddress + config.CodeOffset,
Offset: int64(codeStart),
VirtualAddress: int64(config.BaseAddress + codeStart),
PhysicalAddress: int64(config.BaseAddress + codeStart),
SizeInFile: int64(len(code)),
SizeInMemory: int64(len(code)),
Align: config.Align,

View File

@ -9,6 +9,11 @@ import (
"git.akyoto.dev/cli/q/src/fs"
)
const (
SizeCommands = Segment64Size*3 + ThreadSize
HeaderEnd = HeaderSize + SizeCommands
)
// MachO is the executable format used on MacOS.
type MachO struct {
Header
@ -20,11 +25,6 @@ type MachO struct {
// Write writes the Mach-O format to the given writer.
func Write(writer io.Writer, code []byte, data []byte) {
const (
SizeCommands = Segment64Size*3 + ThreadSize
HeaderEnd = HeaderSize + SizeCommands
)
var (
codeStart, codePadding = fs.Align(HeaderEnd, config.Align)
dataStart, dataPadding = fs.Align(codeStart+len(code), config.Align)
@ -102,7 +102,7 @@ func Write(writer io.Writer, code []byte, data []byte) {
0, 0,
0, 0,
0, 0,
config.BaseAddress + config.CodeOffset, 0,
uint32(config.BaseAddress + codeStart), 0,
0, 0,
0, 0,
0, 0,

View File

@ -10,6 +10,11 @@ import (
"git.akyoto.dev/cli/q/src/fs"
)
const (
NumSections = 3
HeaderEnd = DOSHeaderSize + NTHeaderSize + OptionalHeader64Size + SectionHeaderSize*NumSections
)
// EXE is the portable executable format used on Windows.
type EXE struct {
DOSHeader
@ -20,12 +25,6 @@ type EXE struct {
// Write writes the EXE file to the given writer.
func Write(writer io.Writer, code []byte, data []byte, dlls dll.List) {
if len(data) == 0 {
data = []byte{0}
}
NumSections := 3
HeaderEnd := DOSHeaderSize + NTHeaderSize + OptionalHeader64Size + SectionHeaderSize*NumSections
codeStart, codePadding := fs.Align(HeaderEnd, config.Align)
dataStart, dataPadding := fs.Align(codeStart+len(code), config.Align)
importsStart, importsPadding := fs.Align(dataStart+len(data), config.Align)
@ -115,8 +114,8 @@ func Write(writer io.Writer, code []byte, data []byte, dlls dll.List) {
SizeOfCode: uint32(len(code)),
SizeOfInitializedData: 0,
SizeOfUninitializedData: 0,
AddressOfEntryPoint: config.CodeOffset,
BaseOfCode: config.CodeOffset,
AddressOfEntryPoint: uint32(codeStart),
BaseOfCode: uint32(codeStart),
ImageBase: config.BaseAddress,
SectionAlignment: config.Align, // power of 2, must be greater than or equal to FileAlignment
FileAlignment: config.Align, // power of 2
@ -128,7 +127,7 @@ func Write(writer io.Writer, code []byte, data []byte, dlls dll.List) {
MinorSubsystemVersion: 0,
Win32VersionValue: 0,
SizeOfImage: uint32(imageSize),
SizeOfHeaders: config.CodeOffset, // section bodies begin here
SizeOfHeaders: uint32(codeStart), // section bodies begin here
CheckSum: 0,
Subsystem: uint16(subSystem),
DllCharacteristics: IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA | IMAGE_DLLCHARACTERISTICS_NX_COMPAT | IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE, // IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE
@ -161,9 +160,9 @@ func Write(writer io.Writer, code []byte, data []byte, dlls dll.List) {
{
Name: [8]byte{'.', 't', 'e', 'x', 't'},
VirtualSize: uint32(len(code)),
VirtualAddress: config.CodeOffset,
VirtualAddress: uint32(codeStart),
RawSize: uint32(len(code)), // must be a multiple of FileAlignment
RawAddress: config.CodeOffset, // must be a multiple of FileAlignment
RawAddress: uint32(codeStart), // must be a multiple of FileAlignment
Characteristics: IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ,
},
{