PARAMS ((bfd *, struct mips_got_info *, asection *, bfd_vma));
static bfd_vma mips_elf_got16_entry
PARAMS ((bfd *, struct bfd_link_info *, bfd_vma));
-static unsigned int mips_elf_create_dynamic_relocation
+static boolean mips_elf_create_dynamic_relocation
PARAMS ((bfd *, struct bfd_link_info *, const Elf_Internal_Rela *,
- long, bfd_vma, asection *));
+ struct mips_elf_link_hash_entry *, asection *,
+ bfd_vma, bfd_vma *, asection *));
static void mips_elf_allocate_dynamic_relocations
PARAMS ((bfd *, unsigned int));
static boolean mips_elf_stub_section_p
_bfd_mips_elf_got16_reloc, /* special_function */
"R_MIPS_GOT16", /* name */
false, /* partial_inplace */
- 0, /* src_mask */
+ 0xffff, /* src_mask */
0xffff, /* dst_mask */
false), /* pcrel_offset */
bfd_elf_generic_reloc, /* special_function */
"R_MIPS_CALL16", /* name */
false, /* partial_inplace */
- 0, /* src_mask */
+ 0xffff, /* src_mask */
0xffff, /* dst_mask */
false), /* pcrel_offset */
mips_elf_text_section.symbol = &mips_elf_text_symbol;
mips_elf_text_section.symbol_ptr_ptr = &mips_elf_text_symbol_ptr;
mips_elf_text_symbol.name = ".text";
- mips_elf_text_symbol.flags = BSF_SECTION_SYM;
+ mips_elf_text_symbol.flags = BSF_SECTION_SYM | BSF_DYNAMIC;
mips_elf_text_symbol.section = &mips_elf_text_section;
mips_elf_text_symbol_ptr = &mips_elf_text_symbol;
mips_elf_text_section_ptr = &mips_elf_text_section;
mips_elf_data_section.symbol = &mips_elf_data_symbol;
mips_elf_data_section.symbol_ptr_ptr = &mips_elf_data_symbol_ptr;
mips_elf_data_symbol.name = ".data";
- mips_elf_data_symbol.flags = BSF_SECTION_SYM;
+ mips_elf_data_symbol.flags = BSF_SECTION_SYM | BSF_DYNAMIC;
mips_elf_data_symbol.section = &mips_elf_data_section;
mips_elf_data_symbol_ptr = &mips_elf_data_symbol;
mips_elf_data_section_ptr = &mips_elf_data_section;
bfd_vma index;
bfd_vma address;
- value &= 0xffff0000;
+ /* Although the ABI says that it is "the high-order 16 bits" that we
+ want, it is really the %high value. The complete value is
+ calculated with a `addiu' of a LO16 relocation, just as with a
+ HI16/LO16 pair. */
+ value = mips_elf_high (value) << 16;
g = mips_elf_got_info (elf_hash_table (info)->dynobj, &sgot);
/* Look to see if we already have an appropriate entry. */
if ((address & 0xffff0000) == value)
{
/* This entry has the right high-order 16 bits. */
- index = MIPS_ELF_GOT_SIZE (abfd) * (entry - sgot->contents);
+ index = entry - sgot->contents;
break;
}
}
return NULL;
}
-/* Create a rel.dyn relocation for the dynamic linker to resolve. The
- relocatin is against the symbol with the dynamic symbol table index
- DYNINDX. REL is the original relocation, which is now being made
- dynamic. */
+/* Create a rel.dyn relocation for the dynamic linker to resolve. REL
+ is the original relocation, which is now being transformed into a
+ dyanmic relocation. The ADDENDP is adjusted if necessary; the
+ caller should store the result in place of the original addend. */
-static unsigned int
-mips_elf_create_dynamic_relocation (output_bfd, info, rel, dynindx,
- addend, input_section)
+static boolean
+mips_elf_create_dynamic_relocation (output_bfd, info, rel, h, sec,
+ symbol, addendp, input_section)
bfd *output_bfd;
struct bfd_link_info *info;
const Elf_Internal_Rela *rel;
- long dynindx;
- bfd_vma addend;
+ struct mips_elf_link_hash_entry *h;
+ asection *sec;
+ bfd_vma symbol;
+ bfd_vma *addendp;
asection *input_section;
{
Elf_Internal_Rel outrel;
skip = false;
- /* The symbol for the relocation is the same as it was for the
- original relocation. */
- outrel.r_info = ELF32_R_INFO (dynindx, R_MIPS_REL32);
-
- /* The offset for the dynamic relocation is the same as for the
- original relocation, adjusted by the offset at which the original
- section is output. */
+ /* We begin by assuming that the offset for the dynamic relocation
+ is the same as for the original relocation. We'll adjust this
+ later to reflect the correct output offsets. */
if (elf_section_data (input_section)->stab_info == NULL)
outrel.r_offset = rel->r_offset;
else
{
- bfd_vma off;
-
- off = (_bfd_stab_section_offset
- (output_bfd, &elf_hash_table (info)->stab_info,
- input_section,
- &elf_section_data (input_section)->stab_info,
- rel->r_offset));
- if (off == (bfd_vma) -1)
+ /* Except that in a stab section things are more complex.
+ Because we compress stab information, the offset given in the
+ relocation may not be the one we want; we must let the stabs
+ machinery tell us the offset. */
+ outrel.r_offset
+ = (_bfd_stab_section_offset
+ (output_bfd, &elf_hash_table (info)->stab_info,
+ input_section,
+ &elf_section_data (input_section)->stab_info,
+ rel->r_offset));
+ /* If we didn't need the relocation at all, this value will be
+ -1. */
+ if (outrel.r_offset == (bfd_vma) -1)
skip = true;
- outrel.r_offset = off;
}
- outrel.r_offset += (input_section->output_section->vma
- + input_section->output_offset);
/* If we've decided to skip this relocation, just output an emtpy
- record. */
+ record. Note that R_MIPS_NONE == 0, so that this call to memset
+ is a way of setting R_TYPE to R_MIPS_NONE. */
if (skip)
memset (&outrel, 0, sizeof (outrel));
+ else
+ {
+ long indx;
+ bfd_vma section_offset;
+ /* We must now calculate the dynamic symbol table index to use
+ in the relocation. */
+ if (h != NULL
+ && (! info->symbolic || (h->root.elf_link_hash_flags
+ & ELF_LINK_HASH_DEF_REGULAR) == 0))
+ {
+ indx = h->root.dynindx;
+ BFD_ASSERT (indx != -1);
+ }
+ else
+ {
+ if (sec != NULL && bfd_is_abs_section (sec))
+ indx = 0;
+ else if (sec == NULL || sec->owner == NULL)
+ {
+ bfd_set_error (bfd_error_bad_value);
+ return false;
+ }
+ else
+ {
+ indx = elf_section_data (sec->output_section)->dynindx;
+ if (indx == 0)
+ abort ();
+ }
+
+ /* Figure out how far the target of the relocation is from
+ the beginning of its section. */
+ section_offset = symbol - sec->output_section->vma;
+ /* The relocation we're building is section-relative.
+ Therefore, the original addend must be adjusted by the
+ section offset. */
+ *addendp += symbol - sec->output_section->vma;
+ /* Now, the relocation is just against the section. */
+ symbol = sec->output_section->vma;
+ }
+
+ /* If the relocation was previously an absolute relocation, we
+ must adjust it by the value we give it in the dynamic symbol
+ table. */
+ if (r_type != R_MIPS_REL32)
+ *addendp += symbol;
+
+ /* The relocation is always an REL32 relocation because we don't
+ know where the shared library will wind up at load-time. */
+ outrel.r_info = ELF32_R_INFO (indx, R_MIPS_REL32);
+
+ /* Adjust the output offset of the relocation to reference the
+ correct location in the output file. */
+ outrel.r_offset += (input_section->output_section->vma
+ + input_section->output_offset);
+ }
+
+ /* Put the relocation back out. We have to use the special
+ relocation outputter in the 64-bit case since the 64-bit
+ relocation format is non-standard. */
if (ABI_64_P (output_bfd))
{
(*get_elf_backend_data (output_bfd)->s->swap_reloc_out)
(((Elf32_External_Rel *)
sreloc->contents)
+ sreloc->reloc_count));
+
+ /* Record the index of the first relocation referencing H. This
+ information is later emitted in the .msym section. */
+ if (h != NULL
+ && (h->min_dyn_reloc_index == 0
+ || sreloc->reloc_count < h->min_dyn_reloc_index))
+ h->min_dyn_reloc_index = sreloc->reloc_count;
+
+ /* We've now added another relocation. */
++sreloc->reloc_count;
/* Make sure the output section is writable. The dynamic linker
else
mips_elf_set_cr_type (cptrel, CRT_MIPS_WORD);
mips_elf_set_cr_dist2to (cptrel, 0);
- cptrel.konst = addend;
+ cptrel.konst = *addendp;
cr = (scpt->contents
+ sizeof (Elf32_External_compact_rel));
}
}
- return sreloc->reloc_count - 1;
+ return true;
}
/* Calculate the value produced by the RELOCATION (which comes from
addresses. */
symbol = 0;
else if (info->shared && !info->symbolic && !info->no_undefined)
- relocation = 0;
+ symbol = 0;
else if (strcmp (h->root.root.root.string, "_DYNAMIC_LINK") == 0)
{
/* If this is a dynamic link, we should have created a
somehow as well. */
BFD_ASSERT (! info->shared);
BFD_ASSERT (bfd_get_section_by_name (abfd, ".dynamic") == NULL);
- relocation = 0;
+ symbol = 0;
}
else
{
case R_MIPS_GOT_LO16:
case R_MIPS_CALL_LO16:
/* Find the index into the GOT where this value is located. */
- if (h)
+ if (!local_p)
{
BFD_ASSERT (addend == 0);
g = mips_elf_global_got_index
(elf_hash_table (info)->dynobj,
(struct elf_link_hash_entry*) h);
}
+ else if (r_type == R_MIPS_GOT16)
+ /* There's no need to create a local GOT entry here; the
+ calculation for a local GOT16 entry does not involve G. */
+ break;
else
{
g = mips_elf_local_got_index (abfd, info, symbol + addend);
case R_MIPS_32:
case R_MIPS_REL32:
case R_MIPS_64:
- /* If we're creating a shared library, or this relocation is
- against a symbol in a shared library, then we can't know
- where the symbol will end up. So, we create a relocation
- record in the output, and leave the job up to the dynamic
- linker. */
- if (info->shared || !sec->output_section)
+ if ((info->shared
+ || (elf_hash_table (info)->dynamic_sections_created
+ && h != NULL
+ && ((h->root.elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR)
+ == 0)))
+ && (input_section->flags & SEC_ALLOC) != 0)
{
- unsigned int reloc_index;
-
- BFD_ASSERT (h != NULL);
- reloc_index
- = mips_elf_create_dynamic_relocation (abfd,
- info,
- relocation,
- h->root.dynindx,
- addend,
- input_section);
- if (h->min_dyn_reloc_index == 0
- || reloc_index < h->min_dyn_reloc_index)
- h->min_dyn_reloc_index = reloc_index;
- value = symbol + addend;
+ /* If we're creating a shared library, or this relocation is
+ against a symbol in a shared library, then we can't know
+ where the symbol will end up. So, we create a relocation
+ record in the output, and leave the job up to the dynamic
+ linker. */
+ value = addend;
+ if (!mips_elf_create_dynamic_relocation (abfd,
+ info,
+ relocation,
+ h,
+ sec,
+ symbol,
+ &value,
+ input_section))
+ return false;
}
else
{
const Elf_Internal_Rela *lo16_relocation;
reloc_howto_type *lo16_howto;
- /* Scan ahead to find a matching R_MIPS_LO16
+ /* The combined value is the sum of the HI16 addend,
+ left-shifted by sixteen bits, and the LO16
+ addend, sign extended. (Usually, the code does
+ a `lui' of the HI16 value, and then an `addiu' of
+ the LO16 value.)
+
+ Scan ahead to find a matching R_MIPS_LO16
relocation. */
lo16_relocation
= mips_elf_next_lo16_relocation (rel, relend);
lo16_relocation,
input_bfd, contents);
l &= lo16_howto->src_mask;
+ l = mips_elf_sign_extend (l, 16);
/* Save the high-order bit for later. When we
encounter the R_MIPS_LO16 relocation we will need
last_hi16_addend_valid_p = true;
/* Compute the combined addend. */
- addend |= l;
+ addend += l;
}
else if (r_type == R_MIPS_LO16)
{
| ((addend & 0x7e00000) >> 16)
| (addend & 0x1f));
}
- else if (r_type == R_MIPS16_26
- || r_type == R_MIPS16_26)
- /* The addend is stored without its two least
- significant bits (which are always zero.) */
- addend <<= 2;
}
else
addend = rel->r_addend;
/* There's nothing to do for non-local relocations. */
continue;
- r_symndx = ELF32_R_SYM (rel->r_info);
- sym = local_syms + r_symndx;
- if (ELF_ST_TYPE (sym->st_info) == STT_SECTION)
- /* Adjust the addend appropriately. */
- addend += local_sections[r_symndx]->output_offset;
-
if (r_type == R_MIPS16_GPREL
|| r_type == R_MIPS_GPREL16
|| r_type == R_MIPS_GPREL32)
addend -= (_bfd_get_gp_value (output_bfd)
- _bfd_get_gp_value (input_bfd));
+ else if (r_type == R_MIPS_26 || r_type == R_MIPS16_26)
+ /* The addend is stored without its two least
+ significant bits (which are always zero.) In a
+ non-relocateable link, calculate_relocation will do
+ this shift; here, we must do it ourselves. */
+ addend <<= 2;
+ r_symndx = ELF32_R_SYM (rel->r_info);
+ sym = local_syms + r_symndx;
+ if (ELF_ST_TYPE (sym->st_info) == STT_SECTION)
+ /* Adjust the addend appropriately. */
+ addend += local_sections[r_symndx]->output_offset;
+
/* If the relocation is for a R_MIPS_HI16 or R_MIPS_GOT16,
then we only want to write out the high-order 16 bits.
The subsequent R_MIPS_LO16 will handle the low-order bits. */
if (!h && (r_type == R_MIPS_CALL_LO16
|| r_type == R_MIPS_GOT_LO16
- || r_type == R_MIPS_GOT_DISP
- || r_type == R_MIPS_GOT16))
+ || r_type == R_MIPS_GOT_DISP))
{
/* We may need a local GOT entry for this relocation. We
don't count R_MIPS_GOT_PAGE because we can estimate the
maximum number of pages needed by looking at the size of
- the segment. We don't count R_MIPS_GOT_HI16, or
- R_MIPS_CALL_HI16 because these are always followed by an
- R_MIPS_GOT_LO16 or R_MIPS_CALL_LO16.
+ the segment. Similar comments apply to R_MIPS_GOT16. We
+ don't count R_MIPS_GOT_HI16, or R_MIPS_CALL_HI16 because
+ these are always followed by an R_MIPS_GOT_LO16 or
+ R_MIPS_CALL_LO16.
This estimation is very conservative since we can merge
duplicate entries in the GOT. In order to be less
/* Even though we don't directly need a GOT entry for
this symbol, a symbol must have a dynamic symbol
- table index greater that DT_GOTSYM if there are
+ table index greater that DT_MIPS_GOTSYM if there are
dynamic relocations against it. */
- if (!mips_elf_record_global_got_symbol (h, info, g))
+ if (h != NULL
+ && !mips_elf_record_global_got_symbol (h, info, g))
return false;
}
loadable_size += MIPS_FUNCTION_STUB_SIZE;
/* Assume there are two loadable segments consisting of
- contiguous sections. Is 5 enough? */
+ contiguous sections. Is 5 enough? */
local_gotno = (loadable_size >> 16) + 5;
+ if (IRIX_COMPAT (output_bfd) == ict_irix6)
+ /* It's possible we will need GOT_PAGE entries as well as
+ GOT16 entries. Often, these will be able to share GOT
+ entries, but not always. */
+ local_gotno *= 2;
+
g->local_gotno += local_gotno;
s->_raw_size += local_gotno * MIPS_ELF_GOT_SIZE (dynobj);
if (! MIPS_ELF_ADD_DYNAMIC_ENTRY (info, DT_MIPS_UNREFEXTNO, 0))
return false;
- if (g != NULL && g->global_gotsym != NULL
- && ! MIPS_ELF_ADD_DYNAMIC_ENTRY (info, DT_MIPS_GOTSYM, 0))
+ if (! MIPS_ELF_ADD_DYNAMIC_ENTRY (info, DT_MIPS_GOTSYM, 0))
return false;
if (IRIX_COMPAT (dynobj) == ict_irix5
dyn.d_un.d_val = g->local_gotno;
break;
+ case DT_MIPS_UNREFEXTNO:
+ /* The index into the dynamic symbol table which is the
+ entry of the first external symbol that is not
+ referenced within the same object. */
+ dyn.d_un.d_val = bfd_count_sections (output_bfd) + 1;
+ break;
+
+ case DT_MIPS_GOTSYM:
+ if (g->global_gotsym)
+ {
+ dyn.d_un.d_val = g->global_gotsym->dynindx;
+ break;
+ }
+ /* In case if we don't have global got symbols we default
+ to setting DT_MIPS_GOTSYM to the same value as
+ DT_MIPS_SYMTABNO, so we just fall through. */
+
case DT_MIPS_SYMTABNO:
name = ".dynsym";
elemsize = MIPS_ELF_SYM_SIZE (output_bfd);
dyn.d_un.d_val = s->_raw_size / elemsize;
break;
- case DT_MIPS_UNREFEXTNO:
- /* The index into the dynamic symbol table which is the
- entry of the first external symbol that is not
- referenced within the same object. */
- dyn.d_un.d_val = bfd_count_sections (output_bfd) + 1;
- break;
-
- case DT_MIPS_GOTSYM:
- dyn.d_un.d_val = g->global_gotsym->dynindx;
- break;
-
case DT_MIPS_HIPAGENO:
dyn.d_un.d_val = g->local_gotno - MIPS_RESERVED_GOTNO;
break;