This commit is contained in:
parent
3ae47f93eb
commit
cc2e98ca49
26 changed files with 541 additions and 11 deletions
37
src/elf/AddSections.go
Normal file
37
src/elf/AddSections.go
Normal file
|
@ -0,0 +1,37 @@
|
|||
package elf
|
||||
|
||||
import "bytes"
|
||||
|
||||
// AddSections adds section headers to the ELF file.
|
||||
func (elf *ELF) AddSections() {
|
||||
elf.StringTable = []byte("\000.text\000.shstrtab\000")
|
||||
stringTableStart := elf.DataHeader.Offset + elf.DataHeader.SizeInFile
|
||||
sectionHeaderStart := stringTableStart + int64(len(elf.StringTable))
|
||||
|
||||
elf.SectionHeaders = []SectionHeader{
|
||||
{
|
||||
Type: SectionTypeNULL,
|
||||
},
|
||||
{
|
||||
NameIndex: int32(bytes.Index(elf.StringTable, []byte(".text\000"))),
|
||||
Type: SectionTypePROGBITS,
|
||||
Flags: SectionFlagsAllocate | SectionFlagsExecutable,
|
||||
VirtualAddress: elf.CodeHeader.VirtualAddress,
|
||||
Offset: elf.CodeHeader.Offset,
|
||||
SizeInFile: elf.CodeHeader.SizeInFile,
|
||||
Align: elf.CodeHeader.Align,
|
||||
},
|
||||
{
|
||||
NameIndex: int32(bytes.Index(elf.StringTable, []byte(".shstrtab\000"))),
|
||||
Type: SectionTypeSTRTAB,
|
||||
Offset: int64(stringTableStart),
|
||||
SizeInFile: int64(len(elf.StringTable)),
|
||||
Align: 1,
|
||||
},
|
||||
}
|
||||
|
||||
elf.SectionHeaderEntrySize = SectionHeaderSize
|
||||
elf.SectionHeaderEntryCount = int16(len(elf.SectionHeaders))
|
||||
elf.SectionHeaderOffset = int64(sectionHeaderStart)
|
||||
elf.SectionNameStringTableIndex = 2
|
||||
}
|
15
src/elf/Arch.go
Normal file
15
src/elf/Arch.go
Normal file
|
@ -0,0 +1,15 @@
|
|||
package elf
|
||||
|
||||
import "git.urbach.dev/cli/q/src/build"
|
||||
|
||||
// Arch converts the architecture variable to an ELF-specific constant.
|
||||
func Arch(arch build.Arch) int16 {
|
||||
switch arch {
|
||||
case build.ARM:
|
||||
return ArchitectureARM64
|
||||
case build.X86:
|
||||
return ArchitectureAMD64
|
||||
default:
|
||||
return 0
|
||||
}
|
||||
}
|
11
src/elf/Constants.go
Normal file
11
src/elf/Constants.go
Normal file
|
@ -0,0 +1,11 @@
|
|||
package elf
|
||||
|
||||
const (
|
||||
LittleEndian = 1
|
||||
TypeExecutable = 2
|
||||
TypeDynamic = 3
|
||||
ArchitectureAMD64 = 0x3E
|
||||
ArchitectureARM64 = 0xB7
|
||||
ArchitectureRISCV = 0xF3
|
||||
HeaderEnd = HeaderSize + ProgramHeaderSize*2
|
||||
)
|
79
src/elf/ELF.go
Normal file
79
src/elf/ELF.go
Normal file
|
@ -0,0 +1,79 @@
|
|||
package elf
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"io"
|
||||
|
||||
"git.urbach.dev/cli/q/src/build"
|
||||
"git.urbach.dev/cli/q/src/exe"
|
||||
)
|
||||
|
||||
// ELF represents an ELF file.
|
||||
type ELF struct {
|
||||
Header
|
||||
CodeHeader ProgramHeader
|
||||
DataHeader ProgramHeader
|
||||
SectionHeaders []SectionHeader
|
||||
StringTable []byte
|
||||
}
|
||||
|
||||
// Write writes the ELF64 format to the given writer.
|
||||
func Write(writer io.WriteSeeker, b *build.Build, codeBytes []byte, dataBytes []byte) {
|
||||
x := exe.New(HeaderEnd, b.FileAlign, b.MemoryAlign)
|
||||
x.InitSections(codeBytes, dataBytes)
|
||||
code := x.Sections[0]
|
||||
data := x.Sections[1]
|
||||
|
||||
elf := &ELF{
|
||||
Header: Header{
|
||||
Magic: [4]byte{0x7F, 'E', 'L', 'F'},
|
||||
Class: 2,
|
||||
Endianness: LittleEndian,
|
||||
Version: 1,
|
||||
OSABI: 0,
|
||||
ABIVersion: 0,
|
||||
Type: TypeDynamic,
|
||||
Architecture: Arch(b.Arch),
|
||||
FileVersion: 1,
|
||||
EntryPointInMemory: int64(code.MemoryOffset),
|
||||
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(code.FileOffset),
|
||||
VirtualAddress: int64(code.MemoryOffset),
|
||||
SizeInFile: int64(len(code.Bytes)),
|
||||
SizeInMemory: int64(len(code.Bytes)),
|
||||
Align: int64(b.MemoryAlign),
|
||||
},
|
||||
DataHeader: ProgramHeader{
|
||||
Type: ProgramTypeLOAD,
|
||||
Flags: ProgramFlagsReadable,
|
||||
Offset: int64(data.FileOffset),
|
||||
VirtualAddress: int64(data.MemoryOffset),
|
||||
SizeInFile: int64(len(data.Bytes)),
|
||||
SizeInMemory: int64(len(data.Bytes)),
|
||||
Align: int64(b.MemoryAlign),
|
||||
},
|
||||
}
|
||||
|
||||
elf.AddSections()
|
||||
binary.Write(writer, binary.LittleEndian, &elf.Header)
|
||||
binary.Write(writer, binary.LittleEndian, &elf.CodeHeader)
|
||||
binary.Write(writer, binary.LittleEndian, &elf.DataHeader)
|
||||
writer.Seek(int64(code.Padding), io.SeekCurrent)
|
||||
writer.Write(code.Bytes)
|
||||
writer.Seek(int64(data.Padding), io.SeekCurrent)
|
||||
writer.Write(data.Bytes)
|
||||
writer.Write(elf.StringTable)
|
||||
binary.Write(writer, binary.LittleEndian, &elf.SectionHeaders)
|
||||
}
|
15
src/elf/ELF_test.go
Normal file
15
src/elf/ELF_test.go
Normal file
|
@ -0,0 +1,15 @@
|
|||
package elf_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"git.urbach.dev/cli/q/src/build"
|
||||
"git.urbach.dev/cli/q/src/elf"
|
||||
"git.urbach.dev/cli/q/src/exe"
|
||||
)
|
||||
|
||||
func TestWrite(t *testing.T) {
|
||||
elf.Write(&exe.Discard{}, &build.Build{Arch: build.ARM, FileAlign: 0x4000, MemoryAlign: 0x4000}, nil, nil)
|
||||
elf.Write(&exe.Discard{}, &build.Build{Arch: build.X86, FileAlign: 0x1000, MemoryAlign: 0x1000}, nil, nil)
|
||||
elf.Write(&exe.Discard{}, &build.Build{Arch: build.UnknownArch, FileAlign: 0x1000, MemoryAlign: 0x1000}, nil, nil)
|
||||
}
|
28
src/elf/Header.go
Normal file
28
src/elf/Header.go
Normal file
|
@ -0,0 +1,28 @@
|
|||
package elf
|
||||
|
||||
// HeaderSize is equal to the size of a header in bytes.
|
||||
const HeaderSize = 64
|
||||
|
||||
// Header contains general information.
|
||||
type Header struct {
|
||||
Magic [4]byte
|
||||
Class byte
|
||||
Endianness byte
|
||||
Version byte
|
||||
OSABI byte
|
||||
ABIVersion byte
|
||||
_ [7]byte
|
||||
Type int16
|
||||
Architecture int16
|
||||
FileVersion int32
|
||||
EntryPointInMemory int64
|
||||
ProgramHeaderOffset int64
|
||||
SectionHeaderOffset int64
|
||||
Flags int32
|
||||
Size int16
|
||||
ProgramHeaderEntrySize int16
|
||||
ProgramHeaderEntryCount int16
|
||||
SectionHeaderEntrySize int16
|
||||
SectionHeaderEntryCount int16
|
||||
SectionNameStringTableIndex int16
|
||||
}
|
10
src/elf/ProgramFlags.go
Normal file
10
src/elf/ProgramFlags.go
Normal file
|
@ -0,0 +1,10 @@
|
|||
package elf
|
||||
|
||||
// ProgramFlags specifies the permissions for a segment.
|
||||
type ProgramFlags int32
|
||||
|
||||
const (
|
||||
ProgramFlagsExecutable ProgramFlags = 0x1
|
||||
ProgramFlagsWritable ProgramFlags = 0x2
|
||||
ProgramFlagsReadable ProgramFlags = 0x4
|
||||
)
|
16
src/elf/ProgramHeader.go
Normal file
16
src/elf/ProgramHeader.go
Normal file
|
@ -0,0 +1,16 @@
|
|||
package elf
|
||||
|
||||
// ProgramHeaderSize is equal to the size of a program header in bytes.
|
||||
const ProgramHeaderSize = 56
|
||||
|
||||
// ProgramHeader points to the executable part of our program.
|
||||
type ProgramHeader struct {
|
||||
Type ProgramType
|
||||
Flags ProgramFlags
|
||||
Offset int64
|
||||
VirtualAddress int64
|
||||
PhysicalAddress int64
|
||||
SizeInFile int64
|
||||
SizeInMemory int64
|
||||
Align int64
|
||||
}
|
15
src/elf/ProgramType.go
Normal file
15
src/elf/ProgramType.go
Normal file
|
@ -0,0 +1,15 @@
|
|||
package elf
|
||||
|
||||
// ProgramType indicates the program type.
|
||||
type ProgramType int32
|
||||
|
||||
const (
|
||||
ProgramTypeNULL ProgramType = 0
|
||||
ProgramTypeLOAD ProgramType = 1
|
||||
ProgramTypeDYNAMIC ProgramType = 2
|
||||
ProgramTypeINTERP ProgramType = 3
|
||||
ProgramTypeNOTE ProgramType = 4
|
||||
ProgramTypeSHLIB ProgramType = 5
|
||||
ProgramTypePHDR ProgramType = 6
|
||||
ProgramTypeTLS ProgramType = 7
|
||||
)
|
12
src/elf/SectionFlags.go
Normal file
12
src/elf/SectionFlags.go
Normal file
|
@ -0,0 +1,12 @@
|
|||
package elf
|
||||
|
||||
// SectionFlags defines flags for sections.
|
||||
type SectionFlags int64
|
||||
|
||||
const (
|
||||
SectionFlagsWritable SectionFlags = 1 << 0
|
||||
SectionFlagsAllocate SectionFlags = 1 << 1
|
||||
SectionFlagsExecutable SectionFlags = 1 << 2
|
||||
SectionFlagsStrings SectionFlags = 1 << 5
|
||||
SectionFlagsTLS SectionFlags = 1 << 10
|
||||
)
|
18
src/elf/SectionHeader.go
Normal file
18
src/elf/SectionHeader.go
Normal file
|
@ -0,0 +1,18 @@
|
|||
package elf
|
||||
|
||||
// SectionHeaderSize is equal to the size of a section header in bytes.
|
||||
const SectionHeaderSize = 64
|
||||
|
||||
// SectionHeader points to the data sections of our program.
|
||||
type SectionHeader struct {
|
||||
NameIndex int32
|
||||
Type SectionType
|
||||
Flags SectionFlags
|
||||
VirtualAddress int64
|
||||
Offset int64
|
||||
SizeInFile int64
|
||||
Link int32
|
||||
Info int32
|
||||
Align int64
|
||||
EntrySize int64
|
||||
}
|
19
src/elf/SectionType.go
Normal file
19
src/elf/SectionType.go
Normal file
|
@ -0,0 +1,19 @@
|
|||
package elf
|
||||
|
||||
// SectionType defines the type of the section.
|
||||
type SectionType int32
|
||||
|
||||
const (
|
||||
SectionTypeNULL SectionType = 0
|
||||
SectionTypePROGBITS SectionType = 1
|
||||
SectionTypeSYMTAB SectionType = 2
|
||||
SectionTypeSTRTAB SectionType = 3
|
||||
SectionTypeRELA SectionType = 4
|
||||
SectionTypeHASH SectionType = 5
|
||||
SectionTypeDYNAMIC SectionType = 6
|
||||
SectionTypeNOTE SectionType = 7
|
||||
SectionTypeNOBITS SectionType = 8
|
||||
SectionTypeREL SectionType = 9
|
||||
SectionTypeSHLIB SectionType = 10
|
||||
SectionTypeDYNSYM SectionType = 11
|
||||
)
|
Loading…
Add table
Add a link
Reference in a new issue