diff options
author | emaste <emaste@FreeBSD.org> | 2015-05-27 14:28:19 +0000 |
---|---|---|
committer | emaste <emaste@FreeBSD.org> | 2015-05-27 14:28:19 +0000 |
commit | aa01a21e0c7d20fb276cc0628a159a595e0e617e (patch) | |
tree | 74d3c6f019cc59be7b175c8db630ad55260c4062 /contrib/elftoolchain/elfcopy | |
parent | abf78a3a279a4db8cb4d6cc74dae9ae4c35003e4 (diff) | |
download | FreeBSD-src-aa01a21e0c7d20fb276cc0628a159a595e0e617e.zip FreeBSD-src-aa01a21e0c7d20fb276cc0628a159a595e0e617e.tar.gz |
Update to ELF Tool Chain r3223
Highlights (upstream revisions):
- Fix SHT_GROUP handling in elfcopy/strip (3206 3220 3221)
- Misc elfcopy / strip bug fixes (3215 3216 3217)
- Many C++ demangler improvements (3199 3200 3201 3202 3203 3204 3205
3208 3210 3211 3212)
- Improve GNU binutils compatibility in elfcopy / strip (3213 3214)
- Add -g option to readelf(1): dump contents of section groups (3219)
- Add EM_IAMCU 32-bit Intel MCU (3198)
Also add a compat #define for building with older FreeBSD ELF headers.
The GRP_COMDAT flag was added to elf_common.h in r283110, but it's not
available during the bootstrap build. It is also convenient to be able
to build on older hosts.
Thanks to antoine@ for tracking down issues through multiple exp-runs
and to kaiw@ for fixing.
PR: 198611 (exp-run), 200350
Sponsored by: The FreeBSD Foundation
Diffstat (limited to 'contrib/elftoolchain/elfcopy')
-rw-r--r-- | contrib/elftoolchain/elfcopy/elfcopy.h | 3 | ||||
-rw-r--r-- | contrib/elftoolchain/elfcopy/main.c | 20 | ||||
-rw-r--r-- | contrib/elftoolchain/elfcopy/sections.c | 81 | ||||
-rw-r--r-- | contrib/elftoolchain/elfcopy/symbols.c | 94 |
4 files changed, 185 insertions, 13 deletions
diff --git a/contrib/elftoolchain/elfcopy/elfcopy.h b/contrib/elftoolchain/elfcopy/elfcopy.h index b750246..48574b5 100644 --- a/contrib/elftoolchain/elfcopy/elfcopy.h +++ b/contrib/elftoolchain/elfcopy/elfcopy.h @@ -23,7 +23,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: elfcopy.h 3173 2015-03-27 16:46:13Z emaste $ + * $Id: elfcopy.h 3221 2015-05-24 23:42:43Z kaiwang27 $ */ #include <sys/queue.h> @@ -237,6 +237,7 @@ struct elfcopy { 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. */ diff --git a/contrib/elftoolchain/elfcopy/main.c b/contrib/elftoolchain/elfcopy/main.c index a48aea5..cbd48d3 100644 --- a/contrib/elftoolchain/elfcopy/main.c +++ b/contrib/elftoolchain/elfcopy/main.c @@ -39,7 +39,7 @@ #include "elfcopy.h" -ELFTC_VCSID("$Id: main.c 3174 2015-03-27 17:13:41Z emaste $"); +ELFTC_VCSID("$Id: main.c 3216 2015-05-23 21:16:36Z kaiwang27 $"); enum options { @@ -404,8 +404,19 @@ create_elf(struct elfcopy *ecp) * Insert SHDR table into the internal section list as a "pseudo" * section, so later it will get sorted and resynced just as "normal" * sections. + * + * Under FreeBSD, Binutils objcopy always put the section header + * at the end of all the sections. We want to do the same here. + * + * However, note that the behaviour is still different with Binutils: + * elfcopy checks the FreeBSD OSABI tag to tell whether it needs to + * move the section headers, while Binutils is probably configured + * this way when it's compiled on FreeBSD. */ - shtab = insert_shtab(ecp, 0); + if (oeh.e_ident[EI_OSABI] == ELFOSABI_FREEBSD) + shtab = insert_shtab(ecp, 1); + else + shtab = insert_shtab(ecp, 0); /* * Resync section offsets in the output object. This is needed @@ -485,6 +496,11 @@ free_elf(struct elfcopy *ecp) free(sec); } } + + if (ecp->secndx != NULL) { + free(ecp->secndx); + ecp->secndx = NULL; + } } /* Create a temporary file. */ diff --git a/contrib/elftoolchain/elfcopy/sections.c b/contrib/elftoolchain/elfcopy/sections.c index 7c43a35..a407a42 100644 --- a/contrib/elftoolchain/elfcopy/sections.c +++ b/contrib/elftoolchain/elfcopy/sections.c @@ -34,7 +34,7 @@ #include "elfcopy.h" -ELFTC_VCSID("$Id: sections.c 3185 2015-04-11 08:56:34Z kaiwang27 $"); +ELFTC_VCSID("$Id: sections.c 3220 2015-05-24 23:42:39Z kaiwang27 $"); static void add_gnu_debuglink(struct elfcopy *ecp); static uint32_t calc_crc32(const char *p, size_t len, uint32_t crc); @@ -56,6 +56,7 @@ static void print_data(const char *d, size_t sz); static void print_section(struct section *s); static void *read_section(struct section *s, size_t *size); static void update_reloc(struct elfcopy *ecp, struct section *s); +static void update_section_group(struct elfcopy *ecp, struct section *s); int is_remove_section(struct elfcopy *ecp, const char *name) @@ -552,6 +553,14 @@ copy_content(struct elfcopy *ecp) (s->type == SHT_REL || s->type == SHT_RELA)) filter_reloc(ecp, s); + /* + * The section indices in the SHT_GROUP section needs + * to be updated since we might have stripped some + * sections and changed section numbering. + */ + if (s->type == SHT_GROUP) + update_section_group(ecp, s); + if (is_modify_section(ecp, s->name)) modify_section(ecp, s); @@ -571,6 +580,71 @@ copy_content(struct elfcopy *ecp) } } + +/* + * Update section group section. The section indices in the SHT_GROUP + * section need update after section numbering changed. + */ +static void +update_section_group(struct elfcopy *ecp, struct section *s) +{ + GElf_Shdr ish; + Elf_Data *id; + uint32_t *ws, *wd; + uint64_t n; + size_t ishnum; + int i, j; + + if (!elf_getshnum(ecp->ein, &ishnum)) + errx(EXIT_FAILURE, "elf_getshnum failed: %s", + elf_errmsg(-1)); + + if (gelf_getshdr(s->is, &ish) == NULL) + errx(EXIT_FAILURE, "gelf_getehdr() failed: %s", + elf_errmsg(-1)); + + if ((id = elf_getdata(s->is, NULL)) == NULL) + errx(EXIT_FAILURE, "elf_getdata() failed: %s", + elf_errmsg(-1)); + + if (ish.sh_size == 0) + return; + + if (ish.sh_entsize == 0) + ish.sh_entsize = 4; + + ws = id->d_buf; + + /* We only support COMDAT section. */ +#ifndef GRP_COMDAT +#define GRP_COMDAT 0x1 +#endif + if ((*ws & GRP_COMDAT) == 0) + return; + + if ((s->buf = malloc(ish.sh_size)) == NULL) + err(EXIT_FAILURE, "malloc failed"); + + s->sz = ish.sh_size; + + wd = s->buf; + + /* Copy the flag word as-is. */ + *wd = *ws; + + /* Update the section indices. */ + n = ish.sh_size / ish.sh_entsize; + for(i = 1, j = 1; (uint64_t)i < n; i++) { + if (ws[i] != SHN_UNDEF && ws[i] < ishnum && + ecp->secndx[ws[i]] != 0) + wd[j++] = ecp->secndx[ws[i]]; + else + s->sz -= 4; + } + + s->nocopy = 1; +} + /* * Filter relocation entries, only keep those entries whose * symbol is in the keep list. @@ -1028,8 +1102,11 @@ copy_shdr(struct elfcopy *ecp, struct section *s, const char *name, int copy, osh.sh_flags |= SHF_WRITE; if (sec_flags & SF_CODE) osh.sh_flags |= SHF_EXECINSTR; - } else + } else { osh.sh_flags = ish.sh_flags; + if (ish.sh_type == SHT_REL || ish.sh_type == SHT_RELA) + osh.sh_flags |= SHF_INFO_LINK; + } } if (name == NULL) diff --git a/contrib/elftoolchain/elfcopy/symbols.c b/contrib/elftoolchain/elfcopy/symbols.c index 4a7d38a..05bcd7a 100644 --- a/contrib/elftoolchain/elfcopy/symbols.c +++ b/contrib/elftoolchain/elfcopy/symbols.c @@ -33,7 +33,7 @@ #include "elfcopy.h" -ELFTC_VCSID("$Id: symbols.c 3191 2015-05-04 17:07:01Z jkoshy $"); +ELFTC_VCSID("$Id: symbols.c 3222 2015-05-24 23:47:23Z kaiwang27 $"); /* Symbol table buffer structure. */ struct symbuf { @@ -77,7 +77,8 @@ static int is_weak_symbol(unsigned char st_info); static int lookup_exact_string(hash_head *hash, const char *buf, const char *s); static int generate_symbols(struct elfcopy *ecp); -static void mark_symbols(struct elfcopy *ecp, size_t sc); +static void mark_reloc_symbols(struct elfcopy *ecp, size_t sc); +static void mark_section_group_symbols(struct elfcopy *ecp, size_t sc); static int match_wildcard(const char *name, const char *pattern); uint32_t str_hash(const char *s); @@ -160,6 +161,10 @@ is_needed_symbol(struct elfcopy *ecp, int i, GElf_Sym *s) if (BIT_ISSET(ecp->v_rel, i)) return (1); + /* Symbols refered by COMDAT sections are needed. */ + if (BIT_ISSET(ecp->v_grp, i)) + return (1); + /* * For relocatable files (.o files), global and weak symbols * are needed. @@ -207,7 +212,10 @@ is_remove_symbol(struct elfcopy *ecp, size_t sc, int i, GElf_Sym *s, return (1); if (ecp->v_rel == NULL) - mark_symbols(ecp, sc); + mark_reloc_symbols(ecp, sc); + + if (ecp->v_grp == NULL) + mark_section_group_symbols(ecp, sc); if (is_needed_symbol(ecp, i, s)) return (0); @@ -233,7 +241,7 @@ is_remove_symbol(struct elfcopy *ecp, size_t sc, int i, GElf_Sym *s, * Mark symbols refered by relocation entries. */ static void -mark_symbols(struct elfcopy *ecp, size_t sc) +mark_reloc_symbols(struct elfcopy *ecp, size_t sc) { const char *name; Elf_Data *d; @@ -311,6 +319,49 @@ mark_symbols(struct elfcopy *ecp, size_t sc) elf_errmsg(elferr)); } +static void +mark_section_group_symbols(struct elfcopy *ecp, size_t sc) +{ + const char *name; + Elf_Scn *s; + GElf_Shdr sh; + size_t indx; + int elferr; + + ecp->v_grp = calloc((sc + 7) / 8, 1); + if (ecp->v_grp == NULL) + err(EXIT_FAILURE, "calloc failed"); + + if (elf_getshstrndx(ecp->ein, &indx) == 0) + errx(EXIT_FAILURE, "elf_getshstrndx failed: %s", + elf_errmsg(-1)); + + s = NULL; + while ((s = elf_nextscn(ecp->ein, s)) != NULL) { + if (gelf_getshdr(s, &sh) != &sh) + errx(EXIT_FAILURE, "elf_getshdr failed: %s", + elf_errmsg(-1)); + + if (sh.sh_type != SHT_GROUP) + continue; + + if ((name = elf_strptr(ecp->ein, indx, sh.sh_name)) == NULL) + errx(EXIT_FAILURE, "elf_strptr failed: %s", + elf_errmsg(-1)); + if (is_remove_section(ecp, name)) + continue; + + if (sh.sh_info > 0 && sh.sh_info < sc) + BIT_SET(ecp->v_grp, sh.sh_info); + else if (sh.sh_info != 0) + warnx("invalid symbox index"); + } + elferr = elf_errno(); + if (elferr != 0) + errx(EXIT_FAILURE, "elf_nextscn failed: %s", + elf_errmsg(elferr)); +} + static int generate_symbols(struct elfcopy *ecp) { @@ -351,6 +402,8 @@ generate_symbols(struct elfcopy *ecp) ecp->symtab->buf = sy_buf; ecp->strtab->buf = st_buf; + gsym = NULL; + /* * Create bit vector v_secsym, which is used to mark sections * that already have corresponding STT_SECTION symbols. @@ -384,7 +437,7 @@ generate_symbols(struct elfcopy *ecp) /* Symbol table should exist if this function is called. */ if (symndx == 0) { warnx("can't find .strtab section"); - return (0); + goto clean; } /* Locate .symtab of input object. */ @@ -413,7 +466,6 @@ generate_symbols(struct elfcopy *ecp) * output object, it is used by update_reloc() later to update * relocation information. */ - gsym = NULL; sc = ish.sh_size / ish.sh_entsize; if (sc > 0) { ecp->symndx = calloc(sc, sizeof(*ecp->symndx)); @@ -427,7 +479,7 @@ generate_symbols(struct elfcopy *ecp) if (elferr != 0) errx(EXIT_FAILURE, "elf_getdata failed: %s", elf_errmsg(elferr)); - return (0); + goto clean; } } else return (0); @@ -523,7 +575,7 @@ generate_symbols(struct elfcopy *ecp) * check if that only local symbol is the reserved symbol. */ if (sy_buf->nls <= 1 && sy_buf->ngs == 0) - return (0); + goto clean; /* * Create STT_SECTION symbols for sections that do not already @@ -550,6 +602,7 @@ generate_symbols(struct elfcopy *ecp) sym.st_value = s->vma; sym.st_size = 0; sym.st_info = GELF_ST_INFO(STB_LOCAL, STT_SECTION); + sym.st_other = STV_DEFAULT; /* * Don't let add_to_symtab() touch sym.st_shndx. * In this case, we know the index already. @@ -583,6 +636,12 @@ generate_symbols(struct elfcopy *ecp) } return (1); + +clean: + free(gsym); + free_symtab(ecp); + + return (0); } void @@ -624,7 +683,9 @@ create_symtab(struct elfcopy *ecp) if (((ecp->flags & SYMTAB_INTACT) == 0) && !generate_symbols(ecp)) { TAILQ_REMOVE(&ecp->v_sec, ecp->symtab, sec_list); TAILQ_REMOVE(&ecp->v_sec, ecp->strtab, sec_list); + free(ecp->symtab->buf); free(ecp->symtab); + free(ecp->strtab->buf); free(ecp->strtab); ecp->symtab = NULL; ecp->strtab = NULL; @@ -697,6 +758,23 @@ free_symtab(struct elfcopy *ecp) } } } + + if (ecp->symndx != NULL) { + free(ecp->symndx); + ecp->symndx = NULL; + } + if (ecp->v_rel != NULL) { + free(ecp->v_rel); + ecp->v_rel = NULL; + } + if (ecp->v_grp != NULL) { + free(ecp->v_grp); + ecp->v_grp = NULL; + } + if (ecp->v_secsym != NULL) { + free(ecp->v_secsym); + ecp->v_secsym = NULL; + } } void |