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
This commit is contained in:
parent
ebf86f573a
commit
9447c73201
@ -39,6 +39,7 @@ ELFTC_VCSID("$Id: sections.c 3443 2016-04-15 18:57:54Z kaiwang27 $");
|
||||
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);
|
||||
@ -572,6 +573,14 @@ copy_content(struct elfcopy *ecp)
|
||||
strcmp(s->name, ".shstrtab") == 0)
|
||||
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
|
||||
@ -664,6 +673,140 @@ update_section_group(struct elfcopy *ecp, struct section *s)
|
||||
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)
|
||||
{
|
||||
|
Loading…
x
Reference in New Issue
Block a user