コード例 #1
0
ファイル: cook.c プロジェクト: manojxantony/compiler
static char*
_elf_item(Elf *elf, Elf_Type type, size_t n, size_t off, int *flag) {
    Elf_Data src, dst;

    *flag = 0;
    elf_assert(n);
    elf_assert(valid_type(type));
    if (off > elf->e_size) {
	seterr(ERROR_OUTSIDE);
	return NULL;
    }

    src.d_type = type;
    src.d_version = elf->e_version;
    src.d_size = n * _fsize(elf->e_class, src.d_version, type);
    elf_assert(src.d_size);
    if ((elf->e_size - off) < src.d_size) {
	seterr(truncerr(type));
	return NULL;
    }

    dst.d_version = _elf_version;
    dst.d_size = n * _msize(elf->e_class, dst.d_version, type);
    elf_assert(dst.d_size);

    elf_assert(elf->e_data);
    if (elf->e_rawdata != elf->e_data && dst.d_size <= src.d_size) {
	dst.d_buf = elf->e_data + off;
    }
    else if (!(dst.d_buf = malloc(dst.d_size))) {
	seterr(memerr(type));
	return NULL;
    }
    else {
	*flag = 1;
    }

    if (elf->e_rawdata) {
	src.d_buf = elf->e_rawdata + off;
    }
    else {
	src.d_buf = elf->e_data + off;
    }

    if (_elf_xlatetom(elf, &dst, &src)) {
	if (!*flag) {
	    elf->e_cooked = 1;
	}
	return (char*)dst.d_buf;
    }

    if (*flag) {
	free(dst.d_buf);
	*flag = 0;
    }
    return NULL;
}
コード例 #2
0
ファイル: update.c プロジェクト: sharugupta/OpenUH
static size_t
scn_entsize(const Elf *elf, unsigned version, unsigned stype) {
    Elf_Type type;

    switch ((type = _elf_scn_type(stype))) {
	case ELF_T_BYTE:
	    return 0;
	case ELF_T_VDEF:
	case ELF_T_VNEED:
	    return 0;	/* What else can I do?  Thank you, Sun! */
	default:
	    return _fsize(elf->e_class, version, type);
    }
}
コード例 #3
0
ファイル: 32.fsize.c プロジェクト: cdaffara/symbian-oss_adapt
static size_t
_elf_fsize(unsigned cls, Elf_Type type, unsigned ver) {
    size_t n = 0;

    if (!valid_version(ver)) {
	seterr(ERROR_UNKNOWN_VERSION);
    }
    else if (!valid_type(type)) {
	seterr(ERROR_UNKNOWN_TYPE);
    }
    else if (!(n = _fsize(cls, ver, type))) {
	seterr(ERROR_UNKNOWN_TYPE);
    }
    return n;
}
コード例 #4
0
ファイル: cook.c プロジェクト: gxliu/bdm-osbdm
static char*
_elf_item(void *buf, Elf *elf, Elf_Type type, size_t off) {
    Elf_Data src, dst;

    elf_assert(valid_type(type));
    if (off < 0 || off > elf->e_size) {
	seterr(ERROR_OUTSIDE);
	return NULL;
    }

    src.d_type = type;
    src.d_version = elf->e_version;
    src.d_size = _fsize(elf->e_class, src.d_version, type);
    elf_assert(src.d_size);
    if ((elf->e_size - off) < src.d_size) {
	seterr(truncerr(type));
	return NULL;
    }

    dst.d_version = _elf_version;
    dst.d_size = _msize(elf->e_class, dst.d_version, type);
    elf_assert(dst.d_size);

    if (!(dst.d_buf = buf) && !(dst.d_buf = malloc(dst.d_size))) {
	seterr(memerr(type));
	return NULL;
    }

    elf_assert(elf->e_data);
    if (elf->e_rawdata) {
	src.d_buf = elf->e_rawdata + off;
    }
    else {
	src.d_buf = elf->e_data + off;
    }

    if (_elf_xlatetom(elf, &dst, &src)) {
	return (char*)dst.d_buf;
    }
    if (dst.d_buf != buf) {
	free(dst.d_buf);
    }
    return NULL;
}
コード例 #5
0
ファイル: cook.c プロジェクト: gxliu/bdm-osbdm
static int
_elf_cook_phdr(Elf *elf) {
    size_t num, off, entsz;

    if (elf->e_class == ELFCLASS32) {
	num = ((Elf32_Ehdr*)elf->e_ehdr)->e_phnum;
	off = ((Elf32_Ehdr*)elf->e_ehdr)->e_phoff;
	entsz = ((Elf32_Ehdr*)elf->e_ehdr)->e_phentsize;
    }
#if __LIBELF64
    else if (elf->e_class == ELFCLASS64) {
	num = ((Elf64_Ehdr*)elf->e_ehdr)->e_phnum;
	off = ((Elf64_Ehdr*)elf->e_ehdr)->e_phoff;
	entsz = ((Elf64_Ehdr*)elf->e_ehdr)->e_phentsize;
	/*
	 * Check for overflow on 32-bit systems
	 */
	if (overflow(off, ((Elf64_Ehdr*)elf->e_ehdr)->e_phoff, Elf64_Off)) {
	    seterr(ERROR_OUTSIDE);
	    return 0;
	}
    }
#endif /* __LIBELF64 */
    else {
	seterr(ERROR_UNIMPLEMENTED);
	return 0;
    }
    if (off) {
	Elf_Scn *scn;
	size_t size;
	unsigned i;
	char *p;

	if (num == PN_XNUM) {
	    /*
	     * Overflow in ehdr->e_phnum.
	     * Get real value from first SHDR.
	     */
	    if (!(scn = elf->e_scn_1)) {
		seterr(ERROR_NOSUCHSCN);
		return 0;
	    }
	    if (elf->e_class == ELFCLASS32) {
		num = scn->s_shdr32.sh_info;
	    }
#if __LIBELF64
	    else if (elf->e_class == ELFCLASS64) {
		num = scn->s_shdr64.sh_info;
	    }
#endif /* __LIBELF64 */
	    /* we already had this
	    else {
		seterr(ERROR_UNIMPLEMENTED);
		return 0;
	    }
	    */
	}

	size = _fsize(elf->e_class, elf->e_version, ELF_T_PHDR);
	elf_assert(size);
#if ENABLE_EXTENDED_FORMAT
	if (entsz < size) {
#else /* ENABLE_EXTENDED_FORMAT */
	if (entsz != size) {
#endif /* ENABLE_EXTENDED_FORMAT */
	    seterr(ERROR_EHDR_PHENTSIZE);
	    return 0;
	}
	size = _msize(elf->e_class, _elf_version, ELF_T_PHDR);
	elf_assert(size);
	if (!(p = malloc(num * size))) {
	    seterr(memerr(ELF_T_PHDR));
	    return 0;
	}
	for (i = 0; i < num; i++) {
	    if (!_elf_item(p + i * size, elf, ELF_T_PHDR, off + i * entsz)) {
		free(p);
		return 0;
	    }
	}
	elf->e_phdr = p;
	elf->e_phnum = num;
    }
    return 1;
}

static int
_elf_cook_shdr(Elf *elf) {
    size_t num, off, entsz;

    if (elf->e_class == ELFCLASS32) {
	num = ((Elf32_Ehdr*)elf->e_ehdr)->e_shnum;
	off = ((Elf32_Ehdr*)elf->e_ehdr)->e_shoff;
	entsz = ((Elf32_Ehdr*)elf->e_ehdr)->e_shentsize;
    }
#if __LIBELF64
    else if (elf->e_class == ELFCLASS64) {
	num = ((Elf64_Ehdr*)elf->e_ehdr)->e_shnum;
	off = ((Elf64_Ehdr*)elf->e_ehdr)->e_shoff;
	entsz = ((Elf64_Ehdr*)elf->e_ehdr)->e_shentsize;
	/*
	 * Check for overflow on 32-bit systems
	 */
	if (overflow(off, ((Elf64_Ehdr*)elf->e_ehdr)->e_shoff, Elf64_Off)) {
	    seterr(ERROR_OUTSIDE);
	    return 0;
	}
    }
#endif /* __LIBELF64 */
    else {
	seterr(ERROR_UNIMPLEMENTED);
	return 0;
    }
    if (off) {
	struct tmp {
	    Elf_Scn	scn;
	    Scn_Data	data;
	} *head;
	Elf_Data src, dst;
	Elf_Scn *scn;
	Scn_Data *sd;
	unsigned i;

	if (off < 0 || off > elf->e_size) {
	    seterr(ERROR_OUTSIDE);
	    return 0;
	}

	src.d_type = ELF_T_SHDR;
	src.d_version = elf->e_version;
	src.d_size = _fsize(elf->e_class, src.d_version, ELF_T_SHDR);
	elf_assert(src.d_size);
#if ENABLE_EXTENDED_FORMAT
	if (entsz < src.d_size) {
#else /* ENABLE_EXTENDED_FORMAT */
	if (entsz != src.d_size) {
#endif /* ENABLE_EXTENDED_FORMAT */
	    seterr(ERROR_EHDR_SHENTSIZE);
	    return 0;
	}
	dst.d_version = EV_CURRENT;

	if (num == 0) {
	    union {
		Elf32_Shdr sh32;
#if __LIBELF64
		Elf64_Shdr sh64;
#endif /* __LIBELF64 */
	    } u;

	    /*
	     * Overflow in ehdr->e_shnum.
	     * Get real value from first SHDR.
	     */
	    if (elf->e_size - off < entsz) {
		seterr(ERROR_TRUNC_SHDR);
		return 0;
	    }
	    if (elf->e_rawdata) {
		src.d_buf = elf->e_rawdata + off;
	    }
	    else {
		src.d_buf = elf->e_data + off;
	    }
	    dst.d_buf = &u;
	    dst.d_size = sizeof(u);
	    if (!_elf_xlatetom(elf, &dst, &src)) {
		return 0;
	    }
	    elf_assert(dst.d_size == _msize(elf->e_class, EV_CURRENT, ELF_T_SHDR));
	    elf_assert(dst.d_type == ELF_T_SHDR);
	    if (elf->e_class == ELFCLASS32) {
		num = u.sh32.sh_size;
	    }
#if __LIBELF64
	    else if (elf->e_class == ELFCLASS64) {
		num = u.sh64.sh_size;
		/*
		 * Check for overflow on 32-bit systems
		 */
		if (overflow(num, u.sh64.sh_size, Elf64_Xword)) {
		    seterr(ERROR_OUTSIDE);
		    return 0;
		}
	    }
#endif /* __LIBELF64 */
	}

	if ((elf->e_size - off) / entsz < num) {
	    seterr(ERROR_TRUNC_SHDR);
	    return 0;
	}

	if (!(head = (struct tmp*)malloc(num * sizeof(struct tmp)))) {
	    seterr(ERROR_MEM_SCN);
	    return 0;
	}
	for (scn = NULL, i = num; i-- > 0; ) {
	    head[i].scn = _elf_scn_init;
	    head[i].data = _elf_data_init;
	    head[i].scn.s_link = scn;
	    if (!scn) {
		elf->e_scn_n = &head[i].scn;
	    }
	    scn = &head[i].scn;
	    sd = &head[i].data;

	    if (elf->e_rawdata) {
		src.d_buf = elf->e_rawdata + off + i * entsz;
	    }
	    else {
		src.d_buf = elf->e_data + off + i * entsz;
	    }
	    dst.d_buf = &scn->s_uhdr;
	    dst.d_size = sizeof(scn->s_uhdr);
	    if (!_elf_xlatetom(elf, &dst, &src)) {
		elf->e_scn_n = NULL;
		free(head);
		return 0;
	    }
	    elf_assert(dst.d_size == _msize(elf->e_class, EV_CURRENT, ELF_T_SHDR));
	    elf_assert(dst.d_type == ELF_T_SHDR);

	    scn->s_elf = elf;
	    scn->s_index = i;
	    scn->s_data_1 = sd;
	    scn->s_data_n = sd;

	    sd->sd_scn = scn;

	    if (elf->e_class == ELFCLASS32) {
		Elf32_Shdr *shdr = &scn->s_shdr32;

		scn->s_type = shdr->sh_type;
		scn->s_size = shdr->sh_size;
		scn->s_offset = shdr->sh_offset;
		sd->sd_data.d_align = shdr->sh_addralign;
		sd->sd_data.d_type = _elf_scn_type(scn->s_type);
	    }
#if __LIBELF64
	    else if (elf->e_class == ELFCLASS64) {
		Elf64_Shdr *shdr = &scn->s_shdr64;

		scn->s_type = shdr->sh_type;
		scn->s_size = shdr->sh_size;
		scn->s_offset = shdr->sh_offset;
		sd->sd_data.d_align = shdr->sh_addralign;
		/*
		 * Check for overflow on 32-bit systems
		 */
		if (overflow(scn->s_size, shdr->sh_size, Elf64_Xword)
		 || overflow(scn->s_offset, shdr->sh_offset, Elf64_Off)
		 || overflow(sd->sd_data.d_align, shdr->sh_addralign, Elf64_Xword)) {
		    seterr(ERROR_OUTSIDE);
		    return 0;
		}
		sd->sd_data.d_type = _elf_scn_type(scn->s_type);
		/*
		 * QUIRKS MODE:
		 *
		 * Some 64-bit architectures use 64-bit entries in the
		 * .hash section. This violates the ELF standard, and
		 * should be fixed. It's mostly harmless as long as the
		 * binary and the machine running your program have the
		 * same byte order, but you're in trouble if they don't,
		 * and if the entry size is wrong.
		 *
		 * As a workaround, I let libelf guess the right size
		 * for the binary. This relies pretty much on the fact
		 * that the binary provides correct data in the section
		 * headers. If it doesn't, it's probably broken anyway.
		 * Therefore, libelf uses a standard conforming value
		 * when it's not absolutely sure.
		 */
		if (scn->s_type == SHT_HASH) {
		    int override = 0;

		    /*
		     * sh_entsize must reflect the entry size
		     */
		    if (shdr->sh_entsize == ELF64_FSZ_ADDR) {
			override++;
		    }
		    /*
		     * sh_size must be a multiple of sh_entsize
		     */
		    if (shdr->sh_size % ELF64_FSZ_ADDR == 0) {
			override++;
		    }
		    /*
		     * There must be room for at least 2 entries
		     */
		    if (shdr->sh_size >= 2 * ELF64_FSZ_ADDR) {
			override++;
		    }
		    /*
		     * sh_addralign must be correctly set
		     */
		    if (shdr->sh_addralign == ELF64_FSZ_ADDR) {
			override++;
		    }
		    /*
		     * The section must be properly aligned
		     */
		    if (shdr->sh_offset % ELF64_FSZ_ADDR == 0) {
			override++;
		    }
		    /* XXX: also look at the data? */
		    /*
		     * Make a conservative decision...
		     */
		    if (override >= 5) {
			sd->sd_data.d_type = ELF_T_ADDR;
		    }
		}
		/*
		 * END QUIRKS MODE.
		 */
	    }
#endif /* __LIBELF64 */
	    /* we already had this
	    else {
		seterr(ERROR_UNIMPLEMENTED);
		return 0;
	    }
	    */

	    sd->sd_data.d_size = scn->s_size;
	    sd->sd_data.d_version = _elf_version;
	}
	elf_assert(scn == &head[0].scn);
	elf->e_scn_1 = &head[0].scn;
	head[0].scn.s_freeme = 1;
    }
コード例 #6
0
ファイル: update.c プロジェクト: sharugupta/OpenUH
static off_t
_elf64_layout(Elf *elf, unsigned *flag) {
    int layout = (elf->e_elf_flags & ELF_F_LAYOUT) == 0;
    Elf64_Ehdr *ehdr = (Elf64_Ehdr*)elf->e_ehdr;
    size_t off = 0;
    unsigned version;
    unsigned encoding;
    size_t align_addr;
    size_t entsize;
    unsigned shnum;
    Elf_Scn *scn;

    *flag = elf->e_elf_flags | elf->e_phdr_flags;

    if ((version = ehdr->e_version) == EV_NONE) {
	version = EV_CURRENT;
    }
    if (!valid_version(version)) {
	seterr(ERROR_UNKNOWN_VERSION);
	return -1;
    }
    if ((encoding = ehdr->e_ident[EI_DATA]) == ELFDATANONE) {
	encoding = native_encoding;
    }
    if (!valid_encoding(encoding)) {
	seterr(ERROR_UNKNOWN_ENCODING);
	return -1;
    }
    entsize = _fsize(ELFCLASS64, version, ELF_T_EHDR);
    elf_assert(entsize);
    rewrite(ehdr->e_ehsize, entsize, elf->e_ehdr_flags);
    off = entsize;

    align_addr = _fsize(ELFCLASS64, version, ELF_T_ADDR);
    elf_assert(align_addr);

    if (elf->e_phnum) {
	entsize = _fsize(ELFCLASS64, version, ELF_T_PHDR);
	elf_assert(entsize);
	if (layout) {
	    align(off, align_addr);
	    rewrite(ehdr->e_phoff, off, elf->e_ehdr_flags);
	    off += elf->e_phnum * entsize;
	}
	else {
	    off = max(off, ehdr->e_phoff + elf->e_phnum * entsize);
	}
    }
    else {
	entsize = 0;
	if (layout) {
	    rewrite(ehdr->e_phoff, 0, elf->e_ehdr_flags);
	}
    }
    rewrite(ehdr->e_phnum, elf->e_phnum, elf->e_ehdr_flags);
    rewrite(ehdr->e_phentsize, entsize, elf->e_ehdr_flags);

    for (scn = elf->e_scn_1, shnum = 0; scn; scn = scn->s_link, ++shnum) {
	Elf64_Shdr *shdr = &scn->s_shdr64;
	size_t scn_align = 1;
	off_t len;

	elf_assert(scn->s_index == shnum);

	*flag |= scn->s_scn_flags;

	if (scn->s_index == SHN_UNDEF) {
	    rewrite(shdr->sh_entsize, 0, scn->s_shdr_flags);
	    if (layout) {
		rewrite(shdr->sh_offset, 0, scn->s_shdr_flags);
		rewrite(shdr->sh_size, 0, scn->s_shdr_flags);
		rewrite(shdr->sh_addralign, 0, scn->s_shdr_flags);
	    }
	    *flag |= scn->s_shdr_flags;
	    continue;
	}
	if (shdr->sh_type == SHT_NULL) {
	    *flag |= scn->s_shdr_flags;
	    continue;
	}

	len = scn_data_layout(scn, version, shdr->sh_type, &scn_align, flag);
	if (len == -1) {
	    return -1;
	}

	/*
	 * Never override the program's choice.
	 */
	if (shdr->sh_entsize == 0) {
	    entsize = scn_entsize(elf, version, shdr->sh_type);
	    if (entsize > 1) {
		rewrite(shdr->sh_entsize, entsize, scn->s_shdr_flags);
	    }
	}

	if (layout) {
	    align(off, scn_align);
	    rewrite(shdr->sh_offset, off, scn->s_shdr_flags);
	    rewrite(shdr->sh_size, (size_t)len, scn->s_shdr_flags);
	    rewrite(shdr->sh_addralign, scn_align, scn->s_shdr_flags);

	    if (shdr->sh_type != SHT_NOBITS) {
		off += (size_t)len;
	    }
	}
	else if ((size_t)len > shdr->sh_size) {
	    seterr(ERROR_SCN2SMALL);
	    return -1;
	}
	else {
	    Elf_Scn *scn2;
	    size_t end1, end2;

	    end1 = shdr->sh_offset;
	    if (shdr->sh_type != SHT_NOBITS) {
		end1 += shdr->sh_size;
	    }
	    if (shdr->sh_offset < off) {
		/*
		 * check for overlapping sections
		 */
		for (scn2 = elf->e_scn_1; scn2; scn2 = scn2->s_link) {
		    if (scn2 == scn) {
			break;
		    }
		    end2 = scn2->s_shdr64.sh_offset;
		    if (scn2->s_shdr64.sh_type != SHT_NOBITS) {
			end2 += scn2->s_shdr64.sh_size;
		    }
		    if (end1 > scn2->s_shdr64.sh_offset
		     && end2 > shdr->sh_offset) {
			seterr(ERROR_SCN_OVERLAP);
			return -1;
		    }
		}
	    }
	    if (off < end1) {
		off = end1;
	    }
	}
	*flag |= scn->s_shdr_flags;
    }

    if (shnum) {
	entsize = _fsize(ELFCLASS64, version, ELF_T_SHDR);
	elf_assert(entsize);
	if (layout) {
	    align(off, align_addr);
	    rewrite(ehdr->e_shoff, off, elf->e_ehdr_flags);
	    off += shnum * entsize;
	}
	else {
	    off = max(off, ehdr->e_shoff + shnum * entsize);
	}
    }
    else {
	entsize = 0;
	if (layout) {
	    rewrite(ehdr->e_shoff, 0, elf->e_ehdr_flags);
	}
    }
    if (shnum >= SHN_LORESERVE) {
	Elf_Scn *scn = elf->e_scn_1;
	Elf64_Shdr *shdr = &scn->s_shdr64;

	elf_assert(scn->s_index == 0);
	rewrite(shdr->sh_size, shnum, scn->s_shdr_flags);
	*flag |= scn->s_shdr_flags;
	shnum = 0;
    }
    rewrite(ehdr->e_shnum, shnum, elf->e_ehdr_flags);
    rewrite(ehdr->e_shentsize, entsize, elf->e_ehdr_flags);

    rewrite(ehdr->e_ident[EI_MAG0], ELFMAG0, elf->e_ehdr_flags);
    rewrite(ehdr->e_ident[EI_MAG1], ELFMAG1, elf->e_ehdr_flags);
    rewrite(ehdr->e_ident[EI_MAG2], ELFMAG2, elf->e_ehdr_flags);
    rewrite(ehdr->e_ident[EI_MAG3], ELFMAG3, elf->e_ehdr_flags);
    rewrite(ehdr->e_ident[EI_CLASS], ELFCLASS64, elf->e_ehdr_flags);
    rewrite(ehdr->e_ident[EI_DATA], encoding, elf->e_ehdr_flags);
    rewrite(ehdr->e_ident[EI_VERSION], version, elf->e_ehdr_flags);
    rewrite(ehdr->e_version, version, elf->e_ehdr_flags);

    *flag |= elf->e_ehdr_flags;

    return off;
}