* 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
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
PARAMS ((bfd *, Elf_Internal_Rela *, Elf_Internal_Rela *, bfd_byte *,
bfd_vma));
static void mips_elf_relocate_got_local
static boolean mips_elf_relocate_got_local
PARAMS ((bfd *, bfd *, asection *, Elf_Internal_Rela *,
Elf_Internal_Rela *, bfd_byte *, bfd_vma));
static void mips_elf_relocate_global_got
PARAMS ((bfd *, Elf_Internal_Rela *, bfd_byte *, bfd_vma));
static bfd_reloc_status_type mips16_jump_reloc
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
PARAMS ((struct elf_link_hash_entry *, PTR));
static boolean mips_elf_relocate_section
@ -134,6 +136,8 @@ struct mips_got_info
unsigned long global_gotsym;
/* The number of local .got entries. */
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. */
@ -306,8 +310,9 @@ enum reloc_type
R_MIPS_HIGHER, R_MIPS_HIGHEST,
R_MIPS_CALL_HI16, R_MIPS_CALL_LO16,
R_MIPS_max,
/* This reloc is used for the mips16. */
R_MIPS16_26 = 100
/* These relocs are used for the mips16. */
R_MIPS16_26 = 100,
R_MIPS16_GPREL = 101
};
static reloc_howto_type elf_mips_howto_table[] =
@ -712,6 +717,25 @@ static reloc_howto_type elf_mips16_jump_howto =
0x3ffffff, /* dst_mask */
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
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
@ -1343,6 +1367,82 @@ mips16_jump_reloc (abfd, reloc_entry, symbol, data, input_section,
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. */
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];
}
/* Special handling for the MIPS16 jump, since it is a made up reloc
type with a large value. */
/* Special handling for the MIPS16 relocs, since they are made up
reloc types with a large value. */
if (code == BFD_RELOC_MIPS16_JMP)
return &elf_mips16_jump_howto;
else if (code == BFD_RELOC_MIPS16_GPREL)
return &elf_mips16_gprel_howto;
return NULL;
}
@ -1408,6 +1510,8 @@ mips_info_to_howto_rel (abfd, cache_ptr, dst)
r_type = ELF32_R_TYPE (dst->r_info);
if (r_type == R_MIPS16_26)
cache_ptr->howto = &elf_mips16_jump_howto;
else if (r_type == R_MIPS16_GPREL)
cache_ptr->howto = &elf_mips16_gprel_howto;
else
{
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. */
static void
static boolean
mips_elf_relocate_got_local (output_bfd, input_bfd, sgot, relhi, rello,
contents, addend)
bfd *output_bfd;
@ -4310,8 +4414,8 @@ mips_elf_relocate_got_local (output_bfd, input_bfd, sgot, relhi, rello,
bfd_byte *contents;
bfd_vma addend;
{
int local_gotno;
int i;
unsigned int assigned_gotno;
unsigned int i;
bfd_vma insn;
bfd_vma addlo;
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;
BFD_ASSERT (g != NULL);
local_gotno = g->local_gotno;
assigned_gotno = g->assigned_gotno;
got_contents = sgot->contents;
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);
if (hipage == (address & 0xffff0000))
break;
if (address == (bfd_vma) 0)
{
bfd_put_32 (input_bfd, hipage, got_contents + i * 4);
break;
}
}
BFD_ASSERT (i < local_gotno);
#if 1
if (i == local_gotno)
(*_bfd_error_handler)
("ELF MIPS linker: more got entries are needed for hipage: %x",
hipage);
#endif
if (i == assigned_gotno)
{
if (assigned_gotno >= g->local_gotno)
{
(*_bfd_error_handler)
("more got entries are needed for hipage relocations");
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;
bfd_put_32 (input_bfd, (insn & 0xffff0000) | (i & 0xffff),
contents + relhi->r_offset);
return true;
}
/* 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;
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);
return false;
}
if (r_type != R_MIPS16_26)
howto = elf_mips_howto_table + r_type;
else
if (r_type == R_MIPS16_26)
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
&& (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. */
if (r_type != R_MIPS_GPREL16
&& r_type != R_MIPS_LITERAL
&& r_type != R_MIPS_GPREL32)
&& r_type != R_MIPS_GPREL32
&& r_type != R_MIPS16_GPREL)
addend = 0;
else
{
@ -4833,10 +4945,11 @@ mips_elf_relocate_section (output_bfd, info, input_bfd, input_section,
if ((rel + 1) < relend
&& ELF32_R_TYPE ((rel + 1)->r_info) == R_MIPS_LO16)
{
mips_elf_relocate_got_local (output_bfd, input_bfd, sgot,
rel, rel + 1,
contents,
relocation + addend);
if (! mips_elf_relocate_got_local (output_bfd, input_bfd,
sgot, rel, rel + 1,
contents,
relocation + addend))
return false;
r = bfd_reloc_ok;
}
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);
}
}
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
r = _bfd_final_link_relocate (howto, input_bfd, input_section,
contents, rel->r_offset,
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)
&& scpt != NULL
&& (input_section->flags & SEC_ALLOC) != 0)
@ -5396,6 +5566,7 @@ mips_elf_create_got_section (abfd, info)
return false;
g->global_gotsym = 0;
g->local_gotno = MIPS_RESERVED_GOTNO;
g->assigned_gotno = MIPS_RESERVED_GOTNO;
if (elf_section_data (s) == NULL)
{
s->used_by_bfd =