ELF: Add support for unique section ID to assembler

Clang's integrated assembler supports multiple section with the same
name:

	.section .text,"ax",@progbits,unique,1
	nop
	.section .text,"ax",@progbits,unique,2
	nop

"unique,N" assigns the number, N, as the section ID, to a section.  The
valid values of the section ID are between 0 and 4294967295.  It can be
used to distinguish different sections with the same section name.

This is useful with -fno-unique-section-names -ffunction-sections.
-ffunction-sections by default generates .text.foo, .text.bar, etc.
Using the same string can save lots of space in .strtab.

This patch adds section_id to bfd_section and reuses the linker
internal bit in BFD section flags, SEC_LINKER_CREATED, for assmebler
internal use to mark valid section_id.  It also updates objdump to
compare section pointers if 2 sections comes from the same file since
2 different sections can have the same section name.

bfd/

	PR gas/25380
	* bfd-in2.h: Regenerated.
	* ecoff.c (bfd_debug_section): Add section_id.
	* section.c (bfd_section): Add section_id.
	(SEC_ASSEMBLER_SECTION_ID): New.
	(BFD_FAKE_SECTION): Add section_id.

binutils/

	PR gas/25380
	* objdump.c (sym_ok): Return FALSE if 2 sections are in the
	same file with different section pointers.

gas/

	PR gas/25380
	* config/obj-elf.c (section_match): Removed.
	(get_section): Also match SEC_ASSEMBLER_SECTION_ID and
	section_id.
	(obj_elf_change_section): Replace info and group_name arguments
	with match_p.  Also update the section ID and flags from match_p.
	(obj_elf_section): Handle "unique,N".  Update call to
	obj_elf_change_section.
	* config/obj-elf.h (elf_section_match): New.
	(obj_elf_change_section): Updated.
	* config/tc-arm.c (start_unwind_section): Update call to
	obj_elf_change_section.
	* config/tc-ia64.c (obj_elf_vms_common): Likewise.
	* config/tc-microblaze.c (microblaze_s_data): Likewise.
	(microblaze_s_sdata): Likewise.
	(microblaze_s_rdata): Likewise.
	(microblaze_s_bss): Likewise.
	* config/tc-mips.c (s_change_section): Likewise.
	* config/tc-msp430.c (msp430_profiler): Likewise.
	* config/tc-rx.c (parse_rx_section): Likewise.
	* config/tc-tic6x.c (tic6x_start_unwind_section): Likewise.
	* doc/as.texi: Document "unique,N" in .section directive.
	* testsuite/gas/elf/elf.exp: Run "unique,N" tests.
	* testsuite/gas/elf/section15.d: New file.
	* testsuite/gas/elf/section15.s: Likewise.
	* testsuite/gas/elf/section16.s: Likewise.
	* testsuite/gas/elf/section16a.d: Likewise.
	* testsuite/gas/elf/section16b.d: Likewise.
	* testsuite/gas/elf/section17.d: Likewise.
	* testsuite/gas/elf/section17.l: Likewise.
	* testsuite/gas/elf/section17.s: Likewise.
	* testsuite/gas/i386/unique.d: Likewise.
	* testsuite/gas/i386/unique.s: Likewise.
	* testsuite/gas/i386/x86-64-unique.d: Likewise.
	* testsuite/gas/i386/i386.exp: Run unique and x86-64-unique.

ld/

	PR gas/25380
	* testsuite/ld-i386/pr22001-1c.S: Use "unique,N" in .section
	directives.
	* testsuite/ld-i386/tls-gd1.S: Likewise.
	* testsuite/ld-x86-64/pr21481b.S: Likewise.
This commit is contained in:
H.J. Lu
2020-02-02 17:07:51 -08:00
parent 0f8b5e560e
commit a8c4d40b57
34 changed files with 551 additions and 64 deletions

View File

@@ -518,22 +518,18 @@ struct section_stack
static struct section_stack *section_stack;
/* Match both section group name and the sh_info field. */
struct section_match
{
const char *group_name;
unsigned int info;
};
static bfd_boolean
get_section (bfd *abfd ATTRIBUTE_UNUSED, asection *sec, void *inf)
{
struct section_match *match = (struct section_match *) inf;
struct elf_section_match *match = (struct elf_section_match *) inf;
const char *gname = match->group_name;
const char *group_name = elf_group_name (sec);
unsigned int info = elf_section_data (sec)->this_hdr.sh_info;
return (info == match->info
&& ((bfd_section_flags (sec) & SEC_ASSEMBLER_SECTION_ID)
== (match->flags & SEC_ASSEMBLER_SECTION_ID))
&& sec->section_id == match->section_id
&& (group_name == gname
|| (group_name != NULL
&& gname != NULL
@@ -561,10 +557,9 @@ get_section (bfd *abfd ATTRIBUTE_UNUSED, asection *sec, void *inf)
void
obj_elf_change_section (const char *name,
unsigned int type,
unsigned int info,
bfd_vma attr,
int entsize,
const char *group_name,
struct elf_section_match *match_p,
int linkonce,
int push)
{
@@ -573,7 +568,12 @@ obj_elf_change_section (const char *name,
flagword flags;
const struct elf_backend_data *bed;
const struct bfd_elf_special_section *ssect;
struct section_match match;
if (match_p == NULL)
{
static struct elf_section_match unused_match;
match_p = &unused_match;
}
#ifdef md_flush_pending_output
md_flush_pending_output ();
@@ -594,10 +594,8 @@ obj_elf_change_section (const char *name,
previous_section = now_seg;
previous_subsection = now_subseg;
match.group_name = group_name;
match.info = info;
old_sec = bfd_get_section_by_name_if (stdoutput, name, get_section,
(void *) &match);
(void *) match_p);
if (old_sec)
{
sec = old_sec;
@@ -696,7 +694,7 @@ obj_elf_change_section (const char *name,
#endif
else
{
if (group_name == NULL)
if (match_p->group_name == NULL)
as_warn (_("setting incorrect section attributes for %s"),
name);
override = TRUE;
@@ -732,16 +730,20 @@ obj_elf_change_section (const char *name,
type = bfd_elf_get_default_section_type (flags);
elf_section_type (sec) = type;
elf_section_flags (sec) = attr;
elf_section_data (sec)->this_hdr.sh_info = info;
elf_section_data (sec)->this_hdr.sh_info = match_p->info;
/* Prevent SEC_HAS_CONTENTS from being inadvertently set. */
if (type == SHT_NOBITS)
seg_info (sec)->bss = 1;
/* Set the section ID and flags. */
sec->section_id = match_p->section_id;
flags |= match_p->flags;
bfd_set_section_flags (sec, flags);
if (flags & SEC_MERGE)
sec->entsize = entsize;
elf_group_name (sec) = group_name;
elf_group_name (sec) = match_p->group_name;
/* Add a symbol for this section to the symbol table. */
secsym = symbol_find (name);
@@ -1006,7 +1008,7 @@ obj_elf_section_name (void)
void
obj_elf_section (int push)
{
const char *name, *group_name;
const char *name;
char *beg;
int type, dummy;
bfd_vma attr;
@@ -1014,7 +1016,7 @@ obj_elf_section (int push)
int entsize;
int linkonce;
subsegT new_subsection = -1;
unsigned int info = 0;
struct elf_section_match match;
if (flag_mri)
{
@@ -1040,6 +1042,8 @@ obj_elf_section (int push)
if (name == NULL)
return;
memset (&match, 0, sizeof (match));
symbolS * sym;
if ((sym = symbol_find (name)) != NULL
&& ! symbol_section_p (sym)
@@ -1054,7 +1058,6 @@ obj_elf_section (int push)
type = SHT_NULL;
attr = 0;
gnu_attr = 0;
group_name = NULL;
entsize = 0;
linkonce = 0;
@@ -1159,8 +1162,8 @@ obj_elf_section (int push)
if ((attr & SHF_GROUP) != 0 && *input_line_pointer == ',')
{
++input_line_pointer;
group_name = obj_elf_section_name ();
if (group_name == NULL)
match.group_name = obj_elf_section_name ();
if (match.group_name == NULL)
attr &= ~SHF_GROUP;
else if (*input_line_pointer == ',')
{
@@ -1186,26 +1189,86 @@ obj_elf_section (int push)
const char *now_group = elf_group_name (now_seg);
if (now_group != NULL)
{
group_name = xstrdup (now_group);
match.group_name = xstrdup (now_group);
linkonce = (now_seg->flags & SEC_LINK_ONCE) != 0;
}
}
if ((gnu_attr & SHF_GNU_MBIND) != 0 && *input_line_pointer == ',')
{
char *save = input_line_pointer;
++input_line_pointer;
SKIP_WHITESPACE ();
if (ISDIGIT (* input_line_pointer))
{
char *t = input_line_pointer;
info = strtoul (input_line_pointer,
&input_line_pointer, 0);
if (info == (unsigned int) -1)
match.info = strtoul (input_line_pointer,
&input_line_pointer, 0);
if (match.info == (unsigned int) -1)
{
as_warn (_("unsupported mbind section info: %s"), t);
info = 0;
match.info = 0;
}
}
else
input_line_pointer = save;
}
if (*input_line_pointer == ',')
{
char *save = input_line_pointer;
++input_line_pointer;
SKIP_WHITESPACE ();
if (strncmp (input_line_pointer, "unique", 6) == 0)
{
input_line_pointer += 6;
SKIP_WHITESPACE ();
if (*input_line_pointer == ',')
{
++input_line_pointer;
SKIP_WHITESPACE ();
if (ISDIGIT (* input_line_pointer))
{
bfd_vma id;
bfd_boolean overflow;
char *t = input_line_pointer;
if (sizeof (bfd_vma) <= sizeof (unsigned long))
{
errno = 0;
id = strtoul (input_line_pointer,
&input_line_pointer, 0);
overflow = (id == (unsigned long) -1
&& errno == ERANGE);
}
else
{
id = bfd_scan_vma
(input_line_pointer,
(const char **) &input_line_pointer, 0);
overflow = id == ~(bfd_vma) 0;
}
if (overflow || id > (unsigned int) -1)
{
char *linefeed, saved_char = 0;
if ((linefeed = strchr (t, '\n')) != NULL)
{
saved_char = *linefeed;
*linefeed = '\0';
}
as_bad (_("unsupported section id: %s"), t);
if (saved_char)
*linefeed = saved_char;
}
else
{
match.section_id = id;
match.flags |= SEC_ASSEMBLER_SECTION_ID;
}
}
}
}
else
input_line_pointer = save;
}
}
else
@@ -1238,8 +1301,8 @@ obj_elf_section (int push)
done:
demand_empty_rest_of_line ();
obj_elf_change_section (name, type, info, attr, entsize, group_name,
linkonce, push);
obj_elf_change_section (name, type, attr, entsize, &match, linkonce,
push);
if ((gnu_attr & SHF_GNU_MBIND) != 0)
{