Simplified executable file formats
This commit is contained in:
parent
fe1b353fe6
commit
7092cb6626
@ -8,7 +8,7 @@ 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/exe"
|
||||
"git.akyoto.dev/cli/q/src/sizeof"
|
||||
)
|
||||
|
||||
@ -339,7 +339,7 @@ restart:
|
||||
data, dataLabels = a.Data.Finalize()
|
||||
|
||||
dataStart := Address(config.BaseAddress) + config.CodeOffset + Address(len(code))
|
||||
dataStart += int32(common.Padding(dataStart, config.Align))
|
||||
dataStart += exe.Padding(dataStart, config.Align)
|
||||
|
||||
for _, pointer := range dataPointers {
|
||||
address := dataStart + pointer.Resolve()
|
||||
|
@ -10,11 +10,11 @@ import (
|
||||
"git.akyoto.dev/cli/q/src/asm"
|
||||
"git.akyoto.dev/cli/q/src/config"
|
||||
"git.akyoto.dev/cli/q/src/core"
|
||||
"git.akyoto.dev/cli/q/src/exe/elf"
|
||||
"git.akyoto.dev/cli/q/src/exe/macho"
|
||||
"git.akyoto.dev/cli/q/src/exe/pe"
|
||||
"git.akyoto.dev/cli/q/src/os/linux"
|
||||
"git.akyoto.dev/cli/q/src/os/linux/elf"
|
||||
"git.akyoto.dev/cli/q/src/os/mac"
|
||||
"git.akyoto.dev/cli/q/src/os/mac/macho"
|
||||
"git.akyoto.dev/cli/q/src/os/windows/pe"
|
||||
)
|
||||
|
||||
// Result contains all the compiled functions in a build.
|
||||
@ -147,14 +147,11 @@ func write(writer io.Writer, code []byte, data []byte) error {
|
||||
|
||||
switch config.TargetOS {
|
||||
case "linux":
|
||||
exe := elf.New(code, data)
|
||||
exe.Write(buffer)
|
||||
elf.Write(buffer, code, data)
|
||||
case "mac":
|
||||
exe := macho.New(code, data)
|
||||
exe.Write(buffer)
|
||||
macho.Write(buffer, code, data)
|
||||
case "windows":
|
||||
exe := pe.New(code, data)
|
||||
exe.Write(buffer)
|
||||
pe.Write(buffer, code, data)
|
||||
default:
|
||||
return fmt.Errorf("unsupported platform '%s'", config.TargetOS)
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
package common
|
||||
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 {
|
@ -6,28 +6,28 @@ import (
|
||||
"io"
|
||||
|
||||
"git.akyoto.dev/cli/q/src/config"
|
||||
"git.akyoto.dev/cli/q/src/os/common"
|
||||
"git.akyoto.dev/cli/q/src/exe"
|
||||
)
|
||||
|
||||
// ELF represents an ELF file.
|
||||
type ELF struct {
|
||||
Header
|
||||
CodeHeader ProgramHeader
|
||||
DataHeader ProgramHeader
|
||||
CodePadding []byte
|
||||
Code []byte
|
||||
DataPadding []byte
|
||||
Data []byte
|
||||
CodeHeader ProgramHeader
|
||||
DataHeader ProgramHeader
|
||||
}
|
||||
|
||||
// New creates a new ELF binary.
|
||||
func New(code []byte, data []byte) *ELF {
|
||||
codePadding := common.Padding(HeaderSize+ProgramHeaderSize*2, config.Align)
|
||||
dataOffset := config.CodeOffset + int64(len(code))
|
||||
dataPadding := common.Padding(dataOffset, config.Align)
|
||||
dataOffset += dataPadding
|
||||
// Write writes the ELF64 format to the given writer.
|
||||
func Write(writer io.Writer, code []byte, data []byte) {
|
||||
const HeaderEnd = HeaderSize + ProgramHeaderSize*2
|
||||
|
||||
return &ELF{
|
||||
var (
|
||||
codePadding = exe.Padding(HeaderEnd, config.Align)
|
||||
codeEnd = config.CodeOffset + len(code)
|
||||
dataPadding = exe.Padding(codeEnd, config.Align)
|
||||
dataStart = codeEnd + dataPadding
|
||||
)
|
||||
|
||||
elf := &ELF{
|
||||
Header: Header{
|
||||
Magic: [4]byte{0x7F, 'E', 'L', 'F'},
|
||||
Class: 2,
|
||||
@ -62,30 +62,23 @@ func New(code []byte, data []byte) *ELF {
|
||||
DataHeader: ProgramHeader{
|
||||
Type: ProgramTypeLOAD,
|
||||
Flags: ProgramFlagsReadable,
|
||||
Offset: dataOffset,
|
||||
VirtualAddress: config.BaseAddress + dataOffset,
|
||||
PhysicalAddress: config.BaseAddress + dataOffset,
|
||||
Offset: int64(dataStart),
|
||||
VirtualAddress: int64(config.BaseAddress + dataStart),
|
||||
PhysicalAddress: int64(config.BaseAddress + dataStart),
|
||||
SizeInFile: int64(len(data)),
|
||||
SizeInMemory: int64(len(data)),
|
||||
Align: config.Align,
|
||||
},
|
||||
CodePadding: bytes.Repeat([]byte{0}, int(codePadding)),
|
||||
Code: code,
|
||||
DataPadding: bytes.Repeat([]byte{0}, int(dataPadding)),
|
||||
Data: data,
|
||||
}
|
||||
}
|
||||
|
||||
// Write writes the ELF64 format to the given writer.
|
||||
func (elf *ELF) Write(writer io.Writer) {
|
||||
binary.Write(writer, binary.LittleEndian, &elf.Header)
|
||||
binary.Write(writer, binary.LittleEndian, &elf.CodeHeader)
|
||||
binary.Write(writer, binary.LittleEndian, &elf.DataHeader)
|
||||
writer.Write(elf.CodePadding)
|
||||
writer.Write(elf.Code)
|
||||
writer.Write(bytes.Repeat([]byte{0}, codePadding))
|
||||
writer.Write(code)
|
||||
|
||||
if len(elf.Data) > 0 {
|
||||
writer.Write(elf.DataPadding)
|
||||
writer.Write(elf.Data)
|
||||
if len(data) > 0 {
|
||||
writer.Write(bytes.Repeat([]byte{0}, dataPadding))
|
||||
writer.Write(data)
|
||||
}
|
||||
}
|
12
src/exe/elf/ELF_test.go
Normal file
12
src/exe/elf/ELF_test.go
Normal file
@ -0,0 +1,12 @@
|
||||
package elf_test
|
||||
|
||||
import (
|
||||
"io"
|
||||
"testing"
|
||||
|
||||
"git.akyoto.dev/cli/q/src/exe/elf"
|
||||
)
|
||||
|
||||
func TestWrite(t *testing.T) {
|
||||
elf.Write(io.Discard, nil, nil)
|
||||
}
|
@ -4,8 +4,8 @@
|
||||
|
||||
1. ELF header (0x00 - 0x40)
|
||||
2. Program header (0x40 - 0x78)
|
||||
3. Padding (0x78 - 0x80)
|
||||
4. Machine code (0x80)
|
||||
3. Padding
|
||||
4. Machine code
|
||||
|
||||
## Entry point
|
||||
|
||||
@ -28,3 +28,11 @@ https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/fs/binfm
|
||||
|
||||
ELF register definitions:
|
||||
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/arch/x86/include/asm/elf.h
|
||||
|
||||
## Links
|
||||
|
||||
- https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/include/uapi/linux/elf.h
|
||||
- https://lwn.net/Articles/631631/
|
||||
- https://en.wikipedia.org/wiki/Executable_and_Linkable_Format
|
||||
- https://www.muppetlabs.com/~breadbox/software/tiny/teensy.html
|
||||
- https://nathanotterness.com/2021/10/tiny_elf_modernized.html
|
126
src/exe/macho/MachO.go
Normal file
126
src/exe/macho/MachO.go
Normal file
@ -0,0 +1,126 @@
|
||||
package macho
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"io"
|
||||
|
||||
"git.akyoto.dev/cli/q/src/config"
|
||||
"git.akyoto.dev/cli/q/src/exe"
|
||||
)
|
||||
|
||||
// MachO is the executable format used on MacOS.
|
||||
type MachO struct {
|
||||
Header
|
||||
PageZero Segment64
|
||||
CodeHeader Segment64
|
||||
DataHeader Segment64
|
||||
UnixThread Thread
|
||||
}
|
||||
|
||||
// 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 (
|
||||
codePadding = exe.Padding(HeaderEnd, config.Align)
|
||||
codeEnd = config.CodeOffset + len(code)
|
||||
dataPadding = exe.Padding(codeEnd, config.Align)
|
||||
dataStart = codeEnd + dataPadding
|
||||
)
|
||||
|
||||
m := &MachO{
|
||||
Header: Header{
|
||||
Magic: 0xFEEDFACF,
|
||||
Architecture: CPU_X86_64,
|
||||
MicroArchitecture: 3 | 0x80000000,
|
||||
Type: TypeExecute,
|
||||
NumCommands: 4,
|
||||
SizeCommands: SizeCommands,
|
||||
Flags: FlagNoUndefs | FlagNoHeapExecution,
|
||||
Reserved: 0,
|
||||
},
|
||||
PageZero: Segment64{
|
||||
LoadCommand: LcSegment64,
|
||||
Length: 72,
|
||||
Name: [16]byte{'_', '_', 'P', 'A', 'G', 'E', 'Z', 'E', 'R', 'O'},
|
||||
Address: 0,
|
||||
SizeInMemory: config.BaseAddress,
|
||||
Offset: 0,
|
||||
SizeInFile: 0,
|
||||
NumSections: 0,
|
||||
Flag: 0,
|
||||
MaxProt: 0,
|
||||
InitProt: 0,
|
||||
},
|
||||
CodeHeader: Segment64{
|
||||
LoadCommand: LcSegment64,
|
||||
Length: Segment64Size,
|
||||
Name: [16]byte{'_', '_', 'T', 'E', 'X', 'T'},
|
||||
Address: config.BaseAddress,
|
||||
SizeInMemory: uint64(codeEnd),
|
||||
Offset: 0,
|
||||
SizeInFile: uint64(codeEnd),
|
||||
NumSections: 0,
|
||||
Flag: 0,
|
||||
MaxProt: ProtReadable | ProtExecutable,
|
||||
InitProt: ProtReadable | ProtExecutable,
|
||||
},
|
||||
DataHeader: Segment64{
|
||||
LoadCommand: LcSegment64,
|
||||
Length: Segment64Size,
|
||||
Name: [16]byte{'_', '_', 'D', 'A', 'T', 'A'},
|
||||
Address: uint64(config.BaseAddress + dataStart),
|
||||
SizeInMemory: uint64(len(data)),
|
||||
Offset: uint64(dataStart),
|
||||
SizeInFile: uint64(len(data)),
|
||||
NumSections: 0,
|
||||
Flag: 0,
|
||||
MaxProt: ProtReadable,
|
||||
InitProt: ProtReadable,
|
||||
},
|
||||
UnixThread: Thread{
|
||||
LoadCommand: LcUnixthread,
|
||||
Len: ThreadSize,
|
||||
Type: 0x4,
|
||||
Data: [43]uint32{
|
||||
42,
|
||||
0, 0,
|
||||
0, 0,
|
||||
0, 0,
|
||||
0, 0,
|
||||
0, 0,
|
||||
0, 0,
|
||||
0, 0,
|
||||
0, 0,
|
||||
0, 0,
|
||||
0, 0,
|
||||
0, 0,
|
||||
0, 0,
|
||||
0, 0,
|
||||
0, 0,
|
||||
0, 0,
|
||||
0, 0,
|
||||
config.BaseAddress + config.CodeOffset, 0,
|
||||
0, 0,
|
||||
0, 0,
|
||||
0, 0,
|
||||
0, 0,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
binary.Write(writer, binary.LittleEndian, &m.Header)
|
||||
binary.Write(writer, binary.LittleEndian, &m.PageZero)
|
||||
binary.Write(writer, binary.LittleEndian, &m.CodeHeader)
|
||||
binary.Write(writer, binary.LittleEndian, &m.DataHeader)
|
||||
binary.Write(writer, binary.LittleEndian, &m.UnixThread)
|
||||
|
||||
writer.Write(bytes.Repeat([]byte{0}, int(codePadding)))
|
||||
writer.Write(code)
|
||||
writer.Write(bytes.Repeat([]byte{0}, int(dataPadding)))
|
||||
writer.Write(data)
|
||||
}
|
16
src/exe/macho/macho.md
Normal file
16
src/exe/macho/macho.md
Normal file
@ -0,0 +1,16 @@
|
||||
# Mach-O
|
||||
|
||||
## Notes
|
||||
|
||||
MacOS is the only operating system that requires loading the headers
|
||||
explicitly with both readable and executable permissions.
|
||||
|
||||
## Loader
|
||||
|
||||
https://github.com/apple-oss-distributions/xnu/blob/main/EXTERNAL_HEADERS/mach-o/loader.h
|
||||
|
||||
## Links
|
||||
|
||||
- https://en.wikipedia.org/wiki/Mach-O
|
||||
- https://github.com/aidansteele/osx-abi-macho-file-format-reference
|
||||
- https://stackoverflow.com/questions/39863112/what-is-required-for-a-mach-o-executable-to-load
|
@ -6,7 +6,7 @@ import (
|
||||
"io"
|
||||
|
||||
"git.akyoto.dev/cli/q/src/config"
|
||||
"git.akyoto.dev/cli/q/src/os/common"
|
||||
"git.akyoto.dev/cli/q/src/exe"
|
||||
)
|
||||
|
||||
const NumSections = 2
|
||||
@ -16,30 +16,29 @@ type EXE struct {
|
||||
DOSHeader
|
||||
NTHeader
|
||||
OptionalHeader64
|
||||
Sections [NumSections]SectionHeader
|
||||
CodePadding []byte
|
||||
Code []byte
|
||||
DataPadding []byte
|
||||
Data []byte
|
||||
Sections [NumSections]SectionHeader
|
||||
}
|
||||
|
||||
// New creates a new EXE file.
|
||||
func New(code []byte, data []byte) *EXE {
|
||||
codeStart := uint32(DOSHeaderSize + NTHeaderSize + OptionalHeader64Size + SectionHeaderSize*NumSections)
|
||||
codePadding := common.Padding(codeStart, config.Align)
|
||||
codeStart += codePadding
|
||||
// Write writes the EXE file to the given writer.
|
||||
func Write(writer io.Writer, code []byte, data []byte) {
|
||||
const (
|
||||
HeaderEnd = DOSHeaderSize + NTHeaderSize + OptionalHeader64Size + SectionHeaderSize*NumSections
|
||||
)
|
||||
|
||||
dataStart := codeStart + uint32(len(code))
|
||||
dataPadding := common.Padding(dataStart, config.Align)
|
||||
dataStart += dataPadding
|
||||
var (
|
||||
codePadding = exe.Padding(HeaderEnd, config.Align)
|
||||
codeEnd = config.CodeOffset + len(code)
|
||||
dataPadding = exe.Padding(codeEnd, config.Align)
|
||||
dataStart = codeEnd + dataPadding
|
||||
)
|
||||
|
||||
imageSize := uint32(dataStart + uint32(len(data)))
|
||||
imageSize += common.Padding(imageSize, config.Align)
|
||||
imageSize := dataStart + len(data)
|
||||
imageSize += exe.Padding(imageSize, config.Align)
|
||||
|
||||
return &EXE{
|
||||
pe := &EXE{
|
||||
DOSHeader: DOSHeader{
|
||||
Magic: [4]byte{'M', 'Z', 0, 0},
|
||||
NTHeaderOffset: 0x40,
|
||||
NTHeaderOffset: DOSHeaderSize,
|
||||
},
|
||||
NTHeader: NTHeader{
|
||||
Signature: [4]byte{'P', 'E', 0, 0},
|
||||
@ -53,15 +52,15 @@ func New(code []byte, data []byte) *EXE {
|
||||
MajorLinkerVersion: 0x0E,
|
||||
MinorLinkerVersion: 0x16,
|
||||
SizeOfCode: uint32(len(code)),
|
||||
AddressOfEntryPoint: codeStart,
|
||||
BaseOfCode: codeStart,
|
||||
AddressOfEntryPoint: config.CodeOffset,
|
||||
BaseOfCode: config.CodeOffset,
|
||||
ImageBase: config.BaseAddress,
|
||||
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,
|
||||
SizeOfHeaders: codeStart, // section bodies begin here
|
||||
SizeOfImage: uint32(imageSize),
|
||||
SizeOfHeaders: config.CodeOffset, // section bodies begin here
|
||||
Subsystem: IMAGE_SUBSYSTEM_WINDOWS_GUI,
|
||||
DllCharacteristics: IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA | IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE | IMAGE_DLLCHARACTERISTICS_NX_COMPAT | IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE,
|
||||
SizeOfStackReserve: 0x100000,
|
||||
@ -92,35 +91,29 @@ func New(code []byte, data []byte) *EXE {
|
||||
{
|
||||
Name: [8]byte{'.', 't', 'e', 'x', 't'},
|
||||
VirtualSize: uint32(len(code)),
|
||||
VirtualAddress: codeStart,
|
||||
VirtualAddress: config.CodeOffset,
|
||||
RawSize: uint32(len(code)), // must be a multiple of FileAlignment
|
||||
RawAddress: codeStart, // must be a multiple of FileAlignment
|
||||
RawAddress: config.CodeOffset, // must be a multiple of FileAlignment
|
||||
Characteristics: IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ,
|
||||
},
|
||||
{
|
||||
Name: [8]byte{'.', 'r', 'd', 'a', 't', 'a'},
|
||||
VirtualSize: uint32(len(data)),
|
||||
VirtualAddress: dataStart,
|
||||
VirtualAddress: uint32(dataStart),
|
||||
RawSize: uint32(len(data)), // must be a multiple of FileAlignment
|
||||
RawAddress: dataStart, // must be a multiple of FileAlignment
|
||||
RawAddress: uint32(dataStart), // must be a multiple of FileAlignment
|
||||
Characteristics: IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ,
|
||||
},
|
||||
},
|
||||
CodePadding: bytes.Repeat([]byte{0}, int(codePadding)),
|
||||
Code: code,
|
||||
DataPadding: bytes.Repeat([]byte{0}, int(dataPadding)),
|
||||
Data: data,
|
||||
}
|
||||
}
|
||||
|
||||
// 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.NTHeader)
|
||||
binary.Write(writer, binary.LittleEndian, &pe.OptionalHeader64)
|
||||
binary.Write(writer, binary.LittleEndian, &pe.Sections)
|
||||
binary.Write(writer, binary.LittleEndian, &pe.CodePadding)
|
||||
binary.Write(writer, binary.LittleEndian, &pe.Code)
|
||||
binary.Write(writer, binary.LittleEndian, &pe.DataPadding)
|
||||
binary.Write(writer, binary.LittleEndian, &pe.Data)
|
||||
|
||||
writer.Write(bytes.Repeat([]byte{0}, int(codePadding)))
|
||||
writer.Write(code)
|
||||
writer.Write(bytes.Repeat([]byte{0}, int(dataPadding)))
|
||||
writer.Write(data)
|
||||
}
|
11
src/exe/pe/pe.md
Normal file
11
src/exe/pe/pe.md
Normal file
@ -0,0 +1,11 @@
|
||||
## Portable Executable
|
||||
|
||||
## Links
|
||||
|
||||
- https://learn.microsoft.com/en-us/previous-versions/ms809762(v=msdn.10)
|
||||
- https://learn.microsoft.com/en-us/archive/msdn-magazine/2002/february/inside-windows-win32-portable-executable-file-format-in-detail
|
||||
- https://learn.microsoft.com/en-us/archive/msdn-magazine/2002/march/inside-windows-an-in-depth-look-into-the-win32-portable-executable-file-format-part-2
|
||||
- https://blog.kowalczyk.info/articles/pefileformat.html
|
||||
- https://keyj.emphy.de/win32-pe/
|
||||
- https://corkamiwiki.github.io/PE
|
||||
- https://github.com/ayaka14732/TinyPE-on-Win10
|
@ -2,9 +2,6 @@ package linux
|
||||
|
||||
// https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/arch/x86/entry/syscalls/syscall_64.tbl
|
||||
const (
|
||||
Read = 0
|
||||
Write = 1
|
||||
Open = 2
|
||||
Close = 3
|
||||
Exit = 60
|
||||
)
|
||||
|
@ -1,13 +0,0 @@
|
||||
package elf_test
|
||||
|
||||
import (
|
||||
"io"
|
||||
"testing"
|
||||
|
||||
"git.akyoto.dev/cli/q/src/os/linux/elf"
|
||||
)
|
||||
|
||||
func TestELF(t *testing.T) {
|
||||
exe := elf.New(nil, nil)
|
||||
exe.Write(io.Discard)
|
||||
}
|
@ -1,122 +0,0 @@
|
||||
package macho
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"io"
|
||||
|
||||
"git.akyoto.dev/cli/q/src/config"
|
||||
"git.akyoto.dev/cli/q/src/os/common"
|
||||
)
|
||||
|
||||
// MachO is the executable format used on MacOS.
|
||||
type MachO struct {
|
||||
Header
|
||||
Code []byte
|
||||
Data []byte
|
||||
}
|
||||
|
||||
// New creates a new Mach-O binary.
|
||||
func New(code []byte, data []byte) *MachO {
|
||||
return &MachO{
|
||||
Header: Header{
|
||||
Magic: 0xFEEDFACF,
|
||||
Architecture: CPU_X86_64,
|
||||
MicroArchitecture: 3 | 0x80000000,
|
||||
Type: TypeExecute,
|
||||
NumCommands: 4,
|
||||
SizeCommands: Segment64Size*3 + ThreadSize,
|
||||
Flags: FlagNoUndefs | FlagNoHeapExecution,
|
||||
Reserved: 0,
|
||||
},
|
||||
Code: code,
|
||||
Data: data,
|
||||
}
|
||||
}
|
||||
|
||||
// Write writes the Mach-O format to the given writer.
|
||||
func (m *MachO) Write(writer io.Writer) {
|
||||
binary.Write(writer, binary.LittleEndian, &m.Header)
|
||||
|
||||
binary.Write(writer, binary.LittleEndian, &Segment64{
|
||||
LoadCommand: LcSegment64,
|
||||
Length: 72,
|
||||
Name: [16]byte{'_', '_', 'P', 'A', 'G', 'E', 'Z', 'E', 'R', 'O'},
|
||||
Address: 0,
|
||||
SizeInMemory: config.BaseAddress,
|
||||
Offset: 0,
|
||||
SizeInFile: 0,
|
||||
NumSections: 0,
|
||||
Flag: 0,
|
||||
MaxProt: 0,
|
||||
InitProt: 0,
|
||||
})
|
||||
|
||||
codePadding := common.Padding(HeaderSize+m.Header.SizeCommands, config.Align)
|
||||
codeEnd := uint64(config.CodeOffset + len(m.Code))
|
||||
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,
|
||||
SizeInMemory: config.CodeOffset + uint64(len(m.Code)),
|
||||
Offset: 0,
|
||||
SizeInFile: config.CodeOffset + uint64(len(m.Code)),
|
||||
NumSections: 0,
|
||||
Flag: 0,
|
||||
MaxProt: ProtReadable | ProtExecutable,
|
||||
InitProt: ProtReadable | ProtExecutable,
|
||||
})
|
||||
|
||||
binary.Write(writer, binary.LittleEndian, &Segment64{
|
||||
LoadCommand: LcSegment64,
|
||||
Length: 72,
|
||||
Name: [16]byte{'_', '_', 'D', 'A', 'T', 'A'},
|
||||
Address: config.BaseAddress + dataStart,
|
||||
SizeInMemory: uint64(len(m.Data)),
|
||||
Offset: dataStart,
|
||||
SizeInFile: uint64(len(m.Data)),
|
||||
NumSections: 0,
|
||||
Flag: 0,
|
||||
MaxProt: ProtReadable,
|
||||
InitProt: ProtReadable,
|
||||
})
|
||||
|
||||
binary.Write(writer, binary.LittleEndian, &Thread{
|
||||
LoadCommand: LcUnixthread,
|
||||
Len: 184,
|
||||
Type: 0x4,
|
||||
Data: [43]uint32{
|
||||
42,
|
||||
0, 0,
|
||||
0, 0,
|
||||
0, 0,
|
||||
0, 0,
|
||||
0, 0,
|
||||
0, 0,
|
||||
0, 0,
|
||||
0, 0,
|
||||
0, 0,
|
||||
0, 0,
|
||||
0, 0,
|
||||
0, 0,
|
||||
0, 0,
|
||||
0, 0,
|
||||
0, 0,
|
||||
0, 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)
|
||||
}
|
Loading…
Reference in New Issue
Block a user