Implemented ELF header
This commit is contained in:
parent
cae6696c3e
commit
4554fb82cb
@ -19,7 +19,7 @@ go build
|
|||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
q build
|
./q build examples/hello
|
||||||
```
|
```
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
@ -1,6 +1,12 @@
|
|||||||
package build
|
package build
|
||||||
|
|
||||||
import "path/filepath"
|
import (
|
||||||
|
"bufio"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
|
||||||
|
"git.akyoto.dev/cli/q/build/elf"
|
||||||
|
)
|
||||||
|
|
||||||
// Build describes a compiler build.
|
// Build describes a compiler build.
|
||||||
type Build struct {
|
type Build struct {
|
||||||
@ -30,5 +36,37 @@ func New(directory string) (*Build, error) {
|
|||||||
|
|
||||||
// Run parses the input files and generates an executable file.
|
// Run parses the input files and generates an executable file.
|
||||||
func (build *Build) Run() error {
|
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
|
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