svn commit: r339451 - head/contrib/elftoolchain/elfcopy

Ed Maste emaste at FreeBSD.org
Sat Oct 20 17:27:54 UTC 2018


Author: emaste
Date: Sat Oct 20 17:27:53 2018
New Revision: 339451
URL: https://svnweb.freebsd.org/changeset/base/339451

Log:
  objcopy: restore behaviour required by GCC's build
  
  In r339350 filter_reloc() was removed, to fix the case of stripping
  statically linked binaries with relocations (which may come from ifunc
  use, for example).  As a side effect this changed the behaviour when
  stripping object files - the output was broken both before and after
  r339350, in different ways.  Unfortunately GCC's build process relies
  on the previous behaviour, so:
  
  - Revert r339350, restoring filter_reloc().
  - Fix an unitialized variable use (commited as r3638 in ELF Tool Chain).
  - Change filter_reloc() to omit relocations referencing removed
    symbols, while retaining relocations with no symbol reference.
  - Retain the entire relocation section if it references the dynamic
    symbol table (fix from kaiw in D17596).
  
  PR:		232176
  Reported by:	antoine
  Reviewed by:	kaiw
  MFC with:	r339350
  Sponsored by:	The FreeBSD Foundation
  Differential Revision:	https://reviews.freebsd.org/D17596

Modified:
  head/contrib/elftoolchain/elfcopy/sections.c

Modified: head/contrib/elftoolchain/elfcopy/sections.c
==============================================================================
--- head/contrib/elftoolchain/elfcopy/sections.c	Sat Oct 20 17:22:04 2018	(r339450)
+++ head/contrib/elftoolchain/elfcopy/sections.c	Sat Oct 20 17:27:53 2018	(r339451)
@@ -39,6 +39,7 @@ ELFTC_VCSID("$Id: sections.c 3443 2016-04-15 18:57:54Z
 static void	add_gnu_debuglink(struct elfcopy *ecp);
 static uint32_t calc_crc32(const char *p, size_t len, uint32_t crc);
 static void	check_section_rename(struct elfcopy *ecp, struct section *s);
+static void	filter_reloc(struct elfcopy *ecp, struct section *s);
 static int	get_section_flags(struct elfcopy *ecp, const char *name);
 static void	insert_sections(struct elfcopy *ecp);
 static void	insert_to_strtab(struct section *t, const char *s);
@@ -573,6 +574,14 @@ copy_content(struct elfcopy *ecp)
 			continue;
 
 		/*
+		 * If strip action is STRIP_ALL, relocation info need
+		 * to be stripped. Skip filtering otherwisw.
+		 */
+		if (ecp->strip == STRIP_ALL &&
+		    (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.
@@ -661,6 +670,140 @@ update_section_group(struct elfcopy *ecp, struct secti
 			s->sz -= 4;
 	}
 
+	s->nocopy = 1;
+}
+
+/*
+ * Filter relocation entries, only keep those entries whose
+ * symbol is in the keep list.
+ */
+static void
+filter_reloc(struct elfcopy *ecp, struct section *s)
+{
+	const char	*name;
+	GElf_Shdr	 ish;
+	GElf_Rel	 rel;
+	GElf_Rela	 rela;
+	Elf32_Rel	*rel32;
+	Elf64_Rel	*rel64;
+	Elf32_Rela	*rela32;
+	Elf64_Rela	*rela64;
+	Elf_Data	*id;
+	uint64_t	 cap, n, nrels, sym;
+	int		 elferr, i;
+
+	if (gelf_getshdr(s->is, &ish) == NULL)
+		errx(EXIT_FAILURE, "gelf_getehdr() failed: %s",
+		    elf_errmsg(-1));
+
+	/* We don't want to touch relocation info for dynamic symbols. */
+	if ((ecp->flags & SYMTAB_EXIST) == 0) {
+		/*
+		 * No symbol table in output.  If sh_link points to a section
+		 * that exists in the output object, this relocation section
+		 * is for dynamic symbols.  Don't touch it.
+		 */
+		if (ish.sh_link != 0 && ecp->secndx[ish.sh_link] != 0)
+			return;
+	} else {
+		/* Symbol table exist, check if index equals. */
+		if (ish.sh_link != elf_ndxscn(ecp->symtab->is))
+			return;
+	}
+
+#define	COPYREL(REL, SZ) do {					\
+	if (nrels == 0) {					\
+		if ((REL##SZ = malloc(cap *			\
+		    sizeof(*REL##SZ))) == NULL)			\
+			err(EXIT_FAILURE, "malloc failed");	\
+	}							\
+	if (nrels >= cap) {					\
+		cap *= 2;					\
+		if ((REL##SZ = realloc(REL##SZ, cap *		\
+		    sizeof(*REL##SZ))) == NULL)			\
+			err(EXIT_FAILURE, "realloc failed");	\
+	}							\
+	REL##SZ[nrels].r_offset = REL.r_offset;			\
+	REL##SZ[nrels].r_info	= REL.r_info;			\
+	if (s->type == SHT_RELA)				\
+		rela##SZ[nrels].r_addend = rela.r_addend;	\
+	nrels++;						\
+} while (0)
+
+	nrels = 0;
+	cap = 4;		/* keep list is usually small. */
+	rel32 = NULL;
+	rel64 = NULL;
+	rela32 = NULL;
+	rela64 = NULL;
+	if ((id = elf_getdata(s->is, NULL)) == NULL)
+		errx(EXIT_FAILURE, "elf_getdata() failed: %s",
+		    elf_errmsg(-1));
+	n = ish.sh_size / ish.sh_entsize;
+	for(i = 0; (uint64_t)i < n; i++) {
+		if (s->type == SHT_REL) {
+			if (gelf_getrel(id, i, &rel) != &rel)
+				errx(EXIT_FAILURE, "gelf_getrel failed: %s",
+				    elf_errmsg(-1));
+			sym = GELF_R_SYM(rel.r_info);
+		} else {
+			if (gelf_getrela(id, i, &rela) != &rela)
+				errx(EXIT_FAILURE, "gelf_getrel failed: %s",
+				    elf_errmsg(-1));
+			sym = GELF_R_SYM(rela.r_info);
+		}
+		/*
+		 * If a relocation references a symbol and we are omitting
+		 * either that symbol or the entire symbol table we cannot
+		 * produce valid output, and so just omit the relocation.
+		 * Broken output like this is generally not useful, but some
+		 * uses of elfcopy/strip rely on it - for example, GCC's build
+		 * process uses it to check for build reproducibility by
+		 * stripping objects and comparing them.
+		 *
+		 * Relocations that do not reference a symbol are retained.
+		 */
+		if (sym != 0) {
+			if (ish.sh_link == 0 || ecp->secndx[ish.sh_link] == 0)
+				continue;
+			name = elf_strptr(ecp->ein, elf_ndxscn(ecp->strtab->is),
+			    sym);
+			if (name == NULL)
+				errx(EXIT_FAILURE, "elf_strptr failed: %s",
+				    elf_errmsg(-1));
+			if (lookup_symop_list(ecp, name, SYMOP_KEEP) == NULL)
+				continue;
+		}
+		if (ecp->oec == ELFCLASS32) {
+			if (s->type == SHT_REL)
+				COPYREL(rel, 32);
+			else
+				COPYREL(rela, 32);
+		} else {
+			if (s->type == SHT_REL)
+				COPYREL(rel, 64);
+			else
+				COPYREL(rela, 64);
+		}
+	}
+	elferr = elf_errno();
+	if (elferr != 0)
+		errx(EXIT_FAILURE, "elf_getdata() failed: %s",
+		    elf_errmsg(elferr));
+
+	if (ecp->oec == ELFCLASS32) {
+		if (s->type == SHT_REL)
+			s->buf = rel32;
+		else
+			s->buf = rela32;
+	} else {
+		if (s->type == SHT_REL)
+			s->buf = rel64;
+		else
+			s->buf = rela64;
+	}
+	s->sz = gelf_fsize(ecp->eout, (s->type == SHT_REL ? ELF_T_REL :
+	    ELF_T_RELA), nrels, EV_CURRENT);
 	s->nocopy = 1;
 }
 


More information about the svn-src-head mailing list