diff --git a/src/asm/Finalize.go b/src/asm/Finalize.go index 1457c40..e0e0c87 100644 --- a/src/asm/Finalize.go +++ b/src/asm/Finalize.go @@ -9,9 +9,6 @@ import ( "git.akyoto.dev/cli/q/src/arch/x64" "git.akyoto.dev/cli/q/src/config" "git.akyoto.dev/cli/q/src/os/common" - "git.akyoto.dev/cli/q/src/os/linux/elf" - "git.akyoto.dev/cli/q/src/os/mac/macho" - "git.akyoto.dev/cli/q/src/os/windows/pe" "git.akyoto.dev/cli/q/src/sizeof" ) @@ -341,25 +338,8 @@ restart: data, dataLabels = a.Data.Finalize() - var ( - codeOffset Address - align Address - ) - - switch config.TargetOS { - case "linux": - codeOffset = elf.CodeOffset - align = elf.Align - case "mac": - codeOffset = macho.CodeOffset - align = macho.Align - case "windows": - codeOffset = pe.CodeOffset - align = pe.Align - } - - dataStart := Address(config.BaseAddress) + codeOffset + Address(len(code)) - dataStart += int32(common.Padding(dataStart, align)) + dataStart := Address(config.BaseAddress) + config.CodeOffset + Address(len(code)) + dataStart += int32(common.Padding(dataStart, config.Align)) for _, pointer := range dataPointers { address := dataStart + pointer.Resolve() diff --git a/src/config/config.go b/src/config/config.go index 555e379..79f7d58 100644 --- a/src/config/config.go +++ b/src/config/config.go @@ -8,6 +8,12 @@ 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 = 0x1000 + + // The code offset is the offset of the executable machine code within the file. + CodeOffset = Align ) var ( diff --git a/src/os/common/Padding.go b/src/os/common/Padding.go index da40c13..4f2d726 100644 --- a/src/os/common/Padding.go +++ b/src/os/common/Padding.go @@ -1,6 +1,6 @@ package common // Padding calculates the padding needed to align `n` bytes with the specified alignment. -func Padding[T int64 | uint64 | int32 | uint32](n T, align T) T { +func Padding[T int | uint | int64 | uint64 | int32 | uint32](n T, align T) T { return align - (n % align) } diff --git a/src/os/linux/elf/Constants.go b/src/os/linux/elf/Constants.go index 6396c66..bd4600f 100644 --- a/src/os/linux/elf/Constants.go +++ b/src/os/linux/elf/Constants.go @@ -1,13 +1,5 @@ package elf -const ( - // Align decides 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 = HeaderSize + ProgramHeaderSize*2 -) - const ( LittleEndian = 1 TypeExecutable = 2 diff --git a/src/os/linux/elf/ELF.go b/src/os/linux/elf/ELF.go index 084b903..87818dc 100644 --- a/src/os/linux/elf/ELF.go +++ b/src/os/linux/elf/ELF.go @@ -22,8 +22,9 @@ type ELF struct { // New creates a new ELF binary. func New(code []byte, data []byte) *ELF { - dataOffset := CodeOffset + int64(len(code)) - dataPadding := common.Padding(dataOffset, Align) + codePadding := common.Padding(HeaderSize+ProgramHeaderSize*2, config.Align) + dataOffset := config.CodeOffset + int64(len(code)) + dataPadding := common.Padding(dataOffset, config.Align) dataOffset += dataPadding return &ELF{ @@ -37,7 +38,7 @@ func New(code []byte, data []byte) *ELF { Type: TypeExecutable, Architecture: ArchitectureAMD64, FileVersion: 1, - EntryPointInMemory: config.BaseAddress + CodeOffset, + EntryPointInMemory: config.BaseAddress + config.CodeOffset, ProgramHeaderOffset: HeaderSize, SectionHeaderOffset: 0, Flags: 0, @@ -51,12 +52,12 @@ func New(code []byte, data []byte) *ELF { CodeHeader: ProgramHeader{ Type: ProgramTypeLOAD, Flags: ProgramFlagsExecutable | ProgramFlagsReadable, - Offset: CodeOffset, - VirtualAddress: config.BaseAddress + CodeOffset, - PhysicalAddress: config.BaseAddress + CodeOffset, + Offset: config.CodeOffset, + VirtualAddress: config.BaseAddress + config.CodeOffset, + PhysicalAddress: config.BaseAddress + config.CodeOffset, SizeInFile: int64(len(code)), SizeInMemory: int64(len(code)), - Align: Align, + Align: config.Align, }, DataHeader: ProgramHeader{ Type: ProgramTypeLOAD, @@ -66,9 +67,9 @@ func New(code []byte, data []byte) *ELF { PhysicalAddress: config.BaseAddress + dataOffset, SizeInFile: int64(len(data)), SizeInMemory: int64(len(data)), - Align: Align, + Align: config.Align, }, - CodePadding: nil, + CodePadding: bytes.Repeat([]byte{0}, int(codePadding)), Code: code, DataPadding: bytes.Repeat([]byte{0}, int(dataPadding)), Data: data, diff --git a/src/os/mac/macho/Constants.go b/src/os/mac/macho/Constants.go index 83c62d9..eb9e320 100644 --- a/src/os/mac/macho/Constants.go +++ b/src/os/mac/macho/Constants.go @@ -1,13 +1,5 @@ package macho -const ( - // Align decides 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 = 32 + 0x48*3 + 184 -) - type CPU uint32 const ( diff --git a/src/os/mac/macho/MachO.go b/src/os/mac/macho/MachO.go index 1bc1325..449c11b 100644 --- a/src/os/mac/macho/MachO.go +++ b/src/os/mac/macho/MachO.go @@ -52,19 +52,19 @@ func (m *MachO) Write(writer io.Writer) { InitProt: 0, }) - codeStart := uint64(32 + m.Header.SizeCommands) + codePadding := common.Padding(32+m.Header.SizeCommands, config.Align) codeLength := uint64(len(m.Code)) - codeEnd := codeStart + codeLength - dataPadding := common.Padding(codeEnd, Align) + codeEnd := config.CodeOffset + codeLength + dataPadding := common.Padding(codeEnd, config.Align) dataStart := codeEnd + dataPadding binary.Write(writer, binary.LittleEndian, &Segment64{ LoadCommand: LcSegment64, Length: 72, Name: [16]byte{'_', '_', 'T', 'E', 'X', 'T'}, - Address: config.BaseAddress + codeStart, + Address: config.BaseAddress + config.CodeOffset, SizeInMemory: codeLength, - Offset: 0, + Offset: config.CodeOffset, SizeInFile: codeLength, NumSections: 0, Flag: 0, @@ -110,13 +110,14 @@ func (m *MachO) Write(writer io.Writer) { 0, 0, 0, 0, 0, 0, - config.BaseAddress + uint32(codeStart), 0, + config.BaseAddress + config.CodeOffset, 0, 0, 0, 0, 0, 0, 0, 0, 0, }) + writer.Write(bytes.Repeat([]byte{0}, int(codePadding))) writer.Write(m.Code) writer.Write(bytes.Repeat([]byte{0}, int(dataPadding))) writer.Write(m.Data) diff --git a/src/os/windows/pe/Constants.go b/src/os/windows/pe/Constants.go index 4d38ad5..c77bea7 100644 --- a/src/os/windows/pe/Constants.go +++ b/src/os/windows/pe/Constants.go @@ -1,13 +1,5 @@ package pe -const ( - // Align decides the alignment of the sections. - Align = 0x200 - - // The code offset is the offset of the executable machine code within the file. - CodeOffset = Align -) - // CPU const ( IMAGE_FILE_MACHINE_AMD64 = 0x8664 diff --git a/src/os/windows/pe/DOSHeader.go b/src/os/windows/pe/DOSHeader.go index d9a638b..eabb2f9 100644 --- a/src/os/windows/pe/DOSHeader.go +++ b/src/os/windows/pe/DOSHeader.go @@ -7,5 +7,5 @@ const DOSHeaderSize = 64 type DOSHeader struct { Magic [4]byte _ [56]byte - PEHeaderOffset uint32 + NTHeaderOffset uint32 } diff --git a/src/os/windows/pe/EXE.go b/src/os/windows/pe/EXE.go index 3be2970..f1d5ff3 100644 --- a/src/os/windows/pe/EXE.go +++ b/src/os/windows/pe/EXE.go @@ -14,7 +14,7 @@ const NumSections = 2 // EXE is the portable executable format used on Windows. type EXE struct { DOSHeader - PEHeader + NTHeader OptionalHeader64 Sections [NumSections]SectionHeader CodePadding []byte @@ -25,23 +25,23 @@ type EXE struct { // New creates a new EXE file. func New(code []byte, data []byte) *EXE { - codeStart := uint32(DOSHeaderSize + PEHeaderSize + OptionalHeader64Size + SectionHeaderSize*NumSections) - codePadding := common.Padding(codeStart, Align) + codeStart := uint32(DOSHeaderSize + NTHeaderSize + OptionalHeader64Size + SectionHeaderSize*NumSections) + codePadding := common.Padding(codeStart, config.Align) codeStart += codePadding dataStart := codeStart + uint32(len(code)) - dataPadding := common.Padding(dataStart, Align) + dataPadding := common.Padding(dataStart, config.Align) dataStart += dataPadding imageSize := uint32(dataStart + uint32(len(data))) - imageSize += common.Padding(imageSize, Align) + imageSize += common.Padding(imageSize, config.Align) return &EXE{ DOSHeader: DOSHeader{ Magic: [4]byte{'M', 'Z', 0, 0}, - PEHeaderOffset: 0x40, + NTHeaderOffset: 0x40, }, - PEHeader: PEHeader{ + NTHeader: NTHeader{ Signature: [4]byte{'P', 'E', 0, 0}, Machine: IMAGE_FILE_MACHINE_AMD64, NumberOfSections: NumSections, @@ -54,9 +54,10 @@ func New(code []byte, data []byte) *EXE { MinorLinkerVersion: 0x16, SizeOfCode: uint32(len(code)), AddressOfEntryPoint: codeStart, + BaseOfCode: codeStart, ImageBase: config.BaseAddress, - SectionAlignment: Align, // power of 2, must be greater than or equal to FileAlignment - FileAlignment: Align, // power of 2 + SectionAlignment: config.Align, // power of 2, must be greater than or equal to FileAlignment + FileAlignment: config.Align, // power of 2 MajorOperatingSystemVersion: 0x06, MajorSubsystemVersion: 0x06, SizeOfImage: imageSize, @@ -89,7 +90,7 @@ func New(code []byte, data []byte) *EXE { }, Sections: [NumSections]SectionHeader{ { - Name: [8]byte{'.', 'c', 'o', 'd', 'e'}, + Name: [8]byte{'.', 't', 'e', 'x', 't'}, VirtualSize: uint32(len(code)), VirtualAddress: codeStart, RawSize: uint32(len(code)), // must be a multiple of FileAlignment @@ -97,7 +98,7 @@ func New(code []byte, data []byte) *EXE { Characteristics: IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ, }, { - Name: [8]byte{'.', 'd', 'a', 't', 'a'}, + Name: [8]byte{'.', 'r', 'd', 'a', 't', 'a'}, VirtualSize: uint32(len(data)), VirtualAddress: dataStart, RawSize: uint32(len(data)), // must be a multiple of FileAlignment @@ -115,7 +116,7 @@ func New(code []byte, data []byte) *EXE { // Write writes the EXE file to the given writer. func (pe *EXE) Write(writer io.Writer) { binary.Write(writer, binary.LittleEndian, &pe.DOSHeader) - binary.Write(writer, binary.LittleEndian, &pe.PEHeader) + binary.Write(writer, binary.LittleEndian, &pe.NTHeader) binary.Write(writer, binary.LittleEndian, &pe.OptionalHeader64) binary.Write(writer, binary.LittleEndian, &pe.Sections) binary.Write(writer, binary.LittleEndian, &pe.CodePadding) diff --git a/src/os/windows/pe/PEHeader.go b/src/os/windows/pe/NTHeader.go similarity index 84% rename from src/os/windows/pe/PEHeader.go rename to src/os/windows/pe/NTHeader.go index 2de3439..08c577e 100644 --- a/src/os/windows/pe/PEHeader.go +++ b/src/os/windows/pe/NTHeader.go @@ -1,8 +1,8 @@ package pe -const PEHeaderSize = 24 +const NTHeaderSize = 24 -type PEHeader struct { +type NTHeader struct { Signature [4]byte Machine uint16 NumberOfSections uint16