* elf-bfd.h (bfd_elf_section_data): Add rel_count and rel_count2

fields.
	(_bfd_elf_init_reloc_shdr): New function.
	* elf.c (_bfd_elf_new_section_hook): Use bfd_zalloc, rather than
	bfd_alloc followed by memset.
	(_bfd_elf_init_reloc_shdr): New function, split out from ...
	(elf_fake_sections): Here.
	(assign_section_numbers): Assign section numbers for the second
	relocation section, if required.
	* elflink.h (elf_link_output_relocs): New function.
	(elf_link_size_reloc_section): Likewise.
	(elf_bfd_final_link): Use elf_link_size_reloc_section.
	(elf_link_input_bfd): Use elf_link_output_relocs.
	* elf32-mips.c (_bfd_mips_elf_fake_sections): Use
	_bfd_elf_init_reloc_shdr to initialize rel_hdr2.
This commit is contained in:
Mark Mitchell 1999-07-01 23:20:08 +00:00
parent b1c5e0ee59
commit 23bc299bd8
5 changed files with 248 additions and 101 deletions

View File

@ -1,3 +1,22 @@
1999-07-01 Mark Mitchell <mark@codesourcery.com>
* elf-bfd.h (bfd_elf_section_data): Add rel_count and rel_count2
fields.
(_bfd_elf_init_reloc_shdr): New function.
* elf.c (_bfd_elf_new_section_hook): Use bfd_zalloc, rather than
bfd_alloc followed by memset.
(_bfd_elf_init_reloc_shdr): New function, split out from ...
(elf_fake_sections): Here.
(assign_section_numbers): Assign section numbers for the second
relocation section, if required.
* elflink.h (elf_link_output_relocs): New function.
(elf_link_size_reloc_section): Likewise.
(elf_bfd_final_link): Use elf_link_size_reloc_section.
(elf_link_input_bfd): Use elf_link_output_relocs.
* elf32-mips.c (_bfd_mips_elf_fake_sections): Use
_bfd_elf_init_reloc_shdr to initialize rel_hdr2.
Thu Jul 1 13:58:48 1999 Jeffrey A Law (law@cygnus.com)
* elf-hppa.h (_bfd_elf_hppa_gen_reloc_type): Handle R_PCREL_CALL

View File

@ -574,12 +574,19 @@ struct bfd_elf_section_data
/* If there is a second reloc section associated with this section,
as can happen on Irix 6, this field points to the header. */
Elf_Internal_Shdr *rel_hdr2;
/* The number of relocations currently assigned to REL_HDR. */
unsigned int rel_count;
/* The number of relocations currently assigned to REL_HDR2. */
unsigned int rel_count2;
/* The ELF section number of this section. Only used for an output
file. */
int this_idx;
/* The ELF section number of the reloc section associated with this
section, if any. Only used for an output file. */
/* The ELF section number of the reloc section indicated by
REL_HDR if any. Only used for an output file. */
int rel_idx;
/* The ELF section number of the reloc section indicated by
REL_HDR2 if any. Only used for an output file. */
int rel_idx2;
/* Used by the backend linker to store the symbol hash table entries
associated with relocs against global symbols. */
struct elf_link_hash_entry **rel_hashes;
@ -897,6 +904,8 @@ extern boolean _bfd_elf_find_nearest_line PARAMS ((bfd *, asection *,
#define _bfd_elf_minisymbol_to_symbol _bfd_generic_minisymbol_to_symbol
extern int _bfd_elf_sizeof_headers PARAMS ((bfd *, boolean));
extern boolean _bfd_elf_new_section_hook PARAMS ((bfd *, asection *));
extern boolean _bfd_elf_init_reloc_shdr
PARAMS ((bfd *, Elf_Internal_Shdr *, asection *, boolean));
/* If the target doesn't have reloc handling written yet: */
extern void _bfd_elf_no_info_to_howto PARAMS ((bfd *, arelent *,

View File

@ -1337,11 +1337,10 @@ _bfd_elf_new_section_hook (abfd, sec)
{
struct bfd_elf_section_data *sdata;
sdata = (struct bfd_elf_section_data *) bfd_alloc (abfd, sizeof (*sdata));
sdata = (struct bfd_elf_section_data *) bfd_zalloc (abfd, sizeof (*sdata));
if (!sdata)
return false;
sec->used_by_bfd = (PTR) sdata;
memset (sdata, 0, sizeof (*sdata));
/* Indicate whether or not this section should use RELA relocations. */
sdata->use_rela_p
@ -1441,6 +1440,43 @@ bfd_section_from_phdr (abfd, hdr, index)
return true;
}
/* Initialize REL_HDR, the section-header for new section, containing
relocations against ASECT. If USE_RELA_P is true, we use RELA
relocations; otherwise, we use REL relocations. */
boolean
_bfd_elf_init_reloc_shdr (abfd, rel_hdr, asect, use_rela_p)
bfd *abfd;
Elf_Internal_Shdr *rel_hdr;
asection *asect;
boolean use_rela_p;
{
char *name;
struct elf_backend_data *bed;
bed = get_elf_backend_data (abfd);
name = bfd_alloc (abfd, sizeof ".rela" + strlen (asect->name));
if (name == NULL)
return false;
sprintf (name, "%s%s", use_rela_p ? ".rela" : ".rel", asect->name);
rel_hdr->sh_name =
(unsigned int) _bfd_stringtab_add (elf_shstrtab (abfd), name,
true, false);
if (rel_hdr->sh_name == (unsigned int) -1)
return false;
rel_hdr->sh_type = use_rela_p ? SHT_RELA : SHT_REL;
rel_hdr->sh_entsize = (use_rela_p
? bed->s->sizeof_rela
: bed->s->sizeof_rel);
rel_hdr->sh_addralign = bed->s->file_align;
rel_hdr->sh_flags = 0;
rel_hdr->sh_addr = 0;
rel_hdr->sh_size = 0;
rel_hdr->sh_offset = 0;
return true;
}
/* Set up an ELF internal section header for a section. */
/*ARGSUSED*/
@ -1580,39 +1616,15 @@ elf_fake_sections (abfd, asect, failedptrarg)
(*bed->elf_backend_fake_sections) (abfd, this_hdr, asect);
/* If the section has relocs, set up a section header for the
SHT_REL[A] section. */
if ((asect->flags & SEC_RELOC) != 0)
{
Elf_Internal_Shdr *rela_hdr;
int use_rela_p = elf_section_data (asect)->use_rela_p;
char *name;
rela_hdr = &elf_section_data (asect)->rel_hdr;
name = bfd_alloc (abfd, sizeof ".rela" + strlen (asect->name));
if (name == NULL)
{
*failedptr = true;
return;
}
sprintf (name, "%s%s", use_rela_p ? ".rela" : ".rel", asect->name);
rela_hdr->sh_name =
(unsigned int) _bfd_stringtab_add (elf_shstrtab (abfd), name,
true, false);
if (rela_hdr->sh_name == (unsigned int) -1)
{
*failedptr = true;
return;
}
rela_hdr->sh_type = use_rela_p ? SHT_RELA : SHT_REL;
rela_hdr->sh_entsize = (use_rela_p
? bed->s->sizeof_rela
: bed->s->sizeof_rel);
rela_hdr->sh_addralign = bed->s->file_align;
rela_hdr->sh_flags = 0;
rela_hdr->sh_addr = 0;
rela_hdr->sh_size = 0;
rela_hdr->sh_offset = 0;
}
SHT_REL[A] section. If two relocation sections are required for
this section, it is up to the processor-specific back-end to
create the other. */
if ((asect->flags & SEC_RELOC) != 0
&& !_bfd_elf_init_reloc_shdr (abfd,
&elf_section_data (asect)->rel_hdr,
asect,
elf_section_data (asect)->use_rela_p))
*failedptr = true;
}
/* Assign all ELF section numbers. The dummy first section is handled here
@ -1640,6 +1652,11 @@ assign_section_numbers (abfd)
d->rel_idx = 0;
else
d->rel_idx = section_number++;
if (d->rel_hdr2)
d->rel_idx2 = section_number++;
else
d->rel_idx2 = 0;
}
t->shstrtab_section = section_number++;
@ -1688,6 +1705,8 @@ assign_section_numbers (abfd)
i_shdrp[d->this_idx] = &d->this_hdr;
if (d->rel_idx != 0)
i_shdrp[d->rel_idx] = &d->rel_hdr;
if (d->rel_idx2 != 0)
i_shdrp[d->rel_idx2] = d->rel_hdr2;
/* Fill in the sh_link and sh_info fields while we're at it. */
@ -1699,6 +1718,11 @@ assign_section_numbers (abfd)
d->rel_hdr.sh_link = t->symtab_section;
d->rel_hdr.sh_info = d->this_idx;
}
if (d->rel_idx2 != 0)
{
d->rel_hdr2->sh_link = t->symtab_section;
d->rel_hdr2->sh_info = d->this_idx;
}
switch (d->this_hdr.sh_type)
{

View File

@ -2788,6 +2788,23 @@ _bfd_mips_elf_fake_sections (abfd, hdr, sec)
hdr->sh_entsize = 8;
}
/* The generic elf_fake_sections will set up REL_HDR using the
default kind of relocations. But, we may actually need both
kinds of relocations, so we set up the second header here. */
if ((sec->flags & SEC_RELOC) != 0)
{
struct bfd_elf_section_data *esd;
esd = elf_section_data (sec);
BFD_ASSERT (esd->rel_hdr2 == NULL);
esd->rel_hdr2
= (Elf_Internal_Shdr *) bfd_zalloc (abfd, sizeof (Elf_Internal_Shdr));
if (!esd->rel_hdr2)
return false;
_bfd_elf_init_reloc_shdr (abfd, esd->rel_hdr2, sec,
!elf_section_data (sec)->use_rela_p);
}
return true;
}

View File

@ -56,6 +56,10 @@ static boolean elf_link_read_relocs_from_section
PARAMS ((bfd *, Elf_Internal_Shdr *, PTR, Elf_Internal_Rela *));
static void elf_link_remove_section_and_adjust_dynindices
PARAMS ((struct bfd_link_info *, asection *));
static void elf_link_output_relocs
PARAMS ((bfd *, asection *, Elf_Internal_Shdr *, Elf_Internal_Rela *));
static boolean elf_link_size_reloc_section
PARAMS ((bfd *, Elf_Internal_Shdr *, asection *));
/* Given an ELF BFD, add symbols to the global hash table as
appropriate. */
@ -2063,12 +2067,15 @@ elf_link_read_relocs_from_section (abfd, shdr, external_relocs,
return true;
}
/* Read and swap the relocs for a section. They may have been cached.
If the EXTERNAL_RELOCS and INTERNAL_RELOCS arguments are not NULL,
they are used as buffers to read into. They are known to be large
enough. If the INTERNAL_RELOCS relocs argument is NULL, the return
value is allocated using either malloc or bfd_alloc, according to
the KEEP_MEMORY argument. */
/* Read and swap the relocs for a section O. They may have been
cached. If the EXTERNAL_RELOCS and INTERNAL_RELOCS arguments are
not NULL, they are used as buffers to read into. They are known to
be large enough. If the INTERNAL_RELOCS relocs argument is NULL,
the return value is allocated using either malloc or bfd_alloc,
according to the KEEP_MEMORY argument. If O has two relocation
sections (both REL and RELA relocations), then the REL_HDR
relocations will appear first in INTERNAL_RELOCS, followed by the
REL_HDR2 relocations. */
Elf_Internal_Rela *
NAME(_bfd_elf,link_read_relocs) (abfd, o, external_relocs, internal_relocs,
@ -3669,6 +3676,48 @@ struct elf_outext_info
struct elf_final_link_info *finfo;
};
/* Compute the size of, and allocate space for, REL_HDR which is the
section header for a section containing relocations for O. */
static boolean
elf_link_size_reloc_section (abfd, rel_hdr, o)
bfd *abfd;
Elf_Internal_Shdr *rel_hdr;
asection *o;
{
register struct elf_link_hash_entry **p, **pend;
/* We are overestimating the size required for the relocation
sections, in the case that we are using both REL and RELA
relocations for a single section. In that case, RELOC_COUNT will
be the total number of relocations required, and we allocate
space for that many REL relocations as well as that many RELA
relocations. This approximation is wasteful of disk space.
However, until we keep track of how many of each kind of
relocation is required, it's difficult to calculate the right
value. */
rel_hdr->sh_size = rel_hdr->sh_entsize * o->reloc_count;
/* The contents field must last into write_object_contents, so we
allocate it with bfd_alloc rather than malloc. */
rel_hdr->contents = (PTR) bfd_alloc (abfd, rel_hdr->sh_size);
if (rel_hdr->contents == NULL && rel_hdr->sh_size != 0)
return false;
p = ((struct elf_link_hash_entry **)
bfd_malloc (o->reloc_count
* sizeof (struct elf_link_hash_entry *)));
if (p == NULL && o->reloc_count != 0)
return false;
elf_section_data (o)->rel_hashes = p;
pend = p + o->reloc_count;
for (; p < pend; p++)
*p = NULL;
return true;
}
/* Do the final step of an ELF link. */
boolean
@ -3830,32 +3879,16 @@ elf_bfd_final_link (abfd, info)
{
if ((o->flags & SEC_RELOC) != 0)
{
Elf_Internal_Shdr *rel_hdr;
register struct elf_link_hash_entry **p, **pend;
rel_hdr = &elf_section_data (o)->rel_hdr;
rel_hdr->sh_size = rel_hdr->sh_entsize * o->reloc_count;
/* The contents field must last into write_object_contents,
so we allocate it with bfd_alloc rather than malloc. */
rel_hdr->contents = (PTR) bfd_alloc (abfd, rel_hdr->sh_size);
if (rel_hdr->contents == NULL && rel_hdr->sh_size != 0)
if (!elf_link_size_reloc_section (abfd,
&elf_section_data (o)->rel_hdr,
o))
goto error_return;
p = ((struct elf_link_hash_entry **)
bfd_malloc (o->reloc_count
* sizeof (struct elf_link_hash_entry *)));
if (p == NULL && o->reloc_count != 0)
if (elf_section_data (o)->rel_hdr2
&& !elf_link_size_reloc_section (abfd,
elf_section_data (o)->rel_hdr2,
o))
goto error_return;
elf_section_data (o)->rel_hashes = p;
pend = p + o->reloc_count;
for (; p < pend; p++)
*p = NULL;
/* Use the reloc_count field as an index when outputting the
relocs. */
o->reloc_count = 0;
}
}
@ -4717,6 +4750,76 @@ elf_link_output_extsym (h, data)
return true;
}
/* Copy the relocations indicated by the INTERNAL_RELOCS (which
originated from the section given by INPUT_REL_HDR) to the
OUTPUT_BFD. */
static void
elf_link_output_relocs (output_bfd, input_section, input_rel_hdr,
internal_relocs)
bfd *output_bfd;
asection *input_section;
Elf_Internal_Shdr *input_rel_hdr;
Elf_Internal_Rela *internal_relocs;
{
Elf_Internal_Rela *irela;
Elf_Internal_Rela *irelaend;
Elf_Internal_Shdr *output_rel_hdr;
asection *output_section;
unsigned int *rel_countp;
output_section = input_section->output_section;
output_rel_hdr = NULL;
if (elf_section_data (output_section)->rel_hdr.sh_entsize
== input_rel_hdr->sh_entsize)
{
output_rel_hdr = &elf_section_data (output_section)->rel_hdr;
rel_countp = &elf_section_data (output_section)->rel_count;
}
else if (elf_section_data (output_section)->rel_hdr2
&& (elf_section_data (output_section)->rel_hdr2->sh_entsize
== input_rel_hdr->sh_entsize))
{
output_rel_hdr = elf_section_data (output_section)->rel_hdr2;
rel_countp = &elf_section_data (output_section)->rel_count2;
}
BFD_ASSERT (output_rel_hdr != NULL);
irela = internal_relocs;
irelaend = irela + input_rel_hdr->sh_size / input_rel_hdr->sh_entsize;
if (input_rel_hdr->sh_entsize == sizeof (Elf_External_Rel))
{
Elf_External_Rel *erel;
erel = ((Elf_External_Rel *) output_rel_hdr->contents + *rel_countp);
for (; irela < irelaend; irela++, erel++)
{
Elf_Internal_Rel irel;
irel.r_offset = irela->r_offset;
irel.r_info = irela->r_info;
BFD_ASSERT (irela->r_addend == 0);
elf_swap_reloc_out (output_bfd, &irel, erel);
}
}
else
{
Elf_External_Rela *erela;
BFD_ASSERT (input_rel_hdr->sh_entsize
== sizeof (Elf_External_Rela));
erela = ((Elf_External_Rela *) output_rel_hdr->contents + *rel_countp);
for (; irela < irelaend; irela++, erela++)
elf_swap_reloca_out (output_bfd, irela, erela);
}
/* Bump the counter, so that we know where to add the next set of
relocations. */
*rel_countp += input_rel_hdr->sh_size / input_rel_hdr->sh_entsize;
}
/* Link an input file into the linker output file. This function
handles all the sections and relocations of the input file at once.
This is so that we only have to read the local symbols once, and
@ -4978,7 +5081,6 @@ elf_link_input_bfd (finfo, input_bfd)
Elf_Internal_Rela *irelaend;
struct elf_link_hash_entry **rel_hash;
Elf_Internal_Shdr *input_rel_hdr;
Elf_Internal_Shdr *output_rel_hdr;
/* Adjust the reloc addresses and symbol indices. */
@ -5109,40 +5211,16 @@ elf_link_input_bfd (finfo, input_bfd)
/* Swap out the relocs. */
input_rel_hdr = &elf_section_data (o)->rel_hdr;
output_rel_hdr = &elf_section_data (o->output_section)->rel_hdr;
BFD_ASSERT (output_rel_hdr->sh_entsize
== input_rel_hdr->sh_entsize);
irela = internal_relocs;
irelaend = irela + o->reloc_count;
if (input_rel_hdr->sh_entsize == sizeof (Elf_External_Rel))
{
Elf_External_Rel *erel;
erel = ((Elf_External_Rel *) output_rel_hdr->contents
+ o->output_section->reloc_count);
for (; irela < irelaend; irela++, erel++)
{
Elf_Internal_Rel irel;
irel.r_offset = irela->r_offset;
irel.r_info = irela->r_info;
BFD_ASSERT (irela->r_addend == 0);
elf_swap_reloc_out (output_bfd, &irel, erel);
}
}
else
{
Elf_External_Rela *erela;
BFD_ASSERT (input_rel_hdr->sh_entsize
== sizeof (Elf_External_Rela));
erela = ((Elf_External_Rela *) output_rel_hdr->contents
+ o->output_section->reloc_count);
for (; irela < irelaend; irela++, erela++)
elf_swap_reloca_out (output_bfd, irela, erela);
}
o->output_section->reloc_count += o->reloc_count;
elf_link_output_relocs (output_bfd, o,
input_rel_hdr,
internal_relocs);
internal_relocs
+= input_rel_hdr->sh_size / input_rel_hdr->sh_entsize;
input_rel_hdr = elf_section_data (o)->rel_hdr2;
if (input_rel_hdr)
elf_link_output_relocs (output_bfd, o,
input_rel_hdr,
internal_relocs);
}
}