* elf32-mips.c (struct mips_got_info): Add assigned_gotno field.

(mips_elf_relocate_got_local): Change return type to boolean.
	Don't assume that the first zero entry is unassigned; instead, use
	assigned_gotno.
	(mips_elf_relocate_section): Check return value of
	mips_elf_relocate_got_local.
	(mips_elf_create_got_section): Initialize assigned_gotno field.
This commit is contained in:
Ian Lance Taylor 1997-02-27 23:38:19 +00:00
parent 8a683c6720
commit 85d6f0b476
2 changed files with 212 additions and 31 deletions

View File

@ -1,3 +1,13 @@
Thu Feb 27 18:36:23 1997 Ian Lance Taylor <ian@cygnus.com>
* elf32-mips.c (struct mips_got_info): Add assigned_gotno field.
(mips_elf_relocate_got_local): Change return type to boolean.
Don't assume that the first zero entry is unassigned; instead, use
assigned_gotno.
(mips_elf_relocate_section): Check return value of
mips_elf_relocate_got_local.
(mips_elf_create_got_section): Initialize assigned_gotno field.
start-sanitize-d30v start-sanitize-d30v
Wed Feb 26 15:19:51 1997 Martin M. Hunt <hunt@pizza.cygnus.com> Wed Feb 26 15:19:51 1997 Martin M. Hunt <hunt@pizza.cygnus.com>

View File

@ -75,13 +75,15 @@ static boolean mips_elf_final_link
static void mips_elf_relocate_hi16 static void mips_elf_relocate_hi16
PARAMS ((bfd *, Elf_Internal_Rela *, Elf_Internal_Rela *, bfd_byte *, PARAMS ((bfd *, Elf_Internal_Rela *, Elf_Internal_Rela *, bfd_byte *,
bfd_vma)); bfd_vma));
static void mips_elf_relocate_got_local static boolean mips_elf_relocate_got_local
PARAMS ((bfd *, bfd *, asection *, Elf_Internal_Rela *, PARAMS ((bfd *, bfd *, asection *, Elf_Internal_Rela *,
Elf_Internal_Rela *, bfd_byte *, bfd_vma)); Elf_Internal_Rela *, bfd_byte *, bfd_vma));
static void mips_elf_relocate_global_got static void mips_elf_relocate_global_got
PARAMS ((bfd *, Elf_Internal_Rela *, bfd_byte *, bfd_vma)); PARAMS ((bfd *, Elf_Internal_Rela *, bfd_byte *, bfd_vma));
static bfd_reloc_status_type mips16_jump_reloc static bfd_reloc_status_type mips16_jump_reloc
PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **)); PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
static bfd_reloc_status_type mips16_gprel_reloc
PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
static boolean mips_elf_adjust_dynindx static boolean mips_elf_adjust_dynindx
PARAMS ((struct elf_link_hash_entry *, PTR)); PARAMS ((struct elf_link_hash_entry *, PTR));
static boolean mips_elf_relocate_section static boolean mips_elf_relocate_section
@ -134,6 +136,8 @@ struct mips_got_info
unsigned long global_gotsym; unsigned long global_gotsym;
/* The number of local .got entries. */ /* The number of local .got entries. */
unsigned int local_gotno; unsigned int local_gotno;
/* The number of local .got entries we have used. */
unsigned int assigned_gotno;
}; };
/* The number of local .got entries we reserve. */ /* The number of local .got entries we reserve. */
@ -306,8 +310,9 @@ enum reloc_type
R_MIPS_HIGHER, R_MIPS_HIGHEST, R_MIPS_HIGHER, R_MIPS_HIGHEST,
R_MIPS_CALL_HI16, R_MIPS_CALL_LO16, R_MIPS_CALL_HI16, R_MIPS_CALL_LO16,
R_MIPS_max, R_MIPS_max,
/* This reloc is used for the mips16. */ /* These relocs are used for the mips16. */
R_MIPS16_26 = 100 R_MIPS16_26 = 100,
R_MIPS16_GPREL = 101
}; };
static reloc_howto_type elf_mips_howto_table[] = static reloc_howto_type elf_mips_howto_table[] =
@ -712,6 +717,25 @@ static reloc_howto_type elf_mips16_jump_howto =
0x3ffffff, /* dst_mask */ 0x3ffffff, /* dst_mask */
false); /* pcrel_offset */ false); /* pcrel_offset */
/* The reloc used for the mips16 gprel instruction. The src_mask and
dsk_mask for this howto do not reflect the actual instruction, in
which the value is not contiguous; the masks are for the
convenience of the relocate_section routine. */
static reloc_howto_type elf_mips16_gprel_howto =
HOWTO (R_MIPS16_GPREL, /* type */
0, /* rightshift */
2, /* size (0 = byte, 1 = short, 2 = long) */
16, /* bitsize */
false, /* pc_relative */
0, /* bitpos */
complain_overflow_signed, /* complain_on_overflow */
mips16_gprel_reloc, /* special_function */
"R_MIPS16_GPREL", /* name */
true, /* partial_inplace */
0xffff, /* src_mask */
0xffff, /* dst_mask */
false); /* pcrel_offset */
/* Do a R_MIPS_HI16 relocation. This has to be done in combination /* Do a R_MIPS_HI16 relocation. This has to be done in combination
with a R_MIPS_LO16 reloc, because there is a carry from the LO16 to with a R_MIPS_LO16 reloc, because there is a carry from the LO16 to
the HI16. Here we just save the information we need; we do the the HI16. Here we just save the information we need; we do the
@ -1343,6 +1367,82 @@ mips16_jump_reloc (abfd, reloc_entry, symbol, data, input_section,
abort (); abort ();
} }
/* Handle a mips16 GP relative reloc. */
static bfd_reloc_status_type
mips16_gprel_reloc (abfd, reloc_entry, symbol, data, input_section,
output_bfd, error_message)
bfd *abfd;
arelent *reloc_entry;
asymbol *symbol;
PTR data;
asection *input_section;
bfd *output_bfd;
char **error_message;
{
boolean relocateable;
bfd_reloc_status_type ret;
bfd_vma gp;
unsigned short extend, insn;
unsigned long final;
/* If we're relocating, and this is an external symbol with no
addend, we don't want to change anything. We will only have an
addend if this is a newly created reloc, not read from an ELF
file. */
if (output_bfd != NULL
&& (symbol->flags & BSF_SECTION_SYM) == 0
&& reloc_entry->addend == 0)
{
reloc_entry->address += input_section->output_offset;
return bfd_reloc_ok;
}
if (output_bfd != NULL)
relocateable = true;
else
{
relocateable = false;
output_bfd = symbol->section->output_section->owner;
}
ret = mips_elf_final_gp (output_bfd, symbol, relocateable, error_message,
&gp);
if (ret != bfd_reloc_ok)
return ret;
if (reloc_entry->address > input_section->_cooked_size)
return bfd_reloc_outofrange;
/* Pick up the mips16 extend instruction and the real instruction. */
extend = bfd_get_16 (abfd, (bfd_byte *) data + reloc_entry->address);
insn = bfd_get_16 (abfd, (bfd_byte *) data + reloc_entry->address + 2);
/* Stuff the current addend back as a 32 bit value, do the usual
relocation, and then clean up. */
bfd_put_32 (abfd,
(((extend & 0x1f) << 11)
| (extend & 0x7e0)
| (insn & 0x1f)),
(bfd_byte *) data + reloc_entry->address);
ret = gprel16_with_gp (abfd, symbol, reloc_entry, input_section,
relocateable, data, gp);
final = bfd_get_32 (abfd, (bfd_byte *) data + reloc_entry->address);
bfd_put_16 (abfd,
((extend & 0xf800)
| ((final >> 11) & 0x1f)
| (final & 0x7e0)),
(bfd_byte *) data + reloc_entry->address);
bfd_put_16 (abfd,
((insn & 0xffe0)
| (final & 0x1f)),
(bfd_byte *) data + reloc_entry->address + 2);
return ret;
}
/* A mapping from BFD reloc types to MIPS ELF reloc types. */ /* A mapping from BFD reloc types to MIPS ELF reloc types. */
struct elf_reloc_map { struct elf_reloc_map {
@ -1387,10 +1487,12 @@ bfd_elf32_bfd_reloc_type_lookup (abfd, code)
return &elf_mips_howto_table[(int) mips_reloc_map[i].elf_reloc_val]; return &elf_mips_howto_table[(int) mips_reloc_map[i].elf_reloc_val];
} }
/* Special handling for the MIPS16 jump, since it is a made up reloc /* Special handling for the MIPS16 relocs, since they are made up
type with a large value. */ reloc types with a large value. */
if (code == BFD_RELOC_MIPS16_JMP) if (code == BFD_RELOC_MIPS16_JMP)
return &elf_mips16_jump_howto; return &elf_mips16_jump_howto;
else if (code == BFD_RELOC_MIPS16_GPREL)
return &elf_mips16_gprel_howto;
return NULL; return NULL;
} }
@ -1408,6 +1510,8 @@ mips_info_to_howto_rel (abfd, cache_ptr, dst)
r_type = ELF32_R_TYPE (dst->r_info); r_type = ELF32_R_TYPE (dst->r_info);
if (r_type == R_MIPS16_26) if (r_type == R_MIPS16_26)
cache_ptr->howto = &elf_mips16_jump_howto; cache_ptr->howto = &elf_mips16_jump_howto;
else if (r_type == R_MIPS16_GPREL)
cache_ptr->howto = &elf_mips16_gprel_howto;
else else
{ {
BFD_ASSERT (r_type < (unsigned int) R_MIPS_max); BFD_ASSERT (r_type < (unsigned int) R_MIPS_max);
@ -4299,7 +4403,7 @@ mips_elf_relocate_hi16 (input_bfd, relhi, rello, contents, addend)
/* Handle a MIPS ELF local GOT16 reloc. */ /* Handle a MIPS ELF local GOT16 reloc. */
static void static boolean
mips_elf_relocate_got_local (output_bfd, input_bfd, sgot, relhi, rello, mips_elf_relocate_got_local (output_bfd, input_bfd, sgot, relhi, rello,
contents, addend) contents, addend)
bfd *output_bfd; bfd *output_bfd;
@ -4310,8 +4414,8 @@ mips_elf_relocate_got_local (output_bfd, input_bfd, sgot, relhi, rello,
bfd_byte *contents; bfd_byte *contents;
bfd_vma addend; bfd_vma addend;
{ {
int local_gotno; unsigned int assigned_gotno;
int i; unsigned int i;
bfd_vma insn; bfd_vma insn;
bfd_vma addlo; bfd_vma addlo;
bfd_vma address; bfd_vma address;
@ -4336,33 +4440,36 @@ mips_elf_relocate_got_local (output_bfd, input_bfd, sgot, relhi, rello,
g = (struct mips_got_info *) elf_section_data (sgot)->tdata; g = (struct mips_got_info *) elf_section_data (sgot)->tdata;
BFD_ASSERT (g != NULL); BFD_ASSERT (g != NULL);
local_gotno = g->local_gotno; assigned_gotno = g->assigned_gotno;
got_contents = sgot->contents; got_contents = sgot->contents;
hipage = addend & 0xffff0000; hipage = addend & 0xffff0000;
for (i = MIPS_RESERVED_GOTNO; i < local_gotno; i++) for (i = MIPS_RESERVED_GOTNO; i < assigned_gotno; i++)
{ {
address = bfd_get_32 (input_bfd, got_contents + i * 4); address = bfd_get_32 (input_bfd, got_contents + i * 4);
if (hipage == (address & 0xffff0000)) if (hipage == (address & 0xffff0000))
break; break;
if (address == (bfd_vma) 0)
{
bfd_put_32 (input_bfd, hipage, got_contents + i * 4);
break;
}
} }
BFD_ASSERT (i < local_gotno); if (i == assigned_gotno)
#if 1 {
if (i == local_gotno) if (assigned_gotno >= g->local_gotno)
(*_bfd_error_handler) {
("ELF MIPS linker: more got entries are needed for hipage: %x", (*_bfd_error_handler)
hipage); ("more got entries are needed for hipage relocations");
#endif bfd_set_error (bfd_error_bad_value);
return false;
}
bfd_put_32 (input_bfd, hipage, got_contents + assigned_gotno * 4);
++g->assigned_gotno;
}
i = - ELF_MIPS_GP_OFFSET (output_bfd) + i * 4; i = - ELF_MIPS_GP_OFFSET (output_bfd) + i * 4;
bfd_put_32 (input_bfd, (insn & 0xffff0000) | (i & 0xffff), bfd_put_32 (input_bfd, (insn & 0xffff0000) | (i & 0xffff),
contents + relhi->r_offset); contents + relhi->r_offset);
return true;
} }
/* Handle MIPS ELF CALL16 reloc and global GOT16 reloc. */ /* Handle MIPS ELF CALL16 reloc and global GOT16 reloc. */
@ -4446,15 +4553,19 @@ mips_elf_relocate_section (output_bfd, info, input_bfd, input_section,
bfd_reloc_status_type r; bfd_reloc_status_type r;
r_type = ELF32_R_TYPE (rel->r_info); r_type = ELF32_R_TYPE (rel->r_info);
if ((r_type < 0 || r_type >= (int) R_MIPS_max) && r_type != R_MIPS16_26) if ((r_type < 0 || r_type >= (int) R_MIPS_max)
&& r_type != R_MIPS16_26
&& r_type != R_MIPS16_GPREL)
{ {
bfd_set_error (bfd_error_bad_value); bfd_set_error (bfd_error_bad_value);
return false; return false;
} }
if (r_type != R_MIPS16_26) if (r_type == R_MIPS16_26)
howto = elf_mips_howto_table + r_type;
else
howto = &elf_mips16_jump_howto; howto = &elf_mips16_jump_howto;
else if (r_type == R_MIPS16_GPREL)
howto = &elf_mips16_gprel_howto;
else
howto = elf_mips_howto_table + r_type;
if (dynobj != NULL if (dynobj != NULL
&& (r_type == R_MIPS_CALL16 && (r_type == R_MIPS_CALL16
@ -4480,7 +4591,8 @@ mips_elf_relocate_section (output_bfd, info, input_bfd, input_section,
/* Mix in the change in GP address for a GP relative reloc. */ /* Mix in the change in GP address for a GP relative reloc. */
if (r_type != R_MIPS_GPREL16 if (r_type != R_MIPS_GPREL16
&& r_type != R_MIPS_LITERAL && r_type != R_MIPS_LITERAL
&& r_type != R_MIPS_GPREL32) && r_type != R_MIPS_GPREL32
&& r_type != R_MIPS16_GPREL)
addend = 0; addend = 0;
else else
{ {
@ -4833,10 +4945,11 @@ mips_elf_relocate_section (output_bfd, info, input_bfd, input_section,
if ((rel + 1) < relend if ((rel + 1) < relend
&& ELF32_R_TYPE ((rel + 1)->r_info) == R_MIPS_LO16) && ELF32_R_TYPE ((rel + 1)->r_info) == R_MIPS_LO16)
{ {
mips_elf_relocate_got_local (output_bfd, input_bfd, sgot, if (! mips_elf_relocate_got_local (output_bfd, input_bfd,
rel, rel + 1, sgot, rel, rel + 1,
contents, contents,
relocation + addend); relocation + addend))
return false;
r = bfd_reloc_ok; r = bfd_reloc_ok;
} }
else else
@ -5071,11 +5184,68 @@ mips_elf_relocate_section (output_bfd, info, input_bfd, input_section,
bfd_put_16 (input_bfd, insn, contents + rel->r_offset); bfd_put_16 (input_bfd, insn, contents + rel->r_offset);
} }
} }
else if (r_type == R_MIPS16_GPREL)
{
unsigned short extend, insn;
bfd_byte buf[4];
unsigned long final;
/* Extract the addend into buf, run the regular reloc,
and stuff the resulting value back into the
instructions. */
if (rel->r_offset > input_section->_raw_size)
r = bfd_reloc_outofrange;
else
{
extend = bfd_get_16 (input_bfd, contents + rel->r_offset);
insn = bfd_get_16 (input_bfd, contents + rel->r_offset + 2);
bfd_put_32 (input_bfd,
(((extend & 0x1f) << 11)
| (extend & 0x7e0)
| (insn & 0x1f)),
buf);
r = _bfd_final_link_relocate (howto, input_bfd,
input_section, buf,
(bfd_vma) 0, relocation,
addend);
final = bfd_get_32 (input_bfd, buf);
bfd_put_16 (input_bfd,
((extend & 0xf800)
| ((final >> 11) & 0x1f)
| (final & 0x7e0)),
contents + rel->r_offset);
bfd_put_16 (input_bfd,
((insn & 0xffe0)
| (final & 0x1f)),
contents + rel->r_offset + 2);
}
}
else else
r = _bfd_final_link_relocate (howto, input_bfd, input_section, r = _bfd_final_link_relocate (howto, input_bfd, input_section,
contents, rel->r_offset, contents, rel->r_offset,
relocation, addend); relocation, addend);
/* The jal instruction can only jump to an address which is
divisible by 4, and it can only jump to an address with
the same upper 4 bits as the PC. */
if (r == bfd_reloc_ok
&& (r_type == R_MIPS16_26 || r_type == R_MIPS_26))
{
bfd_vma addr;
addr = relocation;
if (other == STO_MIPS16)
addr &= ~ (bfd_vma) 1;
addr += addend;
if ((addr & 3) != 0
|| ((addr & 0xf0000000)
!= ((input_section->output_section->vma
+ input_section->output_offset
+ rel->r_offset)
& 0xf0000000)))
r = bfd_reloc_overflow;
}
if (SGI_COMPAT (abfd) if (SGI_COMPAT (abfd)
&& scpt != NULL && scpt != NULL
&& (input_section->flags & SEC_ALLOC) != 0) && (input_section->flags & SEC_ALLOC) != 0)
@ -5396,6 +5566,7 @@ mips_elf_create_got_section (abfd, info)
return false; return false;
g->global_gotsym = 0; g->global_gotsym = 0;
g->local_gotno = MIPS_RESERVED_GOTNO; g->local_gotno = MIPS_RESERVED_GOTNO;
g->assigned_gotno = MIPS_RESERVED_GOTNO;
if (elf_section_data (s) == NULL) if (elf_section_data (s) == NULL)
{ {
s->used_by_bfd = s->used_by_bfd =