void encoding(T state, Encoding* obj) { if(obj->nil_p() || (!CBOOL(ascii_only()) && obj->ascii_compatible())) { ascii_only(cNil); num_chars(nil<Fixnum>()); valid_encoding(cNil); } if(byte_size() == 0 && !obj->nil_p() && obj->ascii_compatible()) { ascii_only(cTrue); num_chars(Fixnum::from(0)); valid_encoding(cTrue); } encoding(obj); state->memory()->write_barrier(this, obj); }
void encoding_from(STATE, String* other) { encoding(other->encoding()); state->memory()->write_barrier(this, encoding()); if(other->ascii_only()->true_p()) { ascii_only(cTrue); } else { ascii_only(cNil); } if(other->valid_encoding()->true_p()) { valid_encoding(cTrue); } else { valid_encoding(cNil); } }
/* * destination buffer size */ size_t _elf32_xltsize(const Elf_Data *src, unsigned dv, unsigned encode, int tof) { Elf_Type type = src->d_type; unsigned sv = src->d_version; xlator op; if (!valid_version(sv) || !valid_version(dv)) { seterr(ERROR_UNKNOWN_VERSION); return (size_t)-1; } if (tof) { /* * Encoding doesn't really matter (the translator only looks at * the source, which resides in memory), but we need a proper * encoding to select a translator... */ encode = ELFDATA2LSB; } else if (!valid_encoding(encode)) { seterr(ERROR_UNKNOWN_ENCODING); return (size_t)-1; } if (!valid_type(type)) { seterr(ERROR_UNKNOWN_TYPE); return (size_t)-1; } if (!(op = translator(sv, dv, encode, type, tof))) { seterr(ERROR_UNKNOWN_TYPE); return (size_t)-1; } return (*op)(NULL, src->d_buf, src->d_size); }
/* * direction-independent translation */ static Elf_Data* elf32_xlate(Elf_Data *dst, const Elf_Data *src, unsigned encode, int tof) { Elf_Type type; int dv; int sv; size_t dsize; size_t tmp; xlator op; if (!src || !dst) { return NULL; } if (!src->d_buf || !dst->d_buf) { seterr(ERROR_NULLBUF); return NULL; } if (!valid_encoding(encode)) { seterr(ERROR_UNKNOWN_ENCODING); return NULL; } sv = src->d_version; dv = dst->d_version; if (!valid_version(sv) || !valid_version(dv)) { seterr(ERROR_UNKNOWN_VERSION); return NULL; } type = src->d_type; if (!valid_type(type)) { seterr(ERROR_UNKNOWN_TYPE); return NULL; } op = translator(sv, dv, encode, type, tof); if (!op) { seterr(ERROR_UNKNOWN_TYPE); return NULL; } dsize = (*op)(NULL, src->d_buf, src->d_size); if (dsize == (size_t)-1) { return NULL; } if (dst->d_size < dsize) { seterr(ERROR_DST2SMALL); return NULL; } if (dsize) { tmp = (*op)(dst->d_buf, src->d_buf, src->d_size); if (tmp == (size_t)-1) { return NULL; } elf_assert(tmp == dsize); } dst->d_size = dsize; dst->d_type = type; return dst; }
/* * direction-independent translation */ static Elf_Data* elf32_xlate(Elf_Data *dst, const Elf_Data *src, unsigned encode, int tof) { size_t ssize, dsize, count; Elf_Type type; int sv, dv; xlator op; if (!src || !dst) { return NULL; } if (!src->d_buf || !dst->d_buf) { seterr(ERROR_NULLBUF); return NULL; } if (!valid_encoding(encode)) { seterr(ERROR_UNKNOWN_ENCODING); return NULL; } sv = src->d_version; dv = dst->d_version; if (!valid_version(sv) || !valid_version(dv)) { seterr(ERROR_UNKNOWN_VERSION); return NULL; } type = src->d_type; if (!valid_type(type)) { seterr(ERROR_UNKNOWN_TYPE); return NULL; } ssize = _fmsize(ELFCLASS32, sv, type, 1 - tof); dsize = _fmsize(ELFCLASS32, dv, type, tof); op = translator(sv, dv, encode, type, tof); if (!ssize || !dsize || !op) { seterr(ERROR_UNKNOWN_TYPE); return NULL; } count = src->d_size / ssize; if (dst->d_size < count * dsize) { seterr(ERROR_DST2SMALL); return NULL; } if (count) { (*op)(dst->d_buf, src->d_buf, count); } dst->d_size = count * dsize; dst->d_type = type; return dst; }
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; }