static off_t _elf64_write(Elf *elf, char *outbuf, size_t len) { Elf64_Ehdr *ehdr; Elf64_Shdr *shdr; Elf_Scn *scn; Scn_Data *sd; Elf_Data src; Elf_Data dst; unsigned encode; elf_assert(len); elf_assert(elf->e_ehdr); ehdr = (Elf64_Ehdr*)elf->e_ehdr; encode = ehdr->e_ident[EI_DATA]; src.d_buf = ehdr; src.d_type = ELF_T_EHDR; src.d_size = _msize(ELFCLASS64, _elf_version, ELF_T_EHDR); src.d_version = _elf_version; dst.d_buf = outbuf; dst.d_size = ehdr->e_ehsize; dst.d_version = ehdr->e_version; if (!elf64_xlatetof(&dst, &src, encode)) { return -1; } if (ehdr->e_phnum) { src.d_buf = elf->e_phdr; src.d_type = ELF_T_PHDR; src.d_size = ehdr->e_phnum * _msize(ELFCLASS64, _elf_version, ELF_T_PHDR); src.d_version = _elf_version; dst.d_buf = outbuf + ehdr->e_phoff; dst.d_size = ehdr->e_phnum * ehdr->e_phentsize; dst.d_version = ehdr->e_version; if (!elf64_xlatetof(&dst, &src, encode)) { return -1; } } for (scn = elf->e_scn_1; scn; scn = scn->s_link) { elf_assert(scn->s_magic == SCN_MAGIC); elf_assert(scn->s_elf == elf); src.d_buf = &scn->s_uhdr; src.d_type = ELF_T_SHDR; src.d_size = _msize(ELFCLASS64, EV_CURRENT, ELF_T_SHDR); src.d_version = EV_CURRENT; dst.d_buf = outbuf + ehdr->e_shoff + scn->s_index * ehdr->e_shentsize; dst.d_size = ehdr->e_shentsize; dst.d_version = ehdr->e_version; if (!elf64_xlatetof(&dst, &src, encode)) { return -1; } if (scn->s_index == SHN_UNDEF) { continue; } shdr = &scn->s_shdr64; if (shdr->sh_type == SHT_NULL || shdr->sh_type == SHT_NOBITS) { continue; } /* XXX: this is probably no longer necessary */ if (scn->s_data_1 && !elf_getdata(scn, NULL)) { return -1; } for (sd = scn->s_data_1; sd; sd = sd->sd_link) { elf_assert(sd->sd_magic == DATA_MAGIC); elf_assert(sd->sd_scn == scn); src = sd->sd_data; if (!src.d_size) { continue; } if (!src.d_buf) { seterr(ERROR_NULLBUF); return -1; } dst.d_buf = outbuf + shdr->sh_offset + src.d_off; dst.d_size = src.d_size; dst.d_version = ehdr->e_version; if (valid_type(src.d_type)) { size_t tmp; tmp = _elf64_xltsize(&src, dst.d_version, ELFDATA2LSB, 1); if (tmp == (size_t)-1) { return -1; } dst.d_size = tmp; } else { src.d_type = ELF_T_BYTE; } if (!elf64_xlatetof(&dst, &src, encode)) { return -1; } } } /* cleanup */ if (elf->e_readable && _elf_update_pointers(elf, outbuf, len)) { return -1; } /* NOTE: ehdr is no longer valid! */ ehdr = (Elf64_Ehdr*)elf->e_ehdr; elf_assert(ehdr); elf->e_encoding = ehdr->e_ident[EI_DATA]; elf->e_version = ehdr->e_ident[EI_VERSION]; elf->e_elf_flags &= ~ELF_F_DIRTY; elf->e_ehdr_flags &= ~ELF_F_DIRTY; elf->e_phdr_flags &= ~ELF_F_DIRTY; for (scn = elf->e_scn_1; scn; scn = scn->s_link) { scn->s_scn_flags &= ~ELF_F_DIRTY; scn->s_shdr_flags &= ~ELF_F_DIRTY; for (sd = scn->s_data_1; sd; sd = sd->sd_link) { sd->sd_data_flags &= ~ELF_F_DIRTY; } if (elf->e_readable) { shdr = &scn->s_shdr64; scn->s_type = shdr->sh_type; scn->s_size = shdr->sh_size; scn->s_offset = shdr->sh_offset; } } elf->e_size = len; return len; }
static Elf_Data* _elf_cook_scn(Elf *elf, Elf_Scn *scn, Scn_Data *sd) { Elf_Data dst; Elf_Data src; int flag = 0; size_t dlen; elf_assert(elf->e_data); /* * Prepare source */ src = sd->sd_data; src.d_version = elf->e_version; if (elf->e_rawdata) { src.d_buf = elf->e_rawdata + scn->s_offset; } else { src.d_buf = elf->e_data + scn->s_offset; } /* * Prepare destination (needs prepared source!) */ dst = sd->sd_data; if (elf->e_class == ELFCLASS32) { dlen = _elf32_xltsize(&src, dst.d_version, elf->e_encoding, 0); } #if __LIBELF64 else if (elf->e_class == ELFCLASS64) { dlen = _elf64_xltsize(&src, dst.d_version, elf->e_encoding, 0); } #endif /* __LIBELF64 */ else { elf_assert(valid_class(elf->e_class)); seterr(ERROR_UNIMPLEMENTED); return NULL; } if (dlen == (size_t)-1) { return NULL; } dst.d_size = dlen; if (elf->e_rawdata != elf->e_data && dst.d_size <= src.d_size) { dst.d_buf = elf->e_data + scn->s_offset; } else if (!(dst.d_buf = malloc(dst.d_size))) { seterr(ERROR_MEM_SCNDATA); return NULL; } else { flag = 1; } /* * Translate data */ if (_elf_xlatetom(elf, &dst, &src)) { sd->sd_memdata = (char*)dst.d_buf; sd->sd_data = dst; if (!(sd->sd_free_data = flag)) { elf->e_cooked = 1; } return &sd->sd_data; } if (flag) { free(dst.d_buf); } return NULL; }
static off_t scn_data_layout(Elf_Scn *scn, unsigned v, unsigned type, size_t *algn, unsigned *flag) { Elf *elf = scn->s_elf; Elf_Data *data; int layout = (elf->e_elf_flags & ELF_F_LAYOUT) == 0; size_t scn_align = 1; size_t len = 0; Scn_Data *sd; size_t fsize; if (!(sd = scn->s_data_1)) { /* no data in section */ *algn = scn_align; return (off_t)len; } /* load data from file, if any */ if (!(data = elf_getdata(scn, NULL))) { return (off_t)-1; } elf_assert(data == &sd->sd_data); for (; sd; sd = sd->sd_link) { elf_assert(sd->sd_magic == DATA_MAGIC); elf_assert(sd->sd_scn == scn); if (!valid_version(sd->sd_data.d_version)) { return (off_t)-1; } fsize = sd->sd_data.d_size; if (fsize && type != SHT_NOBITS && valid_type(sd->sd_data.d_type)) { if (elf->e_class == ELFCLASS32) { fsize = _elf32_xltsize(&sd->sd_data, v, ELFDATA2LSB, 1); } #if __LIBELF64 else if (elf->e_class == ELFCLASS64) { fsize = _elf64_xltsize(&sd->sd_data, v, ELFDATA2LSB, 1); } #endif /* __LIBELF64 */ else { elf_assert(valid_class(elf->e_class)); seterr(ERROR_UNIMPLEMENTED); return (off_t)-1; } if (fsize == (size_t)-1) { return (off_t)-1; } } if (layout) { align(len, sd->sd_data.d_align); scn_align = max(scn_align, sd->sd_data.d_align); rewrite(sd->sd_data.d_off, (off_t)len, sd->sd_data_flags); len += fsize; } else { len = max(len, sd->sd_data.d_off + fsize); } *flag |= sd->sd_data_flags; } *algn = scn_align; return (off_t)len; }