/*
* Copyright (c) 2017-2020 The NetBSD Foundation, Inc. All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Maxime Villard.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
static bool
elf_can_drop_unmappable(Elf_Shdr *shdr)
{
/*
* We found relocations from the section 'shdr' towards the rest of
* the binary, but 'shdr' is not mapped. Decide whether to skip the
* relocations from this section.
*
* We skip only if it is a note. It means that we allow notes to
* have relocations towards the rest of the binary, typically with
* the ".note.Xen" section. Notes do not play any role at run time.
*
* Any section other than a note is the sign there is a design
* mistake in the kernel (variables stored outside of rodata/data).
*/
if (shdr->sh_type == SHT_NOTE) {
return true;
}
return false;
}
/*
* Fix up the 'sh_offset' field of the REL/RELA/SYM/STR sections, which
* are all in the "boot" region.
*/
for (i = 0; i < eif.ehdr->e_shnum; i++) {
if (eif.shdr[i].sh_type != SHT_STRTAB &&
eif.shdr[i].sh_type != SHT_REL &&
eif.shdr[i].sh_type != SHT_RELA &&
eif.shdr[i].sh_type != SHT_SYMTAB) {
continue;
}
if (eif.shdr[i].sh_offset == 0) {
/* The bootloader dropped it. */
continue;
}
/* Offset of the section within the boot region. */
offboot = basepa + eif.shdr[i].sh_offset - bootpa;
/* We want (headva + sh_offset) to be the VA of the region. */
eif.shdr[i].sh_offset = (bootva + offboot - headva);
}
}
/*
* Fix up the 'sh_offset' field of the NOBITS/PROGBITS sections.
* We want (headva + sh_offset) to be the VA of the section.
*/
ASSERT(secva > headva);
shdr->sh_offset = secva - headva;
}
}
void
elf_build_info(void)
{
size_t i, j;
/* Locate the section names */
j = eif.ehdr->e_shstrndx;
if (j == SHN_UNDEF) {
fatal("elf_build_info: shstrtab not found");
}
if (j >= eif.ehdr->e_shnum) {
fatal("elf_build_info: wrong shstrtab index");
}
eif.shstrtab = (char *)((uint8_t *)eif.ehdr + eif.shdr[j].sh_offset);
eif.shstrsz = eif.shdr[j].sh_size;
/* Locate the symbol table */
for (i = 0; i < eif.ehdr->e_shnum; i++) {
if (eif.shdr[i].sh_type == SHT_SYMTAB)
break;
}
if (i == eif.ehdr->e_shnum) {
fatal("elf_build_info: symtab not found");
}
if (eif.shdr[i].sh_offset == 0) {
fatal("elf_build_info: symtab not loaded");
}
eif.symtab = (Elf_Sym *)((uint8_t *)eif.ehdr + eif.shdr[i].sh_offset);
eif.symcnt = eif.shdr[i].sh_size / sizeof(Elf_Sym);
/* Also locate the string table */
j = eif.shdr[i].sh_link;
if (j == SHN_UNDEF || j >= eif.ehdr->e_shnum) {
fatal("elf_build_info: wrong strtab index");
}
if (eif.shdr[j].sh_type != SHT_STRTAB) {
fatal("elf_build_info: wrong strtab type");
}
if (eif.shdr[j].sh_offset == 0) {
fatal("elf_build_info: strtab not loaded");
}
eif.strtab = (char *)((uint8_t *)eif.ehdr + eif.shdr[j].sh_offset);
eif.strsz = eif.shdr[j].sh_size;
}
/*
* Update all symbol values with the appropriate offset.
*/
for (i = 0; i < eif.ehdr->e_shnum; i++) {
if (!elf_section_mappable(&eif.shdr[i])) {
continue;
}
/*
* Perform relocations without addend if there are any.
*/
for (i = 0; i < eif.ehdr->e_shnum; i++) {
Elf_Rel *reltab, *rel;
size_t secidx, nrel;
uintptr_t base;
/*
* Perform relocations with addend if there are any.
*/
for (i = 0; i < eif.ehdr->e_shnum; i++) {
Elf_Rela *relatab, *rela;
size_t secidx, nrela;
uintptr_t base;