blob: 02f1d90785df50b0dd033c93704134d8340a03cd [file] [log] [blame]
Patrick Georgi7333a112020-05-08 20:48:04 +02001/* SPDX-License-Identifier: GPL-2.0-only */
Aaron Durbin4fde5a62014-03-07 15:11:53 -06002
Sol Boucher0e539312015-03-05 15:38:03 -08003#include <inttypes.h>
Aaron Durbin4fde5a62014-03-07 15:11:53 -06004#include <stdio.h>
5#include <stdlib.h>
6#include <string.h>
7
8#include "elfparsing.h"
9#include "rmodule.h"
Aaron Durbindc9f5cd2015-09-08 13:34:43 -050010#include <commonlib/rmodule-defs.h>
Aaron Durbin4fde5a62014-03-07 15:11:53 -060011
Aaron Durbin4fde5a62014-03-07 15:11:53 -060012/*
13 * Architecture specific support operations.
14 */
Sol Boucher0e539312015-03-05 15:38:03 -080015static int valid_reloc_386(Elf64_Rela *rel)
Aaron Durbin4fde5a62014-03-07 15:11:53 -060016{
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
Sol Boucher0e539312015-03-05 15:38:03 -080025static int should_emit_386(Elf64_Rela *rel)
Aaron Durbin4fde5a62014-03-07 15:11:53 -060026{
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
Patrick Rudolph565bebe2018-11-26 15:54:21 +010035static int valid_reloc_amd64(Elf64_Rela *rel)
36{
37 int type;
38
39 type = ELF64_R_TYPE(rel->r_info);
40
Patrick Rudolphd0239092021-06-11 21:24:10 +020041 /*
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. */
Patrick Rudolph565bebe2018-11-26 15:54:21 +010049 return (type == R_AMD64_64 ||
50 type == R_AMD64_PC64 ||
Patrick Rudolph565bebe2018-11-26 15:54:21 +010051 type == R_AMD64_32 ||
Patrick Rudolph44b4ec72019-02-15 14:41:20 +010052 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);
Patrick Rudolph565bebe2018-11-26 15:54:21 +010059}
60
61static 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 ||
Patrick Rudolph565bebe2018-11-26 15:54:21 +010069 type == R_AMD64_32);
70}
71
Sol Boucher0e539312015-03-05 15:38:03 -080072static int valid_reloc_arm(Elf64_Rela *rel)
Aaron Durbin785e47b2014-03-20 11:08:02 -050073{
74 int type;
75
76 type = ELF64_R_TYPE(rel->r_info);
77
Furquan Shaikhc4f08f72014-07-23 13:42:22 -070078 /* Only these 6 relocations are expected to be found. */
Aaron Durbin785e47b2014-03-20 11:08:02 -050079 return (type == R_ARM_ABS32 || type == R_ARM_THM_PC22 ||
Julius Werner84446e62021-02-12 17:37:27 -080080 type == R_ARM_THM_JUMP24 || type == R_ARM_V4BX ||
Furquan Shaikhc4f08f72014-07-23 13:42:22 -070081 type == R_ARM_CALL || type == R_ARM_JUMP24);
Aaron Durbin785e47b2014-03-20 11:08:02 -050082}
83
Sol Boucher0e539312015-03-05 15:38:03 -080084static int should_emit_arm(Elf64_Rela *rel)
Aaron Durbin785e47b2014-03-20 11:08:02 -050085{
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
Sol Boucher0e539312015-03-05 15:38:03 -080094static int valid_reloc_aarch64(Elf64_Rela *rel)
Furquan Shaikhd2338ba2014-08-26 15:21:15 -070095{
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 ||
Furquan Shaikhde77e6a2014-11-21 15:41:10 -0800102 type == R_AARCH64_LDST8_ABS_LO12_NC ||
Furquan Shaikh16c0a412015-06-08 11:58:04 -0700103 type == R_AARCH64_CONDBR19 ||
Furquan Shaikhd2338ba2014-08-26 15:21:15 -0700104 type == R_AARCH64_JUMP26 ||
105 type == R_AARCH64_LDST32_ABS_LO12_NC ||
Aaron Durbina47898e2014-09-18 13:39:16 -0500106 type == R_AARCH64_LDST64_ABS_LO12_NC ||
Furquan Shaikhd2338ba2014-08-26 15:21:15 -0700107 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
Sol Boucher0e539312015-03-05 15:38:03 -0800113static int should_emit_aarch64(Elf64_Rela *rel)
Furquan Shaikhd2338ba2014-08-26 15:21:15 -0700114{
115 int type;
116
117 type = ELF64_R_TYPE(rel->r_info);
118
119 return (type == R_AARCH64_ABS64);
120}
121
Aaron Durbinb39a9742015-09-08 17:24:04 -0500122static const struct arch_ops reloc_ops[] = {
Aaron Durbin4fde5a62014-03-07 15:11:53 -0600123 {
124 .arch = EM_386,
125 .valid_type = valid_reloc_386,
126 .should_emit = should_emit_386,
127 },
Aaron Durbin785e47b2014-03-20 11:08:02 -0500128 {
Patrick Rudolph565bebe2018-11-26 15:54:21 +0100129 .arch = EM_X86_64,
130 .valid_type = valid_reloc_amd64,
131 .should_emit = should_emit_amd64,
132 },
133 {
Aaron Durbin785e47b2014-03-20 11:08:02 -0500134 .arch = EM_ARM,
135 .valid_type = valid_reloc_arm,
136 .should_emit = should_emit_arm,
137 },
Furquan Shaikhd2338ba2014-08-26 15:21:15 -0700138 {
139 .arch = EM_AARCH64,
140 .valid_type = valid_reloc_aarch64,
141 .should_emit = should_emit_aarch64,
142 },
Aaron Durbin4fde5a62014-03-07 15:11:53 -0600143};
144
Julius Werner84446e62021-02-12 17:37:27 -0800145static 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
Raul E Rangel41ba01b2021-07-23 14:53:05 -0600158static 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
Aaron Durbin4fde5a62014-03-07 15:11:53 -0600171/*
172 * Relocation processing loops.
173 */
174
Aaron Durbinb39a9742015-09-08 17:24:04 -0500175static int for_each_reloc(struct rmod_context *ctx, struct reloc_filter *f,
176 int do_emit)
Aaron Durbin4fde5a62014-03-07 15:11:53 -0600177{
178 Elf64_Half i;
179 struct parsed_elf *pelf = &ctx->pelf;
180
181 for (i = 0; i < pelf->ehdr.e_shnum; i++) {
182 Elf64_Shdr *shdr;
183 Elf64_Rela *relocs;
184 Elf64_Xword nrelocs;
185 Elf64_Xword j;
186
187 relocs = pelf->relocs[i];
188
189 /* No relocations in this section. */
190 if (relocs == NULL)
191 continue;
192
193 shdr = &pelf->shdr[i];
194 nrelocs = shdr->sh_size / shdr->sh_entsize;
195
196 for (j = 0; j < nrelocs; j++) {
Aaron Durbinb39a9742015-09-08 17:24:04 -0500197 int filter_emit = 1;
Aaron Durbin4fde5a62014-03-07 15:11:53 -0600198 Elf64_Rela *r = &relocs[j];
199
Sol Boucher0e539312015-03-05 15:38:03 -0800200 if (!ctx->ops->valid_type(r)) {
Aaron Durbin4fde5a62014-03-07 15:11:53 -0600201 ERROR("Invalid reloc type: %u\n",
202 (unsigned int)ELF64_R_TYPE(r->r_info));
Patrick Rudolphd0239092021-06-11 21:24:10 +0200203 if ((ctx->ops->arch == EM_X86_64) &&
204 (ELF64_R_TYPE(r->r_info) == R_AMD64_32S))
205 ERROR("Illegal use of 32bit sign extended addressing at offset 0x%x\n",
206 (unsigned int)r->r_offset);
Aaron Durbin4fde5a62014-03-07 15:11:53 -0600207 return -1;
208 }
209
Julius Werner84446e62021-02-12 17:37:27 -0800210 if (relocation_for_absolute_symbol(ctx, r))
211 continue;
212
Raul E Rangel41ba01b2021-07-23 14:53:05 -0600213 if (relocation_for_weak_extern_symbols(ctx, r))
214 continue;
215
Aaron Durbinb39a9742015-09-08 17:24:04 -0500216 /* Allow the provided filter to have precedence. */
217 if (f != NULL) {
218 filter_emit = f->filter(f, r);
219
220 if (filter_emit < 0)
221 return filter_emit;
222 }
223
224 if (filter_emit && ctx->ops->should_emit(r)) {
Aaron Durbin4fde5a62014-03-07 15:11:53 -0600225 int n = ctx->nrelocs;
226 if (do_emit)
227 ctx->emitted_relocs[n] = r->r_offset;
228 ctx->nrelocs++;
229 }
230 }
231 }
232
233 return 0;
234}
235
236static int find_program_segment(struct rmod_context *ctx)
237{
238 int i;
239 int nsegments;
240 struct parsed_elf *pelf;
Anatol Pomozov8cce7012015-07-10 17:30:01 -0700241 Elf64_Phdr *phdr = NULL;
Aaron Durbin4fde5a62014-03-07 15:11:53 -0600242
243 pelf = &ctx->pelf;
244
245 /* There should only be a single loadable segment. */
246 nsegments = 0;
247 for (i = 0; i < pelf->ehdr.e_phnum; i++) {
248 if (pelf->phdr[i].p_type != PT_LOAD)
249 continue;
250 phdr = &pelf->phdr[i];
251 nsegments++;
252 }
253
254 if (nsegments != 1) {
Patrick Georgi01cfecc2020-01-29 13:31:16 +0100255 ERROR("Unexpected number of loadable segments: %d.\n",
Aaron Durbin4fde5a62014-03-07 15:11:53 -0600256 nsegments);
257 return -1;
258 }
259
260 INFO("Segment at 0x%0llx, file size 0x%0llx, mem size 0x%0llx.\n",
261 (long long)phdr->p_vaddr, (long long)phdr->p_filesz,
262 (long long)phdr->p_memsz);
263
264 ctx->phdr = phdr;
265
266 return 0;
267}
268
269static int
270filter_relocation_sections(struct rmod_context *ctx)
271{
272 int i;
273 const char *shstrtab;
274 struct parsed_elf *pelf;
275 const Elf64_Phdr *phdr;
276
277 pelf = &ctx->pelf;
278 phdr = ctx->phdr;
279 shstrtab = buffer_get(pelf->strtabs[pelf->ehdr.e_shstrndx]);
280
281 /*
282 * Find all relocation sections that contain relocation entries
283 * for sections that fall within the bounds of the segment. For
284 * easier processing the pointer to the relocation array for the
285 * sections that don't fall within the loadable program are NULL'd
286 * out.
287 */
288 for (i = 0; i < pelf->ehdr.e_shnum; i++) {
289 Elf64_Shdr *shdr;
290 Elf64_Word sh_info;
291 const char *section_name;
292
293 shdr = &pelf->shdr[i];
294
295 /* Ignore non-relocation sections. */
296 if (shdr->sh_type != SHT_RELA && shdr->sh_type != SHT_REL)
297 continue;
298
299 /* Obtain section which relocations apply. */
300 sh_info = shdr->sh_info;
301 shdr = &pelf->shdr[sh_info];
302
303 section_name = &shstrtab[shdr->sh_name];
304 DEBUG("Relocation section found for '%s' section.\n",
305 section_name);
306
307 /* Do not process relocations for debug sections. */
308 if (strstr(section_name, ".debug") != NULL) {
309 pelf->relocs[i] = NULL;
310 continue;
311 }
312
313 /*
314 * If relocations apply to a non program section ignore the
315 * relocations for future processing.
316 */
317 if (shdr->sh_type != SHT_PROGBITS) {
318 pelf->relocs[i] = NULL;
319 continue;
320 }
321
322 if (shdr->sh_addr < phdr->p_vaddr ||
323 ((shdr->sh_addr + shdr->sh_size) >
324 (phdr->p_vaddr + phdr->p_memsz))) {
325 ERROR("Relocations being applied to section %d not "
326 "within segment region.\n", sh_info);
327 return -1;
328 }
329 }
330
331 return 0;
332}
333
334static int vaddr_cmp(const void *a, const void *b)
335{
336 const Elf64_Addr *pa = a;
337 const Elf64_Addr *pb = b;
338
339 if (*pa < *pb)
340 return -1;
341 if (*pa > *pb)
342 return 1;
343 return 0;
344}
345
Aaron Durbinb39a9742015-09-08 17:24:04 -0500346int rmodule_collect_relocations(struct rmod_context *ctx,
347 struct reloc_filter *f)
Aaron Durbin4fde5a62014-03-07 15:11:53 -0600348{
Sol Boucher0e539312015-03-05 15:38:03 -0800349 Elf64_Xword nrelocs;
Aaron Durbin4fde5a62014-03-07 15:11:53 -0600350
351 /*
352 * The relocs array in the pelf should only contain relocations that
353 * apply to the program. Count the number relocations. Then collect
354 * them into the allocated buffer.
355 */
Aaron Durbinb39a9742015-09-08 17:24:04 -0500356 if (for_each_reloc(ctx, f, 0))
Aaron Durbin4fde5a62014-03-07 15:11:53 -0600357 return -1;
358
359 nrelocs = ctx->nrelocs;
Sol Boucher0e539312015-03-05 15:38:03 -0800360 INFO("%" PRIu64 " relocations to be emitted.\n", nrelocs);
Furquan Shaikhb237c102014-08-26 14:59:36 -0700361 if (!nrelocs)
362 return 0;
Aaron Durbin4fde5a62014-03-07 15:11:53 -0600363
364 /* Reset the counter for indexing into the array. */
365 ctx->nrelocs = 0;
366 ctx->emitted_relocs = calloc(nrelocs, sizeof(Elf64_Addr));
367 /* Write out the relocations into the emitted_relocs array. */
Aaron Durbinb39a9742015-09-08 17:24:04 -0500368 if (for_each_reloc(ctx, f, 1))
Aaron Durbin4fde5a62014-03-07 15:11:53 -0600369 return -1;
370
371 if (ctx->nrelocs != nrelocs) {
372 ERROR("Mismatch counted and emitted relocations: %zu vs %zu.\n",
373 (size_t)nrelocs, (size_t)ctx->nrelocs);
374 return -1;
375 }
376
377 /* Sort the relocations by their address. */
378 qsort(ctx->emitted_relocs, nrelocs, sizeof(Elf64_Addr), vaddr_cmp);
379
380 return 0;
381}
382
383static int
384populate_sym(struct rmod_context *ctx, const char *sym_name, Elf64_Addr *addr,
Julius Werner84446e62021-02-12 17:37:27 -0800385 int nsyms, int optional)
Aaron Durbin4fde5a62014-03-07 15:11:53 -0600386{
387 int i;
388 Elf64_Sym *syms;
389
390 syms = ctx->pelf.syms;
391
392 for (i = 0; i < nsyms; i++) {
393 if (syms[i].st_name == 0)
394 continue;
Julius Werner84446e62021-02-12 17:37:27 -0800395 if (strcmp(sym_name, &ctx->strtab[syms[i].st_name]))
Aaron Durbin4fde5a62014-03-07 15:11:53 -0600396 continue;
397 DEBUG("%s -> 0x%llx\n", sym_name, (long long)syms[i].st_value);
398 *addr = syms[i].st_value;
399 return 0;
400 }
Aaron Durbinc9b053d2015-09-06 10:39:10 -0500401
402 if (optional) {
403 DEBUG("optional symbol '%s' not found.\n", sym_name);
404 *addr = 0;
405 return 0;
406 }
407
Aaron Durbin4fde5a62014-03-07 15:11:53 -0600408 ERROR("symbol '%s' not found.\n", sym_name);
409 return -1;
410}
411
Aaron Durbin051a1812015-09-08 15:52:01 -0500412static int populate_rmodule_info(struct rmod_context *ctx)
Aaron Durbin4fde5a62014-03-07 15:11:53 -0600413{
414 int i;
Aaron Durbin4fde5a62014-03-07 15:11:53 -0600415 struct parsed_elf *pelf;
416 Elf64_Ehdr *ehdr;
417 int nsyms;
418
419 pelf = &ctx->pelf;
420 ehdr = &pelf->ehdr;
421
Aaron Durbin4fde5a62014-03-07 15:11:53 -0600422 /* Determine number of symbols. */
423 nsyms = 0;
424 for (i = 0; i < ehdr->e_shnum; i++) {
425 if (pelf->shdr[i].sh_type != SHT_SYMTAB)
426 continue;
427
428 nsyms = pelf->shdr[i].sh_size / pelf->shdr[i].sh_entsize;
429 break;
430 }
431
Julius Werner84446e62021-02-12 17:37:27 -0800432 if (populate_sym(ctx, "_rmodule_params", &ctx->parameters_begin, nsyms, 1))
Aaron Durbin4fde5a62014-03-07 15:11:53 -0600433 return -1;
434
Julius Werner84446e62021-02-12 17:37:27 -0800435 if (populate_sym(ctx, "_ermodule_params", &ctx->parameters_end, nsyms, 1))
Aaron Durbin4fde5a62014-03-07 15:11:53 -0600436 return -1;
437
Julius Werner84446e62021-02-12 17:37:27 -0800438 if (populate_sym(ctx, "_bss", &ctx->bss_begin, nsyms, 0))
Aaron Durbin4fde5a62014-03-07 15:11:53 -0600439 return -1;
440
Julius Werner84446e62021-02-12 17:37:27 -0800441 if (populate_sym(ctx, "_ebss", &ctx->bss_end, nsyms, 0))
Aaron Durbin4fde5a62014-03-07 15:11:53 -0600442 return -1;
443
Aaron Durbin4fde5a62014-03-07 15:11:53 -0600444 return 0;
445}
446
447static int
448add_section(struct elf_writer *ew, struct buffer *data, const char *name,
Julius Werner84446e62021-02-12 17:37:27 -0800449 Elf64_Addr addr, Elf64_Word size)
Aaron Durbin4fde5a62014-03-07 15:11:53 -0600450{
451 Elf64_Shdr shdr;
452 int ret;
453
454 memset(&shdr, 0, sizeof(shdr));
455 if (data != NULL) {
456 shdr.sh_type = SHT_PROGBITS;
457 shdr.sh_flags = SHF_ALLOC | SHF_WRITE | SHF_EXECINSTR;
458 } else {
459 shdr.sh_type = SHT_NOBITS;
460 shdr.sh_flags = SHF_ALLOC;
461 }
462 shdr.sh_addr = addr;
463 shdr.sh_offset = addr;
464 shdr.sh_size = size;
465
466 ret = elf_writer_add_section(ew, &shdr, data, name);
467
468 if (ret)
469 ERROR("Could not add '%s' section.\n", name);
470
471 return ret;
472}
473
474static int
475write_elf(const struct rmod_context *ctx, const struct buffer *in,
Julius Werner84446e62021-02-12 17:37:27 -0800476 struct buffer *out)
Aaron Durbin4fde5a62014-03-07 15:11:53 -0600477{
Aaron Durbin4fde5a62014-03-07 15:11:53 -0600478 int ret;
479 int bit64;
480 size_t loc;
481 size_t rmod_data_size;
482 struct elf_writer *ew;
483 struct buffer rmod_data;
484 struct buffer rmod_header;
485 struct buffer program;
486 struct buffer relocs;
487 Elf64_Xword total_size;
488 Elf64_Addr addr;
489 Elf64_Ehdr ehdr;
490
491 bit64 = ctx->pelf.ehdr.e_ident[EI_CLASS] == ELFCLASS64;
492
493 /*
494 * 3 sections will be added to the ELF file.
495 * +------------------+
496 * | rmodule header |
497 * +------------------+
498 * | program |
499 * +------------------+
500 * | relocations |
501 * +------------------+
502 */
503
504 /* Create buffer for header and relocations. */
505 rmod_data_size = sizeof(struct rmodule_header);
506 if (bit64)
507 rmod_data_size += ctx->nrelocs * sizeof(Elf64_Addr);
508 else
509 rmod_data_size += ctx->nrelocs * sizeof(Elf32_Addr);
510
511 if (buffer_create(&rmod_data, rmod_data_size, "rmod"))
512 return -1;
513
514 buffer_splice(&rmod_header, &rmod_data,
515 0, sizeof(struct rmodule_header));
516 buffer_clone(&relocs, &rmod_data);
517 buffer_seek(&relocs, sizeof(struct rmodule_header));
518
519 /* Reset current location. */
520 buffer_set_size(&rmod_header, 0);
521 buffer_set_size(&relocs, 0);
522
523 /* Program contents. */
524 buffer_splice(&program, in, ctx->phdr->p_offset, ctx->phdr->p_filesz);
525
Julius Werner81dc20e2020-10-15 17:37:57 -0700526 /* Create ELF writer. Set entry point to 0 to match section offsets. */
Aaron Durbin4fde5a62014-03-07 15:11:53 -0600527 memcpy(&ehdr, &ctx->pelf.ehdr, sizeof(ehdr));
Julius Werner81dc20e2020-10-15 17:37:57 -0700528 ehdr.e_entry = 0;
Aaron Durbin4fde5a62014-03-07 15:11:53 -0600529 ew = elf_writer_init(&ehdr);
530
531 if (ew == NULL) {
532 ERROR("Failed to create ELF writer.\n");
533 buffer_delete(&rmod_data);
534 return -1;
535 }
536
537 /* Write out rmodule_header. */
538 ctx->xdr->put16(&rmod_header, RMODULE_MAGIC);
539 ctx->xdr->put8(&rmod_header, RMODULE_VERSION_1);
540 ctx->xdr->put8(&rmod_header, 0);
541 /* payload_begin_offset */
542 loc = sizeof(struct rmodule_header);
543 ctx->xdr->put32(&rmod_header, loc);
544 /* payload_end_offset */
545 loc += ctx->phdr->p_filesz;
546 ctx->xdr->put32(&rmod_header, loc);
547 /* relocations_begin_offset */
548 ctx->xdr->put32(&rmod_header, loc);
549 /* relocations_end_offset */
550 if (bit64)
551 loc += ctx->nrelocs * sizeof(Elf64_Addr);
552 else
553 loc += ctx->nrelocs * sizeof(Elf32_Addr);
554 ctx->xdr->put32(&rmod_header, loc);
555 /* module_link_start_address */
Aaron Durbin051a1812015-09-08 15:52:01 -0500556 ctx->xdr->put32(&rmod_header, ctx->phdr->p_vaddr);
Aaron Durbin4fde5a62014-03-07 15:11:53 -0600557 /* module_program_size */
Aaron Durbin051a1812015-09-08 15:52:01 -0500558 ctx->xdr->put32(&rmod_header, ctx->phdr->p_memsz);
Aaron Durbin4fde5a62014-03-07 15:11:53 -0600559 /* module_entry_point */
Aaron Durbin051a1812015-09-08 15:52:01 -0500560 ctx->xdr->put32(&rmod_header, ctx->pelf.ehdr.e_entry);
Aaron Durbin4fde5a62014-03-07 15:11:53 -0600561 /* parameters_begin */
562 ctx->xdr->put32(&rmod_header, ctx->parameters_begin);
563 /* parameters_end */
564 ctx->xdr->put32(&rmod_header, ctx->parameters_end);
565 /* bss_begin */
566 ctx->xdr->put32(&rmod_header, ctx->bss_begin);
567 /* bss_end */
568 ctx->xdr->put32(&rmod_header, ctx->bss_end);
569 /* padding[4] */
570 ctx->xdr->put32(&rmod_header, 0);
571 ctx->xdr->put32(&rmod_header, 0);
572 ctx->xdr->put32(&rmod_header, 0);
573 ctx->xdr->put32(&rmod_header, 0);
574
575 /* Write the relocations. */
Sol Boucher0e539312015-03-05 15:38:03 -0800576 for (unsigned i = 0; i < ctx->nrelocs; i++) {
Aaron Durbin4fde5a62014-03-07 15:11:53 -0600577 if (bit64)
578 ctx->xdr->put64(&relocs, ctx->emitted_relocs[i]);
579 else
580 ctx->xdr->put32(&relocs, ctx->emitted_relocs[i]);
581 }
582
583 total_size = 0;
584 addr = 0;
585
586 /*
587 * There are 2 cases to deal with. The program has a large NOBITS
588 * section and the relocations can fit entirely within occupied memory
589 * region for the program. The other is that the relocations increase
590 * the memory footprint of the program if it was loaded directly into
Frans Hendriks166cbde2018-11-22 14:21:12 +0100591 * the region it would run. The rmodule header is a fixed cost that
Aaron Durbin4fde5a62014-03-07 15:11:53 -0600592 * is considered a part of the program.
593 */
594 total_size += buffer_size(&rmod_header);
Aaron Durbin518a3222014-08-26 13:52:30 -0500595 if (buffer_size(&relocs) + ctx->phdr->p_filesz > ctx->phdr->p_memsz) {
Aaron Durbin4fde5a62014-03-07 15:11:53 -0600596 total_size += buffer_size(&relocs);
597 total_size += ctx->phdr->p_filesz;
Aaron Durbin518a3222014-08-26 13:52:30 -0500598 } else {
599 total_size += ctx->phdr->p_memsz;
Aaron Durbin4fde5a62014-03-07 15:11:53 -0600600 }
601
602 ret = add_section(ew, &rmod_header, ".header", addr,
603 buffer_size(&rmod_header));
604 if (ret < 0)
605 goto out;
606 addr += buffer_size(&rmod_header);
607
608 ret = add_section(ew, &program, ".program", addr, ctx->phdr->p_filesz);
609 if (ret < 0)
610 goto out;
611 addr += ctx->phdr->p_filesz;
612
Furquan Shaikhb237c102014-08-26 14:59:36 -0700613 if (ctx->nrelocs) {
614 ret = add_section(ew, &relocs, ".relocs", addr,
615 buffer_size(&relocs));
616 if (ret < 0)
617 goto out;
618 addr += buffer_size(&relocs);
619 }
Aaron Durbin4fde5a62014-03-07 15:11:53 -0600620
621 if (total_size != addr) {
622 ret = add_section(ew, NULL, ".empty", addr, total_size - addr);
623 if (ret < 0)
624 goto out;
625 }
626
627 /*
628 * Ensure last section has a memory usage that meets the required
629 * total size of the program in memory.
630 */
631
632 ret = elf_writer_serialize(ew, out);
633 if (ret < 0)
634 ERROR("Failed to serialize ELF to buffer.\n");
635
636out:
637 buffer_delete(&rmod_data);
638 elf_writer_destroy(ew);
639
640 return ret;
641}
642
Aaron Durbinb39a9742015-09-08 17:24:04 -0500643int rmodule_init(struct rmod_context *ctx, const struct buffer *elfin)
Aaron Durbin4fde5a62014-03-07 15:11:53 -0600644{
Aaron Durbin4fde5a62014-03-07 15:11:53 -0600645 struct parsed_elf *pelf;
Furquan Shaikh161d2332016-05-26 14:41:02 -0700646 size_t i;
Aaron Durbin4fde5a62014-03-07 15:11:53 -0600647 int ret;
648
649 ret = -1;
Aaron Durbin051a1812015-09-08 15:52:01 -0500650 memset(ctx, 0, sizeof(*ctx));
651 pelf = &ctx->pelf;
Aaron Durbin4fde5a62014-03-07 15:11:53 -0600652
653 if (parse_elf(elfin, pelf, ELF_PARSE_ALL)) {
654 ERROR("Couldn't parse ELF!\n");
655 return -1;
656 }
657
658 /* Only allow executables to be turned into rmodules. */
659 if (pelf->ehdr.e_type != ET_EXEC) {
660 ERROR("ELF is not an executable: %u.\n", pelf->ehdr.e_type);
661 goto out;
662 }
663
664 /* Determine if architecture is supported. */
665 for (i = 0; i < ARRAY_SIZE(reloc_ops); i++) {
666 if (reloc_ops[i].arch == pelf->ehdr.e_machine) {
Aaron Durbin051a1812015-09-08 15:52:01 -0500667 ctx->ops = &reloc_ops[i];
Aaron Durbin4fde5a62014-03-07 15:11:53 -0600668 break;
669 }
670 }
671
Aaron Durbin051a1812015-09-08 15:52:01 -0500672 if (ctx->ops == NULL) {
Aaron Durbin4fde5a62014-03-07 15:11:53 -0600673 ERROR("ELF is unsupported arch: %u.\n", pelf->ehdr.e_machine);
674 goto out;
675 }
676
677 /* Set the endian ops. */
Aaron Durbin051a1812015-09-08 15:52:01 -0500678 if (ctx->pelf.ehdr.e_ident[EI_DATA] == ELFDATA2MSB)
679 ctx->xdr = &xdr_be;
Aaron Durbin4fde5a62014-03-07 15:11:53 -0600680 else
Aaron Durbin051a1812015-09-08 15:52:01 -0500681 ctx->xdr = &xdr_le;
Aaron Durbin4fde5a62014-03-07 15:11:53 -0600682
Julius Werner84446e62021-02-12 17:37:27 -0800683 /* Obtain the string table. */
684 for (i = 0; i < pelf->ehdr.e_shnum; i++) {
685 if (pelf->strtabs[i] == NULL)
686 continue;
687 /* Don't use the section headers' string table. */
688 if (i == pelf->ehdr.e_shstrndx)
689 continue;
690 ctx->strtab = buffer_get(pelf->strtabs[i]);
691 break;
692 }
693
694 if (ctx->strtab == NULL) {
695 ERROR("No string table found.\n");
696 return -1;
697 }
698
Aaron Durbin051a1812015-09-08 15:52:01 -0500699 if (find_program_segment(ctx))
Aaron Durbin4fde5a62014-03-07 15:11:53 -0600700 goto out;
701
Aaron Durbin051a1812015-09-08 15:52:01 -0500702 if (filter_relocation_sections(ctx))
703 goto out;
704
705 ret = 0;
706
707out:
708 return ret;
709}
710
Aaron Durbinb39a9742015-09-08 17:24:04 -0500711void rmodule_cleanup(struct rmod_context *ctx)
Aaron Durbin051a1812015-09-08 15:52:01 -0500712{
713 free(ctx->emitted_relocs);
714 parsed_elf_destroy(&ctx->pelf);
715}
716
717int rmodule_create(const struct buffer *elfin, struct buffer *elfout)
718{
719 struct rmod_context ctx;
720 int ret = -1;
721
722 if (rmodule_init(&ctx, elfin))
Aaron Durbin4fde5a62014-03-07 15:11:53 -0600723 goto out;
724
Aaron Durbinb39a9742015-09-08 17:24:04 -0500725 if (rmodule_collect_relocations(&ctx, NULL))
Aaron Durbin4fde5a62014-03-07 15:11:53 -0600726 goto out;
727
Aaron Durbin051a1812015-09-08 15:52:01 -0500728 if (populate_rmodule_info(&ctx))
Aaron Durbin4fde5a62014-03-07 15:11:53 -0600729 goto out;
730
731 if (write_elf(&ctx, elfin, elfout))
732 goto out;
733
734 ret = 0;
735
736out:
Aaron Durbin051a1812015-09-08 15:52:01 -0500737 rmodule_cleanup(&ctx);
Aaron Durbin4fde5a62014-03-07 15:11:53 -0600738 return ret;
739}
Aaron Durbin694fd132015-10-28 11:39:34 -0500740
741static void rmod_deserialize(struct rmodule_header *rmod, struct buffer *buff,
742 struct xdr *xdr)
743{
744 rmod->magic = xdr->get16(buff);
745 rmod->version = xdr->get8(buff);
746 rmod->type = xdr->get8(buff);
747 rmod->payload_begin_offset = xdr->get32(buff);
748 rmod->payload_end_offset = xdr->get32(buff);
749 rmod->relocations_begin_offset = xdr->get32(buff);
750 rmod->relocations_end_offset = xdr->get32(buff);
751 rmod->module_link_start_address = xdr->get32(buff);
752 rmod->module_program_size = xdr->get32(buff);
753 rmod->module_entry_point = xdr->get32(buff);
754 rmod->parameters_begin = xdr->get32(buff);
755 rmod->parameters_end = xdr->get32(buff);
756 rmod->bss_begin = xdr->get32(buff);
757 rmod->bss_end = xdr->get32(buff);
758 rmod->padding[0] = xdr->get32(buff);
759 rmod->padding[1] = xdr->get32(buff);
760 rmod->padding[2] = xdr->get32(buff);
761 rmod->padding[3] = xdr->get32(buff);
762}
763
764int rmodule_stage_to_elf(Elf64_Ehdr *ehdr, struct buffer *buff)
765{
766 struct buffer reader;
767 struct buffer elf_out;
768 struct rmodule_header rmod;
769 struct xdr *xdr;
770 struct elf_writer *ew;
771 Elf64_Shdr shdr;
772 int bit64;
773 size_t payload_sz;
774 const char *section_name = ".program";
775 const size_t input_sz = buffer_size(buff);
776
777 buffer_clone(&reader, buff);
778
779 xdr = (ehdr->e_ident[EI_DATA] == ELFDATA2MSB) ? &xdr_be : &xdr_le;
780 bit64 = ehdr->e_ident[EI_CLASS] == ELFCLASS64;
781
782 rmod_deserialize(&rmod, &reader, xdr);
783
784 /* Indicate that file is not an rmodule if initial checks fail. */
785 if (rmod.magic != RMODULE_MAGIC)
786 return 1;
787 if (rmod.version != RMODULE_VERSION_1)
788 return 1;
789
790 if (rmod.payload_begin_offset > input_sz ||
791 rmod.payload_end_offset > input_sz ||
792 rmod.relocations_begin_offset > input_sz ||
793 rmod.relocations_end_offset > input_sz) {
794 ERROR("Rmodule fields out of bounds.\n");
795 return -1;
796 }
797
798 ehdr->e_entry = rmod.module_entry_point;
799 ew = elf_writer_init(ehdr);
800
801 if (ew == NULL)
802 return -1;
803
804 payload_sz = rmod.payload_end_offset - rmod.payload_begin_offset;
805 memset(&shdr, 0, sizeof(shdr));
806 shdr.sh_type = SHT_PROGBITS;
807 shdr.sh_flags = SHF_WRITE | SHF_ALLOC | SHF_EXECINSTR;
808 shdr.sh_addr = rmod.module_link_start_address;
809 shdr.sh_size = payload_sz;
810 buffer_splice(&reader, buff, rmod.payload_begin_offset, payload_sz);
811
812 if (elf_writer_add_section(ew, &shdr, &reader, section_name)) {
813 ERROR("Unable to add ELF section: %s\n", section_name);
814 elf_writer_destroy(ew);
815 return -1;
816 }
817
818 if (payload_sz != rmod.module_program_size) {
819 struct buffer b;
820
821 buffer_init(&b, NULL, NULL, 0);
822 memset(&shdr, 0, sizeof(shdr));
823 shdr.sh_type = SHT_NOBITS;
824 shdr.sh_flags = SHF_WRITE | SHF_ALLOC;
825 shdr.sh_addr = rmod.module_link_start_address + payload_sz;
826 shdr.sh_size = rmod.module_program_size - payload_sz;
827 if (elf_writer_add_section(ew, &shdr, &b, ".empty")) {
828 ERROR("Unable to add ELF section: .empty\n");
829 elf_writer_destroy(ew);
830 return -1;
831 }
832 }
833
834 /* Provide a section symbol so the relcoations can reference that. */
835 if (elf_writer_add_symbol(ew, section_name, section_name, shdr.sh_addr,
836 0, STB_LOCAL, STT_SECTION)) {
837 ERROR("Unable to add section symbol to ELF.\n");
838 elf_writer_destroy(ew);
839 return -1;
840 }
841
842 /* Add symbols for the parameters if they are non-zero. */
843 if (rmod.parameters_begin != rmod.parameters_end) {
844 int ret = 0;
845
846 ret |= elf_writer_add_symbol(ew, "_rmodule_params",
847 section_name,
848 rmod.parameters_begin, 0,
849 STB_GLOBAL, STT_NOTYPE);
850 ret |= elf_writer_add_symbol(ew, "_ermodule_params",
851 section_name,
852 rmod.parameters_end, 0,
853 STB_GLOBAL, STT_NOTYPE);
854
855 if (ret != 0) {
856 ERROR("Unable to add module params symbols to ELF\n");
857 elf_writer_destroy(ew);
858 return -1;
859 }
860 }
861
862 if (elf_writer_add_symbol(ew, "_bss", section_name, rmod.bss_begin, 0,
863 STB_GLOBAL, STT_NOTYPE) ||
864 elf_writer_add_symbol(ew, "_ebss", section_name, rmod.bss_end, 0,
865 STB_GLOBAL, STT_NOTYPE)) {
866 ERROR("Unable to add bss symbols to ELF\n");
867 elf_writer_destroy(ew);
868 return -1;
869 }
870
871 ssize_t relocs_sz = rmod.relocations_end_offset;
872 relocs_sz -= rmod.relocations_begin_offset;
873 buffer_splice(&reader, buff, rmod.relocations_begin_offset, relocs_sz);
874 while (relocs_sz > 0) {
875 Elf64_Addr addr;
876
877 if (bit64) {
878 relocs_sz -= sizeof(Elf64_Addr);
879 addr = xdr->get64(&reader);
880 } else {
881 relocs_sz -= sizeof(Elf32_Addr);
882 addr = xdr->get32(&reader);
883 }
884
885 /* Skip any relocations that are below the link address. */
886 if (addr < rmod.module_link_start_address)
887 continue;
888
889 if (elf_writer_add_rel(ew, section_name, addr)) {
890 ERROR("Relocation addition failure.\n");
891 elf_writer_destroy(ew);
892 return -1;
893 }
894 }
895
896 if (elf_writer_serialize(ew, &elf_out)) {
897 ERROR("ELF writer serialize failure.\n");
898 elf_writer_destroy(ew);
899 return -1;
900 }
901
902 elf_writer_destroy(ew);
903
904 /* Flip buffer with the created ELF one. */
905 buffer_delete(buff);
906 *buff = elf_out;
907
908 return 0;
909}