--- contrib/elftoolchain/elfcopy/sections.c	2018/10/20 17:22:04	339450
+++ contrib/elftoolchain/elfcopy/sections.c	2018/10/20 17:27:53	339451
@@ -39,6 +39,7 @@
 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 @@
 			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.
@@ -664,6 +673,140 @@
 	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;
+}
+
 static void
 update_reloc(struct elfcopy *ecp, struct section *s)
 {
