Beispiel #1
0
static int
link_elf_preload_file(const char *filename, linker_file_t *result)
{
    caddr_t		modptr, baseptr, sizeptr, dynptr;
    char		*type;
    elf_file_t		ef;
    linker_file_t	lf;
    int			error;
    vm_offset_t		dp;

    /*
     * Look to see if we have the module preloaded.
     */
    modptr = preload_search_by_name(filename);
    if (modptr == NULL)
	return ENOENT;

    /* It's preloaded, check we can handle it and collect information */
    type = (char *)preload_search_info(modptr, MODINFO_TYPE);
    baseptr = preload_search_info(modptr, MODINFO_ADDR);
    sizeptr = preload_search_info(modptr, MODINFO_SIZE);
    dynptr = preload_search_info(modptr, MODINFO_METADATA|MODINFOMD_DYNAMIC);
    if (type == NULL ||
	    (strcmp(type, "elf" __XSTRING(__ELF_WORD_SIZE) " module") != 0 &&
	    strcmp(type, "elf module") != 0))
	return (EFTYPE);
    if (baseptr == NULL || sizeptr == NULL || dynptr == NULL)
	return (EINVAL);

    ef = kmalloc(sizeof(struct elf_file), M_LINKER, M_WAITOK | M_ZERO);
    ef->modptr = modptr;
    ef->address = *(caddr_t *)baseptr;
#ifdef SPARSE_MAPPING
    ef->object = NULL;
#endif
    dp = (vm_offset_t)ef->address + *(vm_offset_t *)dynptr;
    ef->dynamic = (Elf_Dyn *)dp;
    lf = linker_make_file(filename, ef, &link_elf_module_ops);
    if (lf == NULL) {
	kfree(ef, M_LINKER);
	return ENOMEM;
    }
    lf->address = ef->address;
    lf->size = *(size_t *)sizeptr;

    error = parse_dynamic(lf);
    if (error) {
	linker_file_unload(lf);
	return error;
    }
    link_elf_reloc_local(lf);
    *result = lf;
    return (0);
}
Beispiel #2
0
static int
link_elf_link_preload(linker_class_t cls, const char *filename,
    linker_file_t *result)
{
	Elf_Ehdr *hdr;
	Elf_Shdr *shdr;
	Elf_Sym *es;
	void *modptr, *baseptr, *sizeptr;
	char *type;
	elf_file_t ef;
	linker_file_t lf;
	Elf_Addr off;
	int error, i, j, pb, ra, rl, shstrindex, symstrindex, symtabindex;

	/* Look to see if we have the file preloaded */
	modptr = preload_search_by_name(filename);
	if (modptr == NULL)
		return ENOENT;

	type = (char *)preload_search_info(modptr, MODINFO_TYPE);
	baseptr = preload_search_info(modptr, MODINFO_ADDR);
	sizeptr = preload_search_info(modptr, MODINFO_SIZE);
	hdr = (Elf_Ehdr *)preload_search_info(modptr, MODINFO_METADATA |
	    MODINFOMD_ELFHDR);
	shdr = (Elf_Shdr *)preload_search_info(modptr, MODINFO_METADATA |
	    MODINFOMD_SHDR);
	if (type == NULL || (strcmp(type, "elf" __XSTRING(__ELF_WORD_SIZE)
	    " obj module") != 0 &&
	    strcmp(type, "elf obj module") != 0)) {
		return (EFTYPE);
	}
	if (baseptr == NULL || sizeptr == NULL || hdr == NULL ||
	    shdr == NULL)
		return (EINVAL);

	lf = linker_make_file(filename, &link_elf_class);
	if (lf == NULL)
		return (ENOMEM);

	ef = (elf_file_t)lf;
	ef->preloaded = 1;
	ef->address = *(caddr_t *)baseptr;
	lf->address = *(caddr_t *)baseptr;
	lf->size = *(size_t *)sizeptr;

	if (hdr->e_ident[EI_CLASS] != ELF_TARG_CLASS ||
	    hdr->e_ident[EI_DATA] != ELF_TARG_DATA ||
	    hdr->e_ident[EI_VERSION] != EV_CURRENT ||
	    hdr->e_version != EV_CURRENT ||
	    hdr->e_type != ET_REL ||
	    hdr->e_machine != ELF_TARG_MACH) {
		error = EFTYPE;
		goto out;
	}
	ef->e_shdr = shdr;

	/* Scan the section header for information and table sizing. */
	symtabindex = -1;
	symstrindex = -1;
	for (i = 0; i < hdr->e_shnum; i++) {
		switch (shdr[i].sh_type) {
		case SHT_PROGBITS:
		case SHT_NOBITS:
			ef->nprogtab++;
			break;
		case SHT_SYMTAB:
			symtabindex = i;
			symstrindex = shdr[i].sh_link;
			break;
		case SHT_REL:
			ef->nreltab++;
			break;
		case SHT_RELA:
			ef->nrelatab++;
			break;
		}
	}

	shstrindex = hdr->e_shstrndx;
	if (ef->nprogtab == 0 || symstrindex < 0 ||
	    symstrindex >= hdr->e_shnum ||
	    shdr[symstrindex].sh_type != SHT_STRTAB || shstrindex == 0 ||
	    shstrindex >= hdr->e_shnum ||
	    shdr[shstrindex].sh_type != SHT_STRTAB) {
		printf("%s: bad/missing section headers\n", filename);
		error = ENOEXEC;
		goto out;
	}

	/* Allocate space for tracking the load chunks */
	if (ef->nprogtab != 0)
		ef->progtab = malloc(ef->nprogtab * sizeof(*ef->progtab),
		    M_LINKER, M_WAITOK | M_ZERO);
	if (ef->nreltab != 0)
		ef->reltab = malloc(ef->nreltab * sizeof(*ef->reltab),
		    M_LINKER, M_WAITOK | M_ZERO);
	if (ef->nrelatab != 0)
		ef->relatab = malloc(ef->nrelatab * sizeof(*ef->relatab),
		    M_LINKER, M_WAITOK | M_ZERO);
	if ((ef->nprogtab != 0 && ef->progtab == NULL) ||
	    (ef->nreltab != 0 && ef->reltab == NULL) ||
	    (ef->nrelatab != 0 && ef->relatab == NULL)) {
		error = ENOMEM;
		goto out;
	}

	/* XXX, relocate the sh_addr fields saved by the loader. */
	off = 0;
	for (i = 0; i < hdr->e_shnum; i++) {
		if (shdr[i].sh_addr != 0 && (off == 0 || shdr[i].sh_addr < off))
			off = shdr[i].sh_addr;
	}
	for (i = 0; i < hdr->e_shnum; i++) {
		if (shdr[i].sh_addr != 0)
			shdr[i].sh_addr = shdr[i].sh_addr - off +
			    (Elf_Addr)ef->address;
	}

	ef->ddbsymcnt = shdr[symtabindex].sh_size / sizeof(Elf_Sym);
	ef->ddbsymtab = (Elf_Sym *)shdr[symtabindex].sh_addr;
	ef->ddbstrcnt = shdr[symstrindex].sh_size;
	ef->ddbstrtab = (char *)shdr[symstrindex].sh_addr;
	ef->shstrcnt = shdr[shstrindex].sh_size;
	ef->shstrtab = (char *)shdr[shstrindex].sh_addr;

	/* Now fill out progtab and the relocation tables. */
	pb = 0;
	rl = 0;
	ra = 0;
	for (i = 0; i < hdr->e_shnum; i++) {
		switch (shdr[i].sh_type) {
		case SHT_PROGBITS:
		case SHT_NOBITS:
			ef->progtab[pb].addr = (void *)shdr[i].sh_addr;
			if (shdr[i].sh_type == SHT_PROGBITS)
				ef->progtab[pb].name = "<<PROGBITS>>";
			else
				ef->progtab[pb].name = "<<NOBITS>>";
			ef->progtab[pb].size = shdr[i].sh_size;
			ef->progtab[pb].sec = i;
			if (ef->shstrtab && shdr[i].sh_name != 0)
				ef->progtab[pb].name =
				    ef->shstrtab + shdr[i].sh_name;
			if (ef->progtab[pb].name != NULL && 
			    !strcmp(ef->progtab[pb].name, DPCPU_SETNAME)) {
				void *dpcpu;

				dpcpu = dpcpu_alloc(shdr[i].sh_size);
				if (dpcpu == NULL) {
					error = ENOSPC;
					goto out;
				}
				memcpy(dpcpu, ef->progtab[pb].addr,
				    ef->progtab[pb].size);
				dpcpu_copy(dpcpu, shdr[i].sh_size);
				ef->progtab[pb].addr = dpcpu;
#ifdef VIMAGE
			} else if (ef->progtab[pb].name != NULL &&
			    !strcmp(ef->progtab[pb].name, VNET_SETNAME)) {
				void *vnet_data;

				vnet_data = vnet_data_alloc(shdr[i].sh_size);
				if (vnet_data == NULL) {
					error = ENOSPC;
					goto out;
				}
				memcpy(vnet_data, ef->progtab[pb].addr,
				    ef->progtab[pb].size);
				vnet_data_copy(vnet_data, shdr[i].sh_size);
				ef->progtab[pb].addr = vnet_data;
#endif
			}

			/* Update all symbol values with the offset. */
			for (j = 0; j < ef->ddbsymcnt; j++) {
				es = &ef->ddbsymtab[j];
				if (es->st_shndx != i)
					continue;
				es->st_value += (Elf_Addr)ef->progtab[pb].addr;
			}
			pb++;
			break;
		case SHT_REL:
			ef->reltab[rl].rel = (Elf_Rel *)shdr[i].sh_addr;
			ef->reltab[rl].nrel = shdr[i].sh_size / sizeof(Elf_Rel);
			ef->reltab[rl].sec = shdr[i].sh_info;
			rl++;
			break;
		case SHT_RELA:
			ef->relatab[ra].rela = (Elf_Rela *)shdr[i].sh_addr;
			ef->relatab[ra].nrela =
			    shdr[i].sh_size / sizeof(Elf_Rela);
			ef->relatab[ra].sec = shdr[i].sh_info;
			ra++;
			break;
		}
	}
	if (pb != ef->nprogtab)
		panic("lost progbits");
	if (rl != ef->nreltab)
		panic("lost reltab");
	if (ra != ef->nrelatab)
		panic("lost relatab");

	/* Local intra-module relocations */
	link_elf_reloc_local(lf);

	*result = lf;
	return (0);

out:
	/* preload not done this way */
	linker_file_unload(lf, LINKER_UNLOAD_FORCE);
	return (error);
}
static void *
kobj_open_file_loader(const char *file)
{

	return (preload_search_by_name(file));
}