[BACK]Return to elf.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / sys / arch / amd64 / stand / prekern

Annotation of src/sys/arch/amd64/stand/prekern/elf.c, Revision 1.12

1.12    ! maxv        1: /*     $NetBSD: elf.c,v 1.11 2017/11/13 21:32:21 maxv Exp $    */
1.1       maxv        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: };
                     46:
1.4       maxv       47: extern paddr_t kernpa_start, kernpa_end;
                     48:
1.1       maxv       49: static struct elfinfo eif;
                     50: static const char entrypoint[] = "start_prekern";
                     51:
                     52: static int
                     53: elf_check_header()
                     54: {
                     55:        if (memcmp((char *)eif.ehdr->e_ident, ELFMAG, SELFMAG) != 0 ||
1.2       maxv       56:            eif.ehdr->e_ident[EI_CLASS] != ELFCLASS ||
                     57:            eif.ehdr->e_type != ET_REL) {
1.1       maxv       58:                return -1;
                     59:        }
                     60:        return 0;
                     61: }
                     62:
                     63: static vaddr_t
                     64: elf_get_entrypoint()
                     65: {
                     66:        Elf_Sym *sym;
                     67:        size_t i;
                     68:        char *buf;
                     69:
                     70:        for (i = 0; i < eif.symcnt; i++) {
                     71:                sym = &eif.symtab[i];
                     72:
                     73:                if (ELF_ST_TYPE(sym->st_info) != STT_FUNC)
                     74:                        continue;
                     75:                if (sym->st_name == 0)
                     76:                        continue;
                     77:                if (sym->st_shndx == SHN_UNDEF)
                     78:                        continue; /* Skip external references */
                     79:                buf = eif.strtab + sym->st_name;
                     80:
                     81:                if (!memcmp(buf, entrypoint, sizeof(entrypoint))) {
                     82:                        return (vaddr_t)sym->st_value;
                     83:                }
                     84:        }
                     85:
                     86:        return 0;
                     87: }
                     88:
                     89: static Elf_Shdr *
                     90: elf_find_section(char *name)
                     91: {
                     92:        char *buf;
                     93:        size_t i;
                     94:
                     95:        for (i = 0; i < eif.ehdr->e_shnum; i++) {
                     96:                if (eif.shdr[i].sh_name == 0) {
                     97:                        continue;
                     98:                }
                     99:                buf = eif.shstrtab + eif.shdr[i].sh_name;
                    100:                if (!strcmp(name, buf)) {
                    101:                        return &eif.shdr[i];
                    102:                }
                    103:        }
                    104:
                    105:        return NULL;
                    106: }
                    107:
                    108: static uintptr_t
                    109: elf_sym_lookup(size_t symidx)
                    110: {
                    111:        const Elf_Sym *sym;
                    112:        char *buf, *secname;
                    113:        Elf_Shdr *sec;
                    114:
1.6       maxv      115:        if (symidx == STN_UNDEF) {
                    116:                return 0;
                    117:        }
                    118:
1.1       maxv      119:        if (symidx >= eif.symcnt) {
                    120:                fatal("elf_sym_lookup: symbol beyond table");
                    121:        }
                    122:        sym = &eif.symtab[symidx];
                    123:        buf = eif.strtab + sym->st_name;
                    124:
                    125:        if (sym->st_shndx == SHN_UNDEF) {
                    126:                if (!memcmp(buf, "__start_link_set", 16)) {
                    127:                        secname = buf + 8;
                    128:                        sec = elf_find_section(secname);
                    129:                        if (sec == NULL) {
                    130:                                fatal("elf_sym_lookup: unknown start link set");
                    131:                        }
                    132:                        return (uintptr_t)((uint8_t *)eif.ehdr +
                    133:                            sec->sh_offset);
                    134:                }
                    135:                if (!memcmp(buf, "__stop_link_set", 15)) {
                    136:                        secname = buf + 7;
                    137:                        sec = elf_find_section(secname);
                    138:                        if (sec == NULL) {
                    139:                                fatal("elf_sym_lookup: unknown stop link set");
                    140:                        }
                    141:                        return (uintptr_t)((uint8_t *)eif.ehdr +
                    142:                            sec->sh_offset + sec->sh_size);
                    143:                }
                    144:
                    145:                fatal("elf_sym_lookup: external symbol");
                    146:        }
                    147:        if (sym->st_value == 0) {
                    148:                fatal("elf_sym_lookup: zero value");
                    149:        }
                    150:        return (uintptr_t)sym->st_value;
                    151: }
                    152:
                    153: static void
                    154: elf_apply_reloc(uintptr_t relocbase, const void *data, bool isrela)
                    155: {
                    156:        Elf64_Addr *where, val;
                    157:        Elf32_Addr *where32, val32;
                    158:        Elf64_Addr addr;
                    159:        Elf64_Addr addend;
                    160:        uintptr_t rtype, symidx;
                    161:        const Elf_Rel *rel;
                    162:        const Elf_Rela *rela;
                    163:
                    164:        if (isrela) {
                    165:                rela = (const Elf_Rela *)data;
                    166:                where = (Elf64_Addr *)(relocbase + rela->r_offset);
                    167:                addend = rela->r_addend;
                    168:                rtype = ELF_R_TYPE(rela->r_info);
                    169:                symidx = ELF_R_SYM(rela->r_info);
                    170:        } else {
                    171:                rel = (const Elf_Rel *)data;
                    172:                where = (Elf64_Addr *)(relocbase + rel->r_offset);
                    173:                rtype = ELF_R_TYPE(rel->r_info);
                    174:                symidx = ELF_R_SYM(rel->r_info);
                    175:                /* Addend is 32 bit on 32 bit relocs */
                    176:                switch (rtype) {
                    177:                case R_X86_64_PC32:
                    178:                case R_X86_64_32:
                    179:                case R_X86_64_32S:
                    180:                        addend = *(Elf32_Addr *)where;
                    181:                        break;
                    182:                default:
                    183:                        addend = *where;
                    184:                        break;
                    185:                }
                    186:        }
                    187:
                    188:        switch (rtype) {
                    189:        case R_X86_64_NONE:     /* none */
                    190:                break;
                    191:
                    192:        case R_X86_64_64:               /* S + A */
                    193:                addr = elf_sym_lookup(symidx);
                    194:                val = addr + addend;
                    195:                *where = val;
                    196:                break;
                    197:
                    198:        case R_X86_64_PC32:     /* S + A - P */
                    199:                addr = elf_sym_lookup(symidx);
                    200:                where32 = (Elf32_Addr *)where;
                    201:                val32 = (Elf32_Addr)(addr + addend - (Elf64_Addr)where);
                    202:                *where32 = val32;
                    203:                break;
                    204:
                    205:        case R_X86_64_32:       /* S + A */
                    206:        case R_X86_64_32S:      /* S + A sign extend */
                    207:                addr = elf_sym_lookup(symidx);
                    208:                val32 = (Elf32_Addr)(addr + addend);
                    209:                where32 = (Elf32_Addr *)where;
                    210:                *where32 = val32;
                    211:                break;
                    212:
                    213:        case R_X86_64_GLOB_DAT: /* S */
                    214:        case R_X86_64_JUMP_SLOT:/* XXX need addend + offset */
                    215:                addr = elf_sym_lookup(symidx);
                    216:                *where = addr;
                    217:                break;
                    218:
                    219:        case R_X86_64_RELATIVE: /* B + A */
                    220:                addr = relocbase + addend;
                    221:                val = addr;
                    222:                *where = val;
                    223:                break;
                    224:
                    225:        default:
                    226:                fatal("elf_apply_reloc: unexpected relocation type");
                    227:        }
                    228: }
                    229:
1.4       maxv      230: /* -------------------------------------------------------------------------- */
                    231:
                    232: size_t
                    233: elf_get_head_size(vaddr_t headva)
                    234: {
                    235:        Elf_Ehdr *ehdr;
                    236:        Elf_Shdr *shdr;
                    237:        size_t size;
                    238:
                    239:        ehdr = (Elf_Ehdr *)headva;
                    240:        shdr = (Elf_Shdr *)((uint8_t *)ehdr + ehdr->e_shoff);
                    241:
                    242:        size = (vaddr_t)shdr + (vaddr_t)(ehdr->e_shnum * sizeof(Elf_Shdr)) -
                    243:            (vaddr_t)ehdr;
                    244:
                    245:        return roundup(size, PAGE_SIZE);
                    246: }
                    247:
                    248: void
                    249: elf_build_head(vaddr_t headva)
                    250: {
                    251:        memset(&eif, 0, sizeof(struct elfinfo));
                    252:
                    253:        eif.ehdr = (Elf_Ehdr *)headva;
                    254:        eif.shdr = (Elf_Shdr *)((uint8_t *)eif.ehdr + eif.ehdr->e_shoff);
                    255:
                    256:        if (elf_check_header() == -1) {
1.5       maxv      257:                fatal("elf_build_head: wrong kernel ELF header");
1.4       maxv      258:        }
                    259: }
                    260:
                    261: void
1.10      maxv      262: elf_map_sections()
1.4       maxv      263: {
                    264:        const paddr_t basepa = kernpa_start;
                    265:        const vaddr_t headva = (vaddr_t)eif.ehdr;
1.10      maxv      266:        Elf_Shdr *shdr;
                    267:        int segtype;
                    268:        vaddr_t secva;
                    269:        paddr_t secpa;
1.4       maxv      270:        size_t i, secsz;
                    271:
                    272:        for (i = 0; i < eif.ehdr->e_shnum; i++) {
1.10      maxv      273:                shdr = &eif.shdr[i];
1.4       maxv      274:
1.11      maxv      275:                if (!(shdr->sh_flags & SHF_ALLOC)) {
                    276:                        continue;
                    277:                }
1.10      maxv      278:                if (shdr->sh_type != SHT_NOBITS &&
                    279:                    shdr->sh_type != SHT_PROGBITS) {
1.4       maxv      280:                        continue;
                    281:                }
                    282:
1.10      maxv      283:                if (shdr->sh_flags & SHF_EXECINSTR) {
                    284:                        segtype = BTSEG_TEXT;
                    285:                } else if (shdr->sh_flags & SHF_WRITE) {
                    286:                        segtype = BTSEG_DATA;
                    287:                } else {
                    288:                        segtype = BTSEG_RODATA;
1.4       maxv      289:                }
1.10      maxv      290:                secpa = basepa + shdr->sh_offset;
                    291:                secsz = shdr->sh_size;
                    292:                ASSERT(shdr->sh_offset != 0);
                    293:                ASSERT(secpa % PAGE_SIZE == 0);
1.4       maxv      294:
1.10      maxv      295:                secva = mm_map_segment(segtype, secpa, secsz);
1.4       maxv      296:
                    297:                /* We want (headva + sh_offset) to be the VA of the section. */
1.12    ! maxv      298:                ASSERT(secva > headva);
1.10      maxv      299:                shdr->sh_offset = secva - headva;
1.4       maxv      300:        }
                    301: }
                    302:
                    303: void
                    304: elf_build_boot(vaddr_t bootva, paddr_t bootpa)
1.1       maxv      305: {
1.4       maxv      306:        const paddr_t basepa = kernpa_start;
                    307:        const vaddr_t headva = (vaddr_t)eif.ehdr;
                    308:        size_t i, j, offboot;
1.1       maxv      309:
1.4       maxv      310:        for (i = 0; i < eif.ehdr->e_shnum; i++) {
                    311:                if (eif.shdr[i].sh_type != SHT_STRTAB &&
                    312:                    eif.shdr[i].sh_type != SHT_REL &&
                    313:                    eif.shdr[i].sh_type != SHT_RELA &&
                    314:                    eif.shdr[i].sh_type != SHT_SYMTAB) {
                    315:                        continue;
                    316:                }
                    317:                if (eif.shdr[i].sh_offset == 0) {
                    318:                        /* hasn't been loaded */
                    319:                        continue;
                    320:                }
1.1       maxv      321:
1.4       maxv      322:                /* Offset of the section within the boot region. */
                    323:                offboot = basepa + eif.shdr[i].sh_offset - bootpa;
1.1       maxv      324:
1.4       maxv      325:                /* We want (headva + sh_offset) to be the VA of the region. */
                    326:                eif.shdr[i].sh_offset = (bootva + offboot - headva);
1.1       maxv      327:        }
                    328:
                    329:        /* Locate the section names */
                    330:        j = eif.ehdr->e_shstrndx;
                    331:        if (j == SHN_UNDEF) {
1.5       maxv      332:                fatal("elf_build_boot: shstrtab not found");
1.1       maxv      333:        }
                    334:        if (j >= eif.ehdr->e_shnum) {
1.5       maxv      335:                fatal("elf_build_boot: wrong shstrtab index");
1.1       maxv      336:        }
                    337:        eif.shstrtab = (char *)((uint8_t *)eif.ehdr + eif.shdr[j].sh_offset);
                    338:        eif.shstrsz = eif.shdr[j].sh_size;
                    339:
                    340:        /* Locate the symbol table */
                    341:        for (i = 0; i < eif.ehdr->e_shnum; i++) {
                    342:                if (eif.shdr[i].sh_type == SHT_SYMTAB)
                    343:                        break;
                    344:        }
                    345:        if (i == eif.ehdr->e_shnum) {
1.5       maxv      346:                fatal("elf_build_boot: symtab not found");
1.1       maxv      347:        }
                    348:        eif.symtab = (Elf_Sym *)((uint8_t *)eif.ehdr + eif.shdr[i].sh_offset);
                    349:        eif.symcnt = eif.shdr[i].sh_size / sizeof(Elf_Sym);
                    350:
                    351:        /* Also locate the string table */
                    352:        j = eif.shdr[i].sh_link;
                    353:        if (j == SHN_UNDEF || j >= eif.ehdr->e_shnum) {
1.5       maxv      354:                fatal("elf_build_boot: wrong strtab index");
1.1       maxv      355:        }
                    356:        if (eif.shdr[j].sh_type != SHT_STRTAB) {
1.5       maxv      357:                fatal("elf_build_boot: wrong strtab type");
1.1       maxv      358:        }
                    359:        eif.strtab = (char *)((uint8_t *)eif.ehdr + eif.shdr[j].sh_offset);
                    360:        eif.strsz = eif.shdr[j].sh_size;
                    361: }
                    362:
                    363: vaddr_t
1.4       maxv      364: elf_kernel_reloc()
1.1       maxv      365: {
1.4       maxv      366:        const vaddr_t baseva = (vaddr_t)eif.ehdr;
1.1       maxv      367:        vaddr_t secva, ent;
                    368:        Elf_Sym *sym;
                    369:        size_t i, j;
                    370:
                    371:        print_state(true, "ELF info created");
                    372:
                    373:        /*
                    374:         * The loaded sections are: SHT_PROGBITS, SHT_NOBITS, SHT_STRTAB,
                    375:         * SHT_SYMTAB.
                    376:         */
                    377:
                    378:        /*
                    379:         * Update all symbol values with the appropriate offset.
                    380:         */
                    381:        for (i = 0; i < eif.ehdr->e_shnum; i++) {
                    382:                if (eif.shdr[i].sh_type != SHT_NOBITS &&
                    383:                    eif.shdr[i].sh_type != SHT_PROGBITS) {
                    384:                        continue;
                    385:                }
                    386:                secva = baseva + eif.shdr[i].sh_offset;
                    387:                for (j = 0; j < eif.symcnt; j++) {
                    388:                        sym = &eif.symtab[j];
                    389:                        if (sym->st_shndx != i) {
                    390:                                continue;
                    391:                        }
                    392:                        sym->st_value += (Elf_Addr)secva;
                    393:                }
                    394:        }
                    395:
                    396:        print_state(true, "Symbol values updated");
                    397:
                    398:        /*
                    399:         * Perform relocations without addend if there are any.
                    400:         */
                    401:        for (i = 0; i < eif.ehdr->e_shnum; i++) {
                    402:                Elf_Rel *reltab, *rel;
                    403:                size_t secidx, nrel;
                    404:                uintptr_t base;
                    405:
                    406:                if (eif.shdr[i].sh_type != SHT_REL)
                    407:                        continue;
                    408:
                    409:                reltab = (Elf_Rel *)((uint8_t *)eif.ehdr + eif.shdr[i].sh_offset);
                    410:                nrel = eif.shdr[i].sh_size / sizeof(Elf_Rel);
                    411:
                    412:                secidx = eif.shdr[i].sh_info;
                    413:                if (secidx >= eif.ehdr->e_shnum) {
                    414:                        fatal("elf_kernel_reloc: wrong REL relocation");
                    415:                }
                    416:                base = (uintptr_t)eif.ehdr + eif.shdr[secidx].sh_offset;
                    417:
                    418:                for (j = 0; j < nrel; j++) {
                    419:                        rel = &reltab[j];
                    420:                        elf_apply_reloc(base, rel, false);
                    421:                }
                    422:        }
                    423:
                    424:        print_state(true, "REL relocations applied");
                    425:
                    426:        /*
                    427:         * Perform relocations with addend if there are any.
                    428:         */
                    429:        for (i = 0; i < eif.ehdr->e_shnum; i++) {
                    430:                Elf_Rela *relatab, *rela;
                    431:                size_t secidx, nrela;
                    432:                uintptr_t base;
                    433:
                    434:                if (eif.shdr[i].sh_type != SHT_RELA)
                    435:                        continue;
                    436:
                    437:                relatab = (Elf_Rela *)((uint8_t *)eif.ehdr + eif.shdr[i].sh_offset);
                    438:                nrela = eif.shdr[i].sh_size / sizeof(Elf_Rela);
                    439:
                    440:                secidx = eif.shdr[i].sh_info;
                    441:                if (secidx >= eif.ehdr->e_shnum) {
                    442:                        fatal("elf_kernel_reloc: wrong RELA relocation");
                    443:                }
                    444:                base = (uintptr_t)eif.ehdr + eif.shdr[secidx].sh_offset;
                    445:
                    446:                for (j = 0; j < nrela; j++) {
                    447:                        rela = &relatab[j];
                    448:                        elf_apply_reloc(base, rela, true);
                    449:                }
                    450:        }
                    451:
                    452:        print_state(true, "RELA relocations applied");
                    453:
                    454:        /*
                    455:         * Get the entry point.
                    456:         */
                    457:        ent = elf_get_entrypoint(&eif);
                    458:        if (ent == 0) {
                    459:                fatal("elf_kernel_reloc: entry point not found");
                    460:        }
                    461:
                    462:        print_state(true, "Entry point found");
                    463:
                    464:        return ent;
                    465: }
                    466:

CVSweb <webmaster@jp.NetBSD.org>