summaryrefslogtreecommitdiff
path: root/elf.go
blob: 7030c966cbdd69a6182ef1d517a03a0bbb0978d9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
package main

import (
	"encoding/binary"
)

const (
	EI_NIDENT  = 16
	ET_NONE    = 0
	ET_REL     = 1
	ET_EXEC    = 2
	ET_DYN     = 3
	ET_CORE    = 4
	MIPS       = 0x08
	EHSIZE     = 52
	PHENSIZE   = 0x20
	SHENTSIZE  = 0x28
	PT_NULL    = 0
	PT_LOAD    = 1
	PT_DYNAMIC = 2
	PT_INTERP  = 3
	PT_NOTE    = 4
	PT_SHLIB   = 5
	PT_PHDR    = 6
	PT_TLS     = 7
	PF_READ    = 4
	PF_WRITE   = 2
	PF_EXEC    = 1
)

type ElfHeader struct {
	e_ident     [EI_NIDENT]byte
	e_type      uint16
	e_machine   uint16
	e_version   uint32
	e_entry     uint32
	e_phoff     uint32
	e_shoff     uint32
	e_flags     uint32
	e_ehsize    uint16
	e_phentsize uint16
	e_phnum     uint16
	e_shentsize uint16
	e_shnum     uint16
	e_shstrndx  uint16
}

type ProgramHeader struct {
	ptype  uint32
	offset uint32
	vaddr  uint32
	paddr  uint32
	filesz uint32
	memsz  uint32
	flags  uint32
	align  uint32
}

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
		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
	e.e_entry = e_entry
	e.e_phoff = EHSIZE // Program headers will be after ELF Header
	e.e_shoff = 0
	e.e_ehsize = EHSIZE
	e.e_phentsize = PHENSIZE
	e.e_phnum = e_phnum
	e.e_shentsize = SHENTSIZE
	e.e_shnum = 0
	e.e_shstrndx = 0
	return e
}

/* NOTES: On the ToBytes methods
 * I understand that these two methods are not the prettiest, but I need
 * something to convert these structs to to byte arrays. From what I've read so
 * far there seems to be no way to do this. It appears that encoding/gob
 * ignores the size of data types, which is needed, and json serialization
 * would not produce the proper output.
 */

func (e *ElfHeader) ToBytes() []byte {
	bytes := make([]byte, EHSIZE)
	i := 0
	for _, b := range e.e_ident {
		bytes[i] = b
		i++
	}
	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)
	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
}