package elf import ( "bytes" "encoding/binary" "io" "git.akyoto.dev/cli/q/src/config" "git.akyoto.dev/cli/q/src/fs" ) const HeaderEnd = HeaderSize + ProgramHeaderSize*2 // ELF represents an ELF file. type ELF struct { Header CodeHeader ProgramHeader DataHeader ProgramHeader } // Write writes the ELF64 format to the given writer. func Write(writer io.Writer, code []byte, data []byte) { var ( codeStart, codePadding = fs.Align(HeaderEnd, config.Align) dataStart, dataPadding = fs.Align(codeStart+len(code), config.Align) ) elf := &ELF{ Header: Header{ Magic: [4]byte{0x7F, 'E', 'L', 'F'}, Class: 2, Endianness: LittleEndian, Version: 1, OSABI: 0, ABIVersion: 0, Type: TypeExecutable, Architecture: ArchitectureAMD64, FileVersion: 1, EntryPointInMemory: int64(config.BaseAddress + codeStart), ProgramHeaderOffset: HeaderSize, SectionHeaderOffset: 0, Flags: 0, Size: HeaderSize, ProgramHeaderEntrySize: ProgramHeaderSize, ProgramHeaderEntryCount: 2, SectionHeaderEntrySize: 0, SectionHeaderEntryCount: 0, SectionNameStringTableIndex: 0, }, CodeHeader: ProgramHeader{ Type: ProgramTypeLOAD, Flags: ProgramFlagsExecutable | ProgramFlagsReadable, Offset: int64(codeStart), VirtualAddress: int64(config.BaseAddress + codeStart), PhysicalAddress: int64(config.BaseAddress + codeStart), SizeInFile: int64(len(code)), SizeInMemory: int64(len(code)), Align: config.Align, }, DataHeader: ProgramHeader{ Type: ProgramTypeLOAD, Flags: ProgramFlagsReadable, Offset: int64(dataStart), VirtualAddress: int64(config.BaseAddress + dataStart), PhysicalAddress: int64(config.BaseAddress + dataStart), SizeInFile: int64(len(data)), SizeInMemory: int64(len(data)), Align: config.Align, }, } binary.Write(writer, binary.LittleEndian, &elf.Header) binary.Write(writer, binary.LittleEndian, &elf.CodeHeader) binary.Write(writer, binary.LittleEndian, &elf.DataHeader) writer.Write(bytes.Repeat([]byte{0x00}, codePadding)) writer.Write(code) if len(data) > 0 { writer.Write(bytes.Repeat([]byte{0x00}, dataPadding)) writer.Write(data) } }