/* Object file "section" support for the BFD library.
Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
- 2000, 2001
+ 2000, 2001, 2002
Free Software Foundation, Inc.
Written by Cygnus Support.
.{
. {* The name of the section; the name isn't a copy, the pointer is
. the same as that passed to bfd_make_section. *}
-.
. const char *name;
.
. {* A unique sequence number. *}
-.
. int id;
.
. {* Which section in the bfd; 0..n-1 as sections are created in a bfd. *}
-.
. int index;
.
. {* The next section in the list belonging to the BFD, or NULL. *}
-.
. struct sec *next;
.
. {* The field flags contains attributes of the section. Some
. flags are read in from the object file, and some are
. synthesized from other information. *}
-.
. flagword flags;
.
.#define SEC_NO_FLAGS 0x000
. standard data. *}
.#define SEC_CONSTRUCTOR 0x100
.
-. {* The section is a constructor, and should be placed at the
-. end of the text, data, or bss section(?). *}
-.#define SEC_CONSTRUCTOR_TEXT 0x1100
-.#define SEC_CONSTRUCTOR_DATA 0x2100
-.#define SEC_CONSTRUCTOR_BSS 0x3100
-.
. {* The section has contents - a data section could be
. <<SEC_ALLOC>> | <<SEC_HAS_CONTENTS>>; a debug section could be
. <<SEC_HAS_CONTENTS>> *}
. sections. *}
.#define SEC_COFF_SHARED_LIBRARY 0x800
.
+. {* The section contains thread local data. *}
+.#define SEC_THREAD_LOCAL 0x1000
+.
. {* The section has GOT references. This flag is only for the
. linker, and is currently only used by the elf32-hppa back end.
. It will be set if global offset table references were detected
. backend can assign addresses (for example, in <<a.out>>, where
. the default address for <<.data>> is dependent on the specific
. target and various flags). *}
-.
. bfd_vma vma;
.
. {* The load address of the section - where it would be in a
. rom image; really only used for writing section header
-. information. *}
-.
+. information. *}
. bfd_vma lma;
.
. {* The size of the section in octets, as it will be output.
. Contains a value even if the section has no contents (e.g., the
. size of <<.bss>>). This will be filled in after relocation. *}
-.
. bfd_size_type _cooked_size;
.
. {* The original size on disk of the section, in octets. Normally this
. value is the same as the size, but if some relaxing has
. been done, then this value will be bigger. *}
-.
. bfd_size_type _raw_size;
.
. {* If this section is going to be output, then this value is the
. 100th octet (8-bit quantity) in the output section, this value
. would be 100. However, if the target byte size is 16 bits
. (bfd_octets_per_byte is "2"), this value would be 50. *}
-.
. bfd_vma output_offset;
.
. {* The output section through which to map on output. *}
-.
. struct sec *output_section;
.
. {* The alignment requirement of the section, as an exponent of 2 -
. e.g., 3 aligns to 2^3 (or 8). *}
-.
. unsigned int alignment_power;
.
. {* If an input section, a pointer to a vector of relocation
. records for the data in this section. *}
-.
. struct reloc_cache_entry *relocation;
.
. {* If an output section, a pointer to a vector of pointers to
. relocation records for the data in this section. *}
-.
. struct reloc_cache_entry **orelocation;
.
-. {* The number of relocation records in one of the above *}
-.
+. {* The number of relocation records in one of the above. *}
. unsigned reloc_count;
.
. {* Information below is back end specific - and not always used
. or updated. *}
.
. {* File position of section data. *}
-.
. file_ptr filepos;
.
. {* File position of relocation info. *}
-.
. file_ptr rel_filepos;
.
. {* File position of line data. *}
-.
. file_ptr line_filepos;
.
. {* Pointer to data for applications. *}
-.
. PTR userdata;
.
. {* If the SEC_IN_MEMORY flag is set, this points to the actual
. unsigned char *contents;
.
. {* Attached line number information. *}
-.
. alent *lineno;
.
. {* Number of line number records. *}
-.
. unsigned int lineno_count;
.
. {* Entity size for merging purposes. *}
-.
. unsigned int entsize;
.
. {* Optional information about a COMDAT entry; NULL if not COMDAT. *}
-.
. struct bfd_comdat_info *comdat;
.
. {* When a section is being output, this value changes as more
. linenumbers are written out. *}
-.
. file_ptr moving_line_filepos;
.
. {* What the section number is in the target world. *}
-.
. int target_index;
.
. PTR used_by_bfd;
.
. {* If this is a constructor section then here is a list of the
. relocations created to relocate items within it. *}
-.
. struct relent_chain *constructor_chain;
.
. {* The BFD which owns the section. *}
-.
. bfd *owner;
.
-. {* A symbol which points at this section only *}
+. {* A symbol which points at this section only. *}
. struct symbol_cache_entry *symbol;
. struct symbol_cache_entry **symbol_ptr_ptr;
.
. struct bfd_link_order *link_order_head;
. struct bfd_link_order *link_order_tail;
-.} asection ;
+.} asection;
.
.{* These sections are global, and are managed by BFD. The application
. and target back end are not permitted to change the values in
.#define BFD_COM_SECTION_NAME "*COM*"
.#define BFD_IND_SECTION_NAME "*IND*"
.
-.{* the absolute section *}
+.{* The absolute section. *}
.extern const asection bfd_abs_section;
.#define bfd_abs_section_ptr ((asection *) &bfd_abs_section)
.#define bfd_is_abs_section(sec) ((sec) == bfd_abs_section_ptr)
-.{* Pointer to the undefined section *}
+.{* Pointer to the undefined section. *}
.extern const asection bfd_und_section;
.#define bfd_und_section_ptr ((asection *) &bfd_und_section)
.#define bfd_is_und_section(sec) ((sec) == bfd_und_section_ptr)
-.{* Pointer to the common section *}
+.{* Pointer to the common section. *}
.extern const asection bfd_com_section;
.#define bfd_com_section_ptr ((asection *) &bfd_com_section)
-.{* Pointer to the indirect section *}
+.{* Pointer to the indirect section. *}
.extern const asection bfd_ind_section;
.#define bfd_ind_section_ptr ((asection *) &bfd_ind_section)
.#define bfd_is_ind_section(sec) ((sec) == bfd_ind_section_ptr)
.#define bfd_get_section_size_after_reloc(section) \
. ((section)->reloc_done ? (section)->_cooked_size \
. : (abort (), (bfd_size_type) 1))
+.
+.{* Macros to handle insertion and deletion of a bfd's sections. These
+. only handle the list pointers, ie. do not adjust section_count,
+. target_index etc. *}
+.#define bfd_section_list_remove(ABFD, PS) \
+. do \
+. { \
+. asection **_ps = PS; \
+. asection *_s = *_ps; \
+. *_ps = _s->next; \
+. if (_s->next == NULL) \
+. (ABFD)->section_tail = _ps; \
+. } \
+. while (0)
+.#define bfd_section_list_insert(ABFD, PS, S) \
+. do \
+. { \
+. asection **_ps = PS; \
+. asection *_s = S; \
+. _s->next = *_ps; \
+. *_ps = _s; \
+. if (_s->next == NULL) \
+. (ABFD)->section_tail = &_s->next; \
+. } \
+. while (0)
+.
*/
/* We use a macro to initialize the static asymbol structures because
STD_SECTION (bfd_ind_section, 0, bfd_ind_symbol, BFD_IND_SECTION_NAME, 3);
#undef STD_SECTION
+struct section_hash_entry
+{
+ struct bfd_hash_entry root;
+ asection section;
+};
+
+/* Initialize an entry in the section hash table. */
+
+struct bfd_hash_entry *
+bfd_section_hash_newfunc (entry, table, string)
+ struct bfd_hash_entry *entry;
+ struct bfd_hash_table *table;
+ const char *string;
+{
+ /* Allocate the structure if it has not already been allocated by a
+ subclass. */
+ if (entry == NULL)
+ {
+ entry = bfd_hash_allocate (table, sizeof (struct section_hash_entry));
+ if (entry == NULL)
+ return entry;
+ }
+
+ /* Call the allocation method of the superclass. */
+ entry = bfd_hash_newfunc (entry, table, string);
+ if (entry != NULL)
+ {
+ memset ((PTR) &((struct section_hash_entry *) entry)->section,
+ 0, sizeof (asection));
+ }
+
+ return entry;
+}
+
+#define section_hash_lookup(table, string, create, copy) \
+ ((struct section_hash_entry *) \
+ bfd_hash_lookup ((table), (string), (create), (copy)))
+
+/* Initializes a new section. NEWSECT->NAME is already set. */
+
+static asection *bfd_section_init PARAMS ((bfd *, asection *));
+
+static asection *
+bfd_section_init (abfd, newsect)
+ bfd *abfd;
+ asection *newsect;
+{
+ static int section_id = 0x10; /* id 0 to 3 used by STD_SECTION. */
+
+ newsect->id = section_id;
+ newsect->index = abfd->section_count;
+ newsect->owner = abfd;
+
+ /* Create a symbol whose only job is to point to this section. This
+ is useful for things like relocs which are relative to the base
+ of a section. */
+ newsect->symbol = bfd_make_empty_symbol (abfd);
+ if (newsect->symbol == NULL)
+ return NULL;
+
+ newsect->symbol->name = newsect->name;
+ newsect->symbol->value = 0;
+ newsect->symbol->section = newsect;
+ newsect->symbol->flags = BSF_SECTION_SYM;
+
+ newsect->symbol_ptr_ptr = &newsect->symbol;
+
+ if (! BFD_SEND (abfd, _new_section_hook, (abfd, newsect)))
+ return NULL;
+
+ section_id++;
+ abfd->section_count++;
+ *abfd->section_tail = newsect;
+ abfd->section_tail = &newsect->next;
+ return newsect;
+}
+
/*
DOCDD
INODE
These are the functions exported by the section handling part of BFD.
*/
+/*
+FUNCTION
+ bfd_section_list_clear
+
+SYNOPSIS
+ void bfd_section_list_clear (bfd *);
+
+DESCRIPTION
+ Clears the section list, and also resets the section count and
+ hash table entries.
+*/
+
+void
+bfd_section_list_clear (abfd)
+ bfd *abfd;
+{
+ abfd->sections = NULL;
+ abfd->section_tail = &abfd->sections;
+ abfd->section_count = 0;
+ memset ((PTR) abfd->section_htab.table, 0,
+ abfd->section_htab.size * sizeof (struct bfd_hash_entry *));
+}
+
/*
FUNCTION
bfd_get_section_by_name
bfd *abfd;
const char *name;
{
- asection *sect;
+ struct section_hash_entry *sh;
+
+ sh = section_hash_lookup (&abfd->section_htab, name, false, false);
+ if (sh != NULL)
+ return &sh->section;
- for (sect = abfd->sections; sect != NULL; sect = sect->next)
- if (!strcmp (sect->name, name))
- return sect;
return NULL;
}
abort ();
sprintf (sname + len, ".%d", num++);
}
- while (bfd_get_section_by_name (abfd, sname) != NULL);
+ while (section_hash_lookup (&abfd->section_htab, sname, false, false));
if (count != NULL)
*count = num;
bfd *abfd;
const char *name;
{
- asection *sec = bfd_get_section_by_name (abfd, name);
- if (sec == (asection *) NULL)
+ struct section_hash_entry *sh;
+ asection *newsect;
+
+ if (abfd->output_has_begun)
{
- sec = bfd_make_section (abfd, name);
+ bfd_set_error (bfd_error_invalid_operation);
+ return NULL;
}
- return sec;
+
+ if (strcmp (name, BFD_ABS_SECTION_NAME) == 0)
+ return bfd_abs_section_ptr;
+
+ if (strcmp (name, BFD_COM_SECTION_NAME) == 0)
+ return bfd_com_section_ptr;
+
+ if (strcmp (name, BFD_UND_SECTION_NAME) == 0)
+ return bfd_und_section_ptr;
+
+ if (strcmp (name, BFD_IND_SECTION_NAME) == 0)
+ return bfd_ind_section_ptr;
+
+ sh = section_hash_lookup (&abfd->section_htab, name, true, false);
+ if (sh == NULL)
+ return NULL;
+
+ newsect = &sh->section;
+ if (newsect->name != NULL)
+ {
+ /* Section already exists. */
+ return newsect;
+ }
+
+ newsect->name = name;
+ return bfd_section_init (abfd, newsect);
}
/*
bfd *abfd;
const char *name;
{
- static int section_id = 0x10; /* id 0 to 3 used by STD_SECTION. */
+ struct section_hash_entry *sh;
asection *newsect;
- asection **prev = &abfd->sections;
- asection *sect = abfd->sections;
if (abfd->output_has_begun)
{
return NULL;
}
- while (sect)
- {
- prev = §->next;
- sect = sect->next;
- }
-
- newsect = (asection *) bfd_zalloc (abfd, (bfd_size_type) sizeof (asection));
- if (newsect == NULL)
+ sh = section_hash_lookup (&abfd->section_htab, name, true, false);
+ if (sh == NULL)
return NULL;
- newsect->name = name;
- newsect->id = section_id;
- newsect->index = abfd->section_count;
- newsect->flags = SEC_NO_FLAGS;
-
- newsect->userdata = NULL;
- newsect->contents = NULL;
- newsect->next = (asection *) NULL;
- newsect->relocation = (arelent *) NULL;
- newsect->reloc_count = 0;
- newsect->line_filepos = 0;
- newsect->owner = abfd;
- newsect->comdat = NULL;
-
- /* Create a symbol whos only job is to point to this section. This is
- useful for things like relocs which are relative to the base of a
- section. */
- newsect->symbol = bfd_make_empty_symbol (abfd);
- if (newsect->symbol == NULL)
- {
- bfd_release (abfd, newsect);
- return NULL;
- }
- newsect->symbol->name = name;
- newsect->symbol->value = 0;
- newsect->symbol->section = newsect;
- newsect->symbol->flags = BSF_SECTION_SYM;
-
- newsect->symbol_ptr_ptr = &newsect->symbol;
-
- if (BFD_SEND (abfd, _new_section_hook, (abfd, newsect)) != true)
+ newsect = &sh->section;
+ if (newsect->name != NULL)
{
- bfd_release (abfd, newsect);
- return NULL;
+ /* We are making a section of the same name. It can't go in
+ section_htab without generating a unique section name and
+ that would be pointless; We don't need to traverse the
+ hash table. */
+ newsect = (asection *) bfd_zalloc (abfd, sizeof (asection));
+ if (newsect == NULL)
+ return NULL;
}
- section_id++;
- abfd->section_count++;
- *prev = newsect;
- return newsect;
+ newsect->name = name;
+ return bfd_section_init (abfd, newsect);
}
/*
bfd *abfd;
const char *name;
{
- asection *sect = abfd->sections;
+ struct section_hash_entry *sh;
+ asection *newsect;
- if (strcmp (name, BFD_ABS_SECTION_NAME) == 0)
- {
- return bfd_abs_section_ptr;
- }
- if (strcmp (name, BFD_COM_SECTION_NAME) == 0)
- {
- return bfd_com_section_ptr;
- }
- if (strcmp (name, BFD_UND_SECTION_NAME) == 0)
+ if (abfd->output_has_begun)
{
- return bfd_und_section_ptr;
+ bfd_set_error (bfd_error_invalid_operation);
+ return NULL;
}
- if (strcmp (name, BFD_IND_SECTION_NAME) == 0)
- {
- return bfd_ind_section_ptr;
- }
+ if (strcmp (name, BFD_ABS_SECTION_NAME) == 0
+ || strcmp (name, BFD_COM_SECTION_NAME) == 0
+ || strcmp (name, BFD_UND_SECTION_NAME) == 0
+ || strcmp (name, BFD_IND_SECTION_NAME) == 0)
+ return NULL;
+
+ sh = section_hash_lookup (&abfd->section_htab, name, true, false);
+ if (sh == NULL)
+ return NULL;
- while (sect)
+ newsect = &sh->section;
+ if (newsect->name != NULL)
{
- if (!strcmp (sect->name, name))
- return NULL;
- sect = sect->next;
+ /* Section already exists. */
+ return newsect;
}
- /* The name is not already used; go ahead and make a new section. */
- return bfd_make_section_anyway (abfd, name);
+ newsect->name = name;
+ return bfd_section_init (abfd, newsect);
}
/*
for (spp = &os->owner->sections; *spp; spp = &(*spp)->next)
if (*spp == os)
{
- *spp = os->next;
+ bfd_section_list_remove (os->owner, spp);
os->owner->section_count--;
break;
}
s->flags |= SEC_EXCLUDE;
}
+
+/*
+FUNCTION
+ bfd_discard_group
+
+SYNOPSIS
+ void bfd_discard_group (bfd *abfd, asection *group);
+
+DESCRIPTION
+ Remove all members of @var{group} from the output.
+*/
+
+void
+bfd_discard_group (abfd, group)
+ bfd *abfd;
+ asection *group;
+{
+ if ((group->flags & SEC_GROUP) != 0
+ && abfd->xvec->flavour == bfd_target_elf_flavour)
+ bfd_elf_discard_group (abfd, group);
+}