elf_update.c

来自「M5,一个功能强大的多处理器系统模拟器.很多针对处理器架构,性能的研究都使用它作」· C语言 代码 · 共 886 行 · 第 1/2 页

C
886
字号
        if ((rc = _libelf_resync_sections(e, rc)) < 0)                return ((off_t) -1);        /*         * Compute the space taken up by the section header table, if         * one is needed.         */        if (shnum) {                fsz = _libelf_fsize(ELF_T_SHDR, ec, eh_version, (size_t) 1);                align = _libelf_falign(ELF_T_SHDR, ec);                if (e->e_flags & ELF_F_LAYOUT) {                        if (rc > shoff) {                                LIBELF_SET_ERROR(HEADER, 0);                                return ((off_t) -1);                        }                        if (shoff % align) {                                LIBELF_SET_ERROR(LAYOUT, 0);                                return ((off_t) -1);                        }                } else                        shoff = roundup(rc, align);                rc = shoff + fsz * shnum;        } else                shoff = 0;        /*         * Set the fields of the Executable Header that could potentially use         * extended numbering.         */        _libelf_setphnum(e, ehdr, ec, phnum);        _libelf_setshnum(e, ehdr, ec, shnum);        /*         * Update the `e_phoff' and `e_shoff' fields if the library is         * doing the layout.         */        if ((e->e_flags & ELF_F_LAYOUT) == 0) {                if (ec == ELFCLASS32) {                        eh32->e_phoff = (uint32_t) phoff;                        eh32->e_shoff = (uint32_t) shoff;                } else {                        eh64->e_phoff = (uint64_t) phoff;                        eh64->e_shoff = (uint64_t) shoff;                }        }        return (rc);}/* * Write out the contents of a section. */static off_t_libelf_write_scn(Elf *e, char *nf, Elf_Scn *s, off_t rc){        int ec;        size_t fsz, msz, nobjects;        uint32_t sh_type;        uint64_t sh_off;        int elftype;        Elf_Data *d, dst;        if ((ec = e->e_class) == ELFCLASS32)                sh_type = s->s_shdr.s_shdr32.sh_type;        else                sh_type = s->s_shdr.s_shdr64.sh_type;        /*         * Ignore sections that do not allocate space in the file.         */        if (sh_type == SHT_NOBITS || sh_type == SHT_NULL)                return (rc);        elftype = _libelf_xlate_shtype(sh_type);        assert(elftype >= ELF_T_FIRST && elftype <= ELF_T_LAST);        msz = _libelf_msize(elftype, ec, e->e_version);        sh_off = s->s_offset;        assert(sh_off % _libelf_falign(elftype, ec) == 0);        /*         * If the section has a `rawdata' descriptor, and the section         * contents have not been modified, use its contents directly.         * The `s_rawoff' member contains the offset into the original         * file, while `s_offset' contains its new location in the         * destination.         */        if (STAILQ_EMPTY(&s->s_data)) {                if ((d = elf_rawdata(s, NULL)) == NULL)                        return ((off_t) -1);                STAILQ_FOREACH(d, &s->s_rawdata, d_next) {                        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;                        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);                        rc += d->d_size;                }                return (rc);        }        /*         * Iterate over the set of data descriptors for this section.         * The prior call to _libelf_resync_elf() would have setup the         * descriptors for this step.         */        dst.d_version = e->e_version;        STAILQ_FOREACH(d, &s->s_data, d_next) {                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;                assert(d->d_buf != NULL);                assert(d->d_type == (Elf_Type) elftype);                assert(d->d_version == e->e_version);                assert(d->d_size % msz == 0);                nobjects = d->d_size / msz;                fsz = _libelf_fsize(elftype, ec, e->e_version, nobjects);                dst.d_buf    = nf + rc;                dst.d_size   = fsz;                if (_libelf_xlate(&dst, d, e->e_byteorder, ec, ELF_TOFILE) ==                    NULL)                        return ((off_t) -1);                rc += fsz;        }        return ((off_t) rc);}/* * Write out the file image. * * The original file could have been mapped in with an ELF_C_RDWR * command and the application could have added new content or * re-arranged its sections before calling elf_update().  Consequently * its not safe to work `in place' on the original file.  So we * malloc() the required space for the updated ELF object and build * the object there and write it out to the underlying file at the * end.  Note that the application may have opened the underlying file * in ELF_C_RDWR and only retrieved/modified a few sections.  We take * care to avoid translating file sections unnecessarily. * * Gaps in the coverage of the file by the file's sections will be * filled with the fill character set by elf_fill(3). */static off_t_libelf_write_elf(Elf *e, off_t newsize){        int ec;        off_t rc;        size_t fsz, msz, phnum, shnum;        uint64_t phoff, shoff;        void *ehdr;        char *newfile;        Elf_Data dst, src;        Elf_Scn *scn, *tscn;        Elf32_Ehdr *eh32;        Elf64_Ehdr *eh64;        assert(e->e_kind == ELF_K_ELF);        assert(e->e_cmd != ELF_C_READ);        assert(e->e_fd >= 0);        if ((newfile = malloc((size_t) newsize)) == NULL) {                LIBELF_SET_ERROR(RESOURCE, errno);                return ((off_t) -1);        }        ec = e->e_class;        ehdr = _libelf_ehdr(e, ec, 0);        assert(ehdr != NULL);        phnum = e->e_u.e_elf.e_nphdr;        if (ec == ELFCLASS32) {                eh32 = (Elf32_Ehdr *) ehdr;                phoff = (uint64_t) eh32->e_phoff;                shnum = eh32->e_shnum;                shoff = (uint64_t) eh32->e_shoff;        } else {                eh64 = (Elf64_Ehdr *) ehdr;                phoff = eh64->e_phoff;                shnum = eh64->e_shnum;                shoff = eh64->e_shoff;        }        fsz = _libelf_fsize(ELF_T_EHDR, ec, e->e_version, (size_t) 1);        msz = _libelf_msize(ELF_T_EHDR, ec, e->e_version);        (void) memset(&dst, 0, sizeof(dst));        (void) memset(&src, 0, sizeof(src));        src.d_buf     = ehdr;        src.d_size    = msz;        src.d_type    = ELF_T_EHDR;        src.d_version = dst.d_version = e->e_version;        rc = 0;        dst.d_buf     = newfile + rc;        dst.d_size    = fsz;        if (_libelf_xlate(&dst, &src, e->e_byteorder, ec, ELF_TOFILE) ==            NULL)                goto error;        rc += fsz;        /*         * Write the program header table if present.         */        if (phnum != 0 && phoff != 0) {                assert((unsigned) rc <= phoff);                fsz = _libelf_fsize(ELF_T_PHDR, ec, e->e_version, phnum);                assert(phoff % _libelf_falign(ELF_T_PHDR, ec) == 0);                assert(fsz > 0);                src.d_version = dst.d_version = e->e_version;                src.d_type = ELF_T_PHDR;                if (ec == ELFCLASS32)                        src.d_buf = e->e_u.e_elf.e_phdr.e_phdr32;                else                        src.d_buf = e->e_u.e_elf.e_phdr.e_phdr64;                src.d_size = phnum * _libelf_msize(ELF_T_PHDR, ec,                    e->e_version);                dst.d_size = fsz;                if ((uint64_t) rc < phoff)                        (void) memset(newfile + rc,                            LIBELF_PRIVATE(fillchar), phoff - rc);                dst.d_buf = newfile + rc;                if (_libelf_xlate(&dst, &src, e->e_byteorder, ec, ELF_TOFILE) ==                    NULL)                        goto error;                rc = phoff + fsz;        }        /*         * Write out individual sections.         */        STAILQ_FOREACH(scn, &e->e_u.e_elf.e_scn, s_next)                if ((rc = _libelf_write_scn(e, newfile, scn, rc)) < 0)                        goto error;        /*         * Write out the section header table, if required.         */        if (shnum != 0 && shoff != 0) {                assert((unsigned) rc <= shoff);                if ((uint64_t) rc < shoff)                        (void) memset(newfile + rc,                            LIBELF_PRIVATE(fillchar), shoff - rc);                rc = shoff;                assert(rc % _libelf_falign(ELF_T_SHDR, ec) == 0);                src.d_type = ELF_T_SHDR;                src.d_size = _libelf_msize(ELF_T_SHDR, ec, e->e_version);                src.d_version = dst.d_version = e->e_version;                fsz = _libelf_fsize(ELF_T_SHDR, ec, e->e_version, (size_t) 1);                STAILQ_FOREACH(scn, &e->e_u.e_elf.e_scn, s_next) {                        if (ec == ELFCLASS32)                                src.d_buf = &scn->s_shdr.s_shdr32;                        else                                src.d_buf = &scn->s_shdr.s_shdr64;                        dst.d_size = fsz;                        dst.d_buf = newfile + rc;                        if (_libelf_xlate(&dst, &src, e->e_byteorder, ec,                                ELF_TOFILE) != &dst)                                goto error;                        rc += fsz;                }        }        /*         */        assert(rc == newsize);        /*         * Write out the constructed contents and remap the file in         * read-only.         */        if (e->e_rawfile && munmap(e->e_rawfile, e->e_rawsize) < 0) {                LIBELF_SET_ERROR(IO, errno);                goto error;        }        if (write(e->e_fd, newfile, (size_t) newsize) != newsize ||            lseek(e->e_fd, (off_t) 0, SEEK_SET) < 0) {                LIBELF_SET_ERROR(IO, errno);                goto error;        }        if (e->e_cmd != ELF_C_WRITE) {                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;                }                e->e_rawsize = newsize;        }        /*         * Reset flags, remove existing section descriptors and         * {E,P}HDR pointers so that a subsequent elf_get{e,p}hdr()         * and elf_getscn() will function correctly.         */        e->e_flags &= ~ELF_F_DIRTY;        STAILQ_FOREACH_SAFE(scn, &e->e_u.e_elf.e_scn, s_next, tscn)                _libelf_release_scn(scn);        if (ec == ELFCLASS32) {                free(e->e_u.e_elf.e_ehdr.e_ehdr32);                if (e->e_u.e_elf.e_phdr.e_phdr32)                        free(e->e_u.e_elf.e_phdr.e_phdr32);                e->e_u.e_elf.e_ehdr.e_ehdr32 = NULL;                e->e_u.e_elf.e_phdr.e_phdr32 = NULL;        } else {                free(e->e_u.e_elf.e_ehdr.e_ehdr64);                if (e->e_u.e_elf.e_phdr.e_phdr64)                        free(e->e_u.e_elf.e_phdr.e_phdr64);                e->e_u.e_elf.e_ehdr.e_ehdr64 = NULL;                e->e_u.e_elf.e_phdr.e_phdr64 = NULL;        }        return (rc); error:        if (newfile)                free(newfile);        return ((off_t) -1);}off_telf_update(Elf *e, Elf_Cmd c){        int ec;        off_t rc;        rc = (off_t) -1;        if (e == NULL || e->e_kind != ELF_K_ELF ||            (c != ELF_C_NULL && c != ELF_C_WRITE)) {                LIBELF_SET_ERROR(ARGUMENT, 0);                return (rc);        }        if ((ec = e->e_class) != ELFCLASS32 && ec != ELFCLASS64) {                LIBELF_SET_ERROR(CLASS, 0);                return (rc);        }        if (e->e_version == EV_NONE)                e->e_version = EV_CURRENT;        if (c == ELF_C_WRITE && e->e_cmd == ELF_C_READ) {                LIBELF_SET_ERROR(MODE, 0);                return (rc);        }        if ((rc = _libelf_resync_elf(e)) < 0)                return (rc);        if (c == ELF_C_NULL)                return (rc);        if (e->e_cmd == ELF_C_READ) {                /*                 * This descriptor was opened in read-only mode or by                 * elf_memory().                 */                if (e->e_fd)                        LIBELF_SET_ERROR(MODE, 0);                else                        LIBELF_SET_ERROR(ARGUMENT, 0);                return ((off_t) -1);        }        if (e->e_fd < 0) {                LIBELF_SET_ERROR(SEQUENCE, 0);                return ((off_t) -1);        }        return (_libelf_write_elf(e, rc));}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?