gas/
* config/tc-mips.c (reloc_needs_lo_p): New function. (fixup_has_matching_lo_p): New function. (append_insn): Use reloc_needs_lo_p to check whether a relocation might need a matching %lo(). Reuse the head of mips_hi_fixup_list if that fixup already has a matching %lo(). Don't call frag_wane here. (macro): Call frag_wane here if the last unmatched hi was in the current frag. (pic_need_relax): New function, split out from... (md_estimate_size_before_relax): ...here. (mips_frob_file): Use reloc_needs_lo_p. Use pic_need_relax to test whether BFD_RELOC_MIPS_GOT16 fixups refer to global symbols. gas/testsuite/ * gas/mips/rel12.[sd], gas/mips/rel13.[sd]: New tests. * gas/mips/mips.exp: Run them.
This commit is contained in:
parent
00b28bb047
commit
5919d0127e
8 changed files with 220 additions and 83 deletions
|
@ -1,3 +1,17 @@
|
|||
2003-02-08 Richard Sandiford <rsandifo@redhat.com>
|
||||
|
||||
* config/tc-mips.c (reloc_needs_lo_p): New function.
|
||||
(fixup_has_matching_lo_p): New function.
|
||||
(append_insn): Use reloc_needs_lo_p to check whether a relocation
|
||||
might need a matching %lo(). Reuse the head of mips_hi_fixup_list
|
||||
if that fixup already has a matching %lo(). Don't call frag_wane here.
|
||||
(macro): Call frag_wane here if the last unmatched hi was in the
|
||||
current frag.
|
||||
(pic_need_relax): New function, split out from...
|
||||
(md_estimate_size_before_relax): ...here.
|
||||
(mips_frob_file): Use reloc_needs_lo_p. Use pic_need_relax to test
|
||||
whether BFD_RELOC_MIPS_GOT16 fixups refer to global symbols.
|
||||
|
||||
2003-02-07 Richard Sandiford <rsandifo@redhat.com>
|
||||
|
||||
* config/tc-mips.c (my_getSmallExpression): Rework bracket handling.
|
||||
|
|
|
@ -801,6 +801,10 @@ static int mips_relax_branch;
|
|||
|
||||
enum mips_regclass { MIPS_GR_REG, MIPS_FP_REG, MIPS16_REG };
|
||||
|
||||
static inline bfd_boolean reloc_needs_lo_p
|
||||
PARAMS ((bfd_reloc_code_real_type));
|
||||
static inline bfd_boolean fixup_has_matching_lo_p
|
||||
PARAMS ((fixS *));
|
||||
static int insn_uses_reg
|
||||
PARAMS ((struct mips_cl_insn *ip, unsigned int reg,
|
||||
enum mips_regclass class));
|
||||
|
@ -932,6 +936,8 @@ static void s_mips_file
|
|||
PARAMS ((int));
|
||||
static void s_mips_loc
|
||||
PARAMS ((int));
|
||||
static bfd_boolean pic_need_relax
|
||||
PARAMS ((symbolS *, asection *));
|
||||
static int mips16_extended_frag
|
||||
PARAMS ((fragS *, asection *, long));
|
||||
static int relaxed_branch_length (fragS *, asection *, int);
|
||||
|
@ -1439,6 +1445,31 @@ md_assemble (str)
|
|||
}
|
||||
}
|
||||
|
||||
/* Return true if the given relocation might need a matching %lo().
|
||||
Note that R_MIPS_GOT16 relocations only need a matching %lo() when
|
||||
applied to local symbols. */
|
||||
|
||||
static inline bfd_boolean
|
||||
reloc_needs_lo_p (reloc)
|
||||
bfd_reloc_code_real_type reloc;
|
||||
{
|
||||
return (reloc == BFD_RELOC_HI16_S
|
||||
|| reloc == BFD_RELOC_MIPS_GOT16);
|
||||
}
|
||||
|
||||
/* Return true if the given fixup is followed by a matching R_MIPS_LO16
|
||||
relocation. */
|
||||
|
||||
static inline bfd_boolean
|
||||
fixup_has_matching_lo_p (fixp)
|
||||
fixS *fixp;
|
||||
{
|
||||
return (fixp->fx_next != NULL
|
||||
&& fixp->fx_next->fx_r_type == BFD_RELOC_LO16
|
||||
&& fixp->fx_addsy == fixp->fx_next->fx_addsy
|
||||
&& fixp->fx_offset == fixp->fx_next->fx_offset);
|
||||
}
|
||||
|
||||
/* See whether instruction IP reads register REG. CLASS is the type
|
||||
of register. */
|
||||
|
||||
|
@ -1593,14 +1624,12 @@ append_insn (place, ip, address_expr, reloc_type)
|
|||
char *f;
|
||||
fixS *fixp[3];
|
||||
int nops = 0;
|
||||
bfd_boolean unmatched_reloc_p;
|
||||
|
||||
/* Mark instruction labels in mips16 mode. */
|
||||
mips16_mark_labels ();
|
||||
|
||||
prev_pinfo = prev_insn.insn_mo->pinfo;
|
||||
pinfo = ip->insn_mo->pinfo;
|
||||
unmatched_reloc_p = FALSE;
|
||||
|
||||
if (place == NULL && (! mips_opts.noreorder || prev_nop_frag != NULL))
|
||||
{
|
||||
|
@ -2144,17 +2173,22 @@ append_insn (place, ip, address_expr, reloc_type)
|
|||
|| *reloc_type == BFD_RELOC_MIPS_RELGOT))
|
||||
fixp[0]->fx_no_overflow = 1;
|
||||
|
||||
if (reloc_type[0] == BFD_RELOC_HI16_S)
|
||||
if (reloc_needs_lo_p (*reloc_type))
|
||||
{
|
||||
struct mips_hi_fixup *hi_fixup;
|
||||
|
||||
hi_fixup = ((struct mips_hi_fixup *)
|
||||
xmalloc (sizeof (struct mips_hi_fixup)));
|
||||
/* Reuse the last entry if it already has a matching %lo. */
|
||||
hi_fixup = mips_hi_fixup_list;
|
||||
if (hi_fixup == 0
|
||||
|| !fixup_has_matching_lo_p (hi_fixup->fixp))
|
||||
{
|
||||
hi_fixup = ((struct mips_hi_fixup *)
|
||||
xmalloc (sizeof (struct mips_hi_fixup)));
|
||||
hi_fixup->next = mips_hi_fixup_list;
|
||||
mips_hi_fixup_list = hi_fixup;
|
||||
}
|
||||
hi_fixup->fixp = fixp[0];
|
||||
hi_fixup->seg = now_seg;
|
||||
hi_fixup->next = mips_hi_fixup_list;
|
||||
mips_hi_fixup_list = hi_fixup;
|
||||
unmatched_reloc_p = TRUE;
|
||||
}
|
||||
|
||||
if (reloc_type[1] != BFD_RELOC_UNUSED)
|
||||
|
@ -2706,16 +2740,6 @@ append_insn (place, ip, address_expr, reloc_type)
|
|||
|
||||
/* We just output an insn, so the next one doesn't have a label. */
|
||||
mips_clear_insn_labels ();
|
||||
|
||||
/* We must ensure that a fixup associated with an unmatched %hi
|
||||
reloc does not become a variant frag. Otherwise, the
|
||||
rearrangement of %hi relocs in frob_file may confuse
|
||||
tc_gen_reloc. */
|
||||
if (unmatched_reloc_p)
|
||||
{
|
||||
frag_wane (frag_now);
|
||||
frag_new (0);
|
||||
}
|
||||
}
|
||||
|
||||
/* This function forgets that there was any previous instruction or
|
||||
|
@ -4070,6 +4094,27 @@ macro (ip)
|
|||
expr1.X_add_symbol = NULL;
|
||||
expr1.X_add_number = 1;
|
||||
|
||||
/* Umatched fixups should not be put in the same frag as a relaxable
|
||||
macro. For example, suppose we have:
|
||||
|
||||
lui $4,%hi(l1) # 1
|
||||
la $5,l2 # 2
|
||||
addiu $4,$4,%lo(l1) # 3
|
||||
|
||||
If instructions 1 and 2 were put in the same frag, md_frob_file would
|
||||
move the fixup for #1 after the fixups for the "unrelaxed" version of
|
||||
#2. This would confuse tc_gen_reloc, which expects the relocations
|
||||
for #2 to be the last for that frag.
|
||||
|
||||
If it looks like this situation could happen, put the macro
|
||||
in a new frag. */
|
||||
if (mips_hi_fixup_list != 0
|
||||
&& mips_hi_fixup_list->fixp->fx_frag == frag_now)
|
||||
{
|
||||
frag_wane (frag_now);
|
||||
frag_new (0);
|
||||
}
|
||||
|
||||
switch (mask)
|
||||
{
|
||||
case M_DABS:
|
||||
|
@ -10858,14 +10903,16 @@ mips_frob_file ()
|
|||
segment_info_type *seginfo;
|
||||
int pass;
|
||||
|
||||
assert (l->fixp->fx_r_type == BFD_RELOC_HI16_S);
|
||||
assert (reloc_needs_lo_p (l->fixp->fx_r_type));
|
||||
|
||||
/* Check quickly whether the next fixup happens to be a matching
|
||||
%lo. */
|
||||
if (l->fixp->fx_next != NULL
|
||||
&& l->fixp->fx_next->fx_r_type == BFD_RELOC_LO16
|
||||
&& l->fixp->fx_addsy == l->fixp->fx_next->fx_addsy
|
||||
&& l->fixp->fx_offset == l->fixp->fx_next->fx_offset)
|
||||
/* If a GOT16 relocation turns out to be against a global symbol,
|
||||
there isn't supposed to be a matching LO. */
|
||||
if (l->fixp->fx_r_type == BFD_RELOC_MIPS_GOT16
|
||||
&& !pic_need_relax (l->fixp->fx_addsy, l->seg))
|
||||
continue;
|
||||
|
||||
/* Check quickly whether the next fixup happens to be a matching %lo. */
|
||||
if (fixup_has_matching_lo_p (l->fixp))
|
||||
continue;
|
||||
|
||||
/* Look through the fixups for this segment for a matching %lo.
|
||||
|
@ -10887,9 +10934,8 @@ mips_frob_file ()
|
|||
&& f->fx_offset == l->fixp->fx_offset
|
||||
&& (pass == 1
|
||||
|| prev == NULL
|
||||
|| prev->fx_r_type != BFD_RELOC_HI16_S
|
||||
|| prev->fx_addsy != f->fx_addsy
|
||||
|| prev->fx_offset != f->fx_offset))
|
||||
|| !reloc_needs_lo_p (prev->fx_r_type)
|
||||
|| !fixup_has_matching_lo_p (prev)))
|
||||
{
|
||||
fixS **pf;
|
||||
|
||||
|
@ -12672,6 +12718,64 @@ nopic_need_relax (sym, before_relaxing)
|
|||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/* Return true if the given symbol should be considered local for SVR4 PIC. */
|
||||
|
||||
static bfd_boolean
|
||||
pic_need_relax (sym, segtype)
|
||||
symbolS *sym;
|
||||
asection *segtype;
|
||||
{
|
||||
asection *symsec;
|
||||
bfd_boolean linkonce;
|
||||
|
||||
/* Handle the case of a symbol equated to another symbol. */
|
||||
while (symbol_equated_reloc_p (sym))
|
||||
{
|
||||
symbolS *n;
|
||||
|
||||
/* It's possible to get a loop here in a badly written
|
||||
program. */
|
||||
n = symbol_get_value_expression (sym)->X_add_symbol;
|
||||
if (n == sym)
|
||||
break;
|
||||
sym = n;
|
||||
}
|
||||
|
||||
symsec = S_GET_SEGMENT (sym);
|
||||
|
||||
/* duplicate the test for LINK_ONCE sections as in adjust_reloc_syms */
|
||||
linkonce = FALSE;
|
||||
if (symsec != segtype && ! S_IS_LOCAL (sym))
|
||||
{
|
||||
if ((bfd_get_section_flags (stdoutput, symsec) & SEC_LINK_ONCE)
|
||||
!= 0)
|
||||
linkonce = TRUE;
|
||||
|
||||
/* The GNU toolchain uses an extension for ELF: a section
|
||||
beginning with the magic string .gnu.linkonce is a linkonce
|
||||
section. */
|
||||
if (strncmp (segment_name (symsec), ".gnu.linkonce",
|
||||
sizeof ".gnu.linkonce" - 1) == 0)
|
||||
linkonce = TRUE;
|
||||
}
|
||||
|
||||
/* This must duplicate the test in adjust_reloc_syms. */
|
||||
return (symsec != &bfd_und_section
|
||||
&& symsec != &bfd_abs_section
|
||||
&& ! bfd_is_com_section (symsec)
|
||||
&& !linkonce
|
||||
#ifdef OBJ_ELF
|
||||
/* A global or weak symbol is treated as external. */
|
||||
&& (OUTPUT_FLAVOR != bfd_target_elf_flavour
|
||||
|| (! S_IS_WEAK (sym)
|
||||
&& (! S_IS_EXTERNAL (sym)
|
||||
|| mips_pic == EMBEDDED_PIC)))
|
||||
#endif
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/* Given a mips16 variant frag FRAGP, return non-zero if it needs an
|
||||
extended opcode. SEC is the section the frag is in. */
|
||||
|
||||
|
@ -12950,8 +13054,7 @@ md_estimate_size_before_relax (fragp, segtype)
|
|||
fragS *fragp;
|
||||
asection *segtype;
|
||||
{
|
||||
int change = 0;
|
||||
bfd_boolean linkonce = FALSE;
|
||||
int change;
|
||||
|
||||
if (RELAX_BRANCH_P (fragp->fr_subtype))
|
||||
{
|
||||
|
@ -12967,60 +13070,9 @@ md_estimate_size_before_relax (fragp, segtype)
|
|||
return (RELAX_MIPS16_EXTENDED (fragp->fr_subtype) ? 4 : 2);
|
||||
|
||||
if (mips_pic == NO_PIC)
|
||||
{
|
||||
change = nopic_need_relax (fragp->fr_symbol, 0);
|
||||
}
|
||||
change = nopic_need_relax (fragp->fr_symbol, 0);
|
||||
else if (mips_pic == SVR4_PIC)
|
||||
{
|
||||
symbolS *sym;
|
||||
asection *symsec;
|
||||
|
||||
sym = fragp->fr_symbol;
|
||||
|
||||
/* Handle the case of a symbol equated to another symbol. */
|
||||
while (symbol_equated_reloc_p (sym))
|
||||
{
|
||||
symbolS *n;
|
||||
|
||||
/* It's possible to get a loop here in a badly written
|
||||
program. */
|
||||
n = symbol_get_value_expression (sym)->X_add_symbol;
|
||||
if (n == sym)
|
||||
break;
|
||||
sym = n;
|
||||
}
|
||||
|
||||
symsec = S_GET_SEGMENT (sym);
|
||||
|
||||
/* duplicate the test for LINK_ONCE sections as in adjust_reloc_syms */
|
||||
if (symsec != segtype && ! S_IS_LOCAL (sym))
|
||||
{
|
||||
if ((bfd_get_section_flags (stdoutput, symsec) & SEC_LINK_ONCE)
|
||||
!= 0)
|
||||
linkonce = TRUE;
|
||||
|
||||
/* The GNU toolchain uses an extension for ELF: a section
|
||||
beginning with the magic string .gnu.linkonce is a linkonce
|
||||
section. */
|
||||
if (strncmp (segment_name (symsec), ".gnu.linkonce",
|
||||
sizeof ".gnu.linkonce" - 1) == 0)
|
||||
linkonce = TRUE;
|
||||
}
|
||||
|
||||
/* This must duplicate the test in adjust_reloc_syms. */
|
||||
change = (symsec != &bfd_und_section
|
||||
&& symsec != &bfd_abs_section
|
||||
&& ! bfd_is_com_section (symsec)
|
||||
&& !linkonce
|
||||
#ifdef OBJ_ELF
|
||||
/* A global or weak symbol is treated as external. */
|
||||
&& (OUTPUT_FLAVOR != bfd_target_elf_flavour
|
||||
|| (! S_IS_WEAK (sym)
|
||||
&& (! S_IS_EXTERNAL (sym)
|
||||
|| mips_pic == EMBEDDED_PIC)))
|
||||
#endif
|
||||
);
|
||||
}
|
||||
change = pic_need_relax (fragp->fr_symbol, segtype);
|
||||
else
|
||||
abort ();
|
||||
|
||||
|
|
|
@ -1,3 +1,8 @@
|
|||
2003-02-07 Richard Sandiford <rsandifo@redhat.com>
|
||||
|
||||
* gas/mips/rel12.[sd], gas/mips/rel13.[sd]: New tests.
|
||||
* gas/mips/mips.exp: Run them.
|
||||
|
||||
2003-02-07 Richard Sandiford <rsandifo@redhat.com>
|
||||
|
||||
* gas/mips/expr1.[sd]: New test.
|
||||
|
|
11
gas/testsuite/gas/mips/elf-rel12.d
Normal file
11
gas/testsuite/gas/mips/elf-rel12.d
Normal file
|
@ -0,0 +1,11 @@
|
|||
#as: -march=mips1 -mabi=32
|
||||
#readelf: --relocs
|
||||
#name: MIPS ELF reloc 12
|
||||
|
||||
Relocation section '\.rel\.text' at offset .* contains 4 entries:
|
||||
*Offset * Info * Type * Sym\.Value * Sym\. Name
|
||||
0+0004 * 0+..05 * R_MIPS_HI16 * 0+0000 * l1
|
||||
0+0008 * 0+..06 * R_MIPS_LO16 * 0+0000 * l1
|
||||
0+0000 * 0+..05 * R_MIPS_HI16 * 0+0004 * l2
|
||||
0+000c * 0+..06 * R_MIPS_LO16 * 0+0004 * l2
|
||||
#pass
|
14
gas/testsuite/gas/mips/elf-rel12.s
Normal file
14
gas/testsuite/gas/mips/elf-rel12.s
Normal file
|
@ -0,0 +1,14 @@
|
|||
.ent foo
|
||||
foo:
|
||||
lui $4,%hi(l2)
|
||||
la $3,l1
|
||||
addiu $4,$4,%lo(l2)
|
||||
|
||||
.space 64
|
||||
.end foo
|
||||
|
||||
.globl l1
|
||||
.globl l2
|
||||
.data
|
||||
l1: .word 1
|
||||
l2: .word 2
|
17
gas/testsuite/gas/mips/elf-rel13.d
Normal file
17
gas/testsuite/gas/mips/elf-rel13.d
Normal file
|
@ -0,0 +1,17 @@
|
|||
#as: -march=mips2 -mabi=32 -KPIC
|
||||
#readelf: --relocs
|
||||
#name: MIPS ELF reloc 13
|
||||
|
||||
Relocation section '\.rel\.text' at offset .* contains 9 entries:
|
||||
*Offset * Info * Type * Sym\.Value * Sym\. Name
|
||||
0+0000 * 0+..09 * R_MIPS_GOT16 * 0+0000 * \.data
|
||||
0+0014 * 0+..06 * R_MIPS_LO16 * 0+0000 * \.data
|
||||
0+0010 * 0+..09 * R_MIPS_GOT16 * 0+0000 * \.data
|
||||
0+0018 * 0+..06 * R_MIPS_LO16 * 0+0000 * \.data
|
||||
# The next two lines could be in either order.
|
||||
0+000c * 0+..09 * R_MIPS_GOT16 * 0+0000 * \.rodata
|
||||
0+0008 * 0+..09 * R_MIPS_GOT16 * 0+0000 * \.rodata
|
||||
0+001c * 0+..06 * R_MIPS_LO16 * 0+0000 * \.rodata
|
||||
0+0004 * 0+..09 * R_MIPS_GOT16 * 0+0000 * \.bss
|
||||
0+0020 * 0+..06 * R_MIPS_LO16 * 0+0000 * \.bss
|
||||
#pass
|
22
gas/testsuite/gas/mips/elf-rel13.s
Normal file
22
gas/testsuite/gas/mips/elf-rel13.s
Normal file
|
@ -0,0 +1,22 @@
|
|||
.ent foo
|
||||
foo:
|
||||
lw $4,%got(l1)($gp)
|
||||
lw $4,%got(l2)($gp)
|
||||
lw $4,%got(l3)($gp)
|
||||
lw $4,%got(l3)($gp)
|
||||
lw $4,%got(l1+0x400)($gp)
|
||||
addiu $4,$4,%lo(l1)
|
||||
addiu $4,$4,%lo(l1+0x400)
|
||||
addiu $4,$4,%lo(l3)
|
||||
addiu $4,$4,%lo(l2)
|
||||
.space 64
|
||||
.end foo
|
||||
|
||||
.data
|
||||
l1: .word 1
|
||||
|
||||
.lcomm l2, 4
|
||||
|
||||
.rdata
|
||||
.word 1
|
||||
l3: .word 2
|
|
@ -608,6 +608,8 @@ if { [istarget mips*-*-*] } then {
|
|||
run_dump_test "elf-rel10"
|
||||
run_dump_test "elf-rel11"
|
||||
}
|
||||
run_dump_test "elf-rel12"
|
||||
run_dump_test "elf-rel13"
|
||||
run_dump_test "${tmips}${el}empic"
|
||||
run_dump_test "empic2"
|
||||
run_dump_test "empic3_e"
|
||||
|
|
Loading…
Reference in a new issue