Home | History | Annotate | Line # | Download | only in prekern
elf.c revision 1.21.6.1
      1  1.21.6.1  thorpej /*	$NetBSD: elf.c,v 1.21.6.1 2021/05/13 00:47:22 thorpej Exp $	*/
      2       1.1     maxv 
      3       1.1     maxv /*
      4      1.20     maxv  * Copyright (c) 2017-2020 The NetBSD Foundation, Inc. All rights reserved.
      5       1.1     maxv  *
      6       1.1     maxv  * This code is derived from software contributed to The NetBSD Foundation
      7       1.1     maxv  * by Maxime Villard.
      8       1.1     maxv  *
      9       1.1     maxv  * Redistribution and use in source and binary forms, with or without
     10       1.1     maxv  * modification, are permitted provided that the following conditions
     11       1.1     maxv  * are met:
     12       1.1     maxv  * 1. Redistributions of source code must retain the above copyright
     13       1.1     maxv  *    notice, this list of conditions and the following disclaimer.
     14       1.1     maxv  * 2. Redistributions in binary form must reproduce the above copyright
     15       1.1     maxv  *    notice, this list of conditions and the following disclaimer in the
     16       1.1     maxv  *    documentation and/or other materials provided with the distribution.
     17       1.1     maxv  *
     18       1.1     maxv  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     19       1.1     maxv  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     20       1.1     maxv  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     21       1.1     maxv  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     22       1.1     maxv  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     23       1.1     maxv  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     24       1.1     maxv  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     25       1.1     maxv  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     26       1.1     maxv  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     27       1.1     maxv  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     28       1.1     maxv  * POSSIBILITY OF SUCH DAMAGE.
     29       1.1     maxv  */
     30       1.1     maxv 
     31       1.1     maxv #define	ELFSIZE	64
     32       1.1     maxv 
     33       1.1     maxv #include "prekern.h"
     34       1.1     maxv #include <sys/exec_elf.h>
     35       1.1     maxv 
     36       1.1     maxv struct elfinfo {
     37       1.1     maxv 	Elf_Ehdr *ehdr;
     38       1.1     maxv 	Elf_Shdr *shdr;
     39       1.1     maxv 	char *shstrtab;
     40       1.1     maxv 	size_t shstrsz;
     41       1.1     maxv 	Elf_Sym *symtab;
     42       1.1     maxv 	size_t symcnt;
     43       1.1     maxv 	char *strtab;
     44       1.1     maxv 	size_t strsz;
     45       1.1     maxv };
     46       1.1     maxv 
     47       1.4     maxv extern paddr_t kernpa_start, kernpa_end;
     48       1.4     maxv 
     49       1.1     maxv static struct elfinfo eif;
     50       1.1     maxv static const char entrypoint[] = "start_prekern";
     51       1.1     maxv 
     52       1.1     maxv static int
     53      1.13     maxv elf_check_header(void)
     54       1.1     maxv {
     55       1.1     maxv 	if (memcmp((char *)eif.ehdr->e_ident, ELFMAG, SELFMAG) != 0 ||
     56       1.2     maxv 	    eif.ehdr->e_ident[EI_CLASS] != ELFCLASS ||
     57       1.2     maxv 	    eif.ehdr->e_type != ET_REL) {
     58       1.1     maxv 		return -1;
     59       1.1     maxv 	}
     60       1.1     maxv 	return 0;
     61       1.1     maxv }
     62       1.1     maxv 
     63      1.20     maxv static bool
     64      1.20     maxv elf_section_mappable(Elf_Shdr *shdr)
     65      1.20     maxv {
     66      1.20     maxv 	if (!(shdr->sh_flags & SHF_ALLOC)) {
     67      1.20     maxv 		return false;
     68      1.20     maxv 	}
     69      1.20     maxv 	if (shdr->sh_type != SHT_NOBITS &&
     70      1.20     maxv 	    shdr->sh_type != SHT_PROGBITS) {
     71      1.20     maxv 		return false;
     72      1.20     maxv 	}
     73      1.20     maxv 	return true;
     74      1.20     maxv }
     75      1.20     maxv 
     76      1.20     maxv static bool
     77      1.20     maxv elf_can_drop_unmappable(Elf_Shdr *shdr)
     78      1.20     maxv {
     79      1.20     maxv 	/*
     80      1.20     maxv 	 * We found relocations from the section 'shdr' towards the rest of
     81      1.20     maxv 	 * the binary, but 'shdr' is not mapped. Decide whether to skip the
     82      1.20     maxv 	 * relocations from this section.
     83      1.20     maxv 	 *
     84      1.20     maxv 	 * We skip only if it is a note. It means that we allow notes to
     85      1.20     maxv 	 * have relocations towards the rest of the binary, typically with
     86      1.20     maxv 	 * the ".note.Xen" section. Notes do not play any role at run time.
     87      1.20     maxv 	 *
     88      1.20     maxv 	 * Any section other than a note is the sign there is a design
     89      1.20     maxv 	 * mistake in the kernel (variables stored outside of rodata/data).
     90      1.20     maxv 	 */
     91      1.20     maxv 	if (shdr->sh_type == SHT_NOTE) {
     92      1.20     maxv 		return true;
     93      1.20     maxv 	}
     94      1.20     maxv 	return false;
     95      1.20     maxv }
     96      1.20     maxv 
     97       1.1     maxv static vaddr_t
     98      1.13     maxv elf_get_entrypoint(void)
     99       1.1     maxv {
    100       1.1     maxv 	Elf_Sym *sym;
    101       1.1     maxv 	size_t i;
    102       1.1     maxv 	char *buf;
    103       1.1     maxv 
    104       1.1     maxv 	for (i = 0; i < eif.symcnt; i++) {
    105       1.1     maxv 		sym = &eif.symtab[i];
    106       1.1     maxv 
    107       1.1     maxv 		if (ELF_ST_TYPE(sym->st_info) != STT_FUNC)
    108       1.1     maxv 			continue;
    109       1.1     maxv 		if (sym->st_name == 0)
    110       1.1     maxv 			continue;
    111       1.1     maxv 		if (sym->st_shndx == SHN_UNDEF)
    112       1.1     maxv 			continue; /* Skip external references */
    113       1.1     maxv 		buf = eif.strtab + sym->st_name;
    114       1.1     maxv 
    115       1.1     maxv 		if (!memcmp(buf, entrypoint, sizeof(entrypoint))) {
    116       1.1     maxv 			return (vaddr_t)sym->st_value;
    117       1.1     maxv 		}
    118       1.1     maxv 	}
    119       1.1     maxv 
    120       1.1     maxv 	return 0;
    121       1.1     maxv }
    122       1.1     maxv 
    123       1.1     maxv static Elf_Shdr *
    124       1.1     maxv elf_find_section(char *name)
    125       1.1     maxv {
    126       1.1     maxv 	char *buf;
    127       1.1     maxv 	size_t i;
    128       1.1     maxv 
    129       1.1     maxv 	for (i = 0; i < eif.ehdr->e_shnum; i++) {
    130       1.1     maxv 		if (eif.shdr[i].sh_name == 0) {
    131       1.1     maxv 			continue;
    132       1.1     maxv 		}
    133       1.1     maxv 		buf = eif.shstrtab + eif.shdr[i].sh_name;
    134       1.1     maxv 		if (!strcmp(name, buf)) {
    135       1.1     maxv 			return &eif.shdr[i];
    136       1.1     maxv 		}
    137       1.1     maxv 	}
    138       1.1     maxv 
    139       1.1     maxv 	return NULL;
    140       1.1     maxv }
    141       1.1     maxv 
    142       1.1     maxv static uintptr_t
    143       1.1     maxv elf_sym_lookup(size_t symidx)
    144       1.1     maxv {
    145       1.1     maxv 	const Elf_Sym *sym;
    146       1.1     maxv 	char *buf, *secname;
    147       1.1     maxv 	Elf_Shdr *sec;
    148       1.1     maxv 
    149       1.6     maxv 	if (symidx == STN_UNDEF) {
    150       1.6     maxv 		return 0;
    151       1.6     maxv 	}
    152       1.6     maxv 
    153       1.1     maxv 	if (symidx >= eif.symcnt) {
    154       1.1     maxv 		fatal("elf_sym_lookup: symbol beyond table");
    155       1.1     maxv 	}
    156       1.1     maxv 	sym = &eif.symtab[symidx];
    157       1.1     maxv 	buf = eif.strtab + sym->st_name;
    158       1.1     maxv 
    159       1.1     maxv 	if (sym->st_shndx == SHN_UNDEF) {
    160       1.1     maxv 		if (!memcmp(buf, "__start_link_set", 16)) {
    161       1.1     maxv 			secname = buf + 8;
    162       1.1     maxv 			sec = elf_find_section(secname);
    163       1.1     maxv 			if (sec == NULL) {
    164       1.1     maxv 				fatal("elf_sym_lookup: unknown start link set");
    165       1.1     maxv 			}
    166       1.1     maxv 			return (uintptr_t)((uint8_t *)eif.ehdr +
    167       1.1     maxv 			    sec->sh_offset);
    168       1.1     maxv 		}
    169       1.1     maxv 		if (!memcmp(buf, "__stop_link_set", 15)) {
    170       1.1     maxv 			secname = buf + 7;
    171       1.1     maxv 			sec = elf_find_section(secname);
    172       1.1     maxv 			if (sec == NULL) {
    173       1.1     maxv 				fatal("elf_sym_lookup: unknown stop link set");
    174       1.1     maxv 			}
    175       1.1     maxv 			return (uintptr_t)((uint8_t *)eif.ehdr +
    176       1.1     maxv 			    sec->sh_offset + sec->sh_size);
    177       1.1     maxv 		}
    178       1.1     maxv 
    179       1.1     maxv 		fatal("elf_sym_lookup: external symbol");
    180       1.1     maxv 	}
    181      1.20     maxv 	if (sym->st_shndx >= eif.ehdr->e_shnum) {
    182      1.20     maxv 		fatal("elf_sym_lookup: st_shndx is malformed");
    183      1.20     maxv 	}
    184      1.20     maxv 	if (!elf_section_mappable(&eif.shdr[sym->st_shndx])) {
    185      1.20     maxv 		fatal("elf_sym_lookup: st_shndx not mappable");
    186      1.20     maxv 	}
    187       1.1     maxv 	if (sym->st_value == 0) {
    188       1.1     maxv 		fatal("elf_sym_lookup: zero value");
    189       1.1     maxv 	}
    190       1.1     maxv 	return (uintptr_t)sym->st_value;
    191       1.1     maxv }
    192       1.1     maxv 
    193       1.1     maxv static void
    194       1.1     maxv elf_apply_reloc(uintptr_t relocbase, const void *data, bool isrela)
    195       1.1     maxv {
    196       1.1     maxv 	Elf64_Addr *where, val;
    197       1.1     maxv 	Elf32_Addr *where32, val32;
    198       1.1     maxv 	Elf64_Addr addr;
    199       1.1     maxv 	Elf64_Addr addend;
    200       1.1     maxv 	uintptr_t rtype, symidx;
    201       1.1     maxv 	const Elf_Rel *rel;
    202       1.1     maxv 	const Elf_Rela *rela;
    203       1.1     maxv 
    204       1.1     maxv 	if (isrela) {
    205       1.1     maxv 		rela = (const Elf_Rela *)data;
    206       1.1     maxv 		where = (Elf64_Addr *)(relocbase + rela->r_offset);
    207       1.1     maxv 		addend = rela->r_addend;
    208       1.1     maxv 		rtype = ELF_R_TYPE(rela->r_info);
    209       1.1     maxv 		symidx = ELF_R_SYM(rela->r_info);
    210       1.1     maxv 	} else {
    211       1.1     maxv 		rel = (const Elf_Rel *)data;
    212       1.1     maxv 		where = (Elf64_Addr *)(relocbase + rel->r_offset);
    213       1.1     maxv 		rtype = ELF_R_TYPE(rel->r_info);
    214       1.1     maxv 		symidx = ELF_R_SYM(rel->r_info);
    215       1.1     maxv 		/* Addend is 32 bit on 32 bit relocs */
    216       1.1     maxv 		switch (rtype) {
    217       1.1     maxv 		case R_X86_64_PC32:
    218       1.1     maxv 		case R_X86_64_32:
    219       1.1     maxv 		case R_X86_64_32S:
    220       1.1     maxv 			addend = *(Elf32_Addr *)where;
    221       1.1     maxv 			break;
    222       1.1     maxv 		default:
    223       1.1     maxv 			addend = *where;
    224       1.1     maxv 			break;
    225       1.1     maxv 		}
    226       1.1     maxv 	}
    227       1.1     maxv 
    228       1.1     maxv 	switch (rtype) {
    229       1.1     maxv 	case R_X86_64_NONE:	/* none */
    230       1.1     maxv 		break;
    231       1.1     maxv 
    232       1.1     maxv 	case R_X86_64_64:		/* S + A */
    233       1.1     maxv 		addr = elf_sym_lookup(symidx);
    234       1.1     maxv 		val = addr + addend;
    235       1.1     maxv 		*where = val;
    236       1.1     maxv 		break;
    237       1.1     maxv 
    238       1.1     maxv 	case R_X86_64_PC32:	/* S + A - P */
    239      1.18     maxv 	case R_X86_64_PLT32:
    240       1.1     maxv 		addr = elf_sym_lookup(symidx);
    241       1.1     maxv 		where32 = (Elf32_Addr *)where;
    242       1.1     maxv 		val32 = (Elf32_Addr)(addr + addend - (Elf64_Addr)where);
    243       1.1     maxv 		*where32 = val32;
    244       1.1     maxv 		break;
    245       1.1     maxv 
    246       1.1     maxv 	case R_X86_64_32:	/* S + A */
    247       1.1     maxv 	case R_X86_64_32S:	/* S + A sign extend */
    248       1.1     maxv 		addr = elf_sym_lookup(symidx);
    249       1.1     maxv 		val32 = (Elf32_Addr)(addr + addend);
    250       1.1     maxv 		where32 = (Elf32_Addr *)where;
    251       1.1     maxv 		*where32 = val32;
    252       1.1     maxv 		break;
    253       1.1     maxv 
    254       1.1     maxv 	case R_X86_64_GLOB_DAT:	/* S */
    255       1.1     maxv 	case R_X86_64_JUMP_SLOT:/* XXX need addend + offset */
    256       1.1     maxv 		addr = elf_sym_lookup(symidx);
    257       1.1     maxv 		*where = addr;
    258       1.1     maxv 		break;
    259       1.1     maxv 
    260       1.1     maxv 	case R_X86_64_RELATIVE:	/* B + A */
    261       1.1     maxv 		addr = relocbase + addend;
    262       1.1     maxv 		val = addr;
    263       1.1     maxv 		*where = val;
    264       1.1     maxv 		break;
    265       1.1     maxv 
    266       1.1     maxv 	default:
    267       1.1     maxv 		fatal("elf_apply_reloc: unexpected relocation type");
    268       1.1     maxv 	}
    269       1.1     maxv }
    270       1.1     maxv 
    271       1.4     maxv /* -------------------------------------------------------------------------- */
    272       1.4     maxv 
    273       1.4     maxv size_t
    274       1.4     maxv elf_get_head_size(vaddr_t headva)
    275       1.4     maxv {
    276       1.4     maxv 	Elf_Ehdr *ehdr;
    277       1.4     maxv 	Elf_Shdr *shdr;
    278       1.4     maxv 	size_t size;
    279       1.4     maxv 
    280       1.4     maxv 	ehdr = (Elf_Ehdr *)headva;
    281       1.4     maxv 	shdr = (Elf_Shdr *)((uint8_t *)ehdr + ehdr->e_shoff);
    282       1.4     maxv 
    283       1.4     maxv 	size = (vaddr_t)shdr + (vaddr_t)(ehdr->e_shnum * sizeof(Elf_Shdr)) -
    284       1.4     maxv 	    (vaddr_t)ehdr;
    285       1.4     maxv 
    286       1.4     maxv 	return roundup(size, PAGE_SIZE);
    287       1.4     maxv }
    288       1.4     maxv 
    289       1.4     maxv void
    290       1.4     maxv elf_build_head(vaddr_t headva)
    291       1.4     maxv {
    292       1.4     maxv 	memset(&eif, 0, sizeof(struct elfinfo));
    293       1.4     maxv 
    294       1.4     maxv 	eif.ehdr = (Elf_Ehdr *)headva;
    295       1.4     maxv 	eif.shdr = (Elf_Shdr *)((uint8_t *)eif.ehdr + eif.ehdr->e_shoff);
    296       1.4     maxv 
    297       1.4     maxv 	if (elf_check_header() == -1) {
    298       1.5     maxv 		fatal("elf_build_head: wrong kernel ELF header");
    299       1.4     maxv 	}
    300       1.4     maxv }
    301       1.4     maxv 
    302       1.4     maxv void
    303      1.21     maxv elf_fixup_boot(vaddr_t bootva, paddr_t bootpa)
    304      1.21     maxv {
    305      1.21     maxv 	const paddr_t basepa = kernpa_start;
    306      1.21     maxv 	const vaddr_t headva = (vaddr_t)eif.ehdr;
    307      1.21     maxv 	size_t i, offboot;
    308      1.21     maxv 
    309      1.21     maxv 	/*
    310      1.21     maxv 	 * Fix up the 'sh_offset' field of the REL/RELA/SYM/STR sections, which
    311      1.21     maxv 	 * are all in the "boot" region.
    312      1.21     maxv 	 */
    313      1.21     maxv 	for (i = 0; i < eif.ehdr->e_shnum; i++) {
    314      1.21     maxv 		if (eif.shdr[i].sh_type != SHT_STRTAB &&
    315      1.21     maxv 		    eif.shdr[i].sh_type != SHT_REL &&
    316      1.21     maxv 		    eif.shdr[i].sh_type != SHT_RELA &&
    317      1.21     maxv 		    eif.shdr[i].sh_type != SHT_SYMTAB) {
    318      1.21     maxv 			continue;
    319      1.21     maxv 		}
    320      1.21     maxv 		if (eif.shdr[i].sh_offset == 0) {
    321      1.21     maxv 			/* The bootloader dropped it. */
    322      1.21     maxv 			continue;
    323      1.21     maxv 		}
    324      1.21     maxv 
    325      1.21     maxv 		/* Offset of the section within the boot region. */
    326      1.21     maxv 		offboot = basepa + eif.shdr[i].sh_offset - bootpa;
    327      1.21     maxv 
    328      1.21     maxv 		/* We want (headva + sh_offset) to be the VA of the region. */
    329      1.21     maxv 		eif.shdr[i].sh_offset = (bootva + offboot - headva);
    330      1.21     maxv 	}
    331      1.21     maxv }
    332      1.21     maxv 
    333      1.21     maxv void
    334      1.13     maxv elf_map_sections(void)
    335       1.4     maxv {
    336       1.4     maxv 	const paddr_t basepa = kernpa_start;
    337       1.4     maxv 	const vaddr_t headva = (vaddr_t)eif.ehdr;
    338      1.10     maxv 	Elf_Shdr *shdr;
    339      1.10     maxv 	int segtype;
    340      1.10     maxv 	vaddr_t secva;
    341      1.10     maxv 	paddr_t secpa;
    342      1.14     maxv 	size_t i, secsz, secalign;
    343       1.4     maxv 
    344       1.4     maxv 	for (i = 0; i < eif.ehdr->e_shnum; i++) {
    345      1.10     maxv 		shdr = &eif.shdr[i];
    346       1.4     maxv 
    347      1.19     maxv 		if (!elf_section_mappable(shdr)) {
    348       1.4     maxv 			continue;
    349       1.4     maxv 		}
    350       1.4     maxv 
    351      1.10     maxv 		if (shdr->sh_flags & SHF_EXECINSTR) {
    352      1.10     maxv 			segtype = BTSEG_TEXT;
    353      1.10     maxv 		} else if (shdr->sh_flags & SHF_WRITE) {
    354      1.10     maxv 			segtype = BTSEG_DATA;
    355      1.10     maxv 		} else {
    356      1.10     maxv 			segtype = BTSEG_RODATA;
    357       1.4     maxv 		}
    358      1.10     maxv 		secpa = basepa + shdr->sh_offset;
    359      1.10     maxv 		secsz = shdr->sh_size;
    360      1.14     maxv 		secalign = shdr->sh_addralign;
    361      1.10     maxv 		ASSERT(shdr->sh_offset != 0);
    362      1.10     maxv 		ASSERT(secpa % PAGE_SIZE == 0);
    363      1.16     maxv 		ASSERT(secpa + secsz <= kernpa_end);
    364       1.4     maxv 
    365      1.14     maxv 		secva = mm_map_segment(segtype, secpa, secsz, secalign);
    366       1.4     maxv 
    367      1.21     maxv 		/*
    368      1.21     maxv 		 * Fix up the 'sh_offset' field of the NOBITS/PROGBITS sections.
    369      1.21     maxv 		 * We want (headva + sh_offset) to be the VA of the section.
    370      1.21     maxv 		 */
    371      1.12     maxv 		ASSERT(secva > headva);
    372      1.10     maxv 		shdr->sh_offset = secva - headva;
    373       1.4     maxv 	}
    374       1.4     maxv }
    375       1.4     maxv 
    376       1.4     maxv void
    377      1.21     maxv elf_build_info(void)
    378       1.1     maxv {
    379      1.21     maxv 	size_t i, j;
    380       1.1     maxv 
    381       1.1     maxv 	/* Locate the section names */
    382       1.1     maxv 	j = eif.ehdr->e_shstrndx;
    383       1.1     maxv 	if (j == SHN_UNDEF) {
    384      1.21     maxv 		fatal("elf_build_info: shstrtab not found");
    385       1.1     maxv 	}
    386       1.1     maxv 	if (j >= eif.ehdr->e_shnum) {
    387      1.21     maxv 		fatal("elf_build_info: wrong shstrtab index");
    388       1.1     maxv 	}
    389       1.1     maxv 	eif.shstrtab = (char *)((uint8_t *)eif.ehdr + eif.shdr[j].sh_offset);
    390       1.1     maxv 	eif.shstrsz = eif.shdr[j].sh_size;
    391       1.1     maxv 
    392       1.1     maxv 	/* Locate the symbol table */
    393       1.1     maxv 	for (i = 0; i < eif.ehdr->e_shnum; i++) {
    394       1.1     maxv 		if (eif.shdr[i].sh_type == SHT_SYMTAB)
    395       1.1     maxv 			break;
    396       1.1     maxv 	}
    397       1.1     maxv 	if (i == eif.ehdr->e_shnum) {
    398      1.21     maxv 		fatal("elf_build_info: symtab not found");
    399       1.1     maxv 	}
    400      1.17     maxv 	if (eif.shdr[i].sh_offset == 0) {
    401      1.21     maxv 		fatal("elf_build_info: symtab not loaded");
    402      1.17     maxv 	}
    403       1.1     maxv 	eif.symtab = (Elf_Sym *)((uint8_t *)eif.ehdr + eif.shdr[i].sh_offset);
    404       1.1     maxv 	eif.symcnt = eif.shdr[i].sh_size / sizeof(Elf_Sym);
    405       1.1     maxv 
    406       1.1     maxv 	/* Also locate the string table */
    407       1.1     maxv 	j = eif.shdr[i].sh_link;
    408       1.1     maxv 	if (j == SHN_UNDEF || j >= eif.ehdr->e_shnum) {
    409      1.21     maxv 		fatal("elf_build_info: wrong strtab index");
    410       1.1     maxv 	}
    411       1.1     maxv 	if (eif.shdr[j].sh_type != SHT_STRTAB) {
    412      1.21     maxv 		fatal("elf_build_info: wrong strtab type");
    413       1.1     maxv 	}
    414      1.17     maxv 	if (eif.shdr[j].sh_offset == 0) {
    415      1.21     maxv 		fatal("elf_build_info: strtab not loaded");
    416      1.17     maxv 	}
    417       1.1     maxv 	eif.strtab = (char *)((uint8_t *)eif.ehdr + eif.shdr[j].sh_offset);
    418       1.1     maxv 	eif.strsz = eif.shdr[j].sh_size;
    419       1.1     maxv }
    420       1.1     maxv 
    421       1.1     maxv vaddr_t
    422      1.13     maxv elf_kernel_reloc(void)
    423       1.1     maxv {
    424       1.4     maxv 	const vaddr_t baseva = (vaddr_t)eif.ehdr;
    425       1.1     maxv 	vaddr_t secva, ent;
    426       1.1     maxv 	Elf_Sym *sym;
    427       1.1     maxv 	size_t i, j;
    428       1.1     maxv 
    429  1.21.6.1  thorpej 	print_state(STATE_NORMAL, "ELF info created");
    430       1.1     maxv 
    431       1.1     maxv 	/*
    432       1.1     maxv 	 * Update all symbol values with the appropriate offset.
    433       1.1     maxv 	 */
    434       1.1     maxv 	for (i = 0; i < eif.ehdr->e_shnum; i++) {
    435      1.19     maxv 		if (!elf_section_mappable(&eif.shdr[i])) {
    436       1.1     maxv 			continue;
    437       1.1     maxv 		}
    438      1.19     maxv 
    439      1.17     maxv 		ASSERT(eif.shdr[i].sh_offset != 0);
    440       1.1     maxv 		secva = baseva + eif.shdr[i].sh_offset;
    441       1.1     maxv 		for (j = 0; j < eif.symcnt; j++) {
    442       1.1     maxv 			sym = &eif.symtab[j];
    443       1.1     maxv 			if (sym->st_shndx != i) {
    444       1.1     maxv 				continue;
    445       1.1     maxv 			}
    446       1.1     maxv 			sym->st_value += (Elf_Addr)secva;
    447       1.1     maxv 		}
    448       1.1     maxv 	}
    449       1.1     maxv 
    450  1.21.6.1  thorpej 	print_state(STATE_NORMAL, "Symbol values updated");
    451       1.1     maxv 
    452       1.1     maxv 	/*
    453       1.1     maxv 	 * Perform relocations without addend if there are any.
    454       1.1     maxv 	 */
    455       1.1     maxv 	for (i = 0; i < eif.ehdr->e_shnum; i++) {
    456       1.1     maxv 		Elf_Rel *reltab, *rel;
    457       1.1     maxv 		size_t secidx, nrel;
    458       1.1     maxv 		uintptr_t base;
    459       1.1     maxv 
    460      1.17     maxv 		if (eif.shdr[i].sh_type != SHT_REL) {
    461       1.1     maxv 			continue;
    462      1.17     maxv 		}
    463      1.17     maxv 		ASSERT(eif.shdr[i].sh_offset != 0);
    464       1.1     maxv 		reltab = (Elf_Rel *)((uint8_t *)eif.ehdr + eif.shdr[i].sh_offset);
    465       1.1     maxv 		nrel = eif.shdr[i].sh_size / sizeof(Elf_Rel);
    466       1.1     maxv 
    467       1.1     maxv 		secidx = eif.shdr[i].sh_info;
    468       1.1     maxv 		if (secidx >= eif.ehdr->e_shnum) {
    469      1.19     maxv 			fatal("elf_kernel_reloc: REL sh_info is malformed");
    470      1.19     maxv 		}
    471      1.19     maxv 		if (!elf_section_mappable(&eif.shdr[secidx])) {
    472      1.20     maxv 			if (elf_can_drop_unmappable(&eif.shdr[secidx])) {
    473      1.20     maxv 				continue;
    474      1.20     maxv 			}
    475      1.19     maxv 			fatal("elf_kernel_reloc: REL sh_info not mappable");
    476       1.1     maxv 		}
    477       1.1     maxv 		base = (uintptr_t)eif.ehdr + eif.shdr[secidx].sh_offset;
    478       1.1     maxv 
    479       1.1     maxv 		for (j = 0; j < nrel; j++) {
    480       1.1     maxv 			rel = &reltab[j];
    481       1.1     maxv 			elf_apply_reloc(base, rel, false);
    482       1.1     maxv 		}
    483       1.1     maxv 	}
    484       1.1     maxv 
    485  1.21.6.1  thorpej 	print_state(STATE_NORMAL, "REL relocations applied");
    486       1.1     maxv 
    487       1.1     maxv 	/*
    488       1.1     maxv 	 * Perform relocations with addend if there are any.
    489       1.1     maxv 	 */
    490       1.1     maxv 	for (i = 0; i < eif.ehdr->e_shnum; i++) {
    491       1.1     maxv 		Elf_Rela *relatab, *rela;
    492       1.1     maxv 		size_t secidx, nrela;
    493       1.1     maxv 		uintptr_t base;
    494       1.1     maxv 
    495      1.17     maxv 		if (eif.shdr[i].sh_type != SHT_RELA) {
    496       1.1     maxv 			continue;
    497      1.17     maxv 		}
    498      1.17     maxv 		ASSERT(eif.shdr[i].sh_offset != 0);
    499       1.1     maxv 		relatab = (Elf_Rela *)((uint8_t *)eif.ehdr + eif.shdr[i].sh_offset);
    500       1.1     maxv 		nrela = eif.shdr[i].sh_size / sizeof(Elf_Rela);
    501       1.1     maxv 
    502       1.1     maxv 		secidx = eif.shdr[i].sh_info;
    503       1.1     maxv 		if (secidx >= eif.ehdr->e_shnum) {
    504      1.19     maxv 			fatal("elf_kernel_reloc: RELA sh_info is malformed");
    505      1.19     maxv 		}
    506      1.19     maxv 		if (!elf_section_mappable(&eif.shdr[secidx])) {
    507      1.20     maxv 			if (elf_can_drop_unmappable(&eif.shdr[secidx])) {
    508      1.20     maxv 				continue;
    509      1.20     maxv 			}
    510      1.19     maxv 			fatal("elf_kernel_reloc: RELA sh_info not mappable");
    511       1.1     maxv 		}
    512       1.1     maxv 		base = (uintptr_t)eif.ehdr + eif.shdr[secidx].sh_offset;
    513       1.1     maxv 
    514       1.1     maxv 		for (j = 0; j < nrela; j++) {
    515       1.1     maxv 			rela = &relatab[j];
    516       1.1     maxv 			elf_apply_reloc(base, rela, true);
    517       1.1     maxv 		}
    518       1.1     maxv 	}
    519       1.1     maxv 
    520  1.21.6.1  thorpej 	print_state(STATE_NORMAL, "RELA relocations applied");
    521       1.1     maxv 
    522       1.1     maxv 	/*
    523       1.1     maxv 	 * Get the entry point.
    524       1.1     maxv 	 */
    525      1.13     maxv 	ent = elf_get_entrypoint();
    526       1.1     maxv 	if (ent == 0) {
    527       1.1     maxv 		fatal("elf_kernel_reloc: entry point not found");
    528       1.1     maxv 	}
    529       1.1     maxv 
    530  1.21.6.1  thorpej 	print_state(STATE_NORMAL, "Entry point found");
    531       1.1     maxv 
    532       1.1     maxv 	return ent;
    533       1.1     maxv }
    534