Home | History | Annotate | Line # | Download | only in prekern
elf.c revision 1.6
      1 /*	$NetBSD: elf.c,v 1.6 2017/11/01 17:00:17 maxv Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 2017 The NetBSD Foundation, Inc. All rights reserved.
      5  *
      6  * This code is derived from software contributed to The NetBSD Foundation
      7  * by Maxime Villard.
      8  *
      9  * Redistribution and use in source and binary forms, with or without
     10  * modification, are permitted provided that the following conditions
     11  * are met:
     12  * 1. Redistributions of source code must retain the above copyright
     13  *    notice, this list of conditions and the following disclaimer.
     14  * 2. Redistributions in binary form must reproduce the above copyright
     15  *    notice, this list of conditions and the following disclaimer in the
     16  *    documentation and/or other materials provided with the distribution.
     17  *
     18  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     19  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     20  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     21  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     22  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     23  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     24  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     25  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     26  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     27  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     28  * POSSIBILITY OF SUCH DAMAGE.
     29  */
     30 
     31 #define	ELFSIZE	64
     32 
     33 #include "prekern.h"
     34 #include <sys/exec_elf.h>
     35 
     36 struct elfinfo {
     37 	Elf_Ehdr *ehdr;
     38 	Elf_Shdr *shdr;
     39 	char *shstrtab;
     40 	size_t shstrsz;
     41 	Elf_Sym *symtab;
     42 	size_t symcnt;
     43 	char *strtab;
     44 	size_t strsz;
     45 	struct {
     46 		vaddr_t va;
     47 		size_t sz;
     48 	} text;
     49 	struct {
     50 		vaddr_t va;
     51 		size_t sz;
     52 	} rodata;
     53 	struct {
     54 		vaddr_t va;
     55 		size_t sz;
     56 	} data;
     57 };
     58 
     59 extern paddr_t kernpa_start, kernpa_end;
     60 
     61 static struct elfinfo eif;
     62 static const char entrypoint[] = "start_prekern";
     63 
     64 /* XXX */
     65 static int
     66 memcmp(const char *a, const char *b, size_t c)
     67 {
     68 	size_t i;
     69 	for (i = 0; i < c; i++) {
     70 		if (a[i] != b[i])
     71 			return 1;
     72 	}
     73 	return 0;
     74 }
     75 static int
     76 strcmp(char *a, char *b)
     77 {
     78 	size_t i;
     79 	for (i = 0; a[i] != '\0'; i++) {
     80 		if (a[i] != b[i])
     81 			return 1;
     82 	}
     83 	return 0;
     84 }
     85 
     86 
     87 static int
     88 elf_check_header()
     89 {
     90 	if (memcmp((char *)eif.ehdr->e_ident, ELFMAG, SELFMAG) != 0 ||
     91 	    eif.ehdr->e_ident[EI_CLASS] != ELFCLASS ||
     92 	    eif.ehdr->e_type != ET_REL) {
     93 		return -1;
     94 	}
     95 	return 0;
     96 }
     97 
     98 static vaddr_t
     99 elf_get_entrypoint()
    100 {
    101 	Elf_Sym *sym;
    102 	size_t i;
    103 	char *buf;
    104 
    105 	for (i = 0; i < eif.symcnt; i++) {
    106 		sym = &eif.symtab[i];
    107 
    108 		if (ELF_ST_TYPE(sym->st_info) != STT_FUNC)
    109 			continue;
    110 		if (sym->st_name == 0)
    111 			continue;
    112 		if (sym->st_shndx == SHN_UNDEF)
    113 			continue; /* Skip external references */
    114 		buf = eif.strtab + sym->st_name;
    115 
    116 		if (!memcmp(buf, entrypoint, sizeof(entrypoint))) {
    117 			return (vaddr_t)sym->st_value;
    118 		}
    119 	}
    120 
    121 	return 0;
    122 }
    123 
    124 static Elf_Shdr *
    125 elf_find_section(char *name)
    126 {
    127 	char *buf;
    128 	size_t i;
    129 
    130 	for (i = 0; i < eif.ehdr->e_shnum; i++) {
    131 		if (eif.shdr[i].sh_name == 0) {
    132 			continue;
    133 		}
    134 		buf = eif.shstrtab + eif.shdr[i].sh_name;
    135 		if (!strcmp(name, buf)) {
    136 			return &eif.shdr[i];
    137 		}
    138 	}
    139 
    140 	return NULL;
    141 }
    142 
    143 static uintptr_t
    144 elf_sym_lookup(size_t symidx)
    145 {
    146 	const Elf_Sym *sym;
    147 	char *buf, *secname;
    148 	Elf_Shdr *sec;
    149 
    150 	if (symidx == STN_UNDEF) {
    151 		return 0;
    152 	}
    153 
    154 	if (symidx >= eif.symcnt) {
    155 		fatal("elf_sym_lookup: symbol beyond table");
    156 	}
    157 	sym = &eif.symtab[symidx];
    158 	buf = eif.strtab + sym->st_name;
    159 
    160 	if (sym->st_shndx == SHN_UNDEF) {
    161 		if (!memcmp(buf, "__start_link_set", 16)) {
    162 			secname = buf + 8;
    163 			sec = elf_find_section(secname);
    164 			if (sec == NULL) {
    165 				fatal("elf_sym_lookup: unknown start link set");
    166 			}
    167 			return (uintptr_t)((uint8_t *)eif.ehdr +
    168 			    sec->sh_offset);
    169 		}
    170 		if (!memcmp(buf, "__stop_link_set", 15)) {
    171 			secname = buf + 7;
    172 			sec = elf_find_section(secname);
    173 			if (sec == NULL) {
    174 				fatal("elf_sym_lookup: unknown stop link set");
    175 			}
    176 			return (uintptr_t)((uint8_t *)eif.ehdr +
    177 			    sec->sh_offset + sec->sh_size);
    178 		}
    179 
    180 		fatal("elf_sym_lookup: external symbol");
    181 	}
    182 	if (sym->st_value == 0) {
    183 		fatal("elf_sym_lookup: zero value");
    184 	}
    185 	return (uintptr_t)sym->st_value;
    186 }
    187 
    188 static void
    189 elf_apply_reloc(uintptr_t relocbase, const void *data, bool isrela)
    190 {
    191 	Elf64_Addr *where, val;
    192 	Elf32_Addr *where32, val32;
    193 	Elf64_Addr addr;
    194 	Elf64_Addr addend;
    195 	uintptr_t rtype, symidx;
    196 	const Elf_Rel *rel;
    197 	const Elf_Rela *rela;
    198 
    199 	if (isrela) {
    200 		rela = (const Elf_Rela *)data;
    201 		where = (Elf64_Addr *)(relocbase + rela->r_offset);
    202 		addend = rela->r_addend;
    203 		rtype = ELF_R_TYPE(rela->r_info);
    204 		symidx = ELF_R_SYM(rela->r_info);
    205 	} else {
    206 		rel = (const Elf_Rel *)data;
    207 		where = (Elf64_Addr *)(relocbase + rel->r_offset);
    208 		rtype = ELF_R_TYPE(rel->r_info);
    209 		symidx = ELF_R_SYM(rel->r_info);
    210 		/* Addend is 32 bit on 32 bit relocs */
    211 		switch (rtype) {
    212 		case R_X86_64_PC32:
    213 		case R_X86_64_32:
    214 		case R_X86_64_32S:
    215 			addend = *(Elf32_Addr *)where;
    216 			break;
    217 		default:
    218 			addend = *where;
    219 			break;
    220 		}
    221 	}
    222 
    223 	switch (rtype) {
    224 	case R_X86_64_NONE:	/* none */
    225 		break;
    226 
    227 	case R_X86_64_64:		/* S + A */
    228 		addr = elf_sym_lookup(symidx);
    229 		val = addr + addend;
    230 		*where = val;
    231 		break;
    232 
    233 	case R_X86_64_PC32:	/* S + A - P */
    234 		addr = elf_sym_lookup(symidx);
    235 		where32 = (Elf32_Addr *)where;
    236 		val32 = (Elf32_Addr)(addr + addend - (Elf64_Addr)where);
    237 		*where32 = val32;
    238 		break;
    239 
    240 	case R_X86_64_32:	/* S + A */
    241 	case R_X86_64_32S:	/* S + A sign extend */
    242 		addr = elf_sym_lookup(symidx);
    243 		val32 = (Elf32_Addr)(addr + addend);
    244 		where32 = (Elf32_Addr *)where;
    245 		*where32 = val32;
    246 		break;
    247 
    248 	case R_X86_64_GLOB_DAT:	/* S */
    249 	case R_X86_64_JUMP_SLOT:/* XXX need addend + offset */
    250 		addr = elf_sym_lookup(symidx);
    251 		*where = addr;
    252 		break;
    253 
    254 	case R_X86_64_RELATIVE:	/* B + A */
    255 		addr = relocbase + addend;
    256 		val = addr;
    257 		*where = val;
    258 		break;
    259 
    260 	default:
    261 		fatal("elf_apply_reloc: unexpected relocation type");
    262 	}
    263 }
    264 
    265 /* -------------------------------------------------------------------------- */
    266 
    267 size_t
    268 elf_get_head_size(vaddr_t headva)
    269 {
    270 	Elf_Ehdr *ehdr;
    271 	Elf_Shdr *shdr;
    272 	size_t size;
    273 
    274 	ehdr = (Elf_Ehdr *)headva;
    275 	shdr = (Elf_Shdr *)((uint8_t *)ehdr + ehdr->e_shoff);
    276 
    277 	size = (vaddr_t)shdr + (vaddr_t)(ehdr->e_shnum * sizeof(Elf_Shdr)) -
    278 	    (vaddr_t)ehdr;
    279 
    280 	return roundup(size, PAGE_SIZE);
    281 }
    282 
    283 void
    284 elf_build_head(vaddr_t headva)
    285 {
    286 	memset(&eif, 0, sizeof(struct elfinfo));
    287 
    288 	eif.ehdr = (Elf_Ehdr *)headva;
    289 	eif.shdr = (Elf_Shdr *)((uint8_t *)eif.ehdr + eif.ehdr->e_shoff);
    290 
    291 	if (elf_check_header() == -1) {
    292 		fatal("elf_build_head: wrong kernel ELF header");
    293 	}
    294 }
    295 
    296 static bool
    297 elf_section_is_text(Elf_Shdr *shdr)
    298 {
    299 	if (shdr->sh_type != SHT_NOBITS &&
    300 	    shdr->sh_type != SHT_PROGBITS) {
    301 		return false;
    302 	}
    303 	if (!(shdr->sh_flags & SHF_EXECINSTR)) {
    304 		return false;
    305 	}
    306 	return true;
    307 }
    308 
    309 static bool
    310 elf_section_is_rodata(Elf_Shdr *shdr)
    311 {
    312 	if (shdr->sh_type != SHT_NOBITS &&
    313 	    shdr->sh_type != SHT_PROGBITS) {
    314 		return false;
    315 	}
    316 	if (shdr->sh_flags & (SHF_EXECINSTR|SHF_WRITE)) {
    317 		return false;
    318 	}
    319 	return true;
    320 }
    321 
    322 static bool
    323 elf_section_is_data(Elf_Shdr *shdr)
    324 {
    325 	if (shdr->sh_type != SHT_NOBITS &&
    326 	    shdr->sh_type != SHT_PROGBITS) {
    327 		return false;
    328 	}
    329 	if (!(shdr->sh_flags & SHF_WRITE) ||
    330 	    (shdr->sh_flags & SHF_EXECINSTR)) {
    331 		return false;
    332 	}
    333 	return true;
    334 }
    335 
    336 void
    337 elf_get_text(paddr_t *pa, size_t *sz)
    338 {
    339 	const paddr_t basepa = kernpa_start;
    340 	paddr_t minpa, maxpa, secpa;
    341 	size_t i, secsz;
    342 
    343 	minpa = 0xFFFFFFFFFFFFFFFF, maxpa = 0;
    344 	for (i = 0; i < eif.ehdr->e_shnum; i++) {
    345 		if (!elf_section_is_text(&eif.shdr[i])) {
    346 			continue;
    347 		}
    348 		secpa = basepa + eif.shdr[i].sh_offset;
    349 		secsz = eif.shdr[i].sh_size;
    350 		if (secpa < minpa) {
    351 			minpa = secpa;
    352 		}
    353 		if (secpa + secsz > maxpa) {
    354 			maxpa = secpa + secsz;
    355 		}
    356 	}
    357 	ASSERT(minpa % PAGE_SIZE == 0);
    358 
    359 	*pa = minpa;
    360 	*sz = roundup(maxpa - minpa, PAGE_SIZE);
    361 }
    362 
    363 void
    364 elf_build_text(vaddr_t textva, paddr_t textpa, size_t textsz)
    365 {
    366 	const paddr_t basepa = kernpa_start;
    367 	const vaddr_t headva = (vaddr_t)eif.ehdr;
    368 	size_t i, offtext;
    369 
    370 	eif.text.va = textva;
    371 	eif.text.sz = textsz;
    372 
    373 	for (i = 0; i < eif.ehdr->e_shnum; i++) {
    374 		if (!elf_section_is_text(&eif.shdr[i])) {
    375 			continue;
    376 		}
    377 
    378 		/* Offset of the section within the text segment. */
    379 		offtext = basepa + eif.shdr[i].sh_offset - textpa;
    380 
    381 		/* We want (headva + sh_offset) to be the VA of the section. */
    382 		eif.shdr[i].sh_offset = (eif.text.va + offtext - headva);
    383 	}
    384 }
    385 
    386 void
    387 elf_get_rodata(paddr_t *pa, size_t *sz)
    388 {
    389 	const paddr_t basepa = kernpa_start;
    390 	paddr_t minpa, maxpa, secpa;
    391 	size_t i, secsz;
    392 
    393 	minpa = 0xFFFFFFFFFFFFFFFF, maxpa = 0;
    394 	for (i = 0; i < eif.ehdr->e_shnum; i++) {
    395 		if (!elf_section_is_rodata(&eif.shdr[i])) {
    396 			continue;
    397 		}
    398 		secpa = basepa + eif.shdr[i].sh_offset;
    399 		secsz = eif.shdr[i].sh_size;
    400 		if (secpa < minpa) {
    401 			minpa = secpa;
    402 		}
    403 		if (secpa + secsz > maxpa) {
    404 			maxpa = secpa + secsz;
    405 		}
    406 	}
    407 	ASSERT(minpa % PAGE_SIZE == 0);
    408 
    409 	*pa = minpa;
    410 	*sz = roundup(maxpa - minpa, PAGE_SIZE);
    411 }
    412 
    413 void
    414 elf_build_rodata(vaddr_t rodatava, paddr_t rodatapa, size_t rodatasz)
    415 {
    416 	const paddr_t basepa = kernpa_start;
    417 	const vaddr_t headva = (vaddr_t)eif.ehdr;
    418 	size_t i, offrodata;
    419 
    420 	eif.rodata.va = rodatava;
    421 	eif.rodata.sz = rodatasz;
    422 
    423 	for (i = 0; i < eif.ehdr->e_shnum; i++) {
    424 		if (!elf_section_is_rodata(&eif.shdr[i])) {
    425 			continue;
    426 		}
    427 
    428 		/* Offset of the section within the rodata segment. */
    429 		offrodata = basepa + eif.shdr[i].sh_offset - rodatapa;
    430 
    431 		/* We want (headva + sh_offset) to be the VA of the section. */
    432 		eif.shdr[i].sh_offset = (eif.rodata.va + offrodata - headva);
    433 	}
    434 }
    435 
    436 void
    437 elf_get_data(paddr_t *pa, size_t *sz)
    438 {
    439 	const paddr_t basepa = kernpa_start;
    440 	paddr_t minpa, maxpa, secpa;
    441 	size_t i, secsz;
    442 
    443 	minpa = 0xFFFFFFFFFFFFFFFF, maxpa = 0;
    444 	for (i = 0; i < eif.ehdr->e_shnum; i++) {
    445 		if (!elf_section_is_data(&eif.shdr[i])) {
    446 			continue;
    447 		}
    448 		secpa = basepa + eif.shdr[i].sh_offset;
    449 		secsz = eif.shdr[i].sh_size;
    450 		if (secpa < minpa) {
    451 			minpa = secpa;
    452 		}
    453 		if (secpa + secsz > maxpa) {
    454 			maxpa = secpa + secsz;
    455 		}
    456 	}
    457 	ASSERT(minpa % PAGE_SIZE == 0);
    458 
    459 	*pa = minpa;
    460 	*sz = roundup(maxpa - minpa, PAGE_SIZE);
    461 }
    462 
    463 void
    464 elf_build_data(vaddr_t datava, paddr_t datapa, size_t datasz)
    465 {
    466 	const paddr_t basepa = kernpa_start;
    467 	const vaddr_t headva = (vaddr_t)eif.ehdr;
    468 	size_t i, offdata;
    469 
    470 	eif.data.va = datava;
    471 	eif.data.sz = datasz;
    472 
    473 	for (i = 0; i < eif.ehdr->e_shnum; i++) {
    474 		if (!elf_section_is_data(&eif.shdr[i])) {
    475 			continue;
    476 		}
    477 
    478 		/* Offset of the section within the data segment. */
    479 		offdata = basepa + eif.shdr[i].sh_offset - datapa;
    480 
    481 		/* We want (headva + sh_offset) to be the VA of the section. */
    482 		eif.shdr[i].sh_offset = (eif.data.va + offdata - headva);
    483 	}
    484 }
    485 
    486 void
    487 elf_build_boot(vaddr_t bootva, paddr_t bootpa)
    488 {
    489 	const paddr_t basepa = kernpa_start;
    490 	const vaddr_t headva = (vaddr_t)eif.ehdr;
    491 	size_t i, j, offboot;
    492 
    493 	for (i = 0; i < eif.ehdr->e_shnum; i++) {
    494 		if (eif.shdr[i].sh_type != SHT_STRTAB &&
    495 		    eif.shdr[i].sh_type != SHT_REL &&
    496 		    eif.shdr[i].sh_type != SHT_RELA &&
    497 		    eif.shdr[i].sh_type != SHT_SYMTAB) {
    498 			continue;
    499 		}
    500 		if (eif.shdr[i].sh_offset == 0) {
    501 			/* hasn't been loaded */
    502 			continue;
    503 		}
    504 
    505 		/* Offset of the section within the boot region. */
    506 		offboot = basepa + eif.shdr[i].sh_offset - bootpa;
    507 
    508 		/* We want (headva + sh_offset) to be the VA of the region. */
    509 		eif.shdr[i].sh_offset = (bootva + offboot - headva);
    510 	}
    511 
    512 	/* Locate the section names */
    513 	j = eif.ehdr->e_shstrndx;
    514 	if (j == SHN_UNDEF) {
    515 		fatal("elf_build_boot: shstrtab not found");
    516 	}
    517 	if (j >= eif.ehdr->e_shnum) {
    518 		fatal("elf_build_boot: wrong shstrtab index");
    519 	}
    520 	eif.shstrtab = (char *)((uint8_t *)eif.ehdr + eif.shdr[j].sh_offset);
    521 	eif.shstrsz = eif.shdr[j].sh_size;
    522 
    523 	/* Locate the symbol table */
    524 	for (i = 0; i < eif.ehdr->e_shnum; i++) {
    525 		if (eif.shdr[i].sh_type == SHT_SYMTAB)
    526 			break;
    527 	}
    528 	if (i == eif.ehdr->e_shnum) {
    529 		fatal("elf_build_boot: symtab not found");
    530 	}
    531 	eif.symtab = (Elf_Sym *)((uint8_t *)eif.ehdr + eif.shdr[i].sh_offset);
    532 	eif.symcnt = eif.shdr[i].sh_size / sizeof(Elf_Sym);
    533 
    534 	/* Also locate the string table */
    535 	j = eif.shdr[i].sh_link;
    536 	if (j == SHN_UNDEF || j >= eif.ehdr->e_shnum) {
    537 		fatal("elf_build_boot: wrong strtab index");
    538 	}
    539 	if (eif.shdr[j].sh_type != SHT_STRTAB) {
    540 		fatal("elf_build_boot: wrong strtab type");
    541 	}
    542 	eif.strtab = (char *)((uint8_t *)eif.ehdr + eif.shdr[j].sh_offset);
    543 	eif.strsz = eif.shdr[j].sh_size;
    544 }
    545 
    546 vaddr_t
    547 elf_kernel_reloc()
    548 {
    549 	const vaddr_t baseva = (vaddr_t)eif.ehdr;
    550 	vaddr_t secva, ent;
    551 	Elf_Sym *sym;
    552 	size_t i, j;
    553 
    554 	print_state(true, "ELF info created");
    555 
    556 	/*
    557 	 * The loaded sections are: SHT_PROGBITS, SHT_NOBITS, SHT_STRTAB,
    558 	 * SHT_SYMTAB.
    559 	 */
    560 
    561 	/*
    562 	 * Update all symbol values with the appropriate offset.
    563 	 */
    564 	for (i = 0; i < eif.ehdr->e_shnum; i++) {
    565 		if (eif.shdr[i].sh_type != SHT_NOBITS &&
    566 		    eif.shdr[i].sh_type != SHT_PROGBITS) {
    567 			continue;
    568 		}
    569 		secva = baseva + eif.shdr[i].sh_offset;
    570 		for (j = 0; j < eif.symcnt; j++) {
    571 			sym = &eif.symtab[j];
    572 			if (sym->st_shndx != i) {
    573 				continue;
    574 			}
    575 			sym->st_value += (Elf_Addr)secva;
    576 		}
    577 	}
    578 
    579 	print_state(true, "Symbol values updated");
    580 
    581 	/*
    582 	 * Perform relocations without addend if there are any.
    583 	 */
    584 	for (i = 0; i < eif.ehdr->e_shnum; i++) {
    585 		Elf_Rel *reltab, *rel;
    586 		size_t secidx, nrel;
    587 		uintptr_t base;
    588 
    589 		if (eif.shdr[i].sh_type != SHT_REL)
    590 			continue;
    591 
    592 		reltab = (Elf_Rel *)((uint8_t *)eif.ehdr + eif.shdr[i].sh_offset);
    593 		nrel = eif.shdr[i].sh_size / sizeof(Elf_Rel);
    594 
    595 		secidx = eif.shdr[i].sh_info;
    596 		if (secidx >= eif.ehdr->e_shnum) {
    597 			fatal("elf_kernel_reloc: wrong REL relocation");
    598 		}
    599 		base = (uintptr_t)eif.ehdr + eif.shdr[secidx].sh_offset;
    600 
    601 		for (j = 0; j < nrel; j++) {
    602 			rel = &reltab[j];
    603 			elf_apply_reloc(base, rel, false);
    604 		}
    605 	}
    606 
    607 	print_state(true, "REL relocations applied");
    608 
    609 	/*
    610 	 * Perform relocations with addend if there are any.
    611 	 */
    612 	for (i = 0; i < eif.ehdr->e_shnum; i++) {
    613 		Elf_Rela *relatab, *rela;
    614 		size_t secidx, nrela;
    615 		uintptr_t base;
    616 
    617 		if (eif.shdr[i].sh_type != SHT_RELA)
    618 			continue;
    619 
    620 		relatab = (Elf_Rela *)((uint8_t *)eif.ehdr + eif.shdr[i].sh_offset);
    621 		nrela = eif.shdr[i].sh_size / sizeof(Elf_Rela);
    622 
    623 		secidx = eif.shdr[i].sh_info;
    624 		if (secidx >= eif.ehdr->e_shnum) {
    625 			fatal("elf_kernel_reloc: wrong RELA relocation");
    626 		}
    627 		base = (uintptr_t)eif.ehdr + eif.shdr[secidx].sh_offset;
    628 
    629 		for (j = 0; j < nrela; j++) {
    630 			rela = &relatab[j];
    631 			elf_apply_reloc(base, rela, true);
    632 		}
    633 	}
    634 
    635 	print_state(true, "RELA relocations applied");
    636 
    637 	/*
    638 	 * Get the entry point.
    639 	 */
    640 	ent = elf_get_entrypoint(&eif);
    641 	if (ent == 0) {
    642 		fatal("elf_kernel_reloc: entry point not found");
    643 	}
    644 
    645 	print_state(true, "Entry point found");
    646 
    647 	/*
    648 	 * Remap the code segments with proper permissions.
    649 	 */
    650 	mm_mprotect(eif.text.va, eif.text.sz, MM_PROT_READ|MM_PROT_EXECUTE);
    651 	mm_mprotect(eif.rodata.va, eif.rodata.sz, MM_PROT_READ);
    652 	mm_mprotect(eif.data.va, eif.data.sz, MM_PROT_READ|MM_PROT_WRITE);
    653 
    654 	print_state(true, "Segments protection updated");
    655 
    656 	return ent;
    657 }
    658 
    659