summaryrefslogtreecommitdiffstats
path: root/contrib/elftoolchain/elfcopy
diff options
context:
space:
mode:
authoremaste <emaste@FreeBSD.org>2015-05-27 14:28:19 +0000
committeremaste <emaste@FreeBSD.org>2015-05-27 14:28:19 +0000
commitaa01a21e0c7d20fb276cc0628a159a595e0e617e (patch)
tree74d3c6f019cc59be7b175c8db630ad55260c4062 /contrib/elftoolchain/elfcopy
parentabf78a3a279a4db8cb4d6cc74dae9ae4c35003e4 (diff)
downloadFreeBSD-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.h3
-rw-r--r--contrib/elftoolchain/elfcopy/main.c20
-rw-r--r--contrib/elftoolchain/elfcopy/sections.c81
-rw-r--r--contrib/elftoolchain/elfcopy/symbols.c94
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
OpenPOWER on IntegriCloud