blob: da34eb5e0799c59cddfe7ae2842bc5bf49cfb540 [file] [log] [blame]
Aaron Durbin4fde5a62014-03-07 15:11:53 -06001/*
2 ;* Copyright (C) 2014 Google, Inc.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; version 2 of the License.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
Aaron Durbin4fde5a62014-03-07 15:11:53 -060012 */
13
Sol Boucher0e539312015-03-05 15:38:03 -080014#include <inttypes.h>
Aaron Durbin4fde5a62014-03-07 15:11:53 -060015#include <stdio.h>
16#include <stdlib.h>
17#include <string.h>
18
19#include "elfparsing.h"
20#include "rmodule.h"
Aaron Durbindc9f5cd2015-09-08 13:34:43 -050021#include <commonlib/rmodule-defs.h>
Aaron Durbin4fde5a62014-03-07 15:11:53 -060022
Aaron Durbin4fde5a62014-03-07 15:11:53 -060023/*
24 * Architecture specific support operations.
25 */
Sol Boucher0e539312015-03-05 15:38:03 -080026static int valid_reloc_386(Elf64_Rela *rel)
Aaron Durbin4fde5a62014-03-07 15:11:53 -060027{
28 int type;
29
30 type = ELF64_R_TYPE(rel->r_info);
31
32 /* Only these 2 relocations are expected to be found. */
33 return (type == R_386_32 || type == R_386_PC32);
34}
35
Sol Boucher0e539312015-03-05 15:38:03 -080036static int should_emit_386(Elf64_Rela *rel)
Aaron Durbin4fde5a62014-03-07 15:11:53 -060037{
38 int type;
39
40 type = ELF64_R_TYPE(rel->r_info);
41
42 /* R_386_32 relocations are absolute. Must emit these. */
43 return (type == R_386_32);
44}
45
Sol Boucher0e539312015-03-05 15:38:03 -080046static int valid_reloc_arm(Elf64_Rela *rel)
Aaron Durbin785e47b2014-03-20 11:08:02 -050047{
48 int type;
49
50 type = ELF64_R_TYPE(rel->r_info);
51
Furquan Shaikhc4f08f72014-07-23 13:42:22 -070052 /* Only these 6 relocations are expected to be found. */
Aaron Durbin785e47b2014-03-20 11:08:02 -050053 return (type == R_ARM_ABS32 || type == R_ARM_THM_PC22 ||
Furquan Shaikhc4f08f72014-07-23 13:42:22 -070054 type == R_ARM_THM_JUMP24 || type == R_ARM_V4BX ||
55 type == R_ARM_CALL || type == R_ARM_JUMP24);
Aaron Durbin785e47b2014-03-20 11:08:02 -050056}
57
Sol Boucher0e539312015-03-05 15:38:03 -080058static int should_emit_arm(Elf64_Rela *rel)
Aaron Durbin785e47b2014-03-20 11:08:02 -050059{
60 int type;
61
62 type = ELF64_R_TYPE(rel->r_info);
63
64 /* R_ARM_ABS32 relocations are absolute. Must emit these. */
65 return (type == R_ARM_ABS32);
66}
67
Sol Boucher0e539312015-03-05 15:38:03 -080068static int valid_reloc_aarch64(Elf64_Rela *rel)
Furquan Shaikhd2338ba2014-08-26 15:21:15 -070069{
70 int type;
71
72 type = ELF64_R_TYPE(rel->r_info);
73
74 return (type == R_AARCH64_ADR_PREL_PG_HI21 ||
75 type == R_AARCH64_ADD_ABS_LO12_NC ||
Furquan Shaikhde77e6a2014-11-21 15:41:10 -080076 type == R_AARCH64_LDST8_ABS_LO12_NC ||
Furquan Shaikh16c0a412015-06-08 11:58:04 -070077 type == R_AARCH64_CONDBR19 ||
Furquan Shaikhd2338ba2014-08-26 15:21:15 -070078 type == R_AARCH64_JUMP26 ||
79 type == R_AARCH64_LDST32_ABS_LO12_NC ||
Aaron Durbina47898e2014-09-18 13:39:16 -050080 type == R_AARCH64_LDST64_ABS_LO12_NC ||
Furquan Shaikhd2338ba2014-08-26 15:21:15 -070081 type == R_AARCH64_CALL26 ||
82 type == R_AARCH64_ABS64 ||
83 type == R_AARCH64_LD_PREL_LO19 ||
84 type == R_AARCH64_ADR_PREL_LO21);
85}
86
Sol Boucher0e539312015-03-05 15:38:03 -080087static int should_emit_aarch64(Elf64_Rela *rel)
Furquan Shaikhd2338ba2014-08-26 15:21:15 -070088{
89 int type;
90
91 type = ELF64_R_TYPE(rel->r_info);
92
93 return (type == R_AARCH64_ABS64);
94}
95
Aaron Durbinb39a9742015-09-08 17:24:04 -050096static const struct arch_ops reloc_ops[] = {
Aaron Durbin4fde5a62014-03-07 15:11:53 -060097 {
98 .arch = EM_386,
99 .valid_type = valid_reloc_386,
100 .should_emit = should_emit_386,
101 },
Aaron Durbin785e47b2014-03-20 11:08:02 -0500102 {
103 .arch = EM_ARM,
104 .valid_type = valid_reloc_arm,
105 .should_emit = should_emit_arm,
106 },
Furquan Shaikhd2338ba2014-08-26 15:21:15 -0700107 {
108 .arch = EM_AARCH64,
109 .valid_type = valid_reloc_aarch64,
110 .should_emit = should_emit_aarch64,
111 },
Aaron Durbin4fde5a62014-03-07 15:11:53 -0600112};
113
114/*
115 * Relocation processing loops.
116 */
117
Aaron Durbinb39a9742015-09-08 17:24:04 -0500118static int for_each_reloc(struct rmod_context *ctx, struct reloc_filter *f,
119 int do_emit)
Aaron Durbin4fde5a62014-03-07 15:11:53 -0600120{
121 Elf64_Half i;
122 struct parsed_elf *pelf = &ctx->pelf;
123
124 for (i = 0; i < pelf->ehdr.e_shnum; i++) {
125 Elf64_Shdr *shdr;
126 Elf64_Rela *relocs;
127 Elf64_Xword nrelocs;
128 Elf64_Xword j;
129
130 relocs = pelf->relocs[i];
131
132 /* No relocations in this section. */
133 if (relocs == NULL)
134 continue;
135
136 shdr = &pelf->shdr[i];
137 nrelocs = shdr->sh_size / shdr->sh_entsize;
138
139 for (j = 0; j < nrelocs; j++) {
Aaron Durbinb39a9742015-09-08 17:24:04 -0500140 int filter_emit = 1;
Aaron Durbin4fde5a62014-03-07 15:11:53 -0600141 Elf64_Rela *r = &relocs[j];
142
Sol Boucher0e539312015-03-05 15:38:03 -0800143 if (!ctx->ops->valid_type(r)) {
Aaron Durbin4fde5a62014-03-07 15:11:53 -0600144 ERROR("Invalid reloc type: %u\n",
145 (unsigned int)ELF64_R_TYPE(r->r_info));
146 return -1;
147 }
148
Aaron Durbinb39a9742015-09-08 17:24:04 -0500149 /* Allow the provided filter to have precedence. */
150 if (f != NULL) {
151 filter_emit = f->filter(f, r);
152
153 if (filter_emit < 0)
154 return filter_emit;
155 }
156
157 if (filter_emit && ctx->ops->should_emit(r)) {
Aaron Durbin4fde5a62014-03-07 15:11:53 -0600158 int n = ctx->nrelocs;
159 if (do_emit)
160 ctx->emitted_relocs[n] = r->r_offset;
161 ctx->nrelocs++;
162 }
163 }
164 }
165
166 return 0;
167}
168
169static int find_program_segment(struct rmod_context *ctx)
170{
171 int i;
172 int nsegments;
173 struct parsed_elf *pelf;
Anatol Pomozov8cce7012015-07-10 17:30:01 -0700174 Elf64_Phdr *phdr = NULL;
Aaron Durbin4fde5a62014-03-07 15:11:53 -0600175
176 pelf = &ctx->pelf;
177
178 /* There should only be a single loadable segment. */
179 nsegments = 0;
180 for (i = 0; i < pelf->ehdr.e_phnum; i++) {
181 if (pelf->phdr[i].p_type != PT_LOAD)
182 continue;
183 phdr = &pelf->phdr[i];
184 nsegments++;
185 }
186
187 if (nsegments != 1) {
188 ERROR("Unexepcted number of loadable segments: %d.\n",
189 nsegments);
190 return -1;
191 }
192
193 INFO("Segment at 0x%0llx, file size 0x%0llx, mem size 0x%0llx.\n",
194 (long long)phdr->p_vaddr, (long long)phdr->p_filesz,
195 (long long)phdr->p_memsz);
196
197 ctx->phdr = phdr;
198
199 return 0;
200}
201
202static int
203filter_relocation_sections(struct rmod_context *ctx)
204{
205 int i;
206 const char *shstrtab;
207 struct parsed_elf *pelf;
208 const Elf64_Phdr *phdr;
209
210 pelf = &ctx->pelf;
211 phdr = ctx->phdr;
212 shstrtab = buffer_get(pelf->strtabs[pelf->ehdr.e_shstrndx]);
213
214 /*
215 * Find all relocation sections that contain relocation entries
216 * for sections that fall within the bounds of the segment. For
217 * easier processing the pointer to the relocation array for the
218 * sections that don't fall within the loadable program are NULL'd
219 * out.
220 */
221 for (i = 0; i < pelf->ehdr.e_shnum; i++) {
222 Elf64_Shdr *shdr;
223 Elf64_Word sh_info;
224 const char *section_name;
225
226 shdr = &pelf->shdr[i];
227
228 /* Ignore non-relocation sections. */
229 if (shdr->sh_type != SHT_RELA && shdr->sh_type != SHT_REL)
230 continue;
231
232 /* Obtain section which relocations apply. */
233 sh_info = shdr->sh_info;
234 shdr = &pelf->shdr[sh_info];
235
236 section_name = &shstrtab[shdr->sh_name];
237 DEBUG("Relocation section found for '%s' section.\n",
238 section_name);
239
240 /* Do not process relocations for debug sections. */
241 if (strstr(section_name, ".debug") != NULL) {
242 pelf->relocs[i] = NULL;
243 continue;
244 }
245
246 /*
247 * If relocations apply to a non program section ignore the
248 * relocations for future processing.
249 */
250 if (shdr->sh_type != SHT_PROGBITS) {
251 pelf->relocs[i] = NULL;
252 continue;
253 }
254
255 if (shdr->sh_addr < phdr->p_vaddr ||
256 ((shdr->sh_addr + shdr->sh_size) >
257 (phdr->p_vaddr + phdr->p_memsz))) {
258 ERROR("Relocations being applied to section %d not "
259 "within segment region.\n", sh_info);
260 return -1;
261 }
262 }
263
264 return 0;
265}
266
267static int vaddr_cmp(const void *a, const void *b)
268{
269 const Elf64_Addr *pa = a;
270 const Elf64_Addr *pb = b;
271
272 if (*pa < *pb)
273 return -1;
274 if (*pa > *pb)
275 return 1;
276 return 0;
277}
278
Aaron Durbinb39a9742015-09-08 17:24:04 -0500279int rmodule_collect_relocations(struct rmod_context *ctx,
280 struct reloc_filter *f)
Aaron Durbin4fde5a62014-03-07 15:11:53 -0600281{
Sol Boucher0e539312015-03-05 15:38:03 -0800282 Elf64_Xword nrelocs;
Aaron Durbin4fde5a62014-03-07 15:11:53 -0600283
284 /*
285 * The relocs array in the pelf should only contain relocations that
286 * apply to the program. Count the number relocations. Then collect
287 * them into the allocated buffer.
288 */
Aaron Durbinb39a9742015-09-08 17:24:04 -0500289 if (for_each_reloc(ctx, f, 0))
Aaron Durbin4fde5a62014-03-07 15:11:53 -0600290 return -1;
291
292 nrelocs = ctx->nrelocs;
Sol Boucher0e539312015-03-05 15:38:03 -0800293 INFO("%" PRIu64 " relocations to be emitted.\n", nrelocs);
Furquan Shaikhb237c102014-08-26 14:59:36 -0700294 if (!nrelocs)
295 return 0;
Aaron Durbin4fde5a62014-03-07 15:11:53 -0600296
297 /* Reset the counter for indexing into the array. */
298 ctx->nrelocs = 0;
299 ctx->emitted_relocs = calloc(nrelocs, sizeof(Elf64_Addr));
300 /* Write out the relocations into the emitted_relocs array. */
Aaron Durbinb39a9742015-09-08 17:24:04 -0500301 if (for_each_reloc(ctx, f, 1))
Aaron Durbin4fde5a62014-03-07 15:11:53 -0600302 return -1;
303
304 if (ctx->nrelocs != nrelocs) {
305 ERROR("Mismatch counted and emitted relocations: %zu vs %zu.\n",
306 (size_t)nrelocs, (size_t)ctx->nrelocs);
307 return -1;
308 }
309
310 /* Sort the relocations by their address. */
311 qsort(ctx->emitted_relocs, nrelocs, sizeof(Elf64_Addr), vaddr_cmp);
312
313 return 0;
314}
315
316static int
317populate_sym(struct rmod_context *ctx, const char *sym_name, Elf64_Addr *addr,
Aaron Durbinc9b053d2015-09-06 10:39:10 -0500318 int nsyms, const char *strtab, int optional)
Aaron Durbin4fde5a62014-03-07 15:11:53 -0600319{
320 int i;
321 Elf64_Sym *syms;
322
323 syms = ctx->pelf.syms;
324
325 for (i = 0; i < nsyms; i++) {
326 if (syms[i].st_name == 0)
327 continue;
328 if (strcmp(sym_name, &strtab[syms[i].st_name]))
329 continue;
330 DEBUG("%s -> 0x%llx\n", sym_name, (long long)syms[i].st_value);
331 *addr = syms[i].st_value;
332 return 0;
333 }
Aaron Durbinc9b053d2015-09-06 10:39:10 -0500334
335 if (optional) {
336 DEBUG("optional symbol '%s' not found.\n", sym_name);
337 *addr = 0;
338 return 0;
339 }
340
Aaron Durbin4fde5a62014-03-07 15:11:53 -0600341 ERROR("symbol '%s' not found.\n", sym_name);
342 return -1;
343}
344
Aaron Durbin051a1812015-09-08 15:52:01 -0500345static int populate_rmodule_info(struct rmod_context *ctx)
Aaron Durbin4fde5a62014-03-07 15:11:53 -0600346{
347 int i;
348 const char *strtab;
349 struct parsed_elf *pelf;
350 Elf64_Ehdr *ehdr;
351 int nsyms;
352
353 pelf = &ctx->pelf;
354 ehdr = &pelf->ehdr;
355
356 /* Obtain the string table. */
357 strtab = NULL;
358 for (i = 0; i < ehdr->e_shnum; i++) {
359 if (ctx->pelf.strtabs[i] == NULL)
360 continue;
361 /* Don't use the section headers' string table. */
362 if (i == ehdr->e_shstrndx)
363 continue;
364 strtab = buffer_get(ctx->pelf.strtabs[i]);
365 break;
366 }
367
368 if (strtab == NULL) {
369 ERROR("No string table found.\n");
370 return -1;
371 }
372
373 /* Determine number of symbols. */
374 nsyms = 0;
375 for (i = 0; i < ehdr->e_shnum; i++) {
376 if (pelf->shdr[i].sh_type != SHT_SYMTAB)
377 continue;
378
379 nsyms = pelf->shdr[i].sh_size / pelf->shdr[i].sh_entsize;
380 break;
381 }
382
Aaron Durbindde76292015-09-05 12:59:26 -0500383 if (populate_sym(ctx, "_rmodule_params", &ctx->parameters_begin,
Aaron Durbinc9b053d2015-09-06 10:39:10 -0500384 nsyms, strtab, 1))
Aaron Durbin4fde5a62014-03-07 15:11:53 -0600385 return -1;
386
Aaron Durbindde76292015-09-05 12:59:26 -0500387 if (populate_sym(ctx, "_ermodule_params", &ctx->parameters_end,
Aaron Durbinc9b053d2015-09-06 10:39:10 -0500388 nsyms, strtab, 1))
Aaron Durbin4fde5a62014-03-07 15:11:53 -0600389 return -1;
390
Aaron Durbinc9b053d2015-09-06 10:39:10 -0500391 if (populate_sym(ctx, "_bss", &ctx->bss_begin, nsyms, strtab, 0))
Aaron Durbin4fde5a62014-03-07 15:11:53 -0600392 return -1;
393
Aaron Durbinc9b053d2015-09-06 10:39:10 -0500394 if (populate_sym(ctx, "_ebss", &ctx->bss_end, nsyms, strtab, 0))
Aaron Durbin4fde5a62014-03-07 15:11:53 -0600395 return -1;
396
Aaron Durbin4fde5a62014-03-07 15:11:53 -0600397 return 0;
398}
399
400static int
401add_section(struct elf_writer *ew, struct buffer *data, const char *name,
402 Elf64_Addr addr, Elf64_Word size)
403{
404 Elf64_Shdr shdr;
405 int ret;
406
407 memset(&shdr, 0, sizeof(shdr));
408 if (data != NULL) {
409 shdr.sh_type = SHT_PROGBITS;
410 shdr.sh_flags = SHF_ALLOC | SHF_WRITE | SHF_EXECINSTR;
411 } else {
412 shdr.sh_type = SHT_NOBITS;
413 shdr.sh_flags = SHF_ALLOC;
414 }
415 shdr.sh_addr = addr;
416 shdr.sh_offset = addr;
417 shdr.sh_size = size;
418
419 ret = elf_writer_add_section(ew, &shdr, data, name);
420
421 if (ret)
422 ERROR("Could not add '%s' section.\n", name);
423
424 return ret;
425}
426
427static int
428write_elf(const struct rmod_context *ctx, const struct buffer *in,
429 struct buffer *out)
430{
Aaron Durbin4fde5a62014-03-07 15:11:53 -0600431 int ret;
432 int bit64;
433 size_t loc;
434 size_t rmod_data_size;
435 struct elf_writer *ew;
436 struct buffer rmod_data;
437 struct buffer rmod_header;
438 struct buffer program;
439 struct buffer relocs;
440 Elf64_Xword total_size;
441 Elf64_Addr addr;
442 Elf64_Ehdr ehdr;
443
444 bit64 = ctx->pelf.ehdr.e_ident[EI_CLASS] == ELFCLASS64;
445
446 /*
447 * 3 sections will be added to the ELF file.
448 * +------------------+
449 * | rmodule header |
450 * +------------------+
451 * | program |
452 * +------------------+
453 * | relocations |
454 * +------------------+
455 */
456
457 /* Create buffer for header and relocations. */
458 rmod_data_size = sizeof(struct rmodule_header);
459 if (bit64)
460 rmod_data_size += ctx->nrelocs * sizeof(Elf64_Addr);
461 else
462 rmod_data_size += ctx->nrelocs * sizeof(Elf32_Addr);
463
464 if (buffer_create(&rmod_data, rmod_data_size, "rmod"))
465 return -1;
466
467 buffer_splice(&rmod_header, &rmod_data,
468 0, sizeof(struct rmodule_header));
469 buffer_clone(&relocs, &rmod_data);
470 buffer_seek(&relocs, sizeof(struct rmodule_header));
471
472 /* Reset current location. */
473 buffer_set_size(&rmod_header, 0);
474 buffer_set_size(&relocs, 0);
475
476 /* Program contents. */
477 buffer_splice(&program, in, ctx->phdr->p_offset, ctx->phdr->p_filesz);
478
479 /* Create ELF writer with modified entry point. */
480 memcpy(&ehdr, &ctx->pelf.ehdr, sizeof(ehdr));
Aaron Durbin4fde5a62014-03-07 15:11:53 -0600481 ew = elf_writer_init(&ehdr);
482
483 if (ew == NULL) {
484 ERROR("Failed to create ELF writer.\n");
485 buffer_delete(&rmod_data);
486 return -1;
487 }
488
489 /* Write out rmodule_header. */
490 ctx->xdr->put16(&rmod_header, RMODULE_MAGIC);
491 ctx->xdr->put8(&rmod_header, RMODULE_VERSION_1);
492 ctx->xdr->put8(&rmod_header, 0);
493 /* payload_begin_offset */
494 loc = sizeof(struct rmodule_header);
495 ctx->xdr->put32(&rmod_header, loc);
496 /* payload_end_offset */
497 loc += ctx->phdr->p_filesz;
498 ctx->xdr->put32(&rmod_header, loc);
499 /* relocations_begin_offset */
500 ctx->xdr->put32(&rmod_header, loc);
501 /* relocations_end_offset */
502 if (bit64)
503 loc += ctx->nrelocs * sizeof(Elf64_Addr);
504 else
505 loc += ctx->nrelocs * sizeof(Elf32_Addr);
506 ctx->xdr->put32(&rmod_header, loc);
507 /* module_link_start_address */
Aaron Durbin051a1812015-09-08 15:52:01 -0500508 ctx->xdr->put32(&rmod_header, ctx->phdr->p_vaddr);
Aaron Durbin4fde5a62014-03-07 15:11:53 -0600509 /* module_program_size */
Aaron Durbin051a1812015-09-08 15:52:01 -0500510 ctx->xdr->put32(&rmod_header, ctx->phdr->p_memsz);
Aaron Durbin4fde5a62014-03-07 15:11:53 -0600511 /* module_entry_point */
Aaron Durbin051a1812015-09-08 15:52:01 -0500512 ctx->xdr->put32(&rmod_header, ctx->pelf.ehdr.e_entry);
Aaron Durbin4fde5a62014-03-07 15:11:53 -0600513 /* parameters_begin */
514 ctx->xdr->put32(&rmod_header, ctx->parameters_begin);
515 /* parameters_end */
516 ctx->xdr->put32(&rmod_header, ctx->parameters_end);
517 /* bss_begin */
518 ctx->xdr->put32(&rmod_header, ctx->bss_begin);
519 /* bss_end */
520 ctx->xdr->put32(&rmod_header, ctx->bss_end);
521 /* padding[4] */
522 ctx->xdr->put32(&rmod_header, 0);
523 ctx->xdr->put32(&rmod_header, 0);
524 ctx->xdr->put32(&rmod_header, 0);
525 ctx->xdr->put32(&rmod_header, 0);
526
527 /* Write the relocations. */
Sol Boucher0e539312015-03-05 15:38:03 -0800528 for (unsigned i = 0; i < ctx->nrelocs; i++) {
Aaron Durbin4fde5a62014-03-07 15:11:53 -0600529 if (bit64)
530 ctx->xdr->put64(&relocs, ctx->emitted_relocs[i]);
531 else
532 ctx->xdr->put32(&relocs, ctx->emitted_relocs[i]);
533 }
534
535 total_size = 0;
536 addr = 0;
537
538 /*
539 * There are 2 cases to deal with. The program has a large NOBITS
540 * section and the relocations can fit entirely within occupied memory
541 * region for the program. The other is that the relocations increase
542 * the memory footprint of the program if it was loaded directly into
543 * the region it would run. The rmdoule header is a fixed cost that
544 * is considered a part of the program.
545 */
546 total_size += buffer_size(&rmod_header);
Aaron Durbin518a3222014-08-26 13:52:30 -0500547 if (buffer_size(&relocs) + ctx->phdr->p_filesz > ctx->phdr->p_memsz) {
Aaron Durbin4fde5a62014-03-07 15:11:53 -0600548 total_size += buffer_size(&relocs);
549 total_size += ctx->phdr->p_filesz;
Aaron Durbin518a3222014-08-26 13:52:30 -0500550 } else {
551 total_size += ctx->phdr->p_memsz;
Aaron Durbin4fde5a62014-03-07 15:11:53 -0600552 }
553
554 ret = add_section(ew, &rmod_header, ".header", addr,
555 buffer_size(&rmod_header));
556 if (ret < 0)
557 goto out;
558 addr += buffer_size(&rmod_header);
559
560 ret = add_section(ew, &program, ".program", addr, ctx->phdr->p_filesz);
561 if (ret < 0)
562 goto out;
563 addr += ctx->phdr->p_filesz;
564
Furquan Shaikhb237c102014-08-26 14:59:36 -0700565 if (ctx->nrelocs) {
566 ret = add_section(ew, &relocs, ".relocs", addr,
567 buffer_size(&relocs));
568 if (ret < 0)
569 goto out;
570 addr += buffer_size(&relocs);
571 }
Aaron Durbin4fde5a62014-03-07 15:11:53 -0600572
573 if (total_size != addr) {
574 ret = add_section(ew, NULL, ".empty", addr, total_size - addr);
575 if (ret < 0)
576 goto out;
577 }
578
579 /*
580 * Ensure last section has a memory usage that meets the required
581 * total size of the program in memory.
582 */
583
584 ret = elf_writer_serialize(ew, out);
585 if (ret < 0)
586 ERROR("Failed to serialize ELF to buffer.\n");
587
588out:
589 buffer_delete(&rmod_data);
590 elf_writer_destroy(ew);
591
592 return ret;
593}
594
Aaron Durbinb39a9742015-09-08 17:24:04 -0500595int rmodule_init(struct rmod_context *ctx, const struct buffer *elfin)
Aaron Durbin4fde5a62014-03-07 15:11:53 -0600596{
Aaron Durbin4fde5a62014-03-07 15:11:53 -0600597 struct parsed_elf *pelf;
598 int i;
599 int ret;
600
601 ret = -1;
Aaron Durbin051a1812015-09-08 15:52:01 -0500602 memset(ctx, 0, sizeof(*ctx));
603 pelf = &ctx->pelf;
Aaron Durbin4fde5a62014-03-07 15:11:53 -0600604
605 if (parse_elf(elfin, pelf, ELF_PARSE_ALL)) {
606 ERROR("Couldn't parse ELF!\n");
607 return -1;
608 }
609
610 /* Only allow executables to be turned into rmodules. */
611 if (pelf->ehdr.e_type != ET_EXEC) {
612 ERROR("ELF is not an executable: %u.\n", pelf->ehdr.e_type);
613 goto out;
614 }
615
616 /* Determine if architecture is supported. */
617 for (i = 0; i < ARRAY_SIZE(reloc_ops); i++) {
618 if (reloc_ops[i].arch == pelf->ehdr.e_machine) {
Aaron Durbin051a1812015-09-08 15:52:01 -0500619 ctx->ops = &reloc_ops[i];
Aaron Durbin4fde5a62014-03-07 15:11:53 -0600620 break;
621 }
622 }
623
Aaron Durbin051a1812015-09-08 15:52:01 -0500624 if (ctx->ops == NULL) {
Aaron Durbin4fde5a62014-03-07 15:11:53 -0600625 ERROR("ELF is unsupported arch: %u.\n", pelf->ehdr.e_machine);
626 goto out;
627 }
628
629 /* Set the endian ops. */
Aaron Durbin051a1812015-09-08 15:52:01 -0500630 if (ctx->pelf.ehdr.e_ident[EI_DATA] == ELFDATA2MSB)
631 ctx->xdr = &xdr_be;
Aaron Durbin4fde5a62014-03-07 15:11:53 -0600632 else
Aaron Durbin051a1812015-09-08 15:52:01 -0500633 ctx->xdr = &xdr_le;
Aaron Durbin4fde5a62014-03-07 15:11:53 -0600634
Aaron Durbin051a1812015-09-08 15:52:01 -0500635 if (find_program_segment(ctx))
Aaron Durbin4fde5a62014-03-07 15:11:53 -0600636 goto out;
637
Aaron Durbin051a1812015-09-08 15:52:01 -0500638 if (filter_relocation_sections(ctx))
639 goto out;
640
641 ret = 0;
642
643out:
644 return ret;
645}
646
Aaron Durbinb39a9742015-09-08 17:24:04 -0500647void rmodule_cleanup(struct rmod_context *ctx)
Aaron Durbin051a1812015-09-08 15:52:01 -0500648{
649 free(ctx->emitted_relocs);
650 parsed_elf_destroy(&ctx->pelf);
651}
652
653int rmodule_create(const struct buffer *elfin, struct buffer *elfout)
654{
655 struct rmod_context ctx;
656 int ret = -1;
657
658 if (rmodule_init(&ctx, elfin))
Aaron Durbin4fde5a62014-03-07 15:11:53 -0600659 goto out;
660
Aaron Durbinb39a9742015-09-08 17:24:04 -0500661 if (rmodule_collect_relocations(&ctx, NULL))
Aaron Durbin4fde5a62014-03-07 15:11:53 -0600662 goto out;
663
Aaron Durbin051a1812015-09-08 15:52:01 -0500664 if (populate_rmodule_info(&ctx))
Aaron Durbin4fde5a62014-03-07 15:11:53 -0600665 goto out;
666
667 if (write_elf(&ctx, elfin, elfout))
668 goto out;
669
670 ret = 0;
671
672out:
Aaron Durbin051a1812015-09-08 15:52:01 -0500673 rmodule_cleanup(&ctx);
Aaron Durbin4fde5a62014-03-07 15:11:53 -0600674 return ret;
675}
Aaron Durbin694fd132015-10-28 11:39:34 -0500676
677static void rmod_deserialize(struct rmodule_header *rmod, struct buffer *buff,
678 struct xdr *xdr)
679{
680 rmod->magic = xdr->get16(buff);
681 rmod->version = xdr->get8(buff);
682 rmod->type = xdr->get8(buff);
683 rmod->payload_begin_offset = xdr->get32(buff);
684 rmod->payload_end_offset = xdr->get32(buff);
685 rmod->relocations_begin_offset = xdr->get32(buff);
686 rmod->relocations_end_offset = xdr->get32(buff);
687 rmod->module_link_start_address = xdr->get32(buff);
688 rmod->module_program_size = xdr->get32(buff);
689 rmod->module_entry_point = xdr->get32(buff);
690 rmod->parameters_begin = xdr->get32(buff);
691 rmod->parameters_end = xdr->get32(buff);
692 rmod->bss_begin = xdr->get32(buff);
693 rmod->bss_end = xdr->get32(buff);
694 rmod->padding[0] = xdr->get32(buff);
695 rmod->padding[1] = xdr->get32(buff);
696 rmod->padding[2] = xdr->get32(buff);
697 rmod->padding[3] = xdr->get32(buff);
698}
699
700int rmodule_stage_to_elf(Elf64_Ehdr *ehdr, struct buffer *buff)
701{
702 struct buffer reader;
703 struct buffer elf_out;
704 struct rmodule_header rmod;
705 struct xdr *xdr;
706 struct elf_writer *ew;
707 Elf64_Shdr shdr;
708 int bit64;
709 size_t payload_sz;
710 const char *section_name = ".program";
711 const size_t input_sz = buffer_size(buff);
712
713 buffer_clone(&reader, buff);
714
715 xdr = (ehdr->e_ident[EI_DATA] == ELFDATA2MSB) ? &xdr_be : &xdr_le;
716 bit64 = ehdr->e_ident[EI_CLASS] == ELFCLASS64;
717
718 rmod_deserialize(&rmod, &reader, xdr);
719
720 /* Indicate that file is not an rmodule if initial checks fail. */
721 if (rmod.magic != RMODULE_MAGIC)
722 return 1;
723 if (rmod.version != RMODULE_VERSION_1)
724 return 1;
725
726 if (rmod.payload_begin_offset > input_sz ||
727 rmod.payload_end_offset > input_sz ||
728 rmod.relocations_begin_offset > input_sz ||
729 rmod.relocations_end_offset > input_sz) {
730 ERROR("Rmodule fields out of bounds.\n");
731 return -1;
732 }
733
734 ehdr->e_entry = rmod.module_entry_point;
735 ew = elf_writer_init(ehdr);
736
737 if (ew == NULL)
738 return -1;
739
740 payload_sz = rmod.payload_end_offset - rmod.payload_begin_offset;
741 memset(&shdr, 0, sizeof(shdr));
742 shdr.sh_type = SHT_PROGBITS;
743 shdr.sh_flags = SHF_WRITE | SHF_ALLOC | SHF_EXECINSTR;
744 shdr.sh_addr = rmod.module_link_start_address;
745 shdr.sh_size = payload_sz;
746 buffer_splice(&reader, buff, rmod.payload_begin_offset, payload_sz);
747
748 if (elf_writer_add_section(ew, &shdr, &reader, section_name)) {
749 ERROR("Unable to add ELF section: %s\n", section_name);
750 elf_writer_destroy(ew);
751 return -1;
752 }
753
754 if (payload_sz != rmod.module_program_size) {
755 struct buffer b;
756
757 buffer_init(&b, NULL, NULL, 0);
758 memset(&shdr, 0, sizeof(shdr));
759 shdr.sh_type = SHT_NOBITS;
760 shdr.sh_flags = SHF_WRITE | SHF_ALLOC;
761 shdr.sh_addr = rmod.module_link_start_address + payload_sz;
762 shdr.sh_size = rmod.module_program_size - payload_sz;
763 if (elf_writer_add_section(ew, &shdr, &b, ".empty")) {
764 ERROR("Unable to add ELF section: .empty\n");
765 elf_writer_destroy(ew);
766 return -1;
767 }
768 }
769
770 /* Provide a section symbol so the relcoations can reference that. */
771 if (elf_writer_add_symbol(ew, section_name, section_name, shdr.sh_addr,
772 0, STB_LOCAL, STT_SECTION)) {
773 ERROR("Unable to add section symbol to ELF.\n");
774 elf_writer_destroy(ew);
775 return -1;
776 }
777
778 /* Add symbols for the parameters if they are non-zero. */
779 if (rmod.parameters_begin != rmod.parameters_end) {
780 int ret = 0;
781
782 ret |= elf_writer_add_symbol(ew, "_rmodule_params",
783 section_name,
784 rmod.parameters_begin, 0,
785 STB_GLOBAL, STT_NOTYPE);
786 ret |= elf_writer_add_symbol(ew, "_ermodule_params",
787 section_name,
788 rmod.parameters_end, 0,
789 STB_GLOBAL, STT_NOTYPE);
790
791 if (ret != 0) {
792 ERROR("Unable to add module params symbols to ELF\n");
793 elf_writer_destroy(ew);
794 return -1;
795 }
796 }
797
798 if (elf_writer_add_symbol(ew, "_bss", section_name, rmod.bss_begin, 0,
799 STB_GLOBAL, STT_NOTYPE) ||
800 elf_writer_add_symbol(ew, "_ebss", section_name, rmod.bss_end, 0,
801 STB_GLOBAL, STT_NOTYPE)) {
802 ERROR("Unable to add bss symbols to ELF\n");
803 elf_writer_destroy(ew);
804 return -1;
805 }
806
807 ssize_t relocs_sz = rmod.relocations_end_offset;
808 relocs_sz -= rmod.relocations_begin_offset;
809 buffer_splice(&reader, buff, rmod.relocations_begin_offset, relocs_sz);
810 while (relocs_sz > 0) {
811 Elf64_Addr addr;
812
813 if (bit64) {
814 relocs_sz -= sizeof(Elf64_Addr);
815 addr = xdr->get64(&reader);
816 } else {
817 relocs_sz -= sizeof(Elf32_Addr);
818 addr = xdr->get32(&reader);
819 }
820
821 /* Skip any relocations that are below the link address. */
822 if (addr < rmod.module_link_start_address)
823 continue;
824
825 if (elf_writer_add_rel(ew, section_name, addr)) {
826 ERROR("Relocation addition failure.\n");
827 elf_writer_destroy(ew);
828 return -1;
829 }
830 }
831
832 if (elf_writer_serialize(ew, &elf_out)) {
833 ERROR("ELF writer serialize failure.\n");
834 elf_writer_destroy(ew);
835 return -1;
836 }
837
838 elf_writer_destroy(ew);
839
840 /* Flip buffer with the created ELF one. */
841 buffer_delete(buff);
842 *buff = elf_out;
843
844 return 0;
845}