summaryrefslogtreecommitdiff
path: root/bfd/elf-m10300.c
diff options
context:
space:
mode:
authorNick Clifton <nickc@redhat.com>2007-10-19 17:31:31 +0000
committerNick Clifton <nickc@redhat.com>2007-10-19 17:31:31 +0000
commitbfff1642494227904c6c9a6c285cbaa6cf615bbb (patch)
tree7bf1ece58861b5e9c520e056102994251c0a7504 /bfd/elf-m10300.c
parent97030eea009ba78139fe20eae4585984435ac178 (diff)
downloadbinutils-bfff1642494227904c6c9a6c285cbaa6cf615bbb.tar.gz
binutils-bfff1642494227904c6c9a6c285cbaa6cf615bbb.tar.bz2
binutils-bfff1642494227904c6c9a6c285cbaa6cf615bbb.zip
Add MN10300 linker relaxation support for symbol differences
Diffstat (limited to 'bfd/elf-m10300.c')
-rw-r--r--bfd/elf-m10300.c234
1 files changed, 185 insertions, 49 deletions
diff --git a/bfd/elf-m10300.c b/bfd/elf-m10300.c
index 9aedc06b044..6c688bdcdd2 100644
--- a/bfd/elf-m10300.c
+++ b/bfd/elf-m10300.c
@@ -446,6 +446,30 @@ static reloc_howto_type elf_mn10300_howto_table[] =
0xffffffff, /* src_mask */
0xffffffff, /* dst_mask */
FALSE), /* pcrel_offset */
+
+ EMPTY_HOWTO (24),
+ EMPTY_HOWTO (25),
+ EMPTY_HOWTO (26),
+ EMPTY_HOWTO (27),
+ EMPTY_HOWTO (28),
+ EMPTY_HOWTO (29),
+ EMPTY_HOWTO (30),
+ EMPTY_HOWTO (31),
+ EMPTY_HOWTO (32),
+
+ HOWTO (R_MN10300_SYM_DIFF, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 32, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont,/* complain_on_overflow */
+ NULL, /* special handler. */
+ "R_MN10300_SYM_DIFF", /* name */
+ FALSE, /* partial_inplace */
+ 0xffffffff, /* src_mask */
+ 0xffffffff, /* dst_mask */
+ FALSE) /* pcrel_offset */
};
struct mn10300_reloc_map
@@ -480,6 +504,7 @@ static const struct mn10300_reloc_map mn10300_reloc_map[] =
{ BFD_RELOC_MN10300_GLOB_DAT, R_MN10300_GLOB_DAT },
{ BFD_RELOC_MN10300_JMP_SLOT, R_MN10300_JMP_SLOT },
{ BFD_RELOC_MN10300_RELATIVE, R_MN10300_RELATIVE },
+ { BFD_RELOC_MN10300_SYM_DIFF, R_MN10300_SYM_DIFF }
};
/* Create the GOT section. */
@@ -619,6 +644,7 @@ mn10300_elf_check_relocs (bfd *abfd,
asection *sec,
const Elf_Internal_Rela *relocs)
{
+ bfd_boolean sym_diff_reloc_seen;
Elf_Internal_Shdr *symtab_hdr;
struct elf_link_hash_entry **sym_hashes;
const Elf_Internal_Rela *rel;
@@ -642,6 +668,7 @@ mn10300_elf_check_relocs (bfd *abfd,
dynobj = elf_hash_table (info)->dynobj;
local_got_offsets = elf_local_got_offsets (abfd);
rel_end = relocs + sec->reloc_count;
+ sym_diff_reloc_seen = FALSE;
for (rel = relocs; rel < rel_end; rel++)
{
@@ -814,53 +841,98 @@ mn10300_elf_check_relocs (bfd *abfd,
h->non_got_ref = 1;
break;
+ case R_MN10300_SYM_DIFF:
+ sym_diff_reloc_seen = TRUE;
+ break;
+
case R_MN10300_32:
if (h != NULL)
h->non_got_ref = 1;
- /* If we are creating a shared library, then we need to copy
- the reloc into the shared library. */
+ /* If we are creating a shared library, then we
+ need to copy the reloc into the shared library. */
if (info->shared
- && (sec->flags & SEC_ALLOC) != 0)
+ && (sec->flags & SEC_ALLOC) != 0
+ /* Do not generate a dynamic reloc for a
+ reloc associated with a SYM_DIFF operation. */
+ && ! sym_diff_reloc_seen)
{
- /* When creating a shared object, we must copy these
- reloc types into the output file. We create a reloc
- section in dynobj and make room for this reloc. */
- if (sreloc == NULL)
- {
- const char * name;
-
- name = (bfd_elf_string_from_elf_section
- (abfd,
- elf_elfheader (abfd)->e_shstrndx,
- elf_section_data (sec)->rel_hdr.sh_name));
- if (name == NULL)
- return FALSE;
+ asection * sym_section = NULL;
- BFD_ASSERT (CONST_STRNEQ (name, ".rela")
- && streq (bfd_get_section_name (abfd, sec), name + 5));
+ /* Find the section containing the
+ symbol involved in the relocation. */
+ if (h == NULL)
+ {
+ Elf_Internal_Sym * isymbuf;
+ Elf_Internal_Sym * isym;
+
+ isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents;
+ if (isymbuf == NULL)
+ isymbuf = bfd_elf_get_elf_syms (abfd, symtab_hdr,
+ symtab_hdr->sh_info, 0,
+ NULL, NULL, NULL);
+ if (isymbuf)
+ {
+ isym = isymbuf + r_symndx;
+ /* All we care about is whether this local symbol is absolute. */
+ if (isym->st_shndx == SHN_ABS)
+ sym_section = bfd_abs_section_ptr;
+ }
+ }
+ else
+ {
+ if (h->root.type == bfd_link_hash_defined
+ || h->root.type == bfd_link_hash_defweak)
+ sym_section = h->root.u.def.section;
+ }
- sreloc = bfd_get_section_by_name (dynobj, name);
+ /* If the symbol is absolute then the relocation can
+ be resolved during linking and there is no need for
+ a dynamic reloc. */
+ if (sym_section != bfd_abs_section_ptr)
+ {
+ /* When creating a shared object, we must copy these
+ reloc types into the output file. We create a reloc
+ section in dynobj and make room for this reloc. */
if (sreloc == NULL)
{
- flagword flags;
+ const char * name;
- flags = (SEC_HAS_CONTENTS | SEC_READONLY
- | SEC_IN_MEMORY | SEC_LINKER_CREATED);
- if ((sec->flags & SEC_ALLOC) != 0)
- flags |= SEC_ALLOC | SEC_LOAD;
- sreloc = bfd_make_section_with_flags (dynobj, name, flags);
- if (sreloc == NULL
- || ! bfd_set_section_alignment (dynobj, sreloc, 2))
+ name = (bfd_elf_string_from_elf_section
+ (abfd,
+ elf_elfheader (abfd)->e_shstrndx,
+ elf_section_data (sec)->rel_hdr.sh_name));
+ if (name == NULL)
return FALSE;
+
+ BFD_ASSERT (CONST_STRNEQ (name, ".rela")
+ && streq (bfd_get_section_name (abfd, sec), name + 5));
+
+ sreloc = bfd_get_section_by_name (dynobj, name);
+ if (sreloc == NULL)
+ {
+ flagword flags;
+
+ flags = (SEC_HAS_CONTENTS | SEC_READONLY
+ | SEC_IN_MEMORY | SEC_LINKER_CREATED);
+ if ((sec->flags & SEC_ALLOC) != 0)
+ flags |= SEC_ALLOC | SEC_LOAD;
+ sreloc = bfd_make_section_with_flags (dynobj, name, flags);
+ if (sreloc == NULL
+ || ! bfd_set_section_alignment (dynobj, sreloc, 2))
+ return FALSE;
+ }
}
- }
- sreloc->size += sizeof (Elf32_External_Rela);
+ sreloc->size += sizeof (Elf32_External_Rela);
+ }
}
break;
}
+
+ if (ELF32_R_TYPE (rel->r_info) != R_MN10300_SYM_DIFF)
+ sym_diff_reloc_seen = FALSE;
}
return TRUE;
@@ -904,6 +976,9 @@ mn10300_elf_final_link_relocate (reloc_howto_type *howto,
asection *sym_sec ATTRIBUTE_UNUSED,
int is_local ATTRIBUTE_UNUSED)
{
+ static asection * sym_diff_section;
+ static bfd_vma sym_diff_value;
+ bfd_boolean is_sym_diff_reloc;
unsigned long r_type = howto->type;
bfd_byte * hit_data = contents + offset;
bfd * dynobj;
@@ -937,13 +1012,54 @@ mn10300_elf_final_link_relocate (reloc_howto_type *howto,
return bfd_reloc_dangerous;
}
+ is_sym_diff_reloc = FALSE;
+ if (sym_diff_section != NULL)
+ {
+ BFD_ASSERT (sym_diff_section == input_section);
+
+ switch (r_type)
+ {
+ case R_MN10300_32:
+ case R_MN10300_24:
+ case R_MN10300_16:
+ case R_MN10300_8:
+ value -= sym_diff_value;
+ sym_diff_section = NULL;
+ is_sym_diff_reloc = TRUE;
+ break;
+
+ default:
+ sym_diff_section = NULL;
+ break;
+ }
+ }
+
switch (r_type)
{
+ case R_MN10300_SYM_DIFF:
+ BFD_ASSERT (addend == 0);
+ /* Cache the input section and value.
+ The offset is unreliable, since relaxation may
+ have reduced the following reloc's offset. */
+ sym_diff_section = input_section;
+ sym_diff_value = value;
+ return bfd_reloc_ok;
+
case R_MN10300_NONE:
return bfd_reloc_ok;
case R_MN10300_32:
if (info->shared
+ /* Do not generate relocs when an R_MN10300_32 has been used
+ with an R_MN10300_SYM_DIFF to compute a difference of two
+ symbols. */
+ && is_sym_diff_reloc == FALSE
+ /* Also, do not generate a reloc when the symbol associated
+ with the R_MN10300_32 reloc is absolute - there is no
+ need for a run time computation in this case. */
+ && sym_sec != bfd_abs_section_ptr
+ /* If the section is not going to be allocated at load time
+ then there is no need to generate relocs for it. */
&& (input_section->flags & SEC_ALLOC) != 0)
{
Elf_Internal_Rela outrel;
@@ -1370,6 +1486,10 @@ mn10300_elf_relocate_section (bfd *output_bfd,
&& elf_hash_table (info)->dynamic_sections_created
&& !SYMBOL_REFERENCES_LOCAL (info, hh))
|| (r_type == R_MN10300_32
+ /* _32 relocs in executables force _COPY relocs,
+ such that the address of the symbol ends up
+ being local. */
+ && !info->executable
&& !SYMBOL_REFERENCES_LOCAL (info, hh)
&& ((input_section->flags & SEC_ALLOC) != 0
/* DWARF will emit R_MN10300_32 relocations
@@ -1551,7 +1671,7 @@ static bfd_boolean
elf32_mn10300_count_hash_table_entries (struct bfd_hash_entry *gen_entry ATTRIBUTE_UNUSED,
void * in_args)
{
- int *count = (int *)in_args;
+ int *count = (int *) in_args;
(*count) ++;
return TRUE;
@@ -1576,9 +1696,9 @@ static int
sort_by_value (const void *va, const void *vb)
{
struct elf32_mn10300_link_hash_entry *a
- = *(struct elf32_mn10300_link_hash_entry **)va;
+ = *(struct elf32_mn10300_link_hash_entry **) va;
struct elf32_mn10300_link_hash_entry *b
- = *(struct elf32_mn10300_link_hash_entry **)vb;
+ = *(struct elf32_mn10300_link_hash_entry **) vb;
return a->value - b->value;
}
@@ -1735,8 +1855,14 @@ mn10300_elf_relax_delete_bytes (bfd *abfd,
{
if (isym->st_shndx == sec_shndx
&& isym->st_value > addr
- && isym->st_value < toaddr)
+ && isym->st_value <= toaddr)
isym->st_value -= count;
+ /* Adjust the function symbol's size as well. */
+ else if (isym->st_shndx == sec_shndx
+ && ELF_ST_TYPE (isym->st_info) == STT_FUNC
+ && isym->st_value + isym->st_size > addr
+ && isym->st_value + isym->st_size <= toaddr)
+ isym->st_size -= count;
}
/* Now adjust the global symbols defined in this section. */
@@ -1752,8 +1878,15 @@ mn10300_elf_relax_delete_bytes (bfd *abfd,
|| sym_hash->root.type == bfd_link_hash_defweak)
&& sym_hash->root.u.def.section == sec
&& sym_hash->root.u.def.value > addr
- && sym_hash->root.u.def.value < toaddr)
+ && sym_hash->root.u.def.value <= toaddr)
sym_hash->root.u.def.value -= count;
+ /* Adjust the function symbol's size as well. */
+ else if (sym_hash->root.type == bfd_link_hash_defined
+ && sym_hash->root.u.def.section == sec
+ && sym_hash->type == STT_FUNC
+ && sym_hash->root.u.def.value + sym_hash->size > addr
+ && sym_hash->root.u.def.value + sym_hash->size <= toaddr)
+ sym_hash->size -= count;
}
return TRUE;
@@ -1981,7 +2114,7 @@ mn10300_elf_relax_section (bfd *abfd,
local symbol in the global hash table. */
amt = strlen (sym_name) + 10;
new_name = bfd_malloc (amt);
- if (new_name == 0)
+ if (new_name == NULL)
goto error_return;
sprintf (new_name, "%s_%08x", sym_name, sym_sec->id);
@@ -2090,7 +2223,7 @@ mn10300_elf_relax_section (bfd *abfd,
local symbol in the global hash table. */
amt = strlen (sym_name) + 10;
new_name = bfd_malloc (amt);
- if (new_name == 0)
+ if (new_name == NULL)
goto error_return;
sprintf (new_name, "%s_%08x", sym_name, sym_sec->id);
@@ -2302,7 +2435,7 @@ mn10300_elf_relax_section (bfd *abfd,
local symbol in the global hash table. */
amt = strlen (sym_name) + 10;
new_name = bfd_malloc (amt);
- if (new_name == 0)
+ if (new_name == NULL)
goto error_return;
sprintf (new_name, "%s_%08x", sym_name, sym_sec->id);
sym_name = new_name;
@@ -2514,7 +2647,6 @@ mn10300_elf_relax_section (bfd *abfd,
asection *sym_sec = NULL;
const char *sym_name;
char *new_name;
- bfd_vma saved_addend;
/* A local symbol. */
isym = isymbuf + ELF32_R_SYM (irel->r_info);
@@ -2535,22 +2667,22 @@ mn10300_elf_relax_section (bfd *abfd,
&& ELF_ST_TYPE (isym->st_info) == STT_SECTION
&& sym_sec->sec_info_type == ELF_INFO_TYPE_MERGE)
{
+ bfd_vma saved_addend;
+
saved_addend = irel->r_addend;
- symval = _bfd_elf_rela_local_sym (abfd, isym, &sym_sec, irel);
+ symval = _bfd_elf_rela_local_sym (abfd, isym, & sym_sec, irel);
symval += irel->r_addend;
irel->r_addend = saved_addend;
}
else
- {
- symval = (isym->st_value
- + sym_sec->output_section->vma
- + sym_sec->output_offset);
- }
+ symval = (isym->st_value
+ + sym_sec->output_section->vma
+ + sym_sec->output_offset);
/* Tack on an ID so we can uniquely identify this
local symbol in the global hash table. */
new_name = bfd_malloc ((bfd_size_type) strlen (sym_name) + 10);
- if (new_name == 0)
+ if (new_name == NULL)
goto error_return;
sprintf (new_name, "%s_%08x", sym_name, sym_sec->id);
sym_name = new_name;
@@ -2576,6 +2708,10 @@ mn10300_elf_relax_section (bfd *abfd,
regular reloc processing. */
continue;
+ /* Check for a reference to a discarded symbol and ignore it. */
+ if (h->root.root.u.def.section->output_section == NULL)
+ continue;
+
symval = (h->root.root.u.def.value
+ h->root.root.u.def.section->output_section->vma
+ h->root.root.u.def.section->output_offset);
@@ -3284,7 +3420,7 @@ mn10300_elf_relax_section (bfd *abfd,
case 0x93:
/* sp-based offsets are zero-extended. */
if (code >= 0x90 && code <= 0x93
- && (long)value < 0)
+ && (long) value < 0)
continue;
/* Note that we've changed the relocation contents, etc. */
@@ -3341,7 +3477,7 @@ mn10300_elf_relax_section (bfd *abfd,
/* mov imm16, an zero-extends the immediate. */
if (code == 0xdc
- && (long)value < 0)
+ && (long) value < 0)
continue;
/* Note that we've changed the relocation contents, etc. */
@@ -3422,12 +3558,12 @@ mn10300_elf_relax_section (bfd *abfd,
case 0xe3:
/* cmp imm16, an zero-extends the immediate. */
if (code == 0xdc
- && (long)value < 0)
+ && (long) value < 0)
continue;
/* So do sp-based offsets. */
if (code >= 0xb0 && code <= 0xb3
- && (long)value < 0)
+ && (long) value < 0)
continue;
/* Note that we've changed the relocation contents, etc. */