Index: head/contrib/elftoolchain/elfcopy/elfcopy.h =================================================================== --- head/contrib/elftoolchain/elfcopy/elfcopy.h (revision 297241) +++ head/contrib/elftoolchain/elfcopy/elfcopy.h (revision 297242) @@ -1,319 +1,320 @@ /*- * Copyright (c) 2007-2013 Kai Wang * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $Id: elfcopy.h 3310 2016-01-10 09:10:54Z kaiwang27 $ */ #include #include #include #include "_elftc.h" /* * User specified symbol operation (strip, keep, localize, globalize, * weaken, rename, etc). */ struct symop { const char *name; const char *newname; #define SYMOP_KEEP 0x0001U #define SYMOP_STRIP 0x0002U #define SYMOP_GLOBALIZE 0x0004U #define SYMOP_LOCALIZE 0x0008U #define SYMOP_KEEPG 0x0010U #define SYMOP_WEAKEN 0x0020U #define SYMOP_REDEF 0x0040U unsigned int op; STAILQ_ENTRY(symop) symop_list; }; /* File containing symbol list. */ struct symfile { dev_t dev; ino_t ino; size_t size; char *data; unsigned int op; STAILQ_ENTRY(symfile) symfile_list; }; /* Sections to copy/remove/rename/... */ struct sec_action { const char *name; const char *addopt; const char *newname; const char *string; uint64_t lma; uint64_t vma; int64_t lma_adjust; int64_t vma_adjust; #define SF_ALLOC 0x0001U #define SF_LOAD 0x0002U #define SF_NOLOAD 0x0004U #define SF_READONLY 0x0008U #define SF_DEBUG 0x0010U #define SF_CODE 0x0020U #define SF_DATA 0x0040U #define SF_ROM 0x0080U #define SF_SHARED 0X0100U #define SF_CONTENTS 0x0200U int flags; int add; int append; int compress; int copy; int print; int remove; int rename; int setflags; int setlma; int setvma; STAILQ_ENTRY(sec_action) sac_list; }; /* Sections to add from file. */ struct sec_add { char *name; char *content; size_t size; STAILQ_ENTRY(sec_add) sadd_list; }; struct segment; /* Internal data structure for sections. */ struct section { struct segment *seg; /* containing segment */ struct segment *seg_tls; /* tls segment */ const char *name; /* section name */ char *newname; /* new section name */ Elf_Scn *is; /* input scn */ Elf_Scn *os; /* output scn */ void *buf; /* section content */ uint8_t *pad; /* section padding */ uint64_t off; /* section offset */ uint64_t sz; /* section size */ uint64_t cap; /* section capacity */ uint64_t align; /* section alignment */ uint64_t type; /* section type */ uint64_t vma; /* section virtual addr */ uint64_t lma; /* section load addr */ uint64_t pad_sz;/* section padding size */ int loadable; /* whether loadable */ int pseudo; int nocopy; TAILQ_ENTRY(section) sec_list; /* next section */ }; /* Internal data structure for segments. */ struct segment { - uint64_t addr; /* load addr */ + uint64_t vaddr; /* virtual addr (VMA) */ + uint64_t paddr; /* physical addr (LMA) */ uint64_t off; /* file offset */ uint64_t fsz; /* file size */ uint64_t msz; /* memory size */ uint64_t type; /* segment type */ int remove; /* whether remove */ int nsec; /* number of sections contained */ struct section **v_sec; /* list of sections contained */ STAILQ_ENTRY(segment) seg_list; /* next segment */ }; /* * In-memory representation of ar(1) archive member(object). */ struct ar_obj { char *name; /* member name */ char *buf; /* member content */ void *maddr; /* mmap start address */ uid_t uid; /* user id */ gid_t gid; /* group id */ mode_t md; /* octal file permissions */ size_t size; /* member size */ time_t mtime; /* modification time */ STAILQ_ENTRY(ar_obj) objs; }; /* * Structure encapsulates the "global" data for "elfcopy" program. */ struct elfcopy { const char *progname; /* program name */ int iec; /* elfclass of input object */ Elftc_Bfd_Target_Flavor itf; /* flavour of input object */ Elftc_Bfd_Target_Flavor otf; /* flavour of output object */ const char *otgt; /* output target name */ int oec; /* elfclass of output object */ unsigned char oed; /* endianess of output object */ int oem; /* EM_XXX of output object */ int abi; /* OSABI of output object */ Elf *ein; /* ELF descriptor of input object */ Elf *eout; /* ELF descriptor of output object */ int iphnum; /* num. of input object phdr entries */ int ophnum; /* num. of output object phdr entries */ int nos; /* num. of output object sections */ enum { STRIP_NONE = 0, STRIP_ALL, STRIP_DEBUG, STRIP_DWO, STRIP_NONDEBUG, STRIP_NONDWO, STRIP_UNNEEDED } strip; #define EXECUTABLE 0x00000001U #define DYNAMIC 0x00000002U #define RELOCATABLE 0x00000004U #define SYMTAB_EXIST 0x00000010U #define SYMTAB_INTACT 0x00000020U #define KEEP_GLOBAL 0x00000040U #define DISCARD_LOCAL 0x00000080U #define WEAKEN_ALL 0x00000100U #define PRESERVE_DATE 0x00001000U #define SREC_FORCE_S3 0x00002000U #define SREC_FORCE_LEN 0x00004000U #define SET_START 0x00008000U #define GAP_FILL 0x00010000U #define WILDCARD 0x00020000U #define NO_CHANGE_WARN 0x00040000U #define SEC_ADD 0x00080000U #define SEC_APPEND 0x00100000U #define SEC_COMPRESS 0x00200000U #define SEC_PRINT 0x00400000U #define SEC_REMOVE 0x00800000U #define SEC_COPY 0x01000000U #define DISCARD_LLABEL 0x02000000U #define LOCALIZE_HIDDEN 0x04000000U int flags; /* elfcopy run control flags. */ int64_t change_addr; /* Section address adjustment. */ int64_t change_start; /* Entry point adjustment. */ uint64_t set_start; /* Entry point value. */ unsigned long srec_len; /* S-Record length. */ uint64_t pad_to; /* load address padding. */ uint8_t fill; /* gap fill value. */ char *prefix_sec; /* section prefix. */ char *prefix_alloc; /* alloc section prefix. */ char *prefix_sym; /* symbol prefix. */ char *debuglink; /* GNU debuglink file. */ struct section *symtab; /* .symtab section. */ struct section *strtab; /* .strtab section. */ struct section *shstrtab; /* .shstrtab section. */ uint64_t *secndx; /* section index map. */ uint64_t *symndx; /* symbol index map. */ unsigned char *v_rel; /* symbols needed by relocation. */ unsigned char *v_grp; /* symbols refered by section group. */ unsigned char *v_secsym; /* sections with section symbol. */ STAILQ_HEAD(, segment) v_seg; /* list of segments. */ STAILQ_HEAD(, sec_action) v_sac;/* list of section operations. */ STAILQ_HEAD(, sec_add) v_sadd; /* list of sections to add. */ STAILQ_HEAD(, symop) v_symop; /* list of symbols operations. */ STAILQ_HEAD(, symfile) v_symfile; /* list of symlist files. */ TAILQ_HEAD(, section) v_sec; /* list of sections. */ /* * Fields for the ar(1) archive. */ char *as; /* buffer for archive string table. */ size_t as_sz; /* current size of as table. */ size_t as_cap; /* capacity of as table buffer. */ uint32_t s_cnt; /* current number of symbols. */ uint32_t *s_so; /* symbol offset table. */ size_t s_so_cap; /* capacity of so table buffer. */ char *s_sn; /* symbol name table */ size_t s_sn_cap; /* capacity of sn table buffer. */ size_t s_sn_sz; /* current size of sn table. */ off_t rela_off; /* offset relative to pseudo members. */ STAILQ_HEAD(, ar_obj) v_arobj; /* archive object(member) list. */ }; void add_section(struct elfcopy *_ecp, const char *_optarg); void add_to_shstrtab(struct elfcopy *_ecp, const char *_name); void add_to_symop_list(struct elfcopy *_ecp, const char *_name, const char *_newname, unsigned int _op); void add_to_symtab(struct elfcopy *_ecp, const char *_name, uint64_t _st_value, uint64_t _st_size, uint16_t _st_shndx, unsigned char _st_info, unsigned char _st_other, int _ndx_known); int add_to_inseg_list(struct elfcopy *_ecp, struct section *_sec); void adjust_addr(struct elfcopy *_ecp); void copy_content(struct elfcopy *_ecp); void copy_data(struct section *_s); void copy_phdr(struct elfcopy *_ecp); void copy_shdr(struct elfcopy *_ecp, struct section *_s, const char *_name, int _copy, int _sec_flags); void create_binary(int _ifd, int _ofd); void create_elf(struct elfcopy *_ecp); void create_elf_from_binary(struct elfcopy *_ecp, int _ifd, const char *ifn); void create_elf_from_ihex(struct elfcopy *_ecp, int _ifd); void create_elf_from_srec(struct elfcopy *_ecp, int _ifd); struct section *create_external_section(struct elfcopy *_ecp, const char *_name, char *_newname, void *_buf, uint64_t _size, uint64_t _off, uint64_t _stype, Elf_Type _dtype, uint64_t flags, uint64_t _align, uint64_t _vma, int _loadable); void create_external_symtab(struct elfcopy *_ecp); void create_ihex(int _ifd, int _ofd); void create_pe(struct elfcopy *_ecp, int _ifd, int _ofd); void create_scn(struct elfcopy *_ecp); void create_srec(struct elfcopy *_ecp, int _ifd, int _ofd, const char *_ofn); void create_symtab(struct elfcopy *_ecp); void create_symtab_data(struct elfcopy *_ecp); void create_tempfile(char **_fn, int *_fd); void finalize_external_symtab(struct elfcopy *_ecp); void free_elf(struct elfcopy *_ecp); void free_sec_act(struct elfcopy *_ecp); void free_sec_add(struct elfcopy *_ecp); void free_symtab(struct elfcopy *_ecp); void init_shstrtab(struct elfcopy *_ecp); void insert_to_sec_list(struct elfcopy *_ecp, struct section *_sec, int _tail); struct section *insert_shtab(struct elfcopy *_ecp, int tail); int is_remove_reloc_sec(struct elfcopy *_ecp, uint32_t _sh_info); int is_remove_section(struct elfcopy *_ecp, const char *_name); struct sec_action *lookup_sec_act(struct elfcopy *_ecp, const char *_name, int _add); struct symop *lookup_symop_list(struct elfcopy *_ecp, const char *_name, unsigned int _op); void resync_sections(struct elfcopy *_ecp); void set_shstrtab(struct elfcopy *_ecp); void setup_phdr(struct elfcopy *_ecp); void update_shdr(struct elfcopy *_ecp, int _update_link); #ifndef LIBELF_AR int ac_detect_ar(int _ifd); void ac_create_ar(struct elfcopy *_ecp, int _ifd, int _ofd); #endif /* ! LIBELF_AR */ Index: head/contrib/elftoolchain/elfcopy/segments.c =================================================================== --- head/contrib/elftoolchain/elfcopy/segments.c (revision 297241) +++ head/contrib/elftoolchain/elfcopy/segments.c (revision 297242) @@ -1,497 +1,591 @@ /*- * Copyright (c) 2007-2010,2012 Kai Wang * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include #include #include #include "elfcopy.h" ELFTC_VCSID("$Id: segments.c 3397 2016-02-12 14:35:19Z emaste $"); static void insert_to_inseg_list(struct segment *seg, struct section *sec); /* * elfcopy's segment handling is relatively simpler and less powerful than * libbfd. Program headers are modified or copied from input to output objects, * but never re-generated. As a result, if the input object has incorrect * program headers, the output object's program headers will remain incorrect * or become even worse. */ /* * Check whether a section is "loadable". If so, add it to the * corresponding segment list(s) and return 1. */ int add_to_inseg_list(struct elfcopy *ecp, struct section *s) { struct segment *seg; int loadable; if (ecp->ophnum == 0) return (0); /* * Segment is a different view of an ELF object. One segment can * contain one or more sections, and one section can be included * in one or more segments, or not included in any segment at all. * We call those sections which can be found in one or more segments * "loadable" sections, and call the rest "unloadable" sections. * We keep track of "loadable" sections in their containing * segment(s)' v_sec queue. These information are later used to * recalculate the extents of segments, when sections are removed, * for example. */ loadable = 0; STAILQ_FOREACH(seg, &ecp->v_seg, seg_list) { - if (s->off < seg->off || (s->vma < seg->addr && !s->pseudo)) + if (s->off < seg->off || (s->vma < seg->vaddr && !s->pseudo)) continue; if (s->off + s->sz > seg->off + seg->fsz && s->type != SHT_NOBITS) continue; - if (s->vma + s->sz > seg->addr + seg->msz) + if (s->vma + s->sz > seg->vaddr + seg->msz) continue; insert_to_inseg_list(seg, s); if (seg->type == PT_LOAD) s->seg = seg; else if (seg->type == PT_TLS) s->seg_tls = seg; - s->lma = seg->addr + (s->off - seg->off); + if (s->pseudo) + s->vma = seg->vaddr + (s->off - seg->off); + if (seg->paddr > 0) + s->lma = seg->paddr + (s->off - seg->off); + else + s->lma = 0; loadable = 1; } return (loadable); } void adjust_addr(struct elfcopy *ecp) { struct section *s, *s0; struct segment *seg; struct sec_action *sac; - uint64_t dl, lma, start, end; + uint64_t dl, vma, lma, start, end; int found, i; /* * Apply VMA and global LMA changes in the first iteration. */ TAILQ_FOREACH(s, &ecp->v_sec, sec_list) { /* Only adjust loadable section's address. */ if (!s->loadable) continue; + /* Apply global VMA adjustment. */ + if (ecp->change_addr != 0) + s->vma += ecp->change_addr; + /* Apply global LMA adjustment. */ - if (ecp->change_addr != 0 && s->seg != NULL) + if (ecp->change_addr != 0 && s->seg != NULL && + s->seg->paddr > 0) s->lma += ecp->change_addr; - - if (!s->pseudo) { - /* Apply global VMA adjustment. */ - if (ecp->change_addr != 0) - s->vma += ecp->change_addr; - - /* Apply section VMA adjustment. */ - sac = lookup_sec_act(ecp, s->name, 0); - if (sac == NULL) - continue; - if (sac->setvma) - s->vma = sac->vma; - if (sac->vma_adjust != 0) - s->vma += sac->vma_adjust; - } } /* - * Apply sections LMA change in the second iteration. + * Apply sections VMA change in the second iteration. */ TAILQ_FOREACH(s, &ecp->v_sec, sec_list) { - /* - * Only loadable section that's inside a segment can have - * LMA adjusted. - */ - if (!s->loadable || s->seg == NULL) + if (!s->loadable) continue; /* - * Check if there is a LMA change request for this + * Check if there is a VMA change request for this * section. */ sac = lookup_sec_act(ecp, s->name, 0); if (sac == NULL) continue; - if (!sac->setlma && sac->lma_adjust == 0) + vma = s->vma; + if (sac->setvma) + vma = sac->vma; + if (sac->vma_adjust != 0) + vma += sac->vma_adjust; + if (vma == s->vma) continue; - lma = s->lma; - if (sac->setlma) - lma = sac->lma; - if (sac->lma_adjust != 0) - lma += sac->lma_adjust; - if (lma == s->lma) + + /* + * No need to make segment adjustment if the section doesn't + * belong to any segment. + */ + if (s->seg == NULL) { + s->vma = vma; continue; + } /* - * Check if the LMA change is viable. + * Check if the VMA change is viable. * - * 1. Check if the new LMA is properly aligned accroding to + * 1. Check if the new VMA is properly aligned accroding to * section alignment. * * 2. Compute the new extent of segment that contains this * section, make sure it doesn't overlap with other * segments. */ #ifdef DEBUG - printf("LMA for section %s: %#jx\n", s->name, lma); + printf("VMA for section %s: %#jx\n", s->name, vma); #endif - if (lma % s->align != 0) - errx(EXIT_FAILURE, "The load address %#jx for " + if (vma % s->align != 0) + errx(EXIT_FAILURE, "The VMA %#jx for " "section %s is not aligned to %ju", - (uintmax_t) lma, s->name, (uintmax_t) s->align); + (uintmax_t) vma, s->name, (uintmax_t) s->align); - if (lma < s->lma) { + if (vma < s->vma) { /* Move section to lower address. */ - if (lma < s->lma - s->seg->addr) + if (vma < s->vma - s->seg->vaddr) errx(EXIT_FAILURE, "Not enough space to move " - "section %s load address to %#jx", s->name, - (uintmax_t) lma); - start = lma - (s->lma - s->seg->addr); + "section %s VMA to %#jx", s->name, + (uintmax_t) vma); + start = vma - (s->vma - s->seg->vaddr); if (s == s->seg->v_sec[s->seg->nsec - 1]) end = start + s->seg->msz; else - end = s->seg->addr + s->seg->msz; - + end = s->seg->vaddr + s->seg->msz; } else { /* Move section to upper address. */ if (s == s->seg->v_sec[0]) - start = lma; + start = vma; else - start = s->seg->addr; - end = lma + (s->seg->addr + s->seg->msz - s->lma); + start = s->seg->vaddr; + end = vma + (s->seg->vaddr + s->seg->msz - s->vma); if (end < start) errx(EXIT_FAILURE, "Not enough space to move " - "section %s load address to %#jx", s->name, - (uintmax_t) lma); + "section %s VMA to %#jx", s->name, + (uintmax_t) vma); } #ifdef DEBUG printf("new extent for segment containing %s: (%#jx,%#jx)\n", s->name, start, end); #endif STAILQ_FOREACH(seg, &ecp->v_seg, seg_list) { if (seg == s->seg || seg->type != PT_LOAD) continue; - if (start > seg->addr + seg->msz) + if (start > seg->vaddr + seg->msz) continue; - if (end < seg->addr) + if (end < seg->vaddr) continue; errx(EXIT_FAILURE, "The extent of segment containing " "section %s overlaps with segment(%#jx,%#jx)", - s->name, (uintmax_t) seg->addr, - (uintmax_t) (seg->addr + seg->msz)); + s->name, (uintmax_t) seg->vaddr, + (uintmax_t) (seg->vaddr + seg->msz)); } /* - * Update section LMA and file offset. + * Update section VMA and file offset. */ - if (lma < s->lma) { + if (vma < s->vma) { /* - * To move a section to lower load address, we decrease - * the load addresses of the section and all the - * sections that are before it, and we increase the - * file offsets of all the sections that are after it. + * To move a section to lower VMA, we decrease + * the VMA of the section and all the sections that + * are before it, and we increase the file offsets + * of all the sections that are after it. */ - dl = s->lma - lma; + dl = s->vma - vma; for (i = 0; i < s->seg->nsec; i++) { s0 = s->seg->v_sec[i]; - s0->lma -= dl; + s0->vma -= dl; #ifdef DEBUG - printf("section %s LMA set to %#jx\n", - s0->name, (uintmax_t) s0->lma); + printf("section %s VMA set to %#jx\n", + s0->name, (uintmax_t) s0->vma); #endif if (s0 == s) break; } for (i = i + 1; i < s->seg->nsec; i++) { s0 = s->seg->v_sec[i]; s0->off += dl; #ifdef DEBUG printf("section %s offset set to %#jx\n", s0->name, (uintmax_t) s0->off); #endif } } else { /* - * To move a section to upper load address, we increase - * the load addresses of the section and all the - * sections that are after it, and we increase the - * their file offsets too unless the section in question + * To move a section to upper VMA, we increase + * the VMA of the section and all the sections that + * are after it, and we increase the their file + * offsets too unless the section in question * is the first in its containing segment. */ - dl = lma - s->lma; + dl = vma - s->vma; for (i = 0; i < s->seg->nsec; i++) if (s->seg->v_sec[i] == s) break; if (i >= s->seg->nsec) errx(EXIT_FAILURE, "Internal: section `%s' not" " found in its containing segement", s->name); for (; i < s->seg->nsec; i++) { s0 = s->seg->v_sec[i]; - s0->lma += dl; + s0->vma += dl; #ifdef DEBUG - printf("section %s LMA set to %#jx\n", + printf("section %s VMA set to %#jx\n", s0->name, (uintmax_t) s0->lma); #endif if (s != s->seg->v_sec[0]) { s0->off += dl; #ifdef DEBUG printf("section %s offset set to %#jx\n", s0->name, (uintmax_t) s0->off); #endif } } } } /* * Apply load address padding. */ if (ecp->pad_to != 0) { /* - * Find the section with highest load address. + * Find the section with highest VMA. */ - s = NULL; STAILQ_FOREACH(seg, &ecp->v_seg, seg_list) { if (seg->type != PT_LOAD) continue; for (i = seg->nsec - 1; i >= 0; i--) if (seg->v_sec[i]->type != SHT_NOBITS) break; if (i < 0) continue; if (s == NULL) s = seg->v_sec[i]; else { s0 = seg->v_sec[i]; - if (s0->lma > s->lma) + if (s0->vma > s->vma) s = s0; } } if (s == NULL) - goto issue_warn; + goto adjust_lma; /* No need to pad if the pad_to address is lower. */ - if (ecp->pad_to <= s->lma + s->sz) - goto issue_warn; + if (ecp->pad_to <= s->vma + s->sz) + goto adjust_lma; - s->pad_sz = ecp->pad_to - (s->lma + s->sz); + s->pad_sz = ecp->pad_to - (s->vma + s->sz); #ifdef DEBUG - printf("pad section %s load to address %#jx by %#jx\n", s->name, + printf("pad section %s VMA to address %#jx by %#jx\n", s->name, (uintmax_t) ecp->pad_to, (uintmax_t) s->pad_sz); #endif } -issue_warn: +adjust_lma: + /* + * Apply sections LMA change in the third iteration. + */ + TAILQ_FOREACH(s, &ecp->v_sec, sec_list) { + + /* + * Only loadable section that's inside a segment can have + * LMA adjusted. Also, if LMA of the containing segment is + * set to 0, it probably means we should ignore the LMA. + */ + if (!s->loadable || s->seg == NULL || s->seg->paddr == 0) + continue; + + /* + * Check if there is a LMA change request for this + * section. + */ + sac = lookup_sec_act(ecp, s->name, 0); + if (sac == NULL) + continue; + if (!sac->setlma && sac->lma_adjust == 0) + continue; + lma = s->lma; + if (sac->setlma) + lma = sac->lma; + if (sac->lma_adjust != 0) + lma += sac->lma_adjust; + if (lma == s->lma) + continue; + +#ifdef DEBUG + printf("LMA for section %s: %#jx\n", s->name, lma); +#endif + + /* Check alignment. */ + if (lma % s->align != 0) + errx(EXIT_FAILURE, "The LMA %#jx for " + "section %s is not aligned to %ju", + (uintmax_t) lma, s->name, (uintmax_t) s->align); + + /* + * Update section LMA. + */ + + if (lma < s->lma) { + /* + * To move a section to lower LMA, we decrease + * the LMA of the section and all the sections that + * are before it. + */ + dl = s->lma - lma; + for (i = 0; i < s->seg->nsec; i++) { + s0 = s->seg->v_sec[i]; + s0->lma -= dl; +#ifdef DEBUG + printf("section %s LMA set to %#jx\n", + s0->name, (uintmax_t) s0->lma); +#endif + if (s0 == s) + break; + } + } else { + /* + * To move a section to upper LMA, we increase + * the LMA of the section and all the sections that + * are after it. + */ + dl = lma - s->lma; + for (i = 0; i < s->seg->nsec; i++) + if (s->seg->v_sec[i] == s) + break; + if (i >= s->seg->nsec) + errx(EXIT_FAILURE, "Internal: section `%s' not" + " found in its containing segement", + s->name); + for (; i < s->seg->nsec; i++) { + s0 = s->seg->v_sec[i]; + s0->lma += dl; +#ifdef DEBUG + printf("section %s LMA set to %#jx\n", + s0->name, (uintmax_t) s0->lma); +#endif + } + } + } + + /* * Issue a warning if there are VMA/LMA adjust requests for * some nonexistent sections. */ if ((ecp->flags & NO_CHANGE_WARN) == 0) { STAILQ_FOREACH(sac, &ecp->v_sac, sac_list) { if (!sac->setvma && !sac->setlma && !sac->vma_adjust && !sac->lma_adjust) continue; found = 0; TAILQ_FOREACH(s, &ecp->v_sec, sec_list) { if (s->pseudo || s->name == NULL) continue; if (!strcmp(s->name, sac->name)) { found = 1; break; } } if (!found) warnx("cannot find section `%s'", sac->name); } } } static void insert_to_inseg_list(struct segment *seg, struct section *sec) { struct section *s; int i; seg->nsec++; seg->v_sec = realloc(seg->v_sec, seg->nsec * sizeof(*seg->v_sec)); if (seg->v_sec == NULL) err(EXIT_FAILURE, "realloc failed"); /* * Sort the section in order of offset. */ for (i = seg->nsec - 1; i > 0; i--) { s = seg->v_sec[i - 1]; if (sec->off >= s->off) { seg->v_sec[i] = sec; break; } else seg->v_sec[i] = s; } if (i == 0) seg->v_sec[0] = sec; } void setup_phdr(struct elfcopy *ecp) { struct segment *seg; GElf_Phdr iphdr; size_t iphnum; int i; if (elf_getphnum(ecp->ein, &iphnum) == 0) errx(EXIT_FAILURE, "elf_getphnum failed: %s", elf_errmsg(-1)); ecp->ophnum = ecp->iphnum = iphnum; if (iphnum == 0) return; /* If --only-keep-debug is specified, discard all program headers. */ if (ecp->strip == STRIP_NONDEBUG) { ecp->ophnum = 0; return; } for (i = 0; (size_t)i < iphnum; i++) { if (gelf_getphdr(ecp->ein, i, &iphdr) != &iphdr) errx(EXIT_FAILURE, "gelf_getphdr failed: %s", elf_errmsg(-1)); if ((seg = calloc(1, sizeof(*seg))) == NULL) err(EXIT_FAILURE, "calloc failed"); - seg->addr = iphdr.p_vaddr; + seg->vaddr = iphdr.p_vaddr; + seg->paddr = iphdr.p_paddr; seg->off = iphdr.p_offset; seg->fsz = iphdr.p_filesz; seg->msz = iphdr.p_memsz; seg->type = iphdr.p_type; STAILQ_INSERT_TAIL(&ecp->v_seg, seg, seg_list); } } void copy_phdr(struct elfcopy *ecp) { struct segment *seg; struct section *s; GElf_Phdr iphdr, ophdr; int i; STAILQ_FOREACH(seg, &ecp->v_seg, seg_list) { if (seg->type == PT_PHDR) { if (!TAILQ_EMPTY(&ecp->v_sec)) { s = TAILQ_FIRST(&ecp->v_sec); - if (s->pseudo) - seg->addr = s->lma + + if (s->pseudo) { + seg->vaddr = s->vma + gelf_fsize(ecp->eout, ELF_T_EHDR, 1, EV_CURRENT); + seg->paddr = s->lma + + gelf_fsize(ecp->eout, ELF_T_EHDR, + 1, EV_CURRENT); + } } seg->fsz = seg->msz = gelf_fsize(ecp->eout, ELF_T_PHDR, ecp->ophnum, EV_CURRENT); continue; } + if (seg->nsec > 0) { + s = seg->v_sec[0]; + seg->vaddr = s->vma; + seg->paddr = s->lma; + } + seg->fsz = seg->msz = 0; for (i = 0; i < seg->nsec; i++) { s = seg->v_sec[i]; - seg->msz = s->vma + s->sz - seg->addr; + seg->msz = s->vma + s->sz - seg->vaddr; if (s->type != SHT_NOBITS) seg->fsz = s->off + s->sz - seg->off; } } /* * Allocate space for program headers, note that libelf keep * track of the number in internal variable, and a call to * elf_update is needed to update e_phnum of ehdr. */ if (gelf_newphdr(ecp->eout, ecp->ophnum) == NULL) errx(EXIT_FAILURE, "gelf_newphdr() failed: %s", elf_errmsg(-1)); /* * This elf_update() call is to update the e_phnum field in * ehdr. It's necessary because later we will call gelf_getphdr(), * which does sanity check by comparing ndx argument with e_phnum. */ if (elf_update(ecp->eout, ELF_C_NULL) < 0) errx(EXIT_FAILURE, "elf_update() failed: %s", elf_errmsg(-1)); /* * iphnum == ophnum, since we don't remove program headers even if * they no longer contain sections. */ i = 0; STAILQ_FOREACH(seg, &ecp->v_seg, seg_list) { if (i >= ecp->iphnum) break; if (gelf_getphdr(ecp->ein, i, &iphdr) != &iphdr) errx(EXIT_FAILURE, "gelf_getphdr failed: %s", elf_errmsg(-1)); if (gelf_getphdr(ecp->eout, i, &ophdr) != &ophdr) errx(EXIT_FAILURE, "gelf_getphdr failed: %s", elf_errmsg(-1)); ophdr.p_type = iphdr.p_type; - ophdr.p_vaddr = seg->addr; - ophdr.p_paddr = seg->addr; + ophdr.p_vaddr = seg->vaddr; + ophdr.p_paddr = seg->paddr; ophdr.p_flags = iphdr.p_flags; ophdr.p_align = iphdr.p_align; ophdr.p_offset = seg->off; ophdr.p_filesz = seg->fsz; ophdr.p_memsz = seg->msz; if (!gelf_update_phdr(ecp->eout, i, &ophdr)) errx(EXIT_FAILURE, "gelf_update_phdr failed: %s", elf_errmsg(-1)); i++; } }