summaryrefslogtreecommitdiff
path: root/elf.go
blob: ea901801044977b4828be61c718f4ff446623598 (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
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
		0x01,                                     // Little Endian
		0x01,                                     // ELF Version
		0x00,                                     // Target OS
		0x00,                                     // Target ABI
		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} // Padding
	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++
	}
	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)
	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)
	return bytes
}