This is the mail archive of the
binutils@sources.redhat.com
mailing list for the binutils project.
SHT_GROUP support, part 1
- To: binutils at sourceware dot cygnus dot com
- Subject: SHT_GROUP support, part 1
- From: Alan Modra <amodra at bigpond dot net dot au>
- Date: Sun, 7 Oct 2001 15:58:59 +0930
This is the first part, assembler support, towards providing ELF
SHT_GROUP support in gas and ld. Posted now so that interested people
can review, and correct any silly errors I might have made. I'll
probably start writing the linker support tomorrow.
bfd/ChangeLog
* elf-bfd.h (struct bfd_elf_section_data): Add "group" and
"next_in_group".
* elf.c (_bfd_elf_make_section_from_shdr): Set BFD group flag.
(elf_fake_sections): Set header type for SEC_GROUP, and header
flags for sections in a group.
(set_group_contents): New function.
(_bfd_elf_compute_section_file_positions): Call it.
(assign_section_numbers): Set sh_link for SHT_GROUP.
* section.c (SEC_GROUP): Define.
(struct sec): Comment fixes.
* bfd-in2.h: Regenerate.
gas/ChangeLog
* config/obj-elf.c: (obj_elf_change_section): Add "group" param.
Set elf_section_data group from it. Warn if group name changed.
(obj_elf_parse_section_letters): Parse 'G' too.
(obj_elf_section): Parse group name.
(struct group_list): New.
(build_group_lists): New function.
(elf_frob_file): Create SEC_GROUP section(s).
--
Alan Modra
Index: bfd/elf-bfd.h
===================================================================
RCS file: /cvs/src/src/bfd/elf-bfd.h,v
retrieving revision 1.50
diff -u -p -r1.50 elf-bfd.h
--- elf-bfd.h 2001/10/04 12:30:26 1.50
+++ elf-bfd.h 2001/10/07 06:20:05
@@ -815,6 +815,12 @@ struct bfd_elf_section_data
/* A pointer used for SEC_MERGE optimizations. */
PTR merge_info;
+ /* Group name, if this section is part of a group. */
+ const char *group;
+
+ /* A linked list of sections in the group. */
+ asection *next_in_group;
+
/* A pointer available for the processor specific ELF backend. */
PTR tdata;
Index: bfd/elf.c
===================================================================
RCS file: /cvs/src/src/bfd/elf.c,v
retrieving revision 1.97
diff -u -p -r1.97 elf.c
--- elf.c 2001/10/03 08:33:18 1.97
+++ elf.c 2001/10/07 06:20:09
@@ -52,6 +52,7 @@ static boolean swap_out_syms PARAMS ((bf
static boolean copy_private_bfd_data PARAMS ((bfd *, bfd *));
static char *elf_read PARAMS ((bfd *, file_ptr, bfd_size_type));
static void elf_fake_sections PARAMS ((bfd *, asection *, PTR));
+static void set_group_contents PARAMS ((bfd *, asection *, PTR));
static boolean assign_section_numbers PARAMS ((bfd *));
static INLINE int sym_is_global PARAMS ((bfd *, asymbol *));
static boolean elf_map_symbols PARAMS ((bfd *));
@@ -380,6 +381,8 @@ _bfd_elf_make_section_from_shdr (abfd, h
flags = SEC_NO_FLAGS;
if (hdr->sh_type != SHT_NOBITS)
flags |= SEC_HAS_CONTENTS;
+ if (hdr->sh_type == SHT_GROUP)
+ flags |= SEC_GROUP;
if ((hdr->sh_flags & SHF_ALLOC) != 0)
{
flags |= SEC_ALLOC;
@@ -1847,6 +1850,11 @@ elf_fake_sections (abfd, asect, failedpt
BFD_ASSERT (elf_tdata (abfd)->cverrefs == 0
|| this_hdr->sh_info == elf_tdata (abfd)->cverrefs);
}
+ else if ((asect->flags & SEC_GROUP) != 0)
+ {
+ this_hdr->sh_type = SHT_GROUP;
+ this_hdr->sh_entsize = 4;
+ }
else if ((asect->flags & SEC_ALLOC) != 0
&& ((asect->flags & (SEC_LOAD | SEC_HAS_CONTENTS)) == 0))
this_hdr->sh_type = SHT_NOBITS;
@@ -1866,6 +1874,8 @@ elf_fake_sections (abfd, asect, failedpt
if ((asect->flags & SEC_STRINGS) != 0)
this_hdr->sh_flags |= SHF_STRINGS;
}
+ if (elf_section_data (asect)->group != NULL)
+ this_hdr->sh_flags |= SHF_GROUP;
/* Check for processor-specific section types. */
if (bed->elf_backend_fake_sections)
@@ -1883,6 +1893,43 @@ elf_fake_sections (abfd, asect, failedpt
*failedptr = true;
}
+static void
+set_group_contents (abfd, sec, failedptrarg)
+ bfd *abfd;
+ asection *sec;
+ PTR failedptrarg ATTRIBUTE_UNUSED;
+{
+ asection *elt;
+ unsigned char *loc;
+
+ if (elf_section_data (sec)->this_hdr.sh_type != SHT_GROUP)
+ return;
+
+ elf_section_data (sec)->this_hdr.sh_info =
+ elf_section_syms (abfd)[sec->index]->udata.i;
+
+ /* Get the pointer to the first section in the group that we
+ squirreled away here. */
+ elt = (asection *) sec->lineno;
+
+ loc = sec->contents + sec->_raw_size;
+
+ /* First element is a flag word. Rest of section is elf section
+ indices for all the sections of the group. Write them backwards
+ just to keep the group in the same order as given in .section
+ directives, not that it matters. */
+ while (elt != NULL)
+ {
+ loc -= 4;
+ H_PUT_32 (abfd, elf_section_data (elt)->this_idx, loc);
+ elt = elf_section_data (elt)->next_in_group;
+ }
+ loc -= 4;
+ H_PUT_32 (abfd, 0, loc);
+
+ BFD_ASSERT (loc == sec->contents);
+}
+
/* Assign all ELF section numbers. The dummy first section is handled here
too. The link/info pointers for the standard section types are filled
in here too, while we're at it. */
@@ -2055,6 +2102,9 @@ assign_section_numbers (abfd)
if (s != NULL)
d->this_hdr.sh_link = elf_section_data (s)->this_idx;
break;
+
+ case SHT_GROUP:
+ d->this_hdr.sh_link = t->symtab_section;
}
}
@@ -2328,6 +2378,10 @@ _bfd_elf_compute_section_file_positions
int relocatable_p = ! (abfd->flags & (EXEC_P | DYNAMIC));
if (! swap_out_syms (abfd, &strtab, relocatable_p))
+ return false;
+
+ bfd_map_over_sections (abfd, set_group_contents, &failed);
+ if (failed)
return false;
}
Index: bfd/section.c
===================================================================
RCS file: /cvs/src/src/bfd/section.c,v
retrieving revision 1.36
diff -u -p -r1.36 section.c
--- section.c 2001/09/29 12:07:00 1.36
+++ section.c 2001/10/07 06:20:11
@@ -177,7 +177,7 @@ CODE_FRAGMENT
.
. int id;
.
-. {* Which section is it; 0..nth. *}
+. {* Which section in the bfd; 0..n-1 as sections are created in a bfd. *}
.
. int index;
.
@@ -292,9 +292,10 @@ CODE_FRAGMENT
. objects are to be further relocated. *}
.#define SEC_EXCLUDE 0x40000
.
-. {* The contents of this section are to be sorted by the
-. based on the address specified in the associated symbol
-. table. *}
+. {* The contents of this section are to be sorted based on the sum of
+. the symbol and addend values specified by the associated relocation
+. entries. Entries without associated relocation entries will be
+. appended to the end of the section in an unspecified order. *}
.#define SEC_SORT_ENTRIES 0x80000
.
. {* When linking, duplicate sections of the same name should be
@@ -361,6 +362,9 @@ CODE_FRAGMENT
. size entries. *}
.#define SEC_STRINGS 0x40000000
.
+. {* This section contains data about section groups. *}
+.#define SEC_GROUP 0x80000000
+.
. {* End of section flags. *}
.
. {* Some internal packed boolean fields. *}
@@ -381,7 +385,8 @@ CODE_FRAGMENT
. {* A mark flag used by some linker backends for garbage collection. *}
. unsigned int gc_mark : 1;
.
-. {* Used by the ELF code to mark sections which have been allocated to segments. *}
+. {* Used by the ELF code to mark sections which have been allocated
+. to segments. *}
. unsigned int segment_mark : 1;
.
. {* End of internal packed boolean fields. *}
Index: gas/config/obj-elf.c
===================================================================
RCS file: /cvs/src/src/gas/config/obj-elf.c,v
retrieving revision 1.41
diff -u -p -r1.41 obj-elf.c
--- obj-elf.c 2001/10/07 06:16:54 1.41
+++ obj-elf.c 2001/10/07 06:20:12
@@ -58,6 +58,7 @@ static void elf_s_set_align PARAMS ((sym
static void elf_s_set_other PARAMS ((symbolS *, int));
static int elf_sec_sym_ok_for_reloc PARAMS ((asection *));
static void adjust_stab_sections PARAMS ((bfd *, asection *, PTR));
+static void build_group_lists PARAMS ((bfd *, asection *, PTR));
static int elf_separate_stab_sections PARAMS ((void));
static void elf_init_stab_section PARAMS ((segT));
@@ -74,7 +75,8 @@ static void obj_elf_ident PARAMS ((int))
static void obj_elf_weak PARAMS ((int));
static void obj_elf_local PARAMS ((int));
static void obj_elf_visibility PARAMS ((int));
-static void obj_elf_change_section PARAMS ((char *, int, int, int, int));
+static void obj_elf_change_section
+ PARAMS ((const char *, int, int, int, const char *, int));
static int obj_elf_parse_section_letters PARAMS ((char *, size_t));
static int obj_elf_section_word PARAMS ((char *, size_t));
static char *obj_elf_section_name PARAMS ((void));
@@ -618,9 +620,13 @@ static struct special_section const spec
};
static void
-obj_elf_change_section (name, type, attr, entsize, push)
- char *name;
- int type, attr, entsize, push;
+obj_elf_change_section (name, type, attr, entsize, group, push)
+ const char *name;
+ int type;
+ int attr;
+ int entsize;
+ const char *group;
+ int push;
{
asection *old_sec;
segT sec;
@@ -706,6 +712,7 @@ obj_elf_change_section (name, type, attr
bfd_set_section_flags (stdoutput, sec, flags);
if (flags & SEC_MERGE)
sec->entsize = entsize;
+ elf_section_data (sec)->group = group;
/* Add a symbol for this section to the symbol table. */
secsym = symbol_find (name);
@@ -725,6 +732,9 @@ obj_elf_change_section (name, type, attr
as_warn (_("ignoring changed section attributes for %s"), name);
else if ((flags & SEC_MERGE) && old_sec->entsize != (unsigned) entsize)
as_warn (_("ignoring changed section entity size for %s"), name);
+ else if ((attr & SHF_GROUP) != 0
+ && strcmp (elf_section_data (old_sec)->group, group) != 0)
+ as_warn (_("ignoring new section group for %s"), name);
}
#ifdef md_elf_section_change_hook
@@ -758,6 +768,9 @@ obj_elf_parse_section_letters (str, len)
case 'S':
attr |= SHF_STRINGS;
break;
+ case 'G':
+ attr |= SHF_GROUP;
+ break;
/* Compatibility. */
case 'm':
if (*(str - 1) == 'a')
@@ -772,7 +785,7 @@ obj_elf_parse_section_letters (str, len)
}
default:
{
- char *bad_msg = _("unrecognized .section attribute: want a,w,x,M,S");
+ char *bad_msg = _("unrecognized .section attribute: want a,w,x,M,S,G");
#ifdef md_elf_section_letter
int md_attr = md_elf_section_letter (*str, &bad_msg);
if (md_attr >= 0)
@@ -882,7 +895,7 @@ void
obj_elf_section (push)
int push;
{
- char *name, *beg;
+ char *name, *group, *beg;
int type, attr, dummy;
int entsize;
@@ -913,6 +926,7 @@ obj_elf_section (push)
return;
type = SHT_NULL;
attr = 0;
+ group = NULL;
entsize = 0;
if (*input_line_pointer == ',')
@@ -976,6 +990,19 @@ obj_elf_section (push)
as_warn (_("entity size for SHF_MERGE not specified"));
attr &= ~SHF_MERGE;
}
+
+ if ((attr & SHF_GROUP) != 0 && *input_line_pointer == ',')
+ {
+ ++input_line_pointer;
+ group = obj_elf_section_name ();
+ if (group == NULL)
+ attr &= ~SHF_GROUP;
+ }
+ else if ((attr & SHF_GROUP) != 0)
+ {
+ as_warn (_("group name for SHF_GROUP not specified"));
+ attr &= ~SHF_GROUP;
+ }
}
else
{
@@ -1005,7 +1032,7 @@ obj_elf_section (push)
demand_empty_rest_of_line ();
- obj_elf_change_section (name, type, attr, entsize, push);
+ obj_elf_change_section (name, type, attr, entsize, group, push);
}
/* Change to the .data section. */
@@ -1860,10 +1887,90 @@ elf_frob_symbol (symp, puntp)
#endif
}
+struct group_list
+{
+ asection **member;
+ unsigned int *in_group;
+ unsigned int count;
+};
+
+static void
+build_group_lists (abfd, sec, inf)
+ bfd *abfd ATTRIBUTE_UNUSED;
+ asection *sec;
+ PTR inf;
+{
+ struct group_list *list = (struct group_list *) inf;
+ const char *group_name = elf_section_data (sec)->group;
+ unsigned int i;
+
+ if (group_name == NULL)
+ return;
+
+ for (i = 0; i < list->count; i++)
+ {
+ if (strcmp (group_name, elf_section_data (list->member[i])->group) == 0)
+ {
+ elf_section_data (sec)->next_in_group = list->member[i];
+ list->member[i] = sec;
+ list->in_group[i] += 1;
+ return;
+ }
+ }
+
+ i = list->count;
+ if ((i & 127) == 0)
+ {
+ unsigned int newsize = i + 128;
+ list->member = xrealloc (list->member,
+ newsize * sizeof (*list->member));
+ list->in_group = xrealloc (list->in_group,
+ newsize * sizeof (*list->in_group));
+ }
+ list->member[i] = sec;
+ list->in_group[i] += 1;
+ list->count += 1;
+}
+
void
elf_frob_file ()
{
+ struct group_list group_info;
+ unsigned int i;
+
bfd_map_over_sections (stdoutput, adjust_stab_sections, (PTR) 0);
+
+ group_info.count = 0;
+ group_info.member = NULL;
+ group_info.in_group = NULL;
+ bfd_map_over_sections (stdoutput, build_group_lists, (PTR) &group_info);
+
+ for (i = 0; i < group_info.count; i++)
+ {
+ const char *group_name = elf_section_data (group_info.member[i])->group;
+ asection *s;
+ flagword flags;
+
+ s = subseg_force_new (group_name, 0);
+ flags = SEC_READONLY | SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_GROUP;
+ if (s == NULL
+ || ! bfd_set_section_flags (stdoutput, s, flags)
+ || ! bfd_set_section_alignment (stdoutput, s, 2))
+ {
+ as_fatal (_("can't create group: %s"),
+ bfd_errmsg (bfd_get_error ()));
+ }
+
+ /* Pass a pointer to the first section in this group. This
+ seems as good a field to use as any; It's not used otherwise
+ by the ELF code. We can't set up the section contents here
+ yet, because elf section indices have yet to be calculated. */
+ s->lineno = (alent *) group_info.member[i];
+
+ s->_raw_size = 4 * (group_info.in_group[i] + 1);
+ s->contents = frag_more (s->_raw_size);
+ frag_now->fr_fix = frag_now_fix_octets ();
+ }
#ifdef elf_tc_final_processing
elf_tc_final_processing ();