Implemented ELF header
This commit is contained in:
parent
cae6696c3e
commit
4554fb82cb
@ -19,7 +19,7 @@ go build
|
||||
## Usage
|
||||
|
||||
```shell
|
||||
q build
|
||||
./q build examples/hello
|
||||
```
|
||||
|
||||
## License
|
||||
|
@ -1,6 +1,12 @@
|
||||
package build
|
||||
|
||||
import "path/filepath"
|
||||
import (
|
||||
"bufio"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"git.akyoto.dev/cli/q/build/elf"
|
||||
)
|
||||
|
||||
// Build describes a compiler build.
|
||||
type Build struct {
|
||||
@ -30,5 +36,37 @@ func New(directory string) (*Build, error) {
|
||||
|
||||
// Run parses the input files and generates an executable file.
|
||||
func (build *Build) Run() error {
|
||||
if build.WriteExecutable {
|
||||
sampleCode := []byte{
|
||||
0xb8, 0x3c, 0x00, 0x00, 0x00, // mov rax, 60
|
||||
0xbf, 0x00, 0x00, 0x00, 0x00, // mov rdi, 0
|
||||
0x0f, 0x05, // syscall
|
||||
}
|
||||
|
||||
return writeToDisk(build.ExecutablePath, sampleCode, nil)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// writeToDisk writes the executable file to disk.
|
||||
func writeToDisk(filePath string, code []byte, data []byte) error {
|
||||
file, err := os.Create(filePath)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
buffer := bufio.NewWriter(file)
|
||||
executable := elf.New()
|
||||
executable.Write(buffer)
|
||||
buffer.Flush()
|
||||
|
||||
err = file.Close()
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return os.Chmod(filePath, 0755)
|
||||
}
|
||||
|
32
build/elf/Header.go
Normal file
32
build/elf/Header.go
Normal file
@ -0,0 +1,32 @@
|
||||
package elf
|
||||
|
||||
const (
|
||||
LittleEndian = 1
|
||||
TypeExecutable = 2
|
||||
ArchitectureAMD64 = 0x3E
|
||||
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
|
||||
}
|
37
build/elf/ProgramHeader.go
Normal file
37
build/elf/ProgramHeader.go
Normal file
@ -0,0 +1,37 @@
|
||||
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
|
||||
}
|
||||
|
||||
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
|
||||
)
|
||||
|
||||
type ProgramFlags int32
|
||||
|
||||
const (
|
||||
ProgramFlagsExecutable ProgramFlags = 0x1
|
||||
ProgramFlagsWritable ProgramFlags = 0x2
|
||||
ProgramFlagsReadable ProgramFlags = 0x4
|
||||
)
|
45
build/elf/SectionHeader.go
Normal file
45
build/elf/SectionHeader.go
Normal file
@ -0,0 +1,45 @@
|
||||
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
|
||||
}
|
||||
|
||||
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
|
||||
)
|
||||
|
||||
type SectionFlags int64
|
||||
|
||||
const (
|
||||
SectionFlagsWritable SectionFlags = 1 << 0
|
||||
SectionFlagsAllocate SectionFlags = 1 << 1
|
||||
SectionFlagsExecutable SectionFlags = 1 << 2
|
||||
SectionFlagsStrings SectionFlags = 1 << 5
|
||||
SectionFlagsTLS SectionFlags = 1 << 10
|
||||
)
|
51
build/elf/elf.go
Normal file
51
build/elf/elf.go
Normal file
@ -0,0 +1,51 @@
|
||||
package elf
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"io"
|
||||
)
|
||||
|
||||
const (
|
||||
baseAddress = 0x400000
|
||||
programAlign = 16
|
||||
sectionAlign = 16
|
||||
)
|
||||
|
||||
// ELF64 represents an ELF 64-bit file.
|
||||
type ELF64 struct {
|
||||
Header
|
||||
}
|
||||
|
||||
// New creates a new 64-bit ELF binary.
|
||||
func New() *ELF64 {
|
||||
elf := &ELF64{
|
||||
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: 0,
|
||||
ProgramHeaderOffset: HeaderSize,
|
||||
SectionHeaderOffset: 0, // TODO
|
||||
Flags: 0,
|
||||
Size: HeaderSize,
|
||||
ProgramHeaderEntrySize: ProgramHeaderSize,
|
||||
ProgramHeaderEntryCount: 0,
|
||||
SectionHeaderEntrySize: SectionHeaderSize,
|
||||
SectionHeaderEntryCount: 0,
|
||||
SectionNameStringTableIndex: 0,
|
||||
},
|
||||
}
|
||||
|
||||
return elf
|
||||
}
|
||||
|
||||
// Write writes the ELF64 format to the given writer.
|
||||
func (elf *ELF64) Write(writer io.Writer) {
|
||||
binary.Write(writer, binary.LittleEndian, &elf.Header)
|
||||
}
|
12
build/elf/elf.md
Normal file
12
build/elf/elf.md
Normal file
@ -0,0 +1,12 @@
|
||||
# ELF
|
||||
|
||||
## File contents
|
||||
|
||||
- ELF header
|
||||
- Program headers
|
||||
- Sections
|
||||
- Section headers
|
||||
|
||||
## Entry point
|
||||
|
||||
The entry point is defined in the first 64 bytes (ELF header).
|
Loading…
Reference in New Issue
Block a user