section) against this symbol. */
unsigned int min_dyn_reloc_index;
+ /* We must not create a stub for a symbol that has relocations
+ related to taking the function's address, i.e. any but
+ R_MIPS_CALL*16 ones -- see "MIPS ABI Supplement, 3rd Edition",
+ p. 4-20. */
+ boolean no_fn_stub;
+
/* If there is a stub that 32 bit functions should use to call this
16 bit function, this points to the section containing the stub. */
asection *fn_stub;
static boolean mips_elf_create_dynamic_relocation
PARAMS ((bfd *, struct bfd_link_info *, const Elf_Internal_Rela *,
struct mips_elf_link_hash_entry *, asection *,
- bfd_vma, bfd_vma *, asection *, boolean local_p));
+ bfd_vma, bfd_vma *, asection *));
static void mips_elf_allocate_dynamic_relocations
PARAMS ((bfd *, unsigned int));
static boolean mips_elf_stub_section_p
complain_overflow_dont, /* complain_on_overflow */
/* This needs complex overflow
detection, because the upper four
- bits must match the PC. */
+ bits must match the PC + 4. */
bfd_elf_generic_reloc, /* special_function */
"R_MIPS_26", /* name */
true, /* partial_inplace */
ret->esym.ifd = -2;
ret->possibly_dynamic_relocs = 0;
ret->min_dyn_reloc_index = 0;
+ ret->no_fn_stub = false;
ret->fn_stub = NULL;
ret->need_fn_stub = false;
ret->call_stub = NULL;
}
else if ((h->root.elf_link_hash_flags & ELF_LINK_HASH_NEEDS_PLT) != 0)
{
- /* Set type and value for a symbol with a function stub. */
- h->esym.asym.st = stProc;
- sec = h->root.root.u.def.section;
- if (sec == NULL)
- h->esym.asym.value = 0;
- else
+ struct mips_elf_link_hash_entry *hd = h;
+ boolean no_fn_stub = h->no_fn_stub;
+
+ while (hd->root.root.type == bfd_link_hash_indirect)
{
- output_section = sec->output_section;
- if (output_section != NULL)
- h->esym.asym.value = (h->root.plt.offset
- + sec->output_offset
- + output_section->vma);
- else
- h->esym.asym.value = 0;
+ hd = (struct mips_elf_link_hash_entry *)h->root.root.u.i.link;
+ no_fn_stub = no_fn_stub || hd->no_fn_stub;
}
+
+ if (!no_fn_stub)
+ {
+ /* Set type and value for a symbol with a function stub. */
+ h->esym.asym.st = stProc;
+ sec = hd->root.root.u.def.section;
+ if (sec == NULL)
+ h->esym.asym.value = 0;
+ else
+ {
+ output_section = sec->output_section;
+ if (output_section != NULL)
+ h->esym.asym.value = (hd->root.plt.offset
+ + sec->output_offset
+ + output_section->vma);
+ else
+ h->esym.asym.value = 0;
+ }
#if 0 /* FIXME? */
- h->esym.ifd = 0;
+ h->esym.ifd = 0;
#endif
+ }
}
if (! bfd_ecoff_debug_one_external (einfo->abfd, einfo->debug, einfo->swap,
static boolean
mips_elf_create_dynamic_relocation (output_bfd, info, rel, h, sec,
- symbol, addendp, input_section, local_p)
+ symbol, addendp, input_section)
bfd *output_bfd;
struct bfd_link_info *info;
const Elf_Internal_Rela *rel;
bfd_vma symbol;
bfd_vma *addendp;
asection *input_section;
- boolean local_p;
{
Elf_Internal_Rel outrel;
boolean skip;
/* 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;
+ *addendp += section_offset;
/* Now, the relocation is just against the section. */
symbol = sec->output_section->vma;
}
- /* If the relocation is against a local symbol was previously an
- absolute relocation, we must adjust it by the value we give
- it in the dynamic symbol table. */
- if (local_p && r_type != R_MIPS_REL32)
+ /* If the relocation was previously an absolute relocation and
+ this symbol will not be referred to by the relocation, we must
+ adjust it by the value we give it in the dynamic symbol table.
+ Otherwise leave the job up to the dynamic linker. */
+ if (!indx && r_type != R_MIPS_REL32)
*addendp += symbol;
/* The relocation is always an REL32 relocation because we don't
symbol + addend, sgot->contents + g);
}
}
- else if (r_type == R_MIPS_GOT16)
+ else if (r_type == R_MIPS_GOT16 || r_type == R_MIPS_CALL16)
/* There's no need to create a local GOT entry here; the
calculation for a local GOT16 entry does not involve G. */
break;
sec,
symbol,
&value,
- input_section, local_p))
+ input_section))
return false;
}
else
break;
case R_MIPS16_26:
- /* The calculation for R_MIPS_26 is just the same as for an
+ /* The calculation for R_MIPS16_26 is just the same as for an
R_MIPS_26. It's only the storage of the relocated field into
the output file that's different. That's handled in
mips_elf_perform_relocation. So, we just fall through to the
R_MIPS_26 case here. */
case R_MIPS_26:
if (local_p)
- value = (((addend << 2) | (p & 0xf0000000)) + symbol) >> 2;
+ value = (((addend << 2) | ((p + 4) & 0xf0000000)) + symbol) >> 2;
else
value = (mips_elf_sign_extend (addend << 2, 28) + symbol) >> 2;
value &= howto->dst_mask;
break;
case R_MIPS_GOT16:
+ case R_MIPS_CALL16:
if (local_p)
{
boolean forced;
/* Fall through. */
- case R_MIPS_CALL16:
case R_MIPS_GOT_DISP:
value = g;
overflowed_p = mips_elf_overflow_p (value, 16);
((sub1 << 16) | sub2)).
When producing a relocateable object file, the calculation is
- (((A < 2) | (P & 0xf0000000) + S) >> 2)
+ (((A < 2) | ((P + 4) & 0xf0000000) + S) >> 2)
When producing a fully linked file, the calculation is
- let R = (((A < 2) | (P & 0xf0000000) + S) >> 2)
+ let R = (((A < 2) | ((P + 4) & 0xf0000000) + S) >> 2)
((R & 0x1f0000) << 5) | ((R & 0x3e00000) >> 5) | (R & 0xffff) */
if (!info->relocateable)
/* 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. 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.
+ the segment. Similar comments apply to R_MIPS_GOT16 and
+ R_MIPS_CALL16. 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
break;
}
+ /* We must not create a stub for a symbol that has relocations
+ related to taking the function's address. */
+ switch (r_type)
+ {
+ default:
+ if (h != NULL)
+ {
+ struct mips_elf_link_hash_entry *mh;
+
+ mh = (struct mips_elf_link_hash_entry *) h;
+ mh->no_fn_stub = true;
+ }
+ break;
+ case R_MIPS_CALL16:
+ case R_MIPS_CALL_HI16:
+ case R_MIPS_CALL_LO16:
+ break;
+ }
+
/* If this reloc is not a 16 bit call, and it has a global
symbol, then we will need the fn_stub if there is one.
References from a stub section do not count. */
|| (indmips->min_dyn_reloc_index != 0
&& indmips->min_dyn_reloc_index < dirmips->min_dyn_reloc_index))
dirmips->min_dyn_reloc_index = indmips->min_dyn_reloc_index;
+ if (indmips->no_fn_stub)
+ dirmips->no_fn_stub = true;
}
/* Adjust a symbol defined by a dynamic object and referenced by a
mips_elf_allocate_dynamic_relocations (dynobj,
hmips->possibly_dynamic_relocs);
- /* For a function, create a stub, if needed. */
- if ((h->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_PLT) != 0)
+ /* For a function, create a stub, if allowed. */
+ if (! hmips->no_fn_stub
+ && (h->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_PLT) != 0)
{
if (! elf_hash_table (info)->dynamic_sections_created)
return true;
if (mips_trap)
macro_build ((char *) NULL, &icnt, NULL, "teq", "s,t", 0, 0);
else
- macro_build ((char *) NULL, &icnt, NULL, "break", "c", 7);
+ macro_build ((char *) NULL, &icnt, NULL, "break", "c", 7);
return;
}
macro_build ((char *) NULL, &icnt, NULL,
dbl ? "ddiv" : "div",
"z,s,t", sreg, treg);
- macro_build ((char *) NULL, &icnt, NULL, "break", "c", 7);
+ macro_build ((char *) NULL, &icnt, NULL, "break", "c", 7);
}
expr1.X_add_number = -1;
macro_build ((char *) NULL, &icnt, &expr1,
that later insns are available for delay slot filling. */
--mips_opts.noreorder;
- macro_build ((char *) NULL, &icnt, NULL, "break", "c", 6);
+ macro_build ((char *) NULL, &icnt, NULL, "break", "c", 6);
}
macro_build ((char *) NULL, &icnt, NULL, s, "d", dreg);
break;
}
else if (mips_pic == SVR4_PIC && ! mips_big_got)
{
+ int lw_reloc_type = (int) BFD_RELOC_MIPS_GOT16;
+
/* If this is a reference to an external symbol, and there
is no constant, we want
lw $tempreg,<sym>($gp) (BFD_RELOC_MIPS_GOT16)
+ or if tempreg is PIC_CALL_REG
+ lw $tempreg,<sym>($gp) (BFD_RELOC_MIPS_CALL16)
For a local symbol, we want
lw $tempreg,<sym>($gp) (BFD_RELOC_MIPS_GOT16)
nop
expr1.X_add_number = offset_expr.X_add_number;
offset_expr.X_add_number = 0;
frag_grow (32);
+ if (expr1.X_add_number == 0 && tempreg == PIC_CALL_REG)
+ lw_reloc_type = (int) BFD_RELOC_MIPS_CALL16;
macro_build ((char *) NULL, &icnt, &offset_expr,
dbl ? "ld" : "lw",
- "t,o(b)", tempreg, (int) BFD_RELOC_MIPS_GOT16, GP);
+ "t,o(b)", tempreg, lw_reloc_type, GP);
if (expr1.X_add_number == 0)
{
int off;
else if (mips_pic == SVR4_PIC)
{
int gpdel;
+ int lui_reloc_type = (int) BFD_RELOC_MIPS_GOT_HI16;
+ int lw_reloc_type = (int) BFD_RELOC_MIPS_GOT_LO16;
/* This is the large GOT case. If this is a reference to an
external symbol, and there is no constant, we want
lui $tempreg,<sym> (BFD_RELOC_MIPS_GOT_HI16)
addu $tempreg,$tempreg,$gp
lw $tempreg,<sym>($tempreg) (BFD_RELOC_MIPS_GOT_LO16)
+ or if tempreg is PIC_CALL_REG
+ lui $tempreg,<sym> (BFD_RELOC_MIPS_CALL_HI16)
+ addu $tempreg,$tempreg,$gp
+ lw $tempreg,<sym>($tempreg) (BFD_RELOC_MIPS_CALL_LO16)
For a local symbol, we want
lw $tempreg,<sym>($gp) (BFD_RELOC_MIPS_GOT16)
nop
gpdel = 4;
else
gpdel = 0;
+ if (expr1.X_add_number == 0 && tempreg == PIC_CALL_REG)
+ {
+ lui_reloc_type = (int) BFD_RELOC_MIPS_CALL_HI16;
+ lw_reloc_type = (int) BFD_RELOC_MIPS_CALL_LO16;
+ }
macro_build ((char *) NULL, &icnt, &offset_expr, "lui", "t,u",
- tempreg, (int) BFD_RELOC_MIPS_GOT_HI16);
+ tempreg, lui_reloc_type);
macro_build ((char *) NULL, &icnt, (expressionS *) NULL,
((bfd_arch_bits_per_address (stdoutput) == 32
|| ! ISA_HAS_64BIT_REGS (mips_opts.isa))
"d,v,t", tempreg, tempreg, GP);
macro_build ((char *) NULL, &icnt, &offset_expr,
dbl ? "ld" : "lw",
- "t,o(b)", tempreg, (int) BFD_RELOC_MIPS_GOT_LO16,
- tempreg);
+ "t,o(b)", tempreg, lw_reloc_type, tempreg);
if (expr1.X_add_number == 0)
{
int off;