2 * Copyright (c) 2007-2011,2014 Kai Wang
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 #include <sys/param.h>
37 ELFTC_VCSID("$Id: sections.c 3220 2015-05-24 23:42:39Z kaiwang27 $");
39 static void add_gnu_debuglink(struct elfcopy *ecp);
40 static uint32_t calc_crc32(const char *p, size_t len, uint32_t crc);
41 static void check_section_rename(struct elfcopy *ecp, struct section *s);
42 static void filter_reloc(struct elfcopy *ecp, struct section *s);
43 static int get_section_flags(struct elfcopy *ecp, const char *name);
44 static void insert_sections(struct elfcopy *ecp);
45 static void insert_to_strtab(struct section *t, const char *s);
46 static int is_append_section(struct elfcopy *ecp, const char *name);
47 static int is_compress_section(struct elfcopy *ecp, const char *name);
48 static int is_debug_section(const char *name);
49 static int is_dwo_section(const char *name);
50 static int is_modify_section(struct elfcopy *ecp, const char *name);
51 static int is_print_section(struct elfcopy *ecp, const char *name);
52 static int lookup_string(struct section *t, const char *s);
53 static void modify_section(struct elfcopy *ecp, struct section *s);
54 static void pad_section(struct elfcopy *ecp, struct section *s);
55 static void print_data(const char *d, size_t sz);
56 static void print_section(struct section *s);
57 static void *read_section(struct section *s, size_t *size);
58 static void update_reloc(struct elfcopy *ecp, struct section *s);
59 static void update_section_group(struct elfcopy *ecp, struct section *s);
62 is_remove_section(struct elfcopy *ecp, const char *name)
65 /* Always keep section name table */
66 if (strcmp(name, ".shstrtab") == 0)
68 if (strcmp(name, ".symtab") == 0 ||
69 strcmp(name, ".strtab") == 0) {
70 if (ecp->strip == STRIP_ALL && lookup_symop_list(
71 ecp, NULL, SYMOP_KEEP) == NULL)
77 if (ecp->strip == STRIP_DWO && is_dwo_section(name))
79 if (ecp->strip == STRIP_NONDWO && !is_dwo_section(name))
82 if (is_debug_section(name)) {
83 if (ecp->strip == STRIP_ALL ||
84 ecp->strip == STRIP_DEBUG ||
85 ecp->strip == STRIP_UNNEEDED ||
86 (ecp->flags & DISCARD_LOCAL))
88 if (ecp->strip == STRIP_NONDEBUG)
92 if ((ecp->flags & SEC_REMOVE) || (ecp->flags & SEC_COPY)) {
93 struct sec_action *sac;
95 sac = lookup_sec_act(ecp, name, 0);
96 if ((ecp->flags & SEC_REMOVE) && sac != NULL && sac->remove)
98 if ((ecp->flags & SEC_COPY) && (sac == NULL || !sac->copy))
106 * Relocation section needs to be removed if the section it applies to
110 is_remove_reloc_sec(struct elfcopy *ecp, uint32_t sh_info)
118 if (elf_getshstrndx(ecp->ein, &indx) == 0)
119 errx(EXIT_FAILURE, "elf_getshstrndx failed: %s",
123 while ((is = elf_nextscn(ecp->ein, is)) != NULL) {
124 if (sh_info == elf_ndxscn(is)) {
125 if (gelf_getshdr(is, &ish) == NULL)
126 errx(EXIT_FAILURE, "gelf_getshdr failed: %s",
128 if ((name = elf_strptr(ecp->ein, indx, ish.sh_name)) ==
130 errx(EXIT_FAILURE, "elf_strptr failed: %s",
132 if (is_remove_section(ecp, name))
138 elferr = elf_errno();
140 errx(EXIT_FAILURE, "elf_nextscn failed: %s",
143 /* Remove reloc section if we can't find the target section. */
148 is_append_section(struct elfcopy *ecp, const char *name)
150 struct sec_action *sac;
152 sac = lookup_sec_act(ecp, name, 0);
153 if (sac != NULL && sac->append != 0 && sac->string != NULL)
160 is_compress_section(struct elfcopy *ecp, const char *name)
162 struct sec_action *sac;
164 sac = lookup_sec_act(ecp, name, 0);
165 if (sac != NULL && sac->compress != 0)
172 check_section_rename(struct elfcopy *ecp, struct section *s)
174 struct sec_action *sac;
181 sac = lookup_sec_act(ecp, s->name, 0);
182 if (sac != NULL && sac->rename)
183 s->name = sac->newname;
185 if (!strcmp(s->name, ".symtab") ||
186 !strcmp(s->name, ".strtab") ||
187 !strcmp(s->name, ".shstrtab"))
191 if (s->loadable && ecp->prefix_alloc != NULL)
192 prefix = ecp->prefix_alloc;
193 else if (ecp->prefix_sec != NULL)
194 prefix = ecp->prefix_sec;
196 if (prefix != NULL) {
197 namelen = strlen(s->name) + strlen(prefix) + 1;
198 if ((s->newname = malloc(namelen)) == NULL)
199 err(EXIT_FAILURE, "malloc failed");
200 snprintf(s->newname, namelen, "%s%s", prefix, s->name);
201 s->name = s->newname;
206 get_section_flags(struct elfcopy *ecp, const char *name)
208 struct sec_action *sac;
210 sac = lookup_sec_act(ecp, name, 0);
211 if (sac != NULL && sac->flags)
218 * Determine whether the section are debugging section.
219 * According to libbfd, debugging sections are recognized
223 is_debug_section(const char *name)
225 const char *dbg_sec[] = {
234 for(p = dbg_sec; *p; p++) {
235 if (strncmp(name, *p, strlen(*p)) == 0)
243 is_dwo_section(const char *name)
247 if ((len = strlen(name)) > 4 && strcmp(name + len - 4, ".dwo") == 0)
253 is_print_section(struct elfcopy *ecp, const char *name)
255 struct sec_action *sac;
257 sac = lookup_sec_act(ecp, name, 0);
258 if (sac != NULL && sac->print != 0)
265 is_modify_section(struct elfcopy *ecp, const char *name)
268 if (is_append_section(ecp, name) ||
269 is_compress_section(ecp, name))
276 lookup_sec_act(struct elfcopy *ecp, const char *name, int add)
278 struct sec_action *sac;
283 STAILQ_FOREACH(sac, &ecp->v_sac, sac_list) {
284 if (strcmp(name, sac->name) == 0)
291 if ((sac = malloc(sizeof(*sac))) == NULL)
292 errx(EXIT_FAILURE, "not enough memory");
293 memset(sac, 0, sizeof(*sac));
295 STAILQ_INSERT_TAIL(&ecp->v_sac, sac, sac_list);
301 free_sec_act(struct elfcopy *ecp)
303 struct sec_action *sac, *sac_temp;
305 STAILQ_FOREACH_SAFE(sac, &ecp->v_sac, sac_list, sac_temp) {
306 STAILQ_REMOVE(&ecp->v_sac, sac, sec_action, sac_list);
312 insert_to_sec_list(struct elfcopy *ecp, struct section *sec, int tail)
317 TAILQ_FOREACH(s, &ecp->v_sec, sec_list) {
318 if (sec->off < s->off) {
319 TAILQ_INSERT_BEFORE(s, sec, sec_list);
325 TAILQ_INSERT_TAIL(&ecp->v_sec, sec, sec_list);
328 if (sec->pseudo == 0)
333 * First step of section creation: create scn and internal section
334 * structure, discard sections to be removed.
337 create_scn(struct elfcopy *ecp)
344 uint64_t oldndx, newndx;
345 int elferr, sec_flags;
348 * Insert a pseudo section that contains the ELF header
349 * and program header. Used as reference for section offset
350 * or load address adjustment.
352 if ((s = calloc(1, sizeof(*s))) == NULL)
353 err(EXIT_FAILURE, "calloc failed");
355 s->sz = gelf_fsize(ecp->eout, ELF_T_EHDR, 1, EV_CURRENT) +
356 gelf_fsize(ecp->eout, ELF_T_PHDR, ecp->ophnum, EV_CURRENT);
359 s->loadable = add_to_inseg_list(ecp, s);
360 insert_to_sec_list(ecp, s, 0);
362 /* Create internal .shstrtab section. */
365 if (elf_getshstrndx(ecp->ein, &indx) == 0)
366 errx(EXIT_FAILURE, "elf_getshstrndx failed: %s",
370 while ((is = elf_nextscn(ecp->ein, is)) != NULL) {
371 if (gelf_getshdr(is, &ish) == NULL)
372 errx(EXIT_FAILURE, "219 gelf_getshdr failed: %s",
374 if ((name = elf_strptr(ecp->ein, indx, ish.sh_name)) == NULL)
375 errx(EXIT_FAILURE, "elf_strptr failed: %s",
378 /* Skip sections to be removed. */
379 if (is_remove_section(ecp, name))
383 * Relocation section need to be remove if the section
384 * it applies will be removed.
386 if (ish.sh_type == SHT_REL || ish.sh_type == SHT_RELA)
387 if (ish.sh_info != 0 &&
388 is_remove_reloc_sec(ecp, ish.sh_info))
392 * Section groups should be removed if symbol table will
393 * be removed. (section group's signature stored in symbol
396 if (ish.sh_type == SHT_GROUP && ecp->strip == STRIP_ALL)
399 /* Get section flags set by user. */
400 sec_flags = get_section_flags(ecp, name);
402 /* Create internal section object. */
403 if (strcmp(name, ".shstrtab") != 0) {
404 if ((s = calloc(1, sizeof(*s))) == NULL)
405 err(EXIT_FAILURE, "calloc failed");
408 s->off = ish.sh_offset;
410 s->align = ish.sh_addralign;
411 s->type = ish.sh_type;
412 s->vma = ish.sh_addr;
415 * Search program headers to determine whether section
416 * is loadable, but if user explicitly set section flags
417 * while neither "load" nor "alloc" is set, we make the
418 * section unloadable.
421 (sec_flags & (SF_LOAD | SF_ALLOC)) == 0)
424 s->loadable = add_to_inseg_list(ecp, s);
426 /* Assuming .shstrtab is "unloadable". */
428 s->off = ish.sh_offset;
431 oldndx = newndx = SHN_UNDEF;
432 if (strcmp(name, ".symtab") != 0 &&
433 strcmp(name, ".strtab") != 0) {
434 if (!strcmp(name, ".shstrtab")) {
436 * Add sections specified by --add-section and
437 * gnu debuglink. we want these sections have
438 * smaller index than .shstrtab section.
440 if (ecp->debuglink != NULL)
441 add_gnu_debuglink(ecp);
442 if (ecp->flags & SEC_ADD)
443 insert_sections(ecp);
445 if ((s->os = elf_newscn(ecp->eout)) == NULL)
446 errx(EXIT_FAILURE, "elf_newscn failed: %s",
448 if ((newndx = elf_ndxscn(s->os)) == SHN_UNDEF)
449 errx(EXIT_FAILURE, "elf_ndxscn failed: %s",
452 if ((oldndx = elf_ndxscn(is)) == SHN_UNDEF)
453 errx(EXIT_FAILURE, "elf_ndxscn failed: %s",
455 if (oldndx != SHN_UNDEF && newndx != SHN_UNDEF)
456 ecp->secndx[oldndx] = newndx;
459 * If strip action is STRIP_NONDEBUG(only keep debug),
460 * change sections flags of loadable sections to SHF_NOBITS,
461 * and the content of those sections will be ignored.
463 if (ecp->strip == STRIP_NONDEBUG && (ish.sh_flags & SHF_ALLOC))
464 s->type = SHT_NOBITS;
466 check_section_rename(ecp, s);
468 /* create section header based on input object. */
469 if (strcmp(name, ".symtab") != 0 &&
470 strcmp(name, ".strtab") != 0 &&
471 strcmp(name, ".shstrtab") != 0)
472 copy_shdr(ecp, s, NULL, 0, sec_flags);
474 if (strcmp(name, ".symtab") == 0) {
475 ecp->flags |= SYMTAB_EXIST;
478 if (strcmp(name, ".strtab") == 0)
481 insert_to_sec_list(ecp, s, 0);
483 elferr = elf_errno();
485 errx(EXIT_FAILURE, "elf_nextscn failed: %s",
490 insert_shtab(struct elfcopy *ecp, int tail)
492 struct section *s, *shtab;
497 * Treat section header table as a "pseudo" section, insert it
498 * into section list, so later it will get sorted and resynced
499 * just as normal sections.
501 if ((shtab = calloc(1, sizeof(*shtab))) == NULL)
502 errx(EXIT_FAILURE, "calloc failed");
505 * "shoff" of input object is used as a hint for section
508 if (gelf_getehdr(ecp->ein, &ieh) == NULL)
509 errx(EXIT_FAILURE, "gelf_getehdr() failed: %s",
511 shtab->off = ieh.e_shoff;
514 /* Calculate number of sections in the output object. */
516 TAILQ_FOREACH(s, &ecp->v_sec, sec_list) {
520 /* Remember there is always a null section, so we +1 here. */
521 shtab->sz = gelf_fsize(ecp->eout, ELF_T_SHDR, nsecs + 1, EV_CURRENT);
523 errx(EXIT_FAILURE, "gelf_fsize() failed: %s", elf_errmsg(-1));
524 shtab->align = (ecp->oec == ELFCLASS32 ? 4 : 8);
527 insert_to_sec_list(ecp, shtab, tail);
533 copy_content(struct elfcopy *ecp)
537 TAILQ_FOREACH(s, &ecp->v_sec, sec_list) {
538 /* Skip pseudo section. */
542 /* Skip special sections. */
543 if (strcmp(s->name, ".symtab") == 0 ||
544 strcmp(s->name, ".strtab") == 0 ||
545 strcmp(s->name, ".shstrtab") == 0)
549 * If strip action is STRIP_ALL, relocation info need
550 * to be stripped. Skip filtering otherwisw.
552 if (ecp->strip == STRIP_ALL &&
553 (s->type == SHT_REL || s->type == SHT_RELA))
554 filter_reloc(ecp, s);
557 * The section indices in the SHT_GROUP section needs
558 * to be updated since we might have stripped some
559 * sections and changed section numbering.
561 if (s->type == SHT_GROUP)
562 update_section_group(ecp, s);
564 if (is_modify_section(ecp, s->name))
565 modify_section(ecp, s);
570 * If symbol table is modified, relocation info might
571 * need update, as symbol index may have changed.
573 if ((ecp->flags & SYMTAB_INTACT) == 0 &&
574 (ecp->flags & SYMTAB_EXIST) &&
575 (s->type == SHT_REL || s->type == SHT_RELA))
576 update_reloc(ecp, s);
578 if (is_print_section(ecp, s->name))
585 * Update section group section. The section indices in the SHT_GROUP
586 * section need update after section numbering changed.
589 update_section_group(struct elfcopy *ecp, struct section *s)
598 if (!elf_getshnum(ecp->ein, &ishnum))
599 errx(EXIT_FAILURE, "elf_getshnum failed: %s",
602 if (gelf_getshdr(s->is, &ish) == NULL)
603 errx(EXIT_FAILURE, "gelf_getehdr() failed: %s",
606 if ((id = elf_getdata(s->is, NULL)) == NULL)
607 errx(EXIT_FAILURE, "elf_getdata() failed: %s",
610 if (ish.sh_size == 0)
613 if (ish.sh_entsize == 0)
618 /* We only support COMDAT section. */
620 #define GRP_COMDAT 0x1
622 if ((*ws & GRP_COMDAT) == 0)
625 if ((s->buf = malloc(ish.sh_size)) == NULL)
626 err(EXIT_FAILURE, "malloc failed");
632 /* Copy the flag word as-is. */
635 /* Update the section indices. */
636 n = ish.sh_size / ish.sh_entsize;
637 for(i = 1, j = 1; (uint64_t)i < n; i++) {
638 if (ws[i] != SHN_UNDEF && ws[i] < ishnum &&
639 ecp->secndx[ws[i]] != 0)
640 wd[j++] = ecp->secndx[ws[i]];
649 * Filter relocation entries, only keep those entries whose
650 * symbol is in the keep list.
653 filter_reloc(struct elfcopy *ecp, struct section *s)
664 uint64_t cap, n, nrels;
667 if (gelf_getshdr(s->is, &ish) == NULL)
668 errx(EXIT_FAILURE, "gelf_getehdr() failed: %s",
671 /* We don't want to touch relocation info for dynamic symbols. */
672 if ((ecp->flags & SYMTAB_EXIST) == 0) {
673 if (ish.sh_link == 0 || ecp->secndx[ish.sh_link] == 0) {
675 * This reloc section applies to the symbol table
676 * that was stripped, so discard whole section.
683 /* Symbol table exist, check if index equals. */
684 if (ish.sh_link != elf_ndxscn(ecp->symtab->is))
688 #define COPYREL(REL, SZ) do { \
690 if ((REL##SZ = malloc(cap * \
691 sizeof(Elf##SZ##_Rel))) == NULL) \
692 err(EXIT_FAILURE, "malloc failed"); \
694 if (nrels >= cap) { \
696 if ((REL##SZ = realloc(REL##SZ, cap * \
697 sizeof(Elf##SZ##_Rel))) == NULL) \
698 err(EXIT_FAILURE, "realloc failed"); \
700 REL##SZ[nrels].r_offset = REL.r_offset; \
701 REL##SZ[nrels].r_info = REL.r_info; \
702 if (s->type == SHT_RELA) \
703 rela##SZ[nrels].r_addend = rela.r_addend; \
708 cap = 4; /* keep list is usually small. */
713 if ((id = elf_getdata(s->is, NULL)) == NULL)
714 errx(EXIT_FAILURE, "elf_getdata() failed: %s",
716 n = ish.sh_size / ish.sh_entsize;
717 for(i = 0; (uint64_t)i < n; i++) {
718 if (s->type == SHT_REL) {
719 if (gelf_getrel(id, i, &rel) != &rel)
720 errx(EXIT_FAILURE, "gelf_getrel failed: %s",
723 if (gelf_getrela(id, i, &rela) != &rela)
724 errx(EXIT_FAILURE, "gelf_getrel failed: %s",
727 name = elf_strptr(ecp->ein, elf_ndxscn(ecp->strtab->is),
728 GELF_R_SYM(rel.r_info));
730 errx(EXIT_FAILURE, "elf_strptr failed: %s",
732 if (lookup_symop_list(ecp, name, SYMOP_KEEP) != NULL) {
733 if (ecp->oec == ELFCLASS32) {
734 if (s->type == SHT_REL)
739 if (s->type == SHT_REL)
746 elferr = elf_errno();
748 errx(EXIT_FAILURE, "elf_getdata() failed: %s",
751 if (ecp->oec == ELFCLASS32) {
752 if (s->type == SHT_REL)
757 if (s->type == SHT_REL)
762 s->sz = gelf_fsize(ecp->eout, (s->type == SHT_REL ? ELF_T_REL :
763 ELF_T_RELA), nrels, EV_CURRENT);
768 update_reloc(struct elfcopy *ecp, struct section *s)
777 #define UPDATEREL(REL) do { \
778 if (gelf_get##REL(od, i, &REL) != &REL) \
779 errx(EXIT_FAILURE, "gelf_get##REL failed: %s", \
781 REL.r_info = GELF_R_INFO(ecp->symndx[GELF_R_SYM(REL.r_info)], \
782 GELF_R_TYPE(REL.r_info)); \
783 if (!gelf_update_##REL(od, i, &REL)) \
784 errx(EXIT_FAILURE, "gelf_update_##REL failed: %s", \
790 if (gelf_getshdr(s->os, &osh) == NULL)
791 errx(EXIT_FAILURE, "gelf_getehdr() failed: %s",
793 /* Only process .symtab reloc info. */
794 if (osh.sh_link != elf_ndxscn(ecp->symtab->is))
796 if ((od = elf_getdata(s->os, NULL)) == NULL)
797 errx(EXIT_FAILURE, "elf_getdata() failed: %s",
799 n = osh.sh_size / osh.sh_entsize;
800 for(i = 0; (uint64_t)i < n; i++) {
801 if (s->type == SHT_REL)
809 pad_section(struct elfcopy *ecp, struct section *s)
814 if (s == NULL || s->pad_sz == 0)
817 if ((s->pad = malloc(s->pad_sz)) == NULL)
818 err(EXIT_FAILURE, "malloc failed");
819 memset(s->pad, ecp->fill, s->pad_sz);
821 /* Create a new Elf_Data to contain the padding bytes. */
822 if ((od = elf_newdata(s->os)) == NULL)
823 errx(EXIT_FAILURE, "elf_newdata() failed: %s",
828 od->d_type = ELF_T_BYTE;
829 od->d_size = s->pad_sz;
830 od->d_version = EV_CURRENT;
832 /* Update section header. */
833 if (gelf_getshdr(s->os, &osh) == NULL)
834 errx(EXIT_FAILURE, "gelf_getshdr() failed: %s",
836 osh.sh_size = s->sz + s->pad_sz;
837 if (!gelf_update_shdr(s->os, &osh))
838 errx(EXIT_FAILURE, "elf_update_shdr failed: %s",
843 resync_sections(struct elfcopy *ecp)
845 struct section *s, *ps;
853 TAILQ_FOREACH(s, &ecp->v_sec, sec_list) {
860 * Ignore TLS sections with load address 0 and without
861 * content. We don't need to adjust their file offset or
862 * VMA, only the size matters.
864 if (s->seg_tls != NULL && s->type == SHT_NOBITS &&
868 /* Align section offset. */
873 s->off = roundup(off, s->align);
876 warnx("moving loadable section %s, "
877 "is this intentional?", s->name);
878 s->off = roundup(off, s->align);
881 /* Calculate next section offset. */
883 if (s->pseudo || (s->type != SHT_NOBITS && s->type != SHT_NULL))
891 /* Count padding bytes added through --pad-to. */
895 /* Update section header accordingly. */
896 if (gelf_getshdr(s->os, &osh) == NULL)
897 errx(EXIT_FAILURE, "gelf_getshdr() failed: %s",
899 osh.sh_addr = s->vma;
900 osh.sh_offset = s->off;
902 if (!gelf_update_shdr(s->os, &osh))
903 errx(EXIT_FAILURE, "elf_update_shdr failed: %s",
906 /* Add padding for previous section, if need. */
908 if (ps->pad_sz > 0) {
909 /* Apply padding added by --pad-to. */
910 pad_section(ecp, ps);
911 } else if ((ecp->flags & GAP_FILL) &&
912 (ps->off + ps->sz < s->off)) {
914 * Fill the gap between sections by padding
915 * the section with lower address.
917 ps->pad_sz = s->off - (ps->off + ps->sz);
918 pad_section(ecp, ps);
925 /* Pad the last section, if need. */
926 if (ps != NULL && ps->pad_sz > 0)
927 pad_section(ecp, ps);
931 modify_section(struct elfcopy *ecp, struct section *s)
933 struct sec_action *sac;
934 size_t srcsz, dstsz, p, len;
935 char *b, *c, *d, *src, *end;
938 src = read_section(s, &srcsz);
939 if (src == NULL || srcsz == 0) {
940 /* For empty section, we proceed if we need to append. */
941 if (!is_append_section(ecp, s->name))
945 /* Allocate buffer needed for new section data. */
947 if (is_append_section(ecp, s->name)) {
948 sac = lookup_sec_act(ecp, s->name, 0);
949 dstsz += strlen(sac->string) + 1;
951 if ((b = malloc(dstsz)) == NULL)
952 err(EXIT_FAILURE, "malloc failed");
955 /* Compress section. */
957 if (is_compress_section(ecp, s->name)) {
959 for(c = src; c < end;) {
961 while(c + len < end && c[len] != '\0')
963 if (c + len == end) {
964 /* XXX should we warn here? */
965 strncpy(&b[p], c, len);
970 for (d = b; d < b + p; ) {
971 if (strcmp(d, c) == 0) {
978 strncpy(&b[p], c, len);
985 memcpy(b, src, srcsz);
989 /* Append section. */
990 if (is_append_section(ecp, s->name)) {
991 sac = lookup_sec_act(ecp, s->name, 0);
992 len = strlen(sac->string);
993 strncpy(&b[p], sac->string, len);
1003 print_data(const char *d, size_t sz)
1007 for (c = d; c < d + sz; c++) {
1016 print_section(struct section *s)
1021 if (s->buf != NULL && s->sz > 0) {
1022 print_data(s->buf, s->sz);
1025 while ((id = elf_getdata(s->is, id)) != NULL)
1026 print_data(id->d_buf, id->d_size);
1027 elferr = elf_errno();
1029 errx(EXIT_FAILURE, "elf_getdata() failed: %s",
1030 elf_errmsg(elferr));
1036 read_section(struct section *s, size_t *size)
1046 while ((id = elf_getdata(s->is, id)) != NULL) {
1048 b = malloc(id->d_size);
1050 b = malloc(sz + id->d_size);
1052 err(EXIT_FAILURE, "malloc or realloc failed");
1054 memcpy(&b[sz], id->d_buf, id->d_size);
1057 elferr = elf_errno();
1059 errx(EXIT_FAILURE, "elf_getdata() failed: %s",
1060 elf_errmsg(elferr));
1068 copy_shdr(struct elfcopy *ecp, struct section *s, const char *name, int copy,
1073 if (gelf_getshdr(s->is, &ish) == NULL)
1074 errx(EXIT_FAILURE, "526 gelf_getshdr() failed: %s",
1076 if (gelf_getshdr(s->os, &osh) == NULL)
1077 errx(EXIT_FAILURE, "529 gelf_getshdr() failed: %s",
1081 (void) memcpy(&osh, &ish, sizeof(ish));
1083 osh.sh_type = s->type;
1084 osh.sh_addr = s->vma;
1085 osh.sh_offset = s->off;
1086 osh.sh_size = s->sz;
1087 osh.sh_link = ish.sh_link;
1088 osh.sh_info = ish.sh_info;
1089 osh.sh_addralign = s->align;
1090 osh.sh_entsize = ish.sh_entsize;
1094 if (sec_flags & SF_ALLOC) {
1095 osh.sh_flags |= SHF_ALLOC;
1097 warnx("set SHF_ALLOC flag for "
1098 "unloadable section %s",
1101 if ((sec_flags & SF_READONLY) == 0)
1102 osh.sh_flags |= SHF_WRITE;
1103 if (sec_flags & SF_CODE)
1104 osh.sh_flags |= SHF_EXECINSTR;
1106 osh.sh_flags = ish.sh_flags;
1107 if (ish.sh_type == SHT_REL || ish.sh_type == SHT_RELA)
1108 osh.sh_flags |= SHF_INFO_LINK;
1113 add_to_shstrtab(ecp, s->name);
1115 add_to_shstrtab(ecp, name);
1117 if (!gelf_update_shdr(s->os, &osh))
1118 errx(EXIT_FAILURE, "elf_update_shdr failed: %s",
1123 copy_data(struct section *s)
1128 if (s->nocopy && s->buf == NULL)
1131 if ((id = elf_getdata(s->is, NULL)) == NULL) {
1132 elferr = elf_errno();
1134 errx(EXIT_FAILURE, "elf_getdata() failed: %s",
1135 elf_errmsg(elferr));
1139 if ((od = elf_newdata(s->os)) == NULL)
1140 errx(EXIT_FAILURE, "elf_newdata() failed: %s",
1144 /* Use s->buf as content if s->nocopy is set. */
1145 od->d_align = id->d_align;
1148 od->d_type = id->d_type;
1150 od->d_version = id->d_version;
1152 od->d_align = id->d_align;
1153 od->d_off = id->d_off;
1154 od->d_buf = id->d_buf;
1155 od->d_type = id->d_type;
1156 od->d_size = id->d_size;
1157 od->d_version = id->d_version;
1161 * Alignment Fixup. libelf does not allow the alignment for
1162 * Elf_Data descriptor to be set to 0. In this case we workaround
1163 * it by setting the alignment to 1.
1165 * According to the ELF ABI, alignment 0 and 1 has the same
1166 * meaning: the section has no alignment constraints.
1168 if (od->d_align == 0)
1173 create_external_section(struct elfcopy *ecp, const char *name, char *newname,
1174 void *buf, uint64_t size, uint64_t off, uint64_t stype, Elf_Type dtype,
1175 uint64_t flags, uint64_t align, uint64_t vma, int loadable)
1182 if ((os = elf_newscn(ecp->eout)) == NULL)
1183 errx(EXIT_FAILURE, "elf_newscn() failed: %s",
1185 if ((s = calloc(1, sizeof(*s))) == NULL)
1186 err(EXIT_FAILURE, "calloc failed");
1188 s->newname = newname; /* needs to be free()'ed */
1193 s->loadable = loadable;
1198 insert_to_sec_list(ecp, s, 1);
1200 if (gelf_getshdr(os, &osh) == NULL)
1201 errx(EXIT_FAILURE, "gelf_getshdr() failed: %s",
1203 osh.sh_flags = flags;
1204 osh.sh_type = s->type;
1205 osh.sh_addr = s->vma;
1206 osh.sh_addralign = s->align;
1207 if (!gelf_update_shdr(os, &osh))
1208 errx(EXIT_FAILURE, "gelf_update_shdr() failed: %s",
1210 add_to_shstrtab(ecp, name);
1212 if (buf != NULL && size != 0) {
1213 if ((od = elf_newdata(os)) == NULL)
1214 errx(EXIT_FAILURE, "elf_newdata() failed: %s",
1216 od->d_align = align;
1221 od->d_version = EV_CURRENT;
1225 * Clear SYMTAB_INTACT, as we probably need to update/add new
1226 * STT_SECTION symbols into the symbol table.
1228 ecp->flags &= ~SYMTAB_INTACT;
1234 * Insert sections specified by --add-section to the end of section list.
1237 insert_sections(struct elfcopy *ecp)
1243 /* Put these sections in the end of current list. */
1245 TAILQ_FOREACH(s, &ecp->v_sec, sec_list) {
1246 if (s->type != SHT_NOBITS && s->type != SHT_NULL)
1247 off = s->off + s->sz;
1252 STAILQ_FOREACH(sa, &ecp->v_sadd, sadd_list) {
1254 /* TODO: Add section header vma/lma, flag changes here */
1256 (void) create_external_section(ecp, sa->name, NULL, sa->content,
1257 sa->size, off, SHT_PROGBITS, ELF_T_BYTE, 0, 1, 0, 0);
1262 add_to_shstrtab(struct elfcopy *ecp, const char *name)
1267 insert_to_strtab(s, name);
1271 update_shdr(struct elfcopy *ecp, int update_link)
1277 TAILQ_FOREACH(s, &ecp->v_sec, sec_list) {
1281 if (gelf_getshdr(s->os, &osh) == NULL)
1282 errx(EXIT_FAILURE, "668 gelf_getshdr failed: %s",
1285 /* Find section name in string table and set sh_name. */
1286 osh.sh_name = lookup_string(ecp->shstrtab, s->name);
1289 * sh_link needs to be updated, since the index of the
1290 * linked section might have changed.
1292 if (update_link && osh.sh_link != 0)
1293 osh.sh_link = ecp->secndx[osh.sh_link];
1296 * sh_info of relocation section links to the section to which
1297 * its relocation info applies. So it may need update as well.
1299 if ((s->type == SHT_REL || s->type == SHT_RELA) &&
1301 osh.sh_info = ecp->secndx[osh.sh_info];
1304 * sh_info of SHT_GROUP section needs to point to the correct
1305 * string in the symbol table.
1307 if (s->type == SHT_GROUP && (ecp->flags & SYMTAB_EXIST) &&
1308 (ecp->flags & SYMTAB_INTACT) == 0)
1309 osh.sh_info = ecp->symndx[osh.sh_info];
1311 if (!gelf_update_shdr(s->os, &osh))
1312 errx(EXIT_FAILURE, "gelf_update_shdr() failed: %s",
1315 elferr = elf_errno();
1317 errx(EXIT_FAILURE, "elf_nextscn failed: %s",
1318 elf_errmsg(elferr));
1322 init_shstrtab(struct elfcopy *ecp)
1326 if ((ecp->shstrtab = calloc(1, sizeof(*ecp->shstrtab))) == NULL)
1327 err(EXIT_FAILURE, "calloc failed");
1329 s->name = ".shstrtab";
1334 s->type = SHT_STRTAB;
1337 insert_to_strtab(s, "");
1338 insert_to_strtab(s, ".symtab");
1339 insert_to_strtab(s, ".strtab");
1340 insert_to_strtab(s, ".shstrtab");
1344 set_shstrtab(struct elfcopy *ecp)
1352 if (s->os == NULL) {
1353 /* Input object does not contain .shstrtab section */
1354 if ((s->os = elf_newscn(ecp->eout)) == NULL)
1355 errx(EXIT_FAILURE, "elf_newscn failed: %s",
1357 insert_to_sec_list(ecp, s, 1);
1360 if (gelf_getshdr(s->os, &sh) == NULL)
1361 errx(EXIT_FAILURE, "692 gelf_getshdr() failed: %s",
1364 sh.sh_addralign = 1;
1365 sh.sh_offset = s->off;
1366 sh.sh_type = SHT_STRTAB;
1372 if ((data = elf_newdata(s->os)) == NULL)
1373 errx(EXIT_FAILURE, "elf_newdata() failed: %s",
1377 * If we don't have a symbol table, skip those a few bytes
1378 * which are reserved for this in the beginning of shstrtab.
1380 if (!(ecp->flags & SYMTAB_EXIST)) {
1381 s->sz -= sizeof(".symtab\0.strtab");
1382 memmove(s->buf, (char *)s->buf + sizeof(".symtab\0.strtab"),
1387 if (!gelf_update_shdr(s->os, &sh))
1388 errx(EXIT_FAILURE, "gelf_update_shdr() failed: %s",
1392 data->d_buf = s->buf;
1393 data->d_size = s->sz;
1395 data->d_type = ELF_T_BYTE;
1396 data->d_version = EV_CURRENT;
1398 if (!elf_setshstrndx(ecp->eout, elf_ndxscn(s->os)))
1399 errx(EXIT_FAILURE, "elf_setshstrndx() failed: %s",
1404 add_section(struct elfcopy *ecp, const char *arg)
1412 if ((s = strchr(arg, '=')) == NULL)
1414 "illegal format for --add-section option");
1415 if ((sa = malloc(sizeof(*sa))) == NULL)
1416 err(EXIT_FAILURE, "malloc failed");
1419 if ((sa->name = malloc(len + 1)) == NULL)
1420 err(EXIT_FAILURE, "malloc failed");
1421 strncpy(sa->name, arg, len);
1422 sa->name[len] = '\0';
1425 if (stat(fn, &sb) == -1)
1426 err(EXIT_FAILURE, "stat failed");
1427 sa->size = sb.st_size;
1428 if ((sa->content = malloc(sa->size)) == NULL)
1429 err(EXIT_FAILURE, "malloc failed");
1430 if ((fp = fopen(fn, "r")) == NULL)
1431 err(EXIT_FAILURE, "can not open %s", fn);
1432 if (fread(sa->content, 1, sa->size, fp) == 0 ||
1434 err(EXIT_FAILURE, "fread failed");
1437 STAILQ_INSERT_TAIL(&ecp->v_sadd, sa, sadd_list);
1438 ecp->flags |= SEC_ADD;
1442 free_sec_add(struct elfcopy *ecp)
1444 struct sec_add *sa, *sa_temp;
1446 STAILQ_FOREACH_SAFE(sa, &ecp->v_sadd, sadd_list, sa_temp) {
1447 STAILQ_REMOVE(&ecp->v_sadd, sa, sec_add, sadd_list);
1455 add_gnu_debuglink(struct elfcopy *ecp)
1464 if (ecp->debuglink == NULL)
1467 /* Read debug file content. */
1468 if ((sa = malloc(sizeof(*sa))) == NULL)
1469 err(EXIT_FAILURE, "malloc failed");
1470 if ((sa->name = strdup(".gnu_debuglink")) == NULL)
1471 err(EXIT_FAILURE, "strdup failed");
1472 if (stat(ecp->debuglink, &sb) == -1)
1473 err(EXIT_FAILURE, "stat failed");
1474 if ((buf = malloc(sb.st_size)) == NULL)
1475 err(EXIT_FAILURE, "malloc failed");
1476 if ((fp = fopen(ecp->debuglink, "r")) == NULL)
1477 err(EXIT_FAILURE, "can not open %s", ecp->debuglink);
1478 if (fread(buf, 1, sb.st_size, fp) == 0 ||
1480 err(EXIT_FAILURE, "fread failed");
1483 /* Calculate crc checksum. */
1484 crc = calc_crc32(buf, sb.st_size, 0xFFFFFFFF);
1487 /* Calculate section size and the offset to store crc checksum. */
1488 if ((fnbase = basename(ecp->debuglink)) == NULL)
1489 err(EXIT_FAILURE, "basename failed");
1490 crc_off = roundup(strlen(fnbase) + 1, 4);
1491 sa->size = crc_off + 4;
1493 /* Section content. */
1494 if ((sa->content = calloc(1, sa->size)) == NULL)
1495 err(EXIT_FAILURE, "malloc failed");
1496 strncpy(sa->content, fnbase, strlen(fnbase));
1497 if (ecp->oed == ELFDATA2LSB) {
1498 sa->content[crc_off] = crc & 0xFF;
1499 sa->content[crc_off + 1] = (crc >> 8) & 0xFF;
1500 sa->content[crc_off + 2] = (crc >> 16) & 0xFF;
1501 sa->content[crc_off + 3] = crc >> 24;
1503 sa->content[crc_off] = crc >> 24;
1504 sa->content[crc_off + 1] = (crc >> 16) & 0xFF;
1505 sa->content[crc_off + 2] = (crc >> 8) & 0xFF;
1506 sa->content[crc_off + 3] = crc & 0xFF;
1509 STAILQ_INSERT_TAIL(&ecp->v_sadd, sa, sadd_list);
1510 ecp->flags |= SEC_ADD;
1514 insert_to_strtab(struct section *t, const char *s)
1523 if ((t->buf = malloc(t->cap)) == NULL)
1524 err(EXIT_FAILURE, "malloc failed");
1530 for (c = b; c < b + t->sz;) {
1532 if (!append && len >= slen) {
1533 r = c + (len - slen);
1534 if (strcmp(r, s) == 0)
1536 } else if (len < slen && len != 0) {
1537 r = s + (slen - len);
1538 if (strcmp(c, r) == 0) {
1540 memmove(c, c + len + 1, t->sz - (c - b));
1548 while (t->sz + slen + 1 >= t->cap) {
1550 if ((t->buf = realloc(t->buf, t->cap)) == NULL)
1551 err(EXIT_FAILURE, "realloc failed");
1554 strncpy(&b[t->sz], s, slen);
1555 b[t->sz + slen] = '\0';
1560 lookup_string(struct section *t, const char *s)
1562 const char *b, *c, *r;
1567 for (c = b; c < b + t->sz;) {
1570 r = c + (len - slen);
1571 if (strcmp(r, s) == 0)
1580 static uint32_t crctable[256] =
1582 0x00000000L, 0x77073096L, 0xEE0E612CL, 0x990951BAL,
1583 0x076DC419L, 0x706AF48FL, 0xE963A535L, 0x9E6495A3L,
1584 0x0EDB8832L, 0x79DCB8A4L, 0xE0D5E91EL, 0x97D2D988L,
1585 0x09B64C2BL, 0x7EB17CBDL, 0xE7B82D07L, 0x90BF1D91L,
1586 0x1DB71064L, 0x6AB020F2L, 0xF3B97148L, 0x84BE41DEL,
1587 0x1ADAD47DL, 0x6DDDE4EBL, 0xF4D4B551L, 0x83D385C7L,
1588 0x136C9856L, 0x646BA8C0L, 0xFD62F97AL, 0x8A65C9ECL,
1589 0x14015C4FL, 0x63066CD9L, 0xFA0F3D63L, 0x8D080DF5L,
1590 0x3B6E20C8L, 0x4C69105EL, 0xD56041E4L, 0xA2677172L,
1591 0x3C03E4D1L, 0x4B04D447L, 0xD20D85FDL, 0xA50AB56BL,
1592 0x35B5A8FAL, 0x42B2986CL, 0xDBBBC9D6L, 0xACBCF940L,
1593 0x32D86CE3L, 0x45DF5C75L, 0xDCD60DCFL, 0xABD13D59L,
1594 0x26D930ACL, 0x51DE003AL, 0xC8D75180L, 0xBFD06116L,
1595 0x21B4F4B5L, 0x56B3C423L, 0xCFBA9599L, 0xB8BDA50FL,
1596 0x2802B89EL, 0x5F058808L, 0xC60CD9B2L, 0xB10BE924L,
1597 0x2F6F7C87L, 0x58684C11L, 0xC1611DABL, 0xB6662D3DL,
1598 0x76DC4190L, 0x01DB7106L, 0x98D220BCL, 0xEFD5102AL,
1599 0x71B18589L, 0x06B6B51FL, 0x9FBFE4A5L, 0xE8B8D433L,
1600 0x7807C9A2L, 0x0F00F934L, 0x9609A88EL, 0xE10E9818L,
1601 0x7F6A0DBBL, 0x086D3D2DL, 0x91646C97L, 0xE6635C01L,
1602 0x6B6B51F4L, 0x1C6C6162L, 0x856530D8L, 0xF262004EL,
1603 0x6C0695EDL, 0x1B01A57BL, 0x8208F4C1L, 0xF50FC457L,
1604 0x65B0D9C6L, 0x12B7E950L, 0x8BBEB8EAL, 0xFCB9887CL,
1605 0x62DD1DDFL, 0x15DA2D49L, 0x8CD37CF3L, 0xFBD44C65L,
1606 0x4DB26158L, 0x3AB551CEL, 0xA3BC0074L, 0xD4BB30E2L,
1607 0x4ADFA541L, 0x3DD895D7L, 0xA4D1C46DL, 0xD3D6F4FBL,
1608 0x4369E96AL, 0x346ED9FCL, 0xAD678846L, 0xDA60B8D0L,
1609 0x44042D73L, 0x33031DE5L, 0xAA0A4C5FL, 0xDD0D7CC9L,
1610 0x5005713CL, 0x270241AAL, 0xBE0B1010L, 0xC90C2086L,
1611 0x5768B525L, 0x206F85B3L, 0xB966D409L, 0xCE61E49FL,
1612 0x5EDEF90EL, 0x29D9C998L, 0xB0D09822L, 0xC7D7A8B4L,
1613 0x59B33D17L, 0x2EB40D81L, 0xB7BD5C3BL, 0xC0BA6CADL,
1614 0xEDB88320L, 0x9ABFB3B6L, 0x03B6E20CL, 0x74B1D29AL,
1615 0xEAD54739L, 0x9DD277AFL, 0x04DB2615L, 0x73DC1683L,
1616 0xE3630B12L, 0x94643B84L, 0x0D6D6A3EL, 0x7A6A5AA8L,
1617 0xE40ECF0BL, 0x9309FF9DL, 0x0A00AE27L, 0x7D079EB1L,
1618 0xF00F9344L, 0x8708A3D2L, 0x1E01F268L, 0x6906C2FEL,
1619 0xF762575DL, 0x806567CBL, 0x196C3671L, 0x6E6B06E7L,
1620 0xFED41B76L, 0x89D32BE0L, 0x10DA7A5AL, 0x67DD4ACCL,
1621 0xF9B9DF6FL, 0x8EBEEFF9L, 0x17B7BE43L, 0x60B08ED5L,
1622 0xD6D6A3E8L, 0xA1D1937EL, 0x38D8C2C4L, 0x4FDFF252L,
1623 0xD1BB67F1L, 0xA6BC5767L, 0x3FB506DDL, 0x48B2364BL,
1624 0xD80D2BDAL, 0xAF0A1B4CL, 0x36034AF6L, 0x41047A60L,
1625 0xDF60EFC3L, 0xA867DF55L, 0x316E8EEFL, 0x4669BE79L,
1626 0xCB61B38CL, 0xBC66831AL, 0x256FD2A0L, 0x5268E236L,
1627 0xCC0C7795L, 0xBB0B4703L, 0x220216B9L, 0x5505262FL,
1628 0xC5BA3BBEL, 0xB2BD0B28L, 0x2BB45A92L, 0x5CB36A04L,
1629 0xC2D7FFA7L, 0xB5D0CF31L, 0x2CD99E8BL, 0x5BDEAE1DL,
1630 0x9B64C2B0L, 0xEC63F226L, 0x756AA39CL, 0x026D930AL,
1631 0x9C0906A9L, 0xEB0E363FL, 0x72076785L, 0x05005713L,
1632 0x95BF4A82L, 0xE2B87A14L, 0x7BB12BAEL, 0x0CB61B38L,
1633 0x92D28E9BL, 0xE5D5BE0DL, 0x7CDCEFB7L, 0x0BDBDF21L,
1634 0x86D3D2D4L, 0xF1D4E242L, 0x68DDB3F8L, 0x1FDA836EL,
1635 0x81BE16CDL, 0xF6B9265BL, 0x6FB077E1L, 0x18B74777L,
1636 0x88085AE6L, 0xFF0F6A70L, 0x66063BCAL, 0x11010B5CL,
1637 0x8F659EFFL, 0xF862AE69L, 0x616BFFD3L, 0x166CCF45L,
1638 0xA00AE278L, 0xD70DD2EEL, 0x4E048354L, 0x3903B3C2L,
1639 0xA7672661L, 0xD06016F7L, 0x4969474DL, 0x3E6E77DBL,
1640 0xAED16A4AL, 0xD9D65ADCL, 0x40DF0B66L, 0x37D83BF0L,
1641 0xA9BCAE53L, 0xDEBB9EC5L, 0x47B2CF7FL, 0x30B5FFE9L,
1642 0xBDBDF21CL, 0xCABAC28AL, 0x53B39330L, 0x24B4A3A6L,
1643 0xBAD03605L, 0xCDD70693L, 0x54DE5729L, 0x23D967BFL,
1644 0xB3667A2EL, 0xC4614AB8L, 0x5D681B02L, 0x2A6F2B94L,
1645 0xB40BBE37L, 0xC30C8EA1L, 0x5A05DF1BL, 0x2D02EF8DL
1649 calc_crc32(const char *p, size_t len, uint32_t crc)
1653 for (i = 0; i < len; i++) {
1654 crc = crctable[(crc ^ *p++) & 0xFFL] ^ (crc >> 8);
1657 return (crc ^ 0xFFFFFFFF);