diff options
Diffstat (limited to 'rtemstoolkit/elftoolchain/libelf/elf_update.c')
-rw-r--r-- | rtemstoolkit/elftoolchain/libelf/elf_update.c | 179 |
1 files changed, 105 insertions, 74 deletions
diff --git a/rtemstoolkit/elftoolchain/libelf/elf_update.c b/rtemstoolkit/elftoolchain/libelf/elf_update.c index 9806131..6cc109d 100644 --- a/rtemstoolkit/elftoolchain/libelf/elf_update.c +++ b/rtemstoolkit/elftoolchain/libelf/elf_update.c @@ -24,7 +24,7 @@ * SUCH DAMAGE. */ -#include <sys/mman.h> +#include <sys/param.h> #include <sys/stat.h> #include <assert.h> @@ -37,7 +37,11 @@ #include "_libelf.h" -LIBELF_VCSID("$Id: elf_update.c 1922 2011-09-23 08:04:33Z jkoshy $"); +#if ELFTC_HAVE_MMAP +#include <sys/mman.h> +#endif + +ELFTC_VCSID("$Id: elf_update.c 3190 2015-05-04 15:23:08Z jkoshy $"); /* * Layout strategy: @@ -106,14 +110,14 @@ SLIST_HEAD(_Elf_Extent_List, _Elf_Extent); static int _libelf_compute_section_extents(Elf *e, Elf_Scn *s, off_t rc) { - int ec; - size_t fsz, msz; Elf_Data *d; - Elf32_Shdr *shdr32; - Elf64_Shdr *shdr64; + size_t fsz, msz; + int ec, elftype; uint32_t sh_type; uint64_t d_align; - unsigned int elftype; + Elf32_Shdr *shdr32; + Elf64_Shdr *shdr64; + struct _Libelf_Data *ld; uint64_t scn_size, scn_alignment; uint64_t sh_align, sh_entsize, sh_offset, sh_size; @@ -187,7 +191,9 @@ _libelf_compute_section_extents(Elf *e, Elf_Scn *s, off_t rc) */ scn_size = 0L; scn_alignment = 0; - STAILQ_FOREACH(d, &s->s_data, d_next) { + STAILQ_FOREACH(ld, &s->s_data, d_next) { + + d = &ld->d_data; /* * The data buffer's type is known. @@ -246,7 +252,7 @@ _libelf_compute_section_extents(Elf *e, Elf_Scn *s, off_t rc) scn_size = roundup2(scn_size, d->d_align); d->d_off = scn_size; fsz = _libelf_fsize(d->d_type, ec, d->d_version, - d->d_size / msz); + (size_t) d->d_size / msz); scn_size += fsz; } @@ -265,8 +271,10 @@ _libelf_compute_section_extents(Elf *e, Elf_Scn *s, off_t rc) * offsets and alignment for sanity. */ if (e->e_flags & ELF_F_LAYOUT) { - if (scn_alignment > sh_align || sh_offset % sh_align || - sh_size < scn_size) { + if (scn_alignment > sh_align || + sh_offset % sh_align || + sh_size < scn_size || + sh_offset % _libelf_falign(elftype, ec)) { LIBELF_SET_ERROR(LAYOUT, 0); return (0); } @@ -300,7 +308,7 @@ computeoffset: * Compute the new offset for the section based on * the section's alignment needs. */ - sh_offset = roundup(rc, sh_align); + sh_offset = roundup((uint64_t) rc, sh_align); /* * Update the section header. @@ -464,7 +472,7 @@ _libelf_resync_sections(Elf *e, off_t rc, struct _Elf_Extent_List *extents) return ((off_t) -1); if ((size_t) rc < s->s_offset + s->s_size) - rc = s->s_offset + s->s_size; + rc = (off_t) (s->s_offset + s->s_size); } return (rc); @@ -495,7 +503,7 @@ _libelf_resync_sections(Elf *e, off_t rc, struct _Elf_Extent_List *extents) static off_t _libelf_resync_elf(Elf *e, struct _Elf_Extent_List *extents) { - int ec, eh_class, eh_type; + int ec, eh_class; unsigned int eh_byteorder, eh_version; size_t align, fsz; size_t phnum, shnum; @@ -522,19 +530,22 @@ _libelf_resync_elf(Elf *e, struct _Elf_Extent_List *extents) if (ec == ELFCLASS32) { eh_byteorder = eh32->e_ident[EI_DATA]; eh_class = eh32->e_ident[EI_CLASS]; - phoff = (uint64_t) eh32->e_phoff; - shoff = (uint64_t) eh32->e_shoff; - eh_type = eh32->e_type; + phoff = (off_t) eh32->e_phoff; + shoff = (off_t) eh32->e_shoff; eh_version = eh32->e_version; } else { eh_byteorder = eh64->e_ident[EI_DATA]; eh_class = eh64->e_ident[EI_CLASS]; - phoff = eh64->e_phoff; - shoff = eh64->e_shoff; - eh_type = eh64->e_type; + phoff = (off_t) eh64->e_phoff; + shoff = (off_t) eh64->e_shoff; eh_version = eh64->e_version; } + if (phoff < 0 || shoff < 0) { + LIBELF_SET_ERROR(HEADER, 0); + return ((off_t) -1); + } + if (eh_version == EV_NONE) eh_version = EV_CURRENT; @@ -559,18 +570,20 @@ _libelf_resync_elf(Elf *e, struct _Elf_Extent_List *extents) e->e_byteorder = eh_byteorder; #define INITIALIZE_EHDR(E,EC,V) do { \ + unsigned int _version = (unsigned int) (V); \ (E)->e_ident[EI_MAG0] = ELFMAG0; \ (E)->e_ident[EI_MAG1] = ELFMAG1; \ (E)->e_ident[EI_MAG2] = ELFMAG2; \ (E)->e_ident[EI_MAG3] = ELFMAG3; \ - (E)->e_ident[EI_CLASS] = (EC); \ - (E)->e_ident[EI_VERSION] = (V); \ - (E)->e_ehsize = _libelf_fsize(ELF_T_EHDR, (EC), (V), \ - (size_t) 1); \ - (E)->e_phentsize = (phnum == 0) ? 0 : _libelf_fsize( \ - ELF_T_PHDR, (EC), (V), (size_t) 1); \ - (E)->e_shentsize = _libelf_fsize(ELF_T_SHDR, (EC), (V), \ - (size_t) 1); \ + (E)->e_ident[EI_CLASS] = (unsigned char) (EC); \ + (E)->e_ident[EI_VERSION] = (_version & 0xFFU); \ + (E)->e_ehsize = (uint16_t) _libelf_fsize(ELF_T_EHDR, \ + (EC), _version, (size_t) 1); \ + (E)->e_phentsize = (uint16_t) ((phnum == 0) ? 0 : \ + _libelf_fsize(ELF_T_PHDR, (EC), _version, \ + (size_t) 1)); \ + (E)->e_shentsize = (uint16_t) _libelf_fsize(ELF_T_SHDR, \ + (EC), _version, (size_t) 1); \ } while (0) if (ec == ELFCLASS32) @@ -580,9 +593,10 @@ _libelf_resync_elf(Elf *e, struct _Elf_Extent_List *extents) (void) elf_flagehdr(e, ELF_C_SET, ELF_F_DIRTY); - rc += _libelf_fsize(ELF_T_EHDR, ec, eh_version, (size_t) 1); + rc += (off_t) _libelf_fsize(ELF_T_EHDR, ec, eh_version, (size_t) 1); - if (!_libelf_insert_extent(extents, ELF_EXTENT_EHDR, 0, rc, ehdr)) + if (!_libelf_insert_extent(extents, ELF_EXTENT_EHDR, 0, (uint64_t) rc, + ehdr)) return ((off_t) -1); /* @@ -603,20 +617,20 @@ _libelf_resync_elf(Elf *e, struct _Elf_Extent_List *extents) return ((off_t) -1); } - if (phoff % align) { + if (phoff % (off_t) align) { LIBELF_SET_ERROR(LAYOUT, 0); return ((off_t) -1); } } else - phoff = roundup(rc, align); + phoff = roundup(rc, (off_t) align); - rc = phoff + fsz; + rc = phoff + (off_t) fsz; phdr = _libelf_getphdr(e, ec); - if (!_libelf_insert_extent(extents, ELF_EXTENT_PHDR, phoff, - fsz, phdr)) + if (!_libelf_insert_extent(extents, ELF_EXTENT_PHDR, + (uint64_t) phoff, fsz, phdr)) return ((off_t) -1); } else phoff = 0; @@ -651,18 +665,18 @@ _libelf_resync_elf(Elf *e, struct _Elf_Extent_List *extents) align = _libelf_falign(ELF_T_SHDR, ec); if (e->e_flags & ELF_F_LAYOUT) { - if (shoff % align) { + if (shoff % (off_t) align) { LIBELF_SET_ERROR(LAYOUT, 0); return ((off_t) -1); } } else - shoff = roundup(rc, align); + shoff = roundup(rc, (off_t) align); - if (shoff + fsz > (size_t) rc) - rc = shoff + fsz; + if (shoff + (off_t) fsz > rc) + rc = shoff + (off_t) fsz; - if (!_libelf_insert_extent(extents, ELF_EXTENT_SHDR, shoff, - fsz, NULL)) + if (!_libelf_insert_extent(extents, ELF_EXTENT_SHDR, + (uint64_t) shoff, fsz, NULL)) return ((off_t) -1); } else shoff = 0; @@ -695,21 +709,23 @@ _libelf_resync_elf(Elf *e, struct _Elf_Extent_List *extents) * Write out the contents of an ELF section. */ -static size_t -_libelf_write_scn(Elf *e, char *nf, struct _Elf_Extent *ex) +static off_t +_libelf_write_scn(Elf *e, unsigned char *nf, struct _Elf_Extent *ex) { int ec; - size_t fsz, msz, nobjects, rc; - uint32_t sh_type; - uint64_t sh_off, sh_size; - int elftype; + off_t rc; Elf_Scn *s; + int elftype; Elf_Data *d, dst; + uint32_t sh_type; + struct _Libelf_Data *ld; + uint64_t sh_off, sh_size; + size_t fsz, msz, nobjects; assert(ex->ex_type == ELF_EXTENT_SECTION); s = ex->ex_desc; - rc = ex->ex_start; + rc = (off_t) ex->ex_start; if ((ec = e->e_class) == ELFCLASS32) { sh_type = s->s_shdr.s_shdr32.sh_type; @@ -744,21 +760,26 @@ _libelf_write_scn(Elf *e, char *nf, struct _Elf_Extent *ex) if ((d = elf_rawdata(s, NULL)) == NULL) return ((off_t) -1); - STAILQ_FOREACH(d, &s->s_rawdata, d_next) { + STAILQ_FOREACH(ld, &s->s_rawdata, d_next) { + + d = &ld->d_data; + if ((uint64_t) rc < sh_off + d->d_off) (void) memset(nf + rc, - LIBELF_PRIVATE(fillchar), sh_off + - d->d_off - rc); - rc = sh_off + d->d_off; + LIBELF_PRIVATE(fillchar), + (size_t) (sh_off + d->d_off - + (uint64_t) rc)); + rc = (off_t) (sh_off + d->d_off); assert(d->d_buf != NULL); assert(d->d_type == ELF_T_BYTE); assert(d->d_version == e->e_version); (void) memcpy(nf + rc, - e->e_rawfile + s->s_rawoff + d->d_off, d->d_size); + e->e_rawfile + s->s_rawoff + d->d_off, + (size_t) d->d_size); - rc += d->d_size; + rc += (off_t) d->d_size; } return (rc); @@ -772,21 +793,24 @@ _libelf_write_scn(Elf *e, char *nf, struct _Elf_Extent *ex) dst.d_version = e->e_version; - STAILQ_FOREACH(d, &s->s_data, d_next) { + STAILQ_FOREACH(ld, &s->s_data, d_next) { + + d = &ld->d_data; msz = _libelf_msize(d->d_type, ec, e->e_version); if ((uint64_t) rc < sh_off + d->d_off) (void) memset(nf + rc, - LIBELF_PRIVATE(fillchar), sh_off + d->d_off - rc); + LIBELF_PRIVATE(fillchar), + (size_t) (sh_off + d->d_off - (uint64_t) rc)); - rc = sh_off + d->d_off; + rc = (off_t) (sh_off + d->d_off); assert(d->d_buf != NULL); assert(d->d_version == e->e_version); assert(d->d_size % msz == 0); - nobjects = d->d_size / msz; + nobjects = (size_t) (d->d_size / msz); fsz = _libelf_fsize(d->d_type, ec, e->e_version, nobjects); @@ -797,10 +821,10 @@ _libelf_write_scn(Elf *e, char *nf, struct _Elf_Extent *ex) NULL) return ((off_t) -1); - rc += fsz; + rc += (off_t) fsz; } - return ((off_t) rc); + return (rc); } /* @@ -808,7 +832,7 @@ _libelf_write_scn(Elf *e, char *nf, struct _Elf_Extent *ex) */ static off_t -_libelf_write_ehdr(Elf *e, char *nf, struct _Elf_Extent *ex) +_libelf_write_ehdr(Elf *e, unsigned char *nf, struct _Elf_Extent *ex) { int ec; void *ehdr; @@ -849,7 +873,7 @@ _libelf_write_ehdr(Elf *e, char *nf, struct _Elf_Extent *ex) */ static off_t -_libelf_write_phdr(Elf *e, char *nf, struct _Elf_Extent *ex) +_libelf_write_phdr(Elf *e, unsigned char *nf, struct _Elf_Extent *ex) { int ec; void *ehdr; @@ -898,7 +922,7 @@ _libelf_write_phdr(Elf *e, char *nf, struct _Elf_Extent *ex) NULL) return ((off_t) -1); - return (phoff + fsz); + return ((off_t) (phoff + fsz)); } /* @@ -906,7 +930,7 @@ _libelf_write_phdr(Elf *e, char *nf, struct _Elf_Extent *ex) */ static off_t -_libelf_write_shdr(Elf *e, char *nf, struct _Elf_Extent *ex) +_libelf_write_shdr(Elf *e, unsigned char *nf, struct _Elf_Extent *ex) { int ec; void *ehdr; @@ -958,7 +982,7 @@ _libelf_write_shdr(Elf *e, char *nf, struct _Elf_Extent *ex) return ((off_t) -1); } - return (ex->ex_start + nscn * fsz); + return ((off_t) (ex->ex_start + nscn * fsz)); } /* @@ -982,9 +1006,9 @@ static off_t _libelf_write_elf(Elf *e, off_t newsize, struct _Elf_Extent_List *extents) { off_t nrc, rc; - char *newfile; Elf_Scn *scn, *tscn; struct _Elf_Extent *ex; + unsigned char *newfile; assert(e->e_kind == ELF_K_ELF); assert(e->e_cmd == ELF_C_RDWR || e->e_cmd == ELF_C_WRITE); @@ -1001,7 +1025,7 @@ _libelf_write_elf(Elf *e, off_t newsize, struct _Elf_Extent_List *extents) /* Fill inter-extent gaps. */ if (ex->ex_start > (size_t) rc) (void) memset(newfile + rc, LIBELF_PRIVATE(fillchar), - ex->ex_start - rc); + (size_t) (ex->ex_start - (uint64_t) rc)); switch (ex->ex_type) { case ELF_EXTENT_EHDR: @@ -1047,6 +1071,7 @@ _libelf_write_elf(Elf *e, off_t newsize, struct _Elf_Extent_List *extents) LIBELF_SET_ERROR(IO, errno); goto error; } +#if ELFTC_HAVE_MMAP if (e->e_flags & LIBELF_F_RAWFILE_MMAP) { assert(e->e_rawfile != NULL); assert(e->e_cmd == ELF_C_RDWR); @@ -1055,6 +1080,7 @@ _libelf_write_elf(Elf *e, off_t newsize, struct _Elf_Extent_List *extents) goto error; } } +#endif } /* @@ -1071,21 +1097,26 @@ _libelf_write_elf(Elf *e, off_t newsize, struct _Elf_Extent_List *extents) */ if (e->e_cmd == ELF_C_RDWR) { assert(e->e_rawfile != NULL); - if (e->e_flags & LIBELF_F_RAWFILE_MMAP) { + assert((e->e_flags & LIBELF_F_RAWFILE_MALLOC) || + (e->e_flags & LIBELF_F_RAWFILE_MMAP)); + if (e->e_flags & LIBELF_F_RAWFILE_MALLOC) { + free(e->e_rawfile); + e->e_rawfile = newfile; + newfile = NULL; + } +#if ELFTC_HAVE_MMAP + else if (e->e_flags & LIBELF_F_RAWFILE_MMAP) { if ((e->e_rawfile = mmap(NULL, (size_t) newsize, PROT_READ, MAP_PRIVATE, e->e_fd, (off_t) 0)) == MAP_FAILED) { LIBELF_SET_ERROR(IO, errno); goto error; } - } else if (e->e_flags & LIBELF_F_RAWFILE_MALLOC) { - free(e->e_rawfile); - e->e_rawfile = newfile; - newfile = NULL; } +#endif /* ELFTC_HAVE_MMAP */ /* Record the new size of the file. */ - e->e_rawsize = newsize; + e->e_rawsize = (size_t) newsize; } else { /* File opened in ELF_C_WRITE mode. */ assert(e->e_rawfile == NULL); @@ -1176,7 +1207,7 @@ elf_update(Elf *e, Elf_Cmd c) goto done; } - return (_libelf_write_elf(e, rc, &extents)); + rc = _libelf_write_elf(e, rc, &extents); done: _libelf_release_extents(&extents); |