if (shdr_info[shdr_info[cnt].group_idx].idx == 0)
{
- /* The section group section will be removed. */
+ /* The section group section might be removed.
+ Don't remove the SHF_GROUP flag. The section is
+ either also removed, in which case the flag doesn't matter.
+ Or it moves with the group into the debug file, then
+ it will be reconnected with the new group and should
+ still have the flag set. */
shdr_info[cnt].group_idx = 0;
- shdr_info[cnt].shdr.sh_flags &= ~SHF_GROUP;
}
}
&& shdr_info[cnt].data->d_buf != NULL);
Elf32_Word *grpref = (Elf32_Word *) shdr_info[cnt].data->d_buf;
- for (size_t inner = 0;
+ /* First word is the section group flag.
+ Followed by section indexes, that need to be renumbered. */
+ for (size_t inner = 1;
inner < shdr_info[cnt].data->d_size / sizeof (Elf32_Word);
++inner)
if (grpref[inner] < shnum)
{
Elf_Scn *scn;
const char *name;
+ const char *sig;
Elf_Scn *outscn;
Dwelf_Strent *strent;
GElf_Shdr shdr;
static int
compare_unalloc_sections (const GElf_Shdr *shdr1, const GElf_Shdr *shdr2,
- const char *name1, const char *name2)
+ const char *name1, const char *name2,
+ const char *sig1, const char *sig2)
{
/* Sort by sh_flags as an arbitrary ordering. */
if (shdr1->sh_flags < shdr2->sh_flags)
if (shdr1->sh_size > shdr2->sh_size)
return 1;
+ /* Are they both SHT_GROUP sections? Then compare signatures. */
+ if (sig1 != NULL && sig2 != NULL)
+ return strcmp (sig1, sig2);
+
/* Sort by name as last resort. */
return strcmp (name1, name2);
}
return ((s1->shdr.sh_flags & SHF_ALLOC)
? compare_alloc_sections (s1, s2, rel)
: compare_unalloc_sections (&s1->shdr, &s2->shdr,
- s1->name, s2->name));
+ s1->name, s2->name,
+ s1->sig, s2->sig));
}
static int
return shstrtab->d_buf + shdr->sh_name;
}
+/* Returns the signature of a group section, or NULL if the given
+ section isn't a group. */
+static const char *
+get_group_sig (Elf *elf, GElf_Shdr *shdr)
+{
+ if (shdr->sh_type != SHT_GROUP)
+ return NULL;
+
+ Elf_Scn *symscn = elf_getscn (elf, shdr->sh_link);
+ if (symscn == NULL)
+ error (EXIT_FAILURE, 0, _("bad sh_link for group section: %s"),
+ elf_errmsg (-1));
+
+ GElf_Shdr symshdr_mem;
+ GElf_Shdr *symshdr = gelf_getshdr (symscn, &symshdr_mem);
+ if (symshdr == NULL)
+ error (EXIT_FAILURE, 0, _("couldn't get shdr for group section: %s"),
+ elf_errmsg (-1));
+
+ Elf_Data *symdata = elf_getdata (symscn, NULL);
+ if (symdata == NULL)
+ error (EXIT_FAILURE, 0, _("bad data for group symbol section: %s"),
+ elf_errmsg (-1));
+
+ GElf_Sym sym_mem;
+ GElf_Sym *sym = gelf_getsym (symdata, shdr->sh_info, &sym_mem);
+ if (sym == NULL)
+ error (EXIT_FAILURE, 0, _("couldn't get symbol for group section: %s"),
+ elf_errmsg (-1));
+
+ const char *sig = elf_strptr (elf, symshdr->sh_link, sym->st_name);
+ if (sig == NULL)
+ error (EXIT_FAILURE, 0, _("bad symbol name for group section: %s"),
+ elf_errmsg (-1));
+
+ return sig;
+}
+
/* Fix things up when prelink has moved some allocated sections around
and the debuginfo file's section headers no longer match up.
This fills in SECTIONS[0..NALLOC-1].outscn or exits.
sec->scn = elf_getscn (main, i + 1); /* Really just for ndx. */
sec->outscn = NULL;
sec->strent = NULL;
+ sec->sig = get_group_sig (main, &sec->shdr);
++undo_nalloc;
}
}
sections[i].scn = scn;
sections[i].outscn = NULL;
sections[i].strent = NULL;
+ sections[i].sig = get_group_sig (stripped, shdr);
}
const struct section *stripped_symtab = NULL;
/* Locate a matching unallocated section in SECTIONS. */
inline struct section *find_unalloc_section (const GElf_Shdr *shdr,
- const char *name)
+ const char *name,
+ const char *sig)
{
size_t l = nalloc, u = stripped_shnum - 1;
while (l < u)
size_t i = (l + u) / 2;
struct section *sec = §ions[i];
int cmp = compare_unalloc_sections (shdr, &sec->shdr,
- name, sec->name);
+ name, sec->name,
+ sig, sec->sig);
if (cmp < 0)
u = i;
else if (cmp > 0)
else
{
/* Look for the section that matches. */
- sec = find_unalloc_section (shdr, name);
+ sec = find_unalloc_section (shdr, name,
+ get_group_sig (unstripped, shdr));
if (sec == NULL)
{
/* An additional unallocated section is fine if not SHT_NOBITS.
testrun ${abs_top_builddir}/src/elfcmp testfile-annobingroup-i386.o remerged.elf
+# echo "void * foo (void) { return foo; }" > testfile-annobingroup-x86_64.c
+# gcc -g -O2 -fplugin=annobin -c testfile-annobingroup-x86_64.c
+testfiles testfile-annobingroup-x86_64.o
+
+testrun_compare ${abs_top_builddir}/src/readelf -g testfile-annobingroup-x86_64.o << EOF
+
+Section group [ 1] '.group' with signature '.text.hot.group' contains 3 entries:
+ [11] .text.hot
+ [12] .gnu.build.attributes.hot
+ [13] .rela.gnu.build.attributes.hot
+
+Section group [ 2] '.group' with signature '.text.unlikely.group' contains 3 entries:
+ [14] .text.unlikely
+ [15] .gnu.build.attributes.unlikely
+ [16] .rela.gnu.build.attributes.unlikely
+
+Section group [ 3] '.group' with signature '.text.hot..group' contains 1 entry:
+ [26] .text.hot
+
+Section group [ 4] '.group' with signature '.text.unlikely..group' contains 1 entry:
+ [27] .text.unlikely
+EOF
+
+testrun ${abs_top_builddir}/src/strip -o stripped.elf -f debugfile.elf testfile-annobingroup-x86_64.o
+
+# This would/should work, except for the unknown NOTEs.
+# testrun ${abs_top_builddir}/src/elflint --gnu stripped.elf
+# testrun ${abs_top_builddir}/src/elflint --gnu --debug debugfile.elf
+
+testrun ${abs_top_builddir}/src/unstrip -o remerged.elf stripped.elf debugfile.elf
+
+testrun ${abs_top_builddir}/src/elfcmp testfile-annobingroup-x86_64.o remerged.elf
+
exit 0