xref: /aosp_15_r20/external/coreboot/util/cbfstool/rmodule.c (revision b9411a12aaaa7e1e6a6fb7c5e057f44ee179a49c)
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 
3 #include <inttypes.h>
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include <string.h>
7 
8 #include "elfparsing.h"
9 #include "rmodule.h"
10 #include <commonlib/rmodule-defs.h>
11 
12 /*
13  * Architecture specific support operations.
14  */
valid_reloc_386(Elf64_Rela * rel)15 static int valid_reloc_386(Elf64_Rela *rel)
16 {
17 	int type;
18 
19 	type = ELF64_R_TYPE(rel->r_info);
20 
21 	/* Only these 2 relocations are expected to be found. */
22 	return (type == R_386_32 || type == R_386_PC32);
23 }
24 
should_emit_386(Elf64_Rela * rel)25 static int should_emit_386(Elf64_Rela *rel)
26 {
27 	int type;
28 
29 	type = ELF64_R_TYPE(rel->r_info);
30 
31 	/* R_386_32 relocations are absolute. Must emit these. */
32 	return (type == R_386_32);
33 }
34 
valid_reloc_amd64(Elf64_Rela * rel)35 static int valid_reloc_amd64(Elf64_Rela *rel)
36 {
37 	int type;
38 
39 	type = ELF64_R_TYPE(rel->r_info);
40 
41 	/*
42 	 * Relocation R_AMD64_32S is not allowed. It can only be safely used in protected mode,
43 	 * and when the address pointed to is below 2 GiB in long mode.
44 	 * Using it in assembly operations will break compilation with error:
45 	 * E: Invalid reloc type: 11
46 	 */
47 
48 	/* Only these 5 relocations are expected to be found. */
49 	return (type == R_AMD64_64 ||
50 		type == R_AMD64_PC64 ||
51 		type == R_AMD64_32 ||
52 		type == R_AMD64_PC32 ||
53 	/*
54 	 * binutils 2.31 introduced R_AMD64_PLT32 for non local
55 	 * functions. As we don't care about procedure linkage
56 	 * table entries handle it as R_X86_64_PC32.
57 	 */
58 		type == R_AMD64_PLT32);
59 }
60 
should_emit_amd64(Elf64_Rela * rel)61 static int should_emit_amd64(Elf64_Rela *rel)
62 {
63 	int type;
64 
65 	type = ELF64_R_TYPE(rel->r_info);
66 
67 	/* Only emit absolute relocations */
68 	return (type == R_AMD64_64 ||
69 		type == R_AMD64_32);
70 }
71 
valid_reloc_arm(Elf64_Rela * rel)72 static int valid_reloc_arm(Elf64_Rela *rel)
73 {
74 	int type;
75 
76 	type = ELF64_R_TYPE(rel->r_info);
77 
78 	/* Only these 6 relocations are expected to be found. */
79 	return (type == R_ARM_ABS32 || type == R_ARM_THM_PC22 ||
80 		type == R_ARM_THM_JUMP24 || type == R_ARM_V4BX ||
81 		type == R_ARM_CALL || type == R_ARM_JUMP24);
82 }
83 
should_emit_arm(Elf64_Rela * rel)84 static int should_emit_arm(Elf64_Rela *rel)
85 {
86 	int type;
87 
88 	type = ELF64_R_TYPE(rel->r_info);
89 
90 	/* R_ARM_ABS32 relocations are absolute. Must emit these. */
91 	return (type == R_ARM_ABS32);
92 }
93 
valid_reloc_aarch64(Elf64_Rela * rel)94 static int valid_reloc_aarch64(Elf64_Rela *rel)
95 {
96 	int type;
97 
98 	type = ELF64_R_TYPE(rel->r_info);
99 
100 	return (type == R_AARCH64_ADR_PREL_PG_HI21 ||
101 		type == R_AARCH64_ADD_ABS_LO12_NC  ||
102 		type == R_AARCH64_LDST8_ABS_LO12_NC ||
103 		type == R_AARCH64_CONDBR19 ||
104 		type == R_AARCH64_JUMP26 ||
105 		type == R_AARCH64_LDST32_ABS_LO12_NC ||
106 		type == R_AARCH64_LDST64_ABS_LO12_NC ||
107 		type == R_AARCH64_CALL26 ||
108 		type == R_AARCH64_ABS64 ||
109 		type == R_AARCH64_LD_PREL_LO19 ||
110 		type == R_AARCH64_ADR_PREL_LO21);
111 }
112 
should_emit_aarch64(Elf64_Rela * rel)113 static int should_emit_aarch64(Elf64_Rela *rel)
114 {
115 	int type;
116 
117 	type = ELF64_R_TYPE(rel->r_info);
118 
119 	return (type == R_AARCH64_ABS64);
120 }
121 
122 static const struct arch_ops reloc_ops[] = {
123 	{
124 		.arch = EM_386,
125 		.valid_type = valid_reloc_386,
126 		.should_emit = should_emit_386,
127 	},
128 	{
129 		.arch = EM_X86_64,
130 		.valid_type = valid_reloc_amd64,
131 		.should_emit = should_emit_amd64,
132 	},
133 	{
134 		.arch = EM_ARM,
135 		.valid_type = valid_reloc_arm,
136 		.should_emit = should_emit_arm,
137 	},
138 	{
139 		.arch = EM_AARCH64,
140 		.valid_type = valid_reloc_aarch64,
141 		.should_emit = should_emit_aarch64,
142 	},
143 };
144 
relocation_for_absolute_symbol(struct rmod_context * ctx,Elf64_Rela * r)145 static int relocation_for_absolute_symbol(struct rmod_context *ctx, Elf64_Rela *r)
146 {
147 	Elf64_Sym *s = &ctx->pelf.syms[ELF64_R_SYM(r->r_info)];
148 
149 	if (s->st_shndx == SHN_ABS) {
150 		DEBUG("Omitting relocation for absolute symbol: %s\n",
151 		      &ctx->strtab[s->st_name]);
152 		return 1;
153 	}
154 
155 	return 0;
156 }
157 
relocation_for_weak_extern_symbols(struct rmod_context * ctx,Elf64_Rela * r)158 static int relocation_for_weak_extern_symbols(struct rmod_context *ctx, Elf64_Rela *r)
159 {
160 	Elf64_Sym *s = &ctx->pelf.syms[ELF64_R_SYM(r->r_info)];
161 
162 	if (ELF64_ST_BIND(s->st_info) == STB_WEAK && ELF64_ST_TYPE(s->st_info) == STT_NOTYPE) {
163 		DEBUG("Omitting relocation for undefined extern: %s\n",
164 		      &ctx->strtab[s->st_name]);
165 		return 1;
166 	}
167 
168 	return 0;
169 }
170 
relocation_for_undefined_symbol(struct rmod_context * ctx,Elf64_Rela * r)171 static int relocation_for_undefined_symbol(struct rmod_context *ctx, Elf64_Rela *r)
172 {
173 	Elf64_Sym *s = &ctx->pelf.syms[ELF64_R_SYM(r->r_info)];
174 
175 	if (s->st_shndx == SHN_UNDEF) {
176 		DEBUG("Omitting relocation for undefined symbol: %s\n",
177 		      &ctx->strtab[s->st_name]);
178 		return 1;
179 	}
180 
181 	return 0;
182 }
183 
184 /*
185  * Relocation processing loops.
186  */
187 
for_each_reloc(struct rmod_context * ctx,struct reloc_filter * f,int do_emit)188 static int for_each_reloc(struct rmod_context *ctx, struct reloc_filter *f,
189 				int do_emit)
190 {
191 	Elf64_Half i;
192 	struct parsed_elf *pelf = &ctx->pelf;
193 
194 	for (i = 0; i < pelf->ehdr.e_shnum; i++) {
195 		Elf64_Shdr *shdr;
196 		Elf64_Rela *relocs;
197 		Elf64_Xword nrelocs;
198 		Elf64_Xword j;
199 
200 		relocs = pelf->relocs[i];
201 
202 		/* No relocations in this section. */
203 		if (relocs == NULL)
204 			continue;
205 
206 		shdr = &pelf->shdr[i];
207 		nrelocs = shdr->sh_size / shdr->sh_entsize;
208 
209 		for (j = 0; j < nrelocs; j++) {
210 			int filter_emit = 1;
211 			Elf64_Rela *r = &relocs[j];
212 
213 			if (!ctx->ops->valid_type(r)) {
214 				ERROR("Invalid reloc type: %u\n",
215 				      (unsigned int)ELF64_R_TYPE(r->r_info));
216 				if ((ctx->ops->arch == EM_X86_64) &&
217 				    (ELF64_R_TYPE(r->r_info) == R_AMD64_32S))
218 					ERROR("Illegal use of 32bit sign extended addressing at offset 0x%x\n",
219 					      (unsigned int)r->r_offset);
220 				return -1;
221 			}
222 
223 			if (relocation_for_absolute_symbol(ctx, r))
224 				continue;
225 
226 			if (relocation_for_weak_extern_symbols(ctx, r))
227 				continue;
228 
229 			if (relocation_for_undefined_symbol(ctx, r))
230 				continue;
231 
232 			/* Allow the provided filter to have precedence. */
233 			if (f != NULL) {
234 				filter_emit = f->filter(f, r);
235 
236 				if (filter_emit < 0)
237 					return filter_emit;
238 			}
239 
240 			if (filter_emit && ctx->ops->should_emit(r)) {
241 				int n = ctx->nrelocs;
242 				if (do_emit)
243 					ctx->emitted_relocs[n] = r->r_offset;
244 				ctx->nrelocs++;
245 			}
246 		}
247 	}
248 
249 	return 0;
250 }
251 
find_program_segment(struct rmod_context * ctx)252 static int find_program_segment(struct rmod_context *ctx)
253 {
254 	int i;
255 	int nsegments;
256 	struct parsed_elf *pelf;
257 	Elf64_Phdr *phdr = NULL;
258 
259 	pelf = &ctx->pelf;
260 
261 	/* There should only be a single loadable segment. */
262 	nsegments = 0;
263 	for (i = 0; i < pelf->ehdr.e_phnum; i++) {
264 		if (pelf->phdr[i].p_type != PT_LOAD)
265 			continue;
266 		if (!phdr)
267 			phdr = &pelf->phdr[i];
268 		nsegments++;
269 	}
270 
271 	if (nsegments == 0) {
272 		ERROR("No loadable segment found.\n");
273 		return -1;
274 	}
275 
276 	INFO("Segment at 0x%0llx, file size 0x%0llx, mem size 0x%0llx.\n",
277 	     (long long)phdr->p_vaddr, (long long)phdr->p_filesz,
278 	     (long long)phdr->p_memsz);
279 
280 	ctx->phdr = phdr;
281 	ctx->nsegments = nsegments;
282 
283 	return 0;
284 }
285 
286 static int
filter_relocation_sections(struct rmod_context * ctx)287 filter_relocation_sections(struct rmod_context *ctx)
288 {
289 	int i, j;
290 	const char *shstrtab;
291 	struct parsed_elf *pelf;
292 	const Elf64_Phdr *phdr;
293 
294 	pelf = &ctx->pelf;
295 	shstrtab = buffer_get(pelf->strtabs[pelf->ehdr.e_shstrndx]);
296 
297 	/*
298 	 * Find all relocation sections that contain relocation entries
299 	 * for sections that fall within the bounds of the segments. For
300 	 * easier processing the pointer to the relocation array for the
301 	 * sections that don't fall within the loadable program are NULL'd
302 	 * out.
303 	 */
304 	for (i = 0; i < pelf->ehdr.e_shnum; i++) {
305 		Elf64_Shdr *shdr;
306 		Elf64_Word sh_info;
307 		const char *section_name;
308 
309 		shdr = &pelf->shdr[i];
310 
311 		/* Ignore non-relocation sections. */
312 		if (shdr->sh_type != SHT_RELA && shdr->sh_type != SHT_REL)
313 			continue;
314 
315 		/* Obtain section which relocations apply. */
316 		sh_info = shdr->sh_info;
317 		shdr = &pelf->shdr[sh_info];
318 
319 		section_name = &shstrtab[shdr->sh_name];
320 		DEBUG("Relocation section found for '%s' section.\n",
321 		      section_name);
322 
323 		/* Do not process relocations for debug sections. */
324 		if (strstr(section_name, ".debug") != NULL) {
325 			pelf->relocs[i] = NULL;
326 			continue;
327 		}
328 
329 		/*
330 		 * If relocations apply to a non program section ignore the
331 		 * relocations for future processing.
332 		 */
333 		if (shdr->sh_type != SHT_PROGBITS) {
334 			pelf->relocs[i] = NULL;
335 			continue;
336 		}
337 
338 		for (j = 0; j < pelf->ehdr.e_phnum; j++) {
339 			phdr = &pelf->phdr[j];
340 			if (phdr->p_type == PT_LOAD &&
341 			    shdr->sh_addr >= phdr->p_vaddr &&
342 			    ((shdr->sh_addr + shdr->sh_size) <=
343 			     (phdr->p_vaddr + phdr->p_memsz)))
344 				break;
345 		}
346 		if (j == pelf->ehdr.e_phnum) {
347 			ERROR("Relocations being applied to section %d not "
348 			      "within segments region.\n", sh_info);
349 			pelf->relocs[i] = NULL;
350 			return -1;
351 		}
352 	}
353 
354 	return 0;
355 }
356 
vaddr_cmp(const void * a,const void * b)357 static int vaddr_cmp(const void *a, const void *b)
358 {
359 	const Elf64_Addr *pa = a;
360 	const Elf64_Addr *pb = b;
361 
362 	if (*pa < *pb)
363 		return -1;
364 	if (*pa > *pb)
365 		return 1;
366 	return 0;
367 }
368 
rmodule_collect_relocations(struct rmod_context * ctx,struct reloc_filter * f)369 int rmodule_collect_relocations(struct rmod_context *ctx,
370 				struct reloc_filter *f)
371 {
372 	Elf64_Xword nrelocs;
373 
374 	/*
375 	 * The relocs array in the pelf should only contain relocations that
376 	 * apply to the program. Count the number relocations. Then collect
377 	 * them into the allocated buffer.
378 	 */
379 	if (for_each_reloc(ctx, f, 0))
380 		return -1;
381 
382 	nrelocs = ctx->nrelocs;
383 	INFO("%" PRIu64 " relocations to be emitted.\n", nrelocs);
384 	if (!nrelocs)
385 		return 0;
386 
387 	/* Reset the counter for indexing into the array. */
388 	ctx->nrelocs = 0;
389 	ctx->emitted_relocs = calloc(nrelocs, sizeof(Elf64_Addr));
390 	/* Write out the relocations into the emitted_relocs array. */
391 	if (for_each_reloc(ctx, f, 1))
392 		return -1;
393 
394 	if (ctx->nrelocs != nrelocs) {
395 		ERROR("Mismatch counted and emitted relocations: %zu vs %zu.\n",
396 		      (size_t)nrelocs, (size_t)ctx->nrelocs);
397 		return -1;
398 	}
399 
400 	/* Sort the relocations by their address. */
401 	qsort(ctx->emitted_relocs, nrelocs, sizeof(Elf64_Addr), vaddr_cmp);
402 
403 	return 0;
404 }
405 
406 static int
populate_sym(struct rmod_context * ctx,const char * sym_name,Elf64_Addr * addr,int nsyms,int optional)407 populate_sym(struct rmod_context *ctx, const char *sym_name, Elf64_Addr *addr,
408 	     int nsyms, int optional)
409 {
410 	int i;
411 	Elf64_Sym *syms;
412 
413 	syms = ctx->pelf.syms;
414 
415 	for (i = 0; i < nsyms; i++) {
416 		if (syms[i].st_name == 0)
417 			continue;
418 		if (strcmp(sym_name, &ctx->strtab[syms[i].st_name]))
419 			continue;
420 		DEBUG("%s -> 0x%llx\n", sym_name, (long long)syms[i].st_value);
421 		*addr = syms[i].st_value;
422 		return 0;
423 	}
424 
425 	if (optional) {
426 		DEBUG("optional symbol '%s' not found.\n", sym_name);
427 		*addr = 0;
428 		return 0;
429 	}
430 
431 	ERROR("symbol '%s' not found.\n", sym_name);
432 	return -1;
433 }
434 
populate_rmodule_info(struct rmod_context * ctx)435 static int populate_rmodule_info(struct rmod_context *ctx)
436 {
437 	int i;
438 	struct parsed_elf *pelf;
439 	Elf64_Ehdr *ehdr;
440 	int nsyms;
441 
442 	pelf = &ctx->pelf;
443 	ehdr = &pelf->ehdr;
444 
445 	/* Determine number of symbols. */
446 	nsyms = 0;
447 	for (i = 0; i < ehdr->e_shnum; i++) {
448 		if (pelf->shdr[i].sh_type != SHT_SYMTAB)
449 			continue;
450 
451 		nsyms = pelf->shdr[i].sh_size / pelf->shdr[i].sh_entsize;
452 		break;
453 	}
454 
455 	if (populate_sym(ctx, "_rmodule_params", &ctx->parameters_begin, nsyms, 1))
456 		return -1;
457 
458 	if (populate_sym(ctx, "_ermodule_params", &ctx->parameters_end, nsyms, 1))
459 		return -1;
460 
461 	if (populate_sym(ctx, "_bss", &ctx->bss_begin, nsyms, 0))
462 		return -1;
463 
464 	if (populate_sym(ctx, "_ebss", &ctx->bss_end, nsyms, 0))
465 		return -1;
466 
467 	return 0;
468 }
469 
470 static int
add_section(struct elf_writer * ew,struct buffer * data,const char * name,Elf64_Addr addr,Elf64_Word size)471 add_section(struct elf_writer *ew, struct buffer *data, const char *name,
472 	    Elf64_Addr addr, Elf64_Word size)
473 {
474 	Elf64_Shdr shdr;
475 	int ret;
476 
477 	memset(&shdr, 0, sizeof(shdr));
478 	if (data != NULL) {
479 		shdr.sh_type = SHT_PROGBITS;
480 		shdr.sh_flags = SHF_ALLOC | SHF_WRITE | SHF_EXECINSTR;
481 	} else {
482 		shdr.sh_type = SHT_NOBITS;
483 		shdr.sh_flags = SHF_ALLOC;
484 	}
485 	shdr.sh_addr = addr;
486 	shdr.sh_offset = addr;
487 	shdr.sh_size = size;
488 
489 	ret = elf_writer_add_section(ew, &shdr, data, name);
490 
491 	if (ret)
492 		ERROR("Could not add '%s' section.\n", name);
493 
494 	return ret;
495 }
496 
497 static int
write_elf(const struct rmod_context * ctx,const struct buffer * in,struct buffer * out)498 write_elf(const struct rmod_context *ctx, const struct buffer *in,
499 	  struct buffer *out)
500 {
501 	int ret;
502 	int bit64;
503 	size_t loc;
504 	size_t rmod_data_size;
505 	struct elf_writer *ew;
506 	struct buffer rmod_data;
507 	struct buffer rmod_header;
508 	struct buffer program;
509 	struct buffer relocs;
510 	Elf64_Xword total_size;
511 	Elf64_Addr addr;
512 	Elf64_Ehdr ehdr;
513 
514 	if (ctx->nsegments != 1) {
515 		ERROR("Multiple loadable segments is not supported.\n");
516 		return -1;
517 	}
518 
519 	bit64 = ctx->pelf.ehdr.e_ident[EI_CLASS] == ELFCLASS64;
520 
521 	/*
522 	 * 3 sections will be added  to the ELF file.
523 	 * +------------------+
524 	 * |  rmodule header  |
525 	 * +------------------+
526 	 * |     program      |
527 	 * +------------------+
528 	 * |   relocations    |
529 	 * +------------------+
530 	 */
531 
532 	/* Create buffer for header and relocations. */
533 	rmod_data_size = sizeof(struct rmodule_header);
534 	if (bit64)
535 		rmod_data_size += ctx->nrelocs * sizeof(Elf64_Addr);
536 	else
537 		rmod_data_size += ctx->nrelocs * sizeof(Elf32_Addr);
538 
539 	if (buffer_create(&rmod_data, rmod_data_size, "rmod"))
540 		return -1;
541 
542 	buffer_splice(&rmod_header, &rmod_data,
543 	              0, sizeof(struct rmodule_header));
544 	buffer_clone(&relocs, &rmod_data);
545 	buffer_seek(&relocs, sizeof(struct rmodule_header));
546 
547 	/* Reset current location. */
548 	buffer_set_size(&rmod_header, 0);
549 	buffer_set_size(&relocs, 0);
550 
551 	/* Program contents. */
552 	buffer_splice(&program, in, ctx->phdr->p_offset, ctx->phdr->p_filesz);
553 
554 	/* Create ELF writer. Set entry point to 0 to match section offsets. */
555 	memcpy(&ehdr, &ctx->pelf.ehdr, sizeof(ehdr));
556 	ehdr.e_entry = 0;
557 	ew = elf_writer_init(&ehdr);
558 
559 	if (ew == NULL) {
560 		ERROR("Failed to create ELF writer.\n");
561 		buffer_delete(&rmod_data);
562 		return -1;
563 	}
564 
565 	/* Write out rmodule_header. */
566 	ctx->xdr->put16(&rmod_header, RMODULE_MAGIC);
567 	ctx->xdr->put8(&rmod_header, RMODULE_VERSION_1);
568 	ctx->xdr->put8(&rmod_header, 0);
569 	/* payload_begin_offset */
570 	loc = sizeof(struct rmodule_header);
571 	ctx->xdr->put32(&rmod_header, loc);
572 	/* payload_end_offset */
573 	loc += ctx->phdr->p_filesz;
574 	ctx->xdr->put32(&rmod_header, loc);
575 	/* relocations_begin_offset */
576 	ctx->xdr->put32(&rmod_header, loc);
577 	/* relocations_end_offset */
578 	if (bit64)
579 		loc += ctx->nrelocs * sizeof(Elf64_Addr);
580 	else
581 		loc += ctx->nrelocs * sizeof(Elf32_Addr);
582 	ctx->xdr->put32(&rmod_header, loc);
583 	/* module_link_start_address */
584 	ctx->xdr->put32(&rmod_header, ctx->phdr->p_vaddr);
585 	/* module_program_size */
586 	ctx->xdr->put32(&rmod_header, ctx->phdr->p_memsz);
587 	/* module_entry_point */
588 	ctx->xdr->put32(&rmod_header, ctx->pelf.ehdr.e_entry);
589 	/* parameters_begin */
590 	ctx->xdr->put32(&rmod_header, ctx->parameters_begin);
591 	/* parameters_end */
592 	ctx->xdr->put32(&rmod_header, ctx->parameters_end);
593 	/* bss_begin */
594 	ctx->xdr->put32(&rmod_header, ctx->bss_begin);
595 	/* bss_end */
596 	ctx->xdr->put32(&rmod_header, ctx->bss_end);
597 	/* padding[4] */
598 	ctx->xdr->put32(&rmod_header, 0);
599 	ctx->xdr->put32(&rmod_header, 0);
600 	ctx->xdr->put32(&rmod_header, 0);
601 	ctx->xdr->put32(&rmod_header, 0);
602 
603 	/* Write the relocations. */
604 	for (unsigned i = 0; i < ctx->nrelocs; i++) {
605 		if (bit64)
606 			ctx->xdr->put64(&relocs, ctx->emitted_relocs[i]);
607 		else
608 			ctx->xdr->put32(&relocs, ctx->emitted_relocs[i]);
609 	}
610 
611 	total_size = 0;
612 	addr = 0;
613 
614 	/*
615 	 * There are 2 cases to deal with. The program has a large NOBITS
616 	 * section and the relocations can fit entirely within occupied memory
617 	 * region for the program. The other is that the relocations increase
618 	 * the memory footprint of the program if it was loaded directly into
619 	 * the region it would run. The rmodule header is a fixed cost that
620 	 * is considered a part of the program.
621 	 */
622 	total_size += buffer_size(&rmod_header);
623 	if (buffer_size(&relocs) + ctx->phdr->p_filesz > ctx->phdr->p_memsz) {
624 		total_size += buffer_size(&relocs);
625 		total_size += ctx->phdr->p_filesz;
626 	} else {
627 		total_size += ctx->phdr->p_memsz;
628 	}
629 
630 	ret = add_section(ew, &rmod_header, ".header", addr,
631 	                  buffer_size(&rmod_header));
632 	if (ret < 0)
633 		goto out;
634 	addr += buffer_size(&rmod_header);
635 
636 	ret = add_section(ew, &program, ".program", addr, ctx->phdr->p_filesz);
637 	if (ret < 0)
638 		goto out;
639 	addr += ctx->phdr->p_filesz;
640 
641 	if (ctx->nrelocs) {
642 		ret = add_section(ew, &relocs, ".relocs", addr,
643 				  buffer_size(&relocs));
644 		if (ret < 0)
645 			goto out;
646 		addr += buffer_size(&relocs);
647 	}
648 
649 	if (total_size != addr) {
650 		ret = add_section(ew, NULL, ".empty", addr, total_size - addr);
651 		if (ret < 0)
652 			goto out;
653 	}
654 
655 	/*
656 	 * Ensure last section has a memory usage that meets the required
657 	 * total size of the program in memory.
658 	 */
659 
660 	ret = elf_writer_serialize(ew, out);
661 	if (ret < 0)
662 		ERROR("Failed to serialize ELF to buffer.\n");
663 
664 out:
665 	buffer_delete(&rmod_data);
666 	elf_writer_destroy(ew);
667 
668 	return ret;
669 }
670 
rmodule_init(struct rmod_context * ctx,const struct buffer * elfin)671 int rmodule_init(struct rmod_context *ctx, const struct buffer *elfin)
672 {
673 	struct parsed_elf *pelf;
674 	size_t i;
675 	int ret;
676 
677 	ret = -1;
678 	memset(ctx, 0, sizeof(*ctx));
679 	pelf = &ctx->pelf;
680 
681 	if (parse_elf(elfin, pelf, ELF_PARSE_ALL)) {
682 		ERROR("Couldn't parse ELF!\n");
683 		return -1;
684 	}
685 
686 	/* Only allow executables to be turned into rmodules. */
687 	if (pelf->ehdr.e_type != ET_EXEC) {
688 		ERROR("ELF is not an executable: %u.\n", pelf->ehdr.e_type);
689 		goto out;
690 	}
691 
692 	/* Determine if architecture is supported. */
693 	for (i = 0; i < ARRAY_SIZE(reloc_ops); i++) {
694 		if (reloc_ops[i].arch == pelf->ehdr.e_machine) {
695 			ctx->ops = &reloc_ops[i];
696 			break;
697 		}
698 	}
699 
700 	if (ctx->ops == NULL) {
701 		ERROR("ELF is unsupported arch: %u.\n", pelf->ehdr.e_machine);
702 		goto out;
703 	}
704 
705 	/* Set the endian ops. */
706 	if (ctx->pelf.ehdr.e_ident[EI_DATA] == ELFDATA2MSB)
707 		ctx->xdr = &xdr_be;
708 	else
709 		ctx->xdr = &xdr_le;
710 
711 	/* Obtain the string table. */
712 	for (i = 0; i < pelf->ehdr.e_shnum; i++) {
713 		if (pelf->strtabs[i] == NULL)
714 			continue;
715 		/* Don't use the section headers' string table. */
716 		if (i == pelf->ehdr.e_shstrndx)
717 			continue;
718 		ctx->strtab = buffer_get(pelf->strtabs[i]);
719 		break;
720 	}
721 
722 	if (ctx->strtab == NULL) {
723 		ERROR("No string table found.\n");
724 		return -1;
725 	}
726 
727 	if (find_program_segment(ctx))
728 		goto out;
729 
730 	if (filter_relocation_sections(ctx))
731 		goto out;
732 
733 	ret = 0;
734 
735 out:
736 	return ret;
737 }
738 
rmodule_cleanup(struct rmod_context * ctx)739 void rmodule_cleanup(struct rmod_context *ctx)
740 {
741 	free(ctx->emitted_relocs);
742 	parsed_elf_destroy(&ctx->pelf);
743 }
744 
rmodule_create(const struct buffer * elfin,struct buffer * elfout)745 int rmodule_create(const struct buffer *elfin, struct buffer *elfout)
746 {
747 	struct rmod_context ctx;
748 	int ret = -1;
749 
750 	if (rmodule_init(&ctx, elfin))
751 		goto out;
752 
753 	if (rmodule_collect_relocations(&ctx, NULL))
754 		goto out;
755 
756 	if (populate_rmodule_info(&ctx))
757 		goto out;
758 
759 	if (write_elf(&ctx, elfin, elfout))
760 		goto out;
761 
762 	ret = 0;
763 
764 out:
765 	rmodule_cleanup(&ctx);
766 	return ret;
767 }
768 
rmod_deserialize(struct rmodule_header * rmod,struct buffer * buff,struct xdr * xdr)769 static void rmod_deserialize(struct rmodule_header *rmod, struct buffer *buff,
770 				struct xdr *xdr)
771 {
772 	rmod->magic = xdr->get16(buff);
773 	rmod->version = xdr->get8(buff);
774 	rmod->type = xdr->get8(buff);
775 	rmod->payload_begin_offset = xdr->get32(buff);
776 	rmod->payload_end_offset = xdr->get32(buff);
777 	rmod->relocations_begin_offset = xdr->get32(buff);
778 	rmod->relocations_end_offset = xdr->get32(buff);
779 	rmod->module_link_start_address = xdr->get32(buff);
780 	rmod->module_program_size = xdr->get32(buff);
781 	rmod->module_entry_point = xdr->get32(buff);
782 	rmod->parameters_begin = xdr->get32(buff);
783 	rmod->parameters_end = xdr->get32(buff);
784 	rmod->bss_begin = xdr->get32(buff);
785 	rmod->bss_end = xdr->get32(buff);
786 	rmod->padding[0] = xdr->get32(buff);
787 	rmod->padding[1] = xdr->get32(buff);
788 	rmod->padding[2] = xdr->get32(buff);
789 	rmod->padding[3] = xdr->get32(buff);
790 }
791 
rmodule_stage_to_elf(Elf64_Ehdr * ehdr,struct buffer * buff)792 int rmodule_stage_to_elf(Elf64_Ehdr *ehdr, struct buffer *buff)
793 {
794 	struct buffer reader;
795 	struct buffer elf_out;
796 	struct rmodule_header rmod;
797 	struct xdr *xdr;
798 	struct elf_writer *ew;
799 	Elf64_Shdr shdr;
800 	int bit64;
801 	size_t payload_sz;
802 	const char *section_name = ".program";
803 	const size_t input_sz = buffer_size(buff);
804 
805 	buffer_clone(&reader, buff);
806 
807 	xdr = (ehdr->e_ident[EI_DATA] == ELFDATA2MSB) ? &xdr_be : &xdr_le;
808 	bit64 = ehdr->e_ident[EI_CLASS] == ELFCLASS64;
809 
810 	rmod_deserialize(&rmod, &reader, xdr);
811 
812 	/* Indicate that file is not an rmodule if initial checks fail. */
813 	if (rmod.magic != RMODULE_MAGIC)
814 		return 1;
815 	if (rmod.version != RMODULE_VERSION_1)
816 		return 1;
817 
818 	if (rmod.payload_begin_offset > input_sz ||
819 	    rmod.payload_end_offset > input_sz ||
820 	    rmod.relocations_begin_offset > input_sz ||
821 	    rmod.relocations_end_offset > input_sz) {
822 		ERROR("Rmodule fields out of bounds.\n");
823 		return -1;
824 	}
825 
826 	ehdr->e_entry = rmod.module_entry_point;
827 	ew = elf_writer_init(ehdr);
828 
829 	if (ew == NULL)
830 		return -1;
831 
832 	payload_sz = rmod.payload_end_offset - rmod.payload_begin_offset;
833 	memset(&shdr, 0, sizeof(shdr));
834 	shdr.sh_type = SHT_PROGBITS;
835 	shdr.sh_flags = SHF_WRITE | SHF_ALLOC | SHF_EXECINSTR;
836 	shdr.sh_addr = rmod.module_link_start_address;
837 	shdr.sh_size = payload_sz;
838 	buffer_splice(&reader, buff, rmod.payload_begin_offset, payload_sz);
839 
840 	if (elf_writer_add_section(ew, &shdr, &reader, section_name)) {
841 		ERROR("Unable to add ELF section: %s\n", section_name);
842 		elf_writer_destroy(ew);
843 		return -1;
844 	}
845 
846 	if (payload_sz != rmod.module_program_size) {
847 		struct buffer b;
848 
849 		buffer_init(&b, NULL, NULL, 0);
850 		memset(&shdr, 0, sizeof(shdr));
851 		shdr.sh_type = SHT_NOBITS;
852 		shdr.sh_flags = SHF_WRITE | SHF_ALLOC;
853 		shdr.sh_addr = rmod.module_link_start_address + payload_sz;
854 		shdr.sh_size = rmod.module_program_size - payload_sz;
855 		if (elf_writer_add_section(ew, &shdr, &b, ".empty")) {
856 			ERROR("Unable to add ELF section: .empty\n");
857 			elf_writer_destroy(ew);
858 			return -1;
859 		}
860 	}
861 
862 	/* Provide a section symbol so the relcoations can reference that. */
863 	if (elf_writer_add_symbol(ew, section_name, section_name, shdr.sh_addr,
864 					0, STB_LOCAL, STT_SECTION)) {
865 		ERROR("Unable to add section symbol to ELF.\n");
866 		elf_writer_destroy(ew);
867 		return -1;
868 	}
869 
870 	/* Add symbols for the parameters if they are non-zero. */
871 	if (rmod.parameters_begin != rmod.parameters_end) {
872 		int ret = 0;
873 
874 		ret |= elf_writer_add_symbol(ew, "_rmodule_params",
875 						section_name,
876 						rmod.parameters_begin, 0,
877 						STB_GLOBAL, STT_NOTYPE);
878 		ret |= elf_writer_add_symbol(ew, "_ermodule_params",
879 						section_name,
880 						rmod.parameters_end, 0,
881 						STB_GLOBAL, STT_NOTYPE);
882 
883 		if (ret != 0) {
884 			ERROR("Unable to add module params symbols to ELF\n");
885 			elf_writer_destroy(ew);
886 			return -1;
887 		}
888 	}
889 
890 	if (elf_writer_add_symbol(ew, "_bss", section_name, rmod.bss_begin, 0,
891 					STB_GLOBAL, STT_NOTYPE) ||
892 	    elf_writer_add_symbol(ew, "_ebss", section_name, rmod.bss_end, 0,
893 					STB_GLOBAL, STT_NOTYPE)) {
894 		ERROR("Unable to add bss symbols to ELF\n");
895 		elf_writer_destroy(ew);
896 		return -1;
897 	}
898 
899 	ssize_t relocs_sz = rmod.relocations_end_offset;
900 	relocs_sz -= rmod.relocations_begin_offset;
901 	buffer_splice(&reader, buff, rmod.relocations_begin_offset, relocs_sz);
902 	while (relocs_sz > 0) {
903 		Elf64_Addr addr;
904 
905 		if (bit64) {
906 			relocs_sz -= sizeof(Elf64_Addr);
907 			addr = xdr->get64(&reader);
908 		} else {
909 			relocs_sz -= sizeof(Elf32_Addr);
910 			addr = xdr->get32(&reader);
911 		}
912 
913 		/* Skip any relocations that are below the link address. */
914 		if (addr < rmod.module_link_start_address)
915 			continue;
916 
917 		if (elf_writer_add_rel(ew, section_name, addr)) {
918 			ERROR("Relocation addition failure.\n");
919 			elf_writer_destroy(ew);
920 			return -1;
921 		}
922 	}
923 
924 	if (elf_writer_serialize(ew, &elf_out)) {
925 		ERROR("ELF writer serialize failure.\n");
926 		elf_writer_destroy(ew);
927 		return -1;
928 	}
929 
930 	elf_writer_destroy(ew);
931 
932 	/* Flip buffer with the created ELF one. */
933 	buffer_delete(buff);
934 	*buff = elf_out;
935 
936 	return 0;
937 }
938