Author: emaste
Date: Thu Oct 25 15:18:54 2018
New Revision: 339726
URL: https://svnweb.freebsd.org/changeset/base/339726

Log:
  MFC r339451: 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
  Approved by:  re (gjb, kib)
  Sponsored by: The FreeBSD Foundation

Modified:
  stable/12/contrib/elftoolchain/elfcopy/sections.c
Directory Properties:
  stable/12/   (props changed)

Modified: stable/12/contrib/elftoolchain/elfcopy/sections.c
==============================================================================
--- stable/12/contrib/elftoolchain/elfcopy/sections.c   Thu Oct 25 15:14:16 
2018        (r339725)
+++ stable/12/contrib/elftoolchain/elfcopy/sections.c   Thu Oct 25 15:18:54 
2018        (r339726)
@@ -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;
 }
 
_______________________________________________
svn-src-all@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to