summaryrefslogtreecommitdiff
path: root/mld/link.h
blob: 9096975a6a5d6fd33d95cde8fbb327520f7da262 (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
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
/* Copyright (c) 2024 Freya Murphy */

#ifndef __LINK_H__
#define __LINK_H__

#include <linux/limits.h>
#include <mlimits.h>
#include <mips.h>
#include <merror.h>
#include <stdint.h>
#include <elf.h>


// when mapping porinters, we need to bounds check to
// make sure its in the mapped object file
//
// this checks that
// 1. the end is in the file
// 2. the off and len doesnt integer overflow
#define BOUND_CHK(obj, len, off) \
	(off > UINT32_MAX - len || off + len > obj->mapped_size)

// when relocating segments, we need to bounds check to
// make sure it wont overflow the addresses past the 32bit
// ELF file
#define ADDR_CHK(lnk_f, seg_f, max) \
	((lnk_f) > max - (seg_f) || (lnk_f) + (seg_f) > max)

// checks if a phdr and shdr are matches
#define PHDR_SHDR_MATCH(phdr, shdr) (              \
	((phdr)->p_offset == (shdr)->sh_offset) && \
	((phdr)->p_filesz == (shdr)->sh_size))     \

// start addresses for each tyoe of segment
#define TEXT_VADDR_MIN 0x00400000
#define DATA_VADDR_MIN 0x10000000

// pre define
struct linker;
struct object;
struct segment;

///
/// relocation table
///

struct relocation_table {
	uint32_t type;
	union {
		void *raw;
		Elf32_Rel  *rel;
		Elf32_Rela *rela;
	};
	size_t len;
	struct symbol_table *symtab;
};

///
/// string table
///

struct string_table {
	char *data;
	size_t len;
};

int strtab_init(struct string_table *strtab);
void strtab_free(struct string_table *strtab);

int strtab_push(struct string_table *strtab, const char *str, size_t *res);
int strtab_get(struct string_table *strtab, const char *str, size_t *res);

///
/// symbol table
///

struct symbol_table {
	struct string_table *strtab;
	Elf32_Sym *syms;
	size_t len;
	size_t size;
};

int symtab_init(struct symbol_table *symtab);
void symtab_free(struct symbol_table *symtab);

int symtab_push(struct symbol_table *symtab, const Elf32_Sym *sym);
int symtab_get(struct symbol_table *symtab, Elf32_Sym **sym, const char *name);

///
/// segment
///

/* a loadable program segment */
struct segment {
	// segment data
	char *name;
	unsigned char *bytes;

	// current loc
	uint32_t off;
	uint32_t vaddr;

	// new loc
	uint32_t new_off;
	uint32_t new_vaddr;

	// meta
	bool read;
	bool write;
	bool execute;
	uint32_t align;

	// size
	uint32_t size;

	// phdr
	Elf32_Phdr *phdr;
	uint32_t phdr_idx;

	// shdr
	Elf32_Shdr *shdr;
	uint32_t shdr_idx;

	// object im related to
	struct object *obj;
	// segment table entry im related to
	struct segment_table_entry *ent;

	// relocation table
	struct relocation_table reltab;
};

int segment_load(struct object *object, struct segment *segment, size_t index);

///
/// segment table
///

struct segment_table_entry {
	char *name;
	uint32_t len;
	uint32_t size;
	uint32_t off;
	uint32_t vaddr;
	// weak segment pointers. we do not own these!!!
	struct segment **parts;
};

int segtab_ent_init(struct segment_table_entry *ent);
void segtab_ent_free(struct segment_table_entry *ent);

int segtab_ent_push(struct segment_table_entry *ent, struct segment *seg);
uint32_t segtab_ent_size(struct segment_table_entry *ent);

// holds each segment by name
// and all the segment parts from each of the
// object files
struct segment_table {
	uint32_t len;
	uint32_t size;
	struct segment_table_entry *entries;
};

int segtab_init(struct segment_table *segtab);
void segtab_free(struct segment_table *segtab);

/* create a new entry with <seg> as its first segment part */
int segtab_push(struct segment_table *segtab, struct segment_table_entry **ent,
		struct segment *seg);

/* find a segment table entry with a given name */
int segtab_get(struct segment_table *segtab, struct segment_table_entry **ent,
	       const char *name);

///
/// object file
///

struct object {
	// file
	int fd;
	char *mapped;
	size_t mapped_size;

	// ehdr
	Elf32_Ehdr *ehdr;

	// section header table
	Elf32_Shdr *shdr;
	size_t shdr_len;

	// program table
	Elf32_Phdr *phdr;
	size_t phdr_len;

	// object meta
	const char *name;
	size_t index;

	// segments
	size_t segment_len;
	struct segment *segments;

	// section header strtab
	struct string_table *shstrtab;

	// strtabs
	struct string_table *strtabs;
	// symtabs
	struct symbol_table *symtabs;
};

int object_load(struct object *object, char *path);

void object_free(struct object *object);

///
/// linker
///

struct linker {
	size_t obj_len;
	struct object *objects;

	struct linker_arguments *args;

	// current pointers to relocate
	// sections
	uint32_t off;
	uint32_t text_vaddr;
	uint32_t data_vaddr;

	// elf tables
	struct string_table shstrtab;
	struct string_table strtab;
	struct symbol_table symtab;

	// output elf
	Elf32_Ehdr ehdr;
	Elf32_Phdr *phdr;
	uint32_t phdr_len;
	Elf32_Shdr *shdr;
	uint32_t shdr_len;

	uint32_t symtab_shidx;
	uint32_t strtab_shidx;
	uint32_t shstrtab_shidx;

	// section alignment after phdr bytes
	uint32_t secalign;

	// all segments
	struct segment_table segments;
};

/* defines arguments to the linker */
struct linker_arguments {
	char **in_files;
	int in_count;
	char *out_file;
	bool freestanding;
};

/* link object files */
int link_files(struct linker_arguments args);

#endif /* __LINK_H__ */