diff options
| author | Jacob McDonnell <jacob@jacobmcdonnell.com> | 2024-08-25 17:53:06 -0400 |
|---|---|---|
| committer | Jacob McDonnell <jacob@jacobmcdonnell.com> | 2024-08-25 17:53:06 -0400 |
| commit | ef89f5a85c590b35910ce89c37a2a8d920e1554e (patch) | |
| tree | 5afb58c82348abcda0c3b8eb2dfa4fa1293b28ee | |
| parent | 843806d7c80bfec8fcea5fae81961fa35c91a804 (diff) | |
| -rwxr-xr-x | README.md | 8 | ||||
| -rwxr-xr-x | assemble.go | 7 | ||||
| -rwxr-xr-x | elf.go | 51 | ||||
| -rwxr-xr-x | qdma.go | 152 | ||||
| -rwxr-xr-x | symbol.go | 5 |
5 files changed, 130 insertions, 93 deletions
@@ -7,6 +7,14 @@ QDMA is a simple MIPS assembler written in Go for emulator. QDMA implements a partial version of the Executable and Linkable Format (ELF), [See Partial ELF for more information](#Partial-ELF). +## Options + +- `-o output` set an output file name + +- `-b` Set byte order to big endian (default is native) + +- `-l` Set byte order to little endian (default is native) + ## TODO - ~Assemble Instructions into Binary~ diff --git a/assemble.go b/assemble.go index 923fb33..9554080 100755 --- a/assemble.go +++ b/assemble.go @@ -2,7 +2,6 @@ package main import ( "bufio" - "encoding/binary" "fmt" "os" "regexp" @@ -91,10 +90,10 @@ func Encode(inst []string, pc int32) ([]byte, error) { for _, s := range inst { switch s { case "syscall": - binary.NativeEndian.PutUint32(bytes, 12) + byteOrder.PutUint32(bytes, 12) return bytes, nil case "nop": - binary.NativeEndian.PutUint32(bytes, 0) + byteOrder.PutUint32(bytes, 0) return bytes, nil } } @@ -177,7 +176,7 @@ func Encode(inst []string, pc int32) ([]byte, error) { (RegNums[inst[1]] << 16) | (0xFFFF & uint32(imm)) } fmt.Println(inst) - binary.NativeEndian.PutUint32(bytes, ret) + byteOrder.PutUint32(bytes, ret) return bytes, nil } @@ -60,11 +60,18 @@ func EHInit(e_entry uint32, e_phnum uint16) ElfHeader { var e ElfHeader e.e_ident = [EI_NIDENT]byte{0x7f, 0x45, 0x4c, 0x46, // ELF magic number 0x01, // 32-bit format - 0x01, // Little Endian + 0x00, // Endian 0x01, // ELF Version 0x00, // Target OS 0x00, // Target ABI 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} // Padding + + if byteOrder == binary.BigEndian { + e.e_ident[5] = 0x02 + } else { + e.e_ident[5] = 0x01 + } + e.e_type = ET_EXEC e.e_machine = MIPS e.e_version = 0x01 @@ -95,31 +102,31 @@ func (e *ElfHeader) ToBytes() []byte { bytes[i] = b i++ } - binary.NativeEndian.PutUint16(bytes[EI_NIDENT:], e.e_type) - binary.NativeEndian.PutUint16(bytes[18:], e.e_machine) - binary.NativeEndian.PutUint32(bytes[20:], e.e_version) - binary.NativeEndian.PutUint32(bytes[24:], e.e_entry) - binary.NativeEndian.PutUint32(bytes[28:], e.e_phoff) - binary.NativeEndian.PutUint32(bytes[32:], e.e_shoff) - binary.NativeEndian.PutUint32(bytes[36:], e.e_flags) - binary.NativeEndian.PutUint16(bytes[40:], e.e_ehsize) - binary.NativeEndian.PutUint16(bytes[42:], e.e_phentsize) - binary.NativeEndian.PutUint16(bytes[44:], e.e_phnum) - binary.NativeEndian.PutUint16(bytes[46:], e.e_shentsize) - binary.NativeEndian.PutUint16(bytes[48:], e.e_shnum) - binary.NativeEndian.PutUint16(bytes[50:], e.e_shstrndx) + byteOrder.PutUint16(bytes[EI_NIDENT:], e.e_type) + byteOrder.PutUint16(bytes[18:], e.e_machine) + byteOrder.PutUint32(bytes[20:], e.e_version) + byteOrder.PutUint32(bytes[24:], e.e_entry) + byteOrder.PutUint32(bytes[28:], e.e_phoff) + byteOrder.PutUint32(bytes[32:], e.e_shoff) + byteOrder.PutUint32(bytes[36:], e.e_flags) + byteOrder.PutUint16(bytes[40:], e.e_ehsize) + byteOrder.PutUint16(bytes[42:], e.e_phentsize) + byteOrder.PutUint16(bytes[44:], e.e_phnum) + byteOrder.PutUint16(bytes[46:], e.e_shentsize) + byteOrder.PutUint16(bytes[48:], e.e_shnum) + byteOrder.PutUint16(bytes[50:], e.e_shstrndx) return bytes } func (p *ProgramHeader) ToBytes() []byte { bytes := make([]byte, PHENSIZE) - binary.NativeEndian.PutUint32(bytes[0:], p.ptype) - binary.NativeEndian.PutUint32(bytes[4:], p.offset) - binary.NativeEndian.PutUint32(bytes[8:], p.vaddr) - binary.NativeEndian.PutUint32(bytes[12:], p.paddr) - binary.NativeEndian.PutUint32(bytes[16:], p.filesz) - binary.NativeEndian.PutUint32(bytes[20:], p.memsz) - binary.NativeEndian.PutUint32(bytes[24:], p.flags) - binary.NativeEndian.PutUint32(bytes[28:], p.align) + byteOrder.PutUint32(bytes[0:], p.ptype) + byteOrder.PutUint32(bytes[4:], p.offset) + byteOrder.PutUint32(bytes[8:], p.vaddr) + byteOrder.PutUint32(bytes[12:], p.paddr) + byteOrder.PutUint32(bytes[16:], p.filesz) + byteOrder.PutUint32(bytes[20:], p.memsz) + byteOrder.PutUint32(bytes[24:], p.flags) + byteOrder.PutUint32(bytes[28:], p.align) return bytes } @@ -1,84 +1,108 @@ package main import ( + "encoding/binary" "os" - "strings" ) -func main() { - for _, arg := range os.Args[1:] { - tempData, err := os.CreateTemp("", "data*") - Check(err) - dName := tempData.Name() - defer os.Remove(dName) +type PathPair struct { + input string + output string +} - tempRoData, err := os.CreateTemp("", "rodata*") - Check(err) - rName := tempRoData.Name() - defer os.Remove(rName) +var byteOrder binary.ByteOrder = binary.NativeEndian - tempText, err := os.CreateTemp("", "text*") - Check(err) - tName := tempText.Name() - defer os.Remove(tName) - - // First pass to find the address of all labels and encode the data - LabelFind(arg, tempData, tempRoData) - - var names [3]string - var PHeaders [4]ProgramHeader - i := 0 - n := 0 - - if SectionPos[TEXT] > 0 { - PHeaders[i] = ProgramHeader{PT_LOAD, 0, 0, 0, - uint32(SectionPos[TEXT]), uint32(SectionPos[TEXT]), PF_READ + - PF_EXEC, 0} - names[i] = tName - i++ - n++ - // Second pass to assemble the instructions. - Assemble(arg, tempText) +func main() { + var inputFiles []PathPair + for i, arg := range os.Args[1:] { + switch arg { + case "-b": + byteOrder = binary.BigEndian + case "-l": + byteOrder = binary.LittleEndian + case "-o": + inputFiles = append(inputFiles, PathPair{os.Args[i+3], os.Args[i+2]}) } + } - if SectionPos[DATA] > 0 { - PHeaders[i] = ProgramHeader{PT_LOAD, 0, 0, 0, - uint32(SectionPos[DATA]), uint32(SectionPos[DATA]), PF_READ + - PF_WRITE, 0} - names[i] = dName - i++ - n++ - } + for _, p := range inputFiles { + AssembleFile(p) + } +} - if SectionPos[RODATA] > 0 { - PHeaders[i] = ProgramHeader{PT_LOAD, 0, 0, 0, - uint32(SectionPos[RODATA]), uint32(SectionPos[RODATA]), PF_READ, 0} - names[i] = rName - i++ - n++ - } +func AssembleFile(path PathPair) { + tempData, err := os.CreateTemp("", "data*") + Check(err) + dName := tempData.Name() + defer os.Remove(dName) - if SectionPos[BSS] > 0 { - PHeaders[i] = ProgramHeader{PT_LOAD, 0, 0, 0, 0, - uint32(SectionPos[BSS]), PF_READ + PF_WRITE, 0} - i++ - } + tempRoData, err := os.CreateTemp("", "rodata*") + Check(err) + rName := tempRoData.Name() + defer os.Remove(rName) - var fOffset, mOffset uint32 = 0, 0 - for j, p := range PHeaders[:i] { - PHeaders[j].offset = uint32(i*PHENSIZE) + fOffset + EHSIZE - fOffset += p.filesz - PHeaders[j].vaddr = mOffset - mOffset += p.memsz - } + tempText, err := os.CreateTemp("", "text*") + Check(err) + tName := tempText.Name() + defer os.Remove(tName) + + // First pass to find the address of all labels and encode the data + LabelFind(path.input, tempData, tempRoData) + + var names [3]string + var PHeaders [4]ProgramHeader + i := 0 + n := 0 + + if SectionPos[TEXT] > 0 { + PHeaders[i] = ProgramHeader{PT_LOAD, 0, 0, 0, + uint32(SectionPos[TEXT]), uint32(SectionPos[TEXT]), PF_READ + + PF_EXEC, 0} + names[i] = tName + i++ + n++ + // Second pass to assemble the instructions. + Assemble(path.input, tempText) + } + + if SectionPos[DATA] > 0 { + PHeaders[i] = ProgramHeader{PT_LOAD, 0, 0, 0, + uint32(SectionPos[DATA]), uint32(SectionPos[DATA]), PF_READ + + PF_WRITE, 0} + names[i] = dName + i++ + n++ + } + + if SectionPos[RODATA] > 0 { + PHeaders[i] = ProgramHeader{PT_LOAD, 0, 0, 0, + uint32(SectionPos[RODATA]), uint32(SectionPos[RODATA]), PF_READ, 0} + names[i] = rName + i++ + n++ + } - EHeader := EHInit(0, uint16(i)) - WriteBinary(arg, EHeader, PHeaders[:i], names[:n]) + if SectionPos[BSS] > 0 { + PHeaders[i] = ProgramHeader{PT_LOAD, 0, 0, 0, 0, + uint32(SectionPos[BSS]), PF_READ + PF_WRITE, 0} + i++ } + + var fOffset, mOffset uint32 = 0, 0 + for j, p := range PHeaders[:i] { + PHeaders[j].offset = uint32(i*PHENSIZE) + fOffset + EHSIZE + fOffset += p.filesz + PHeaders[j].vaddr = mOffset + mOffset += p.memsz + } + + EHeader := EHInit(0, uint16(i)) + WriteBinary(path, EHeader, PHeaders[:i], names[:n]) + } -func WriteBinary(path string, e ElfHeader, ps []ProgramHeader, ns []string) { - out, err := os.Create(strings.ReplaceAll(path, ".asm", ".bin")) +func WriteBinary(path PathPair, e ElfHeader, ps []ProgramHeader, ns []string) { + out, err := os.Create(path.output) Check(err) defer out.Close() _, err = out.Write(e.ToBytes()) @@ -2,7 +2,6 @@ package main import ( "bufio" - "encoding/binary" "os" "regexp" "strconv" @@ -170,9 +169,9 @@ func EncodeData(line []string) ([]byte, error) { case 1: bytes[0] = uint8(data) case 2: - binary.NativeEndian.PutUint16(bytes, uint16(data)) + byteOrder.PutUint16(bytes, uint16(data)) case 4: - binary.NativeEndian.PutUint32(bytes, uint32(data)) + byteOrder.PutUint32(bytes, uint32(data)) } } else if isString { if nullTerm { |
