/* $NetBSD: exec_sub.c,v 1.6 2009/03/14 21:04:17 dsl Exp $ */ #include #include "execkern.h" #include #include #ifdef BOOT void B_PRINT(const unsigned char *p); #endif static inline void bzero4(void *ptr, size_t siz); static void xk_aout(struct execkern_arg *xarg, struct exec *hdr); static void xk_elf(struct execkern_arg *xarg, Elf32_Ehdr *hdr); #ifdef LOADBSD static void DPRINT_SEC(const char *ident, const struct execkern_section *sec); extern int opt_v; extern const char *kernel_fn; static void DPRINT_SEC(const char *ident, const struct execkern_section *sec) { if (opt_v) xwarnx("section (%s): img %p, sz %d, pad %d", ident, sec->sec_image, sec->sec_size, sec->sec_pad); } #define ERRX(arg) xerrx arg #else #define DPRINT_SEC(ident, sec) /**/ #define ERRX(arg) return 1 #endif /* * This code is size-hacked version of * * sec->sec_image = (image); * sec->sec_size = (size); * sec->sec_pad = (pad); * DPRINT_SEC((ident), sec); * sec++; */ #define SECTION(sec, ident, image, size, pad) \ do { \ u_long *wp = (void *) sec; \ *(void **)wp++ = (image); \ *wp++ = (size); \ *wp++ = (pad); \ DPRINT_SEC((ident), sec); \ sec = (void *) wp; \ } while (0) #define SECTION_NOPAD(sec, ident, image, size) \ SECTION(sec, (ident), (image), (size), 0) static inline void bzero4(void *ptr, size_t siz) { u_long *p; u_short s; p = ptr; s = siz >> 2; while (s--) *p++ = 0; } /* * fill in loading information from an a.out executable */ static void xk_aout(struct execkern_arg *xarg, struct exec *hdr) { unsigned u; char *s; struct execkern_section *sec; xarg->entry_addr = hdr->a_entry; sec = xarg->sec; /* text section and padding between data section */ s = (void *) (hdr + 1); SECTION(sec, "text", s, hdr->a_text, -hdr->a_text & (AOUT_LDPGSZ-1)); /* data and bss sections */ s += hdr->a_text; SECTION(sec, "data/bss", s, hdr->a_data, hdr->a_bss); /* size of symbol table */ SECTION_NOPAD(sec, "symtab size", &sec[1].sec_size, sizeof(u_long)); /* symbol table section */ s += hdr->a_data; SECTION_NOPAD(sec, "symbol", s, u = hdr->a_syms); /* string table section */ if (u) { #ifdef LOADBSD if (opt_v) xwarnx("symbol table found"); #endif s += u; SECTION_NOPAD(sec, "string", s, *(u_long *) s); } } /* * fill in loading information from an ELF executable */ static void xk_elf(struct execkern_arg *xarg, Elf32_Ehdr *hdr) { char *top = (void *) hdr; struct execkern_section *sec; Elf32_Phdr *ph; Elf32_Shdr *sh, *sym, *str, *stab, *shstr; const char *shstrtab, *shname; unsigned u, dpos, pd; const char *const shstrtab_new = SHSTRTAB_FAKE; xarg->entry_addr = hdr->e_entry; /* * text, data, bss */ ph = (void *) (top + hdr->e_phoff); xarg->load_addr = ph->p_vaddr; sec = xarg->sec; sec->sec_image = top + ph->p_offset; sec->sec_size = ph->p_filesz; if (hdr->e_phnum != 1) { sec->sec_pad = ph[1].p_vaddr - (ph->p_vaddr + ph->p_filesz); DPRINT_SEC("program (text)", sec); sec++; ph++; sec->sec_image = top + ph->p_offset; sec->sec_size = ph->p_filesz; } sec->sec_pad = ph->p_memsz - ph->p_filesz; DPRINT_SEC("program (data/bss)", sec); sec++; /* * symbol size */ xarg->elfsymsiz = 0; /* no symbol */ SECTION_NOPAD(sec, "symtab size", &xarg->elfsymsiz, sizeof(int)); /* * ELF header */ xarg->ehdr = *hdr; xarg->ehdr.e_shstrndx = 0; /* .shstrtab will be the 1st section */ SECTION_NOPAD(sec, "ELF header", &xarg->ehdr, sizeof(Elf32_Ehdr)); sh = (void *) (top + hdr->e_shoff); /* section header */ shstr = sh + hdr->e_shstrndx; /* .shstrtab */ shstrtab = top + shstr->sh_offset; sym = str = stab = 0; for (u = 0; sh++, ++u < hdr->e_shnum; ) { shname = shstrtab + sh->sh_name; if (!strcmp(shname, shstrtab_new + SHNAME_OFF_SYMTAB)) sym = sh; /* .symtab */ if (!strcmp(shname, shstrtab_new + SHNAME_OFF_STRTAB)) str = sh; /* .strtab */ if (!strcmp(shname, shstrtab_new + SHNAME_OFF_STAB)) stab = sh; /* .stab */ } if (shstr == 0 || sym == 0 || str == 0) xarg->ehdr.e_shnum = 0; /* no symbol */ else { #ifdef LOADBSD if (opt_v) { xwarnx("symbol table found"); if (stab) xwarnx("debugging information found"); } #endif xarg->elfsymsiz = 1; /* has symbol */ xarg->ehdr.e_shnum = 3; xarg->ehdr.e_shoff = sizeof(Elf32_Ehdr); SECTION_NOPAD(sec, "section header (shstrtab)", shstr, sizeof(Elf32_Shdr)); SECTION_NOPAD(sec, "section header (symbol)", sym, sizeof(Elf32_Shdr)); SECTION_NOPAD(sec, "section header (string)", str, sizeof(Elf32_Shdr)); dpos = sizeof(Elf32_Ehdr) + sizeof(Elf32_Shdr) * 3; u = SIZE_SHSTRTAB_FAKE; if (stab) { xarg->ehdr.e_shnum++; SECTION_NOPAD(sec, "section header (stab)", stab, sizeof(Elf32_Shdr)); dpos += sizeof(Elf32_Shdr); u = SIZE_SHSTRTAB_FAKE_WITH_STAB; } /* new .shstrtab section */ memcpy(xarg->shstrtab_fake, shstrtab_new, u); /* * DDB requires symtab be aligned. */ pd = -u & ALIGNBYTES; SECTION(sec, "shstrtab", &xarg->shstrtab_fake, u, pd); shstr->sh_name = SHNAME_OFF_SHSTRTAB; shstr->sh_offset = dpos; dpos += u + pd; SECTION_NOPAD(sec, "symtab", top + sym->sh_offset, sym->sh_size); sym->sh_name = SHNAME_OFF_SYMTAB; sym->sh_offset = dpos; dpos += sym->sh_size; SECTION_NOPAD(sec, "strtab", top + str->sh_offset, str->sh_size); str->sh_name = SHNAME_OFF_STRTAB; str->sh_offset = dpos; dpos += str->sh_size; if (stab) { SECTION_NOPAD(sec, "stab", top + stab->sh_offset, stab->sh_size); stab->sh_name = SHNAME_OFF_STAB; stab->sh_offset = dpos; } } } int xk_load(struct execkern_arg *xarg, void *buf, u_long loadaddr) /* loadaddr: for a.out */ { struct exec *ahdr; Elf32_Ehdr *ehdr; unsigned u; /* Unused section entries should be cleared to zero. */ bzero4(xarg->sec, sizeof xarg->sec); xarg->load_addr = loadaddr; /* * check exec header */ ahdr = buf; ehdr = buf; if (N_GETMAGIC(*ahdr) == NMAGIC) { /* * this is an a.out */ #ifdef LOADBSD if (opt_v) xwarnx("%s: is an a.out", kernel_fn); #endif #ifdef BOOT B_PRINT("This is an a.out\r\n"); #endif if ((u = N_GETMID(*ahdr)) != MID_M68K) ERRX((1, "%s: Wrong architecture (mid %u)", kernel_fn, u)); /* * fill in loading information */ xk_aout(xarg, ahdr); } else { /* * check ELF header */ if (*(u_int32_t *)&ehdr->e_ident[EI_MAG0] != (ELFMAG0<<24 | ELFMAG1<<16 | ELFMAG2<<8 | ELFMAG3) || *(u_int16_t *)&ehdr->e_ident[EI_CLASS] != (ELFCLASS32 << 8 | ELFDATA2MSB)) ERRX((1, "%s: Not an NMAGIC a.out or a 32bit BE ELF", kernel_fn)); /* * this is an ELF */ #ifdef LOADBSD if (opt_v) xwarnx("%s: is an ELF", kernel_fn); #endif #ifdef BOOT B_PRINT("This is an ELF\r\n"); #endif if (ehdr->e_ident[EI_VERSION] != EV_CURRENT || ehdr->e_version != EV_CURRENT) ERRX((1, "%s: Unsupported ELF version", kernel_fn)); if ((u = ehdr->e_machine) != EM_68K) ERRX((1, "%s: Wrong architecture (mid %u)", kernel_fn, u)); if (ehdr->e_type != ET_EXEC) ERRX((1, "%s: Not an executable", kernel_fn)); if ((u = ehdr->e_phnum) != 1 && u != 2) ERRX((1, "%s: Wrong number (%u) of loading sections", kernel_fn, u)); /* * fill in loading information */ xk_elf(xarg, ehdr); } return 0; }