@ -4934,8 +4934,8 @@ xtensa_find_unaligned_loops (bfd *abfd ATTRIBUTE_UNUSED,
}
static void
xg_apply_tentative _value ( fixS * fixP , valueT val )
static int
xg_apply_fix _value ( fixS * fixP , valueT val )
{
xtensa_isa isa = xtensa_default_isa ;
static xtensa_insnbuf insnbuf = NULL ;
@ -4967,11 +4967,9 @@ xg_apply_tentative_value (fixS *fixP, valueT val)
/* CONST16 immediates are not PC-relative, despite the fact that we
reuse the normal PC - relative operand relocations for the low part
of a CONST16 operand . The code in tc_gen_reloc does not decode
the opcodes so it is more convenient to detect this special case
here . */
of a CONST16 operand . */
if ( opcode = = xtensa_const16_opcode )
return ;
return 0 ;
xtensa_insnbuf_set_operand ( slotbuf , fmt , slot , opcode ,
get_relaxable_immed ( opcode ) , val ,
@ -4979,6 +4977,8 @@ xg_apply_tentative_value (fixS *fixP, valueT val)
xtensa_format_set_slot ( isa , fmt , slot , insnbuf , slotbuf ) ;
xtensa_insnbuf_to_chars ( isa , insnbuf , fixpos , 0 ) ;
return 1 ;
}
@ -5452,11 +5452,8 @@ md_pcrel_from (fixS *fixP)
valueT addr = fixP - > fx_where + fixP - > fx_frag - > fr_address ;
bfd_boolean alt_reloc ;
if ( fixP - > fx_done )
return addr ;
if ( fixP - > fx_r_type = = BFD_RELOC_XTENSA_ASM_EXPAND )
return addr ;
return 0 ;
if ( ! insnbuf )
{
@ -5477,14 +5474,15 @@ md_pcrel_from (fixS *fixP)
xtensa_format_get_slot ( isa , fmt , slot , insnbuf , slotbuf ) ;
opcode = xtensa_opcode_decode ( isa , fmt , slot , slotbuf ) ;
/* Check for "alternate" relocation (operand not specified). */
/* Check for "alternate" relocations (operand not specified). None
of the current uses for these are really PC - relative . */
if ( alt_reloc | | opcode = = xtensa_const16_opcode )
{
if ( opcode ! = xtensa_l32r_opcode
& & opcode ! = xtensa_const16_opcode )
as_fatal ( _ ( " invalid relocation for '%s' instruction " ) ,
xtensa_opcode_name ( isa , opcode ) ) ;
return addr ;
return 0 ;
}
opnum = get_relaxable_immed ( opcode ) ;
@ -5496,7 +5494,7 @@ md_pcrel_from (fixS *fixP)
fixP - > fx_line ,
_ ( " invalid relocation for operand %d of '%s' " ) ,
opnum , xtensa_opcode_name ( isa , opcode ) ) ;
return addr ;
return 0 ;
}
return 0 - opnd_value ;
}
@ -5509,6 +5507,7 @@ xtensa_force_relocation (fixS *fix)
{
switch ( fix - > fx_r_type )
{
case BFD_RELOC_XTENSA_ASM_EXPAND :
case BFD_RELOC_XTENSA_SLOT0_ALT :
case BFD_RELOC_XTENSA_SLOT1_ALT :
case BFD_RELOC_XTENSA_SLOT2_ALT :
@ -5524,8 +5523,6 @@ xtensa_force_relocation (fixS *fix)
case BFD_RELOC_XTENSA_SLOT12_ALT :
case BFD_RELOC_XTENSA_SLOT13_ALT :
case BFD_RELOC_XTENSA_SLOT14_ALT :
case BFD_RELOC_VTABLE_INHERIT :
case BFD_RELOC_VTABLE_ENTRY :
return 1 ;
default :
break ;
@ -5539,6 +5536,33 @@ xtensa_force_relocation (fixS *fix)
}
/* TC_VALIDATE_FIX_SUB hook */
int
xtensa_validate_fix_sub ( fixS * fix )
{
segT add_symbol_segment , sub_symbol_segment ;
/* The difference of two symbols should be resolved by the assembler when
linkrelax is not set . If the linker may relax the section containing
the symbols , then an Xtensa DIFF relocation must be generated so that
the linker knows to adjust the difference value . */
if ( ! linkrelax | | fix - > fx_addsy = = NULL )
return 0 ;
/* Make sure both symbols are in the same segment, and that segment is
" normal " and relaxable . If the segment is not " normal " , then the
fix is not valid . If the segment is not " relaxable " , then the fix
should have been handled earlier . */
add_symbol_segment = S_GET_SEGMENT ( fix - > fx_addsy ) ;
if ( ! SEG_NORMAL ( add_symbol_segment ) | |
! relaxable_section ( add_symbol_segment ) )
return 0 ;
sub_symbol_segment = S_GET_SEGMENT ( fix - > fx_subsy ) ;
return ( sub_symbol_segment = = add_symbol_segment ) ;
}
/* NO_PSEUDO_DOT hook */
/* This function has nothing to do with pseudo dots, but this is the
@ -5586,38 +5610,124 @@ xtensa_fix_adjustable (fixS *fixP)
| | fixP - > fx_r_type = = BFD_RELOC_VTABLE_ENTRY )
return 0 ;
if ( fixP - > fx_addsy
& & ( S_IS_EXTERNAL ( fixP - > fx_addsy ) | | S_IS_WEAK ( fixP - > fx_addsy ) ) )
return 0 ;
return 1 ;
}
void
md_apply_fix3 ( fixS * fixP , valueT * valP , segT seg ATTRIBUTE_UNUSED )
{
if ( fixP - > fx_pcrel = = 0 & & fixP - > fx_addsy = = 0 )
md_apply_fix3 ( fixS * fixP , valueT * valP , segT seg )
{
char * const fixpos = fixP - > fx_frag - > fr_literal + fixP - > fx_where ;
valueT val ;
switch ( fixP - > fx_r_type )
{
case BFD_RELOC_XTENSA_ASM_EXPAND :
fixP - > fx_done = 1 ;
case BFD_RELOC_32 :
case BFD_RELOC_16 :
case BFD_RELOC_8 :
if ( linkrelax & & fixP - > fx_subsy )
{
switch ( fixP - > fx_r_type )
{
case BFD_RELOC_8 :
fixP - > fx_r_type = BFD_RELOC_XTENSA_DIFF8 ;
break ;
case BFD_RELOC_16 :
fixP - > fx_r_type = BFD_RELOC_XTENSA_DIFF16 ;
break ;
case BFD_RELOC_32 :
fixP - > fx_r_type = BFD_RELOC_XTENSA_DIFF32 ;
break ;
default :
break ;
}
case BFD_RELOC_XTENSA_ASM_SIMPLIFY :
as_bad ( _ ( " unhandled local relocation fix %s " ) ,
bfd_get_reloc_code_name ( fixP - > fx_r_type ) ) ;
/* An offset is only allowed when it results from adjusting a
local symbol into a section - relative offset . If the offset
came from the original expression , tc_fix_adjustable will have
prevented the fix from being converted to a section - relative
form so that we can flag the error here . */
if ( fixP - > fx_offset ! = 0 & & ! symbol_section_p ( fixP - > fx_addsy ) )
as_bad_where ( fixP - > fx_file , fixP - > fx_line ,
_ ( " cannot represent subtraction with an offset " ) ) ;
val = ( S_GET_VALUE ( fixP - > fx_addsy ) + fixP - > fx_offset
- S_GET_VALUE ( fixP - > fx_subsy ) ) ;
/* The difference value gets written out, and the DIFF reloc
identifies the address of the subtracted symbol ( i . e . , the one
with the lowest address ) . */
* valP = val ;
fixP - > fx_offset - = val ;
fixP - > fx_subsy = NULL ;
}
else if ( ! fixP - > fx_addsy )
{
val = * valP ;
fixP - > fx_done = 1 ;
}
else
break ;
md_number_to_chars ( fixpos , val , fixP - > fx_size ) ;
fixP - > fx_no_overflow = 0 ; /* Use the standard overflow check. */
break ;
case BFD_RELOC_32 :
case BFD_RELOC_16 :
case BFD_RELOC_8 :
/* The only one we support that isn't an instruction field. */
md_number_to_chars ( fixpos , * valP , fixP - > fx_size ) ;
case BFD_RELOC_XTENSA_SLOT0_OP :
case BFD_RELOC_XTENSA_SLOT1_OP :
case BFD_RELOC_XTENSA_SLOT2_OP :
case BFD_RELOC_XTENSA_SLOT3_OP :
case BFD_RELOC_XTENSA_SLOT4_OP :
case BFD_RELOC_XTENSA_SLOT5_OP :
case BFD_RELOC_XTENSA_SLOT6_OP :
case BFD_RELOC_XTENSA_SLOT7_OP :
case BFD_RELOC_XTENSA_SLOT8_OP :
case BFD_RELOC_XTENSA_SLOT9_OP :
case BFD_RELOC_XTENSA_SLOT10_OP :
case BFD_RELOC_XTENSA_SLOT11_OP :
case BFD_RELOC_XTENSA_SLOT12_OP :
case BFD_RELOC_XTENSA_SLOT13_OP :
case BFD_RELOC_XTENSA_SLOT14_OP :
if ( linkrelax )
{
/* Write the tentative value of a PC-relative relocation to a
local symbol into the instruction . The value will be ignored
by the linker , and it makes the object file disassembly
readable when all branch targets are encoded in relocations . */
assert ( fixP - > fx_addsy ) ;
if ( S_GET_SEGMENT ( fixP - > fx_addsy ) = = seg & & ! fixP - > fx_plt
& & ! S_FORCE_RELOC ( fixP - > fx_addsy , 1 ) )
{
val = ( S_GET_VALUE ( fixP - > fx_addsy ) + fixP - > fx_offset
- md_pcrel_from ( fixP ) ) ;
( void ) xg_apply_fix_value ( fixP , val ) ;
}
}
else if ( ! fixP - > fx_addsy )
{
val = * valP ;
if ( xg_apply_fix_value ( fixP , val ) )
fixP - > fx_done = 1 ;
}
break ;
case BFD_RELOC_XTENSA_ASM_EXPAND :
case BFD_RELOC_XTENSA_SLOT0_ALT :
case BFD_RELOC_XTENSA_SLOT1_ALT :
case BFD_RELOC_XTENSA_SLOT2_ALT :
case BFD_RELOC_XTENSA_SLOT3_ALT :
case BFD_RELOC_XTENSA_SLOT4_ALT :
case BFD_RELOC_XTENSA_SLOT5_ALT :
case BFD_RELOC_XTENSA_SLOT6_ALT :
case BFD_RELOC_XTENSA_SLOT7_ALT :
case BFD_RELOC_XTENSA_SLOT8_ALT :
case BFD_RELOC_XTENSA_SLOT9_ALT :
case BFD_RELOC_XTENSA_SLOT10_ALT :
case BFD_RELOC_XTENSA_SLOT11_ALT :
case BFD_RELOC_XTENSA_SLOT12_ALT :
case BFD_RELOC_XTENSA_SLOT13_ALT :
case BFD_RELOC_XTENSA_SLOT14_ALT :
/* These all need to be resolved at link-time. Do nothing now. */
break ;
case BFD_RELOC_VTABLE_INHERIT :
@ -5630,7 +5740,6 @@ md_apply_fix3 (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
bfd_get_reloc_code_name ( fixP - > fx_r_type ) ) ;
}
}
}
char *
@ -5687,10 +5796,9 @@ md_estimate_size_before_relax (fragS *fragP, segT seg ATTRIBUTE_UNUSED)
format . */
arelent *
tc_gen_reloc ( asection * section , fixS * fixp )
tc_gen_reloc ( asection * section ATTRIBUTE_UNUSED , fixS * fixp )
{
arelent * reloc ;
bfd_boolean apply_tentative_value = FALSE ;
reloc = ( arelent * ) xmalloc ( sizeof ( arelent ) ) ;
reloc - > sym_ptr_ptr = ( asymbol * * ) xmalloc ( sizeof ( asymbol * ) ) ;
@ -5701,129 +5809,8 @@ tc_gen_reloc (asection *section, fixS *fixp)
They ' d better have been fully resolved by this point . */
assert ( ( int ) fixp - > fx_r_type > 0 ) ;
if ( linkrelax & & fixp - > fx_subsy
& & ( fixp - > fx_r_type = = BFD_RELOC_8
| | fixp - > fx_r_type = = BFD_RELOC_16
| | fixp - > fx_r_type = = BFD_RELOC_32 ) )
{
int diff_size = 0 ;
bfd_vma diff_value , diff_mask = 0 ;
switch ( fixp - > fx_r_type )
{
case BFD_RELOC_8 :
fixp - > fx_r_type = BFD_RELOC_XTENSA_DIFF8 ;
diff_size = 1 ;
diff_mask = 0xff ;
break ;
case BFD_RELOC_16 :
fixp - > fx_r_type = BFD_RELOC_XTENSA_DIFF16 ;
diff_size = 2 ;
diff_mask = 0xffff ;
break ;
case BFD_RELOC_32 :
fixp - > fx_r_type = BFD_RELOC_XTENSA_DIFF32 ;
diff_size = 4 ;
diff_mask = 0xffffffff ;
break ;
default :
break ;
}
/* An offset is only allowed when it results from adjusting a local
symbol into a section - relative offset . If the offset came from the
original expression , tc_fix_adjustable will have prevented the fix
from being converted to a section - relative form so that we can flag
the error here . */
if ( fixp - > fx_offset ! = 0 & & ! symbol_section_p ( fixp - > fx_addsy ) )
{
as_bad_where ( fixp - > fx_file , fixp - > fx_line ,
_ ( " cannot represent subtraction with an offset " ) ) ;
free ( reloc - > sym_ptr_ptr ) ;
free ( reloc ) ;
return NULL ;
}
assert ( S_GET_SEGMENT ( fixp - > fx_addsy )
= = S_GET_SEGMENT ( fixp - > fx_subsy ) ) ;
diff_value = ( S_GET_VALUE ( fixp - > fx_addsy ) + fixp - > fx_offset
- S_GET_VALUE ( fixp - > fx_subsy ) ) ;
/* Check for overflow. */
if ( ( diff_value & ~ diff_mask ) ! = 0 )
{
as_bad_where ( fixp - > fx_file , fixp - > fx_line ,
_ ( " value of %ld too large " ) , diff_value ) ;
free ( reloc - > sym_ptr_ptr ) ;
free ( reloc ) ;
return NULL ;
}
md_number_to_chars ( fixp - > fx_frag - > fr_literal + fixp - > fx_where ,
diff_value , diff_size ) ;
reloc - > addend = fixp - > fx_offset - diff_value ;
}
else
{
reloc - > addend = fixp - > fx_offset ;
switch ( fixp - > fx_r_type )
{
case BFD_RELOC_XTENSA_SLOT0_OP :
case BFD_RELOC_XTENSA_SLOT1_OP :
case BFD_RELOC_XTENSA_SLOT2_OP :
case BFD_RELOC_XTENSA_SLOT3_OP :
case BFD_RELOC_XTENSA_SLOT4_OP :
case BFD_RELOC_XTENSA_SLOT5_OP :
case BFD_RELOC_XTENSA_SLOT6_OP :
case BFD_RELOC_XTENSA_SLOT7_OP :
case BFD_RELOC_XTENSA_SLOT8_OP :
case BFD_RELOC_XTENSA_SLOT9_OP :
case BFD_RELOC_XTENSA_SLOT10_OP :
case BFD_RELOC_XTENSA_SLOT11_OP :
case BFD_RELOC_XTENSA_SLOT12_OP :
case BFD_RELOC_XTENSA_SLOT13_OP :
case BFD_RELOC_XTENSA_SLOT14_OP :
/* As a special case, the immediate value for a CONST16 opcode
should not be applied , since this kind of relocation is
handled specially for CONST16 and is not really PC - relative .
Rather than decode the opcode here , just wait and handle it
in xg_apply_tentative_value . */
apply_tentative_value = TRUE ;
break ;
case BFD_RELOC_XTENSA_SLOT0_ALT :
case BFD_RELOC_XTENSA_SLOT1_ALT :
case BFD_RELOC_XTENSA_SLOT2_ALT :
case BFD_RELOC_XTENSA_SLOT3_ALT :
case BFD_RELOC_XTENSA_SLOT4_ALT :
case BFD_RELOC_XTENSA_SLOT5_ALT :
case BFD_RELOC_XTENSA_SLOT6_ALT :
case BFD_RELOC_XTENSA_SLOT7_ALT :
case BFD_RELOC_XTENSA_SLOT8_ALT :
case BFD_RELOC_XTENSA_SLOT9_ALT :
case BFD_RELOC_XTENSA_SLOT10_ALT :
case BFD_RELOC_XTENSA_SLOT11_ALT :
case BFD_RELOC_XTENSA_SLOT12_ALT :
case BFD_RELOC_XTENSA_SLOT13_ALT :
case BFD_RELOC_XTENSA_SLOT14_ALT :
case BFD_RELOC_XTENSA_ASM_EXPAND :
case BFD_RELOC_32 :
case BFD_RELOC_XTENSA_PLT :
case BFD_RELOC_VTABLE_INHERIT :
case BFD_RELOC_VTABLE_ENTRY :
break ;
case BFD_RELOC_XTENSA_ASM_SIMPLIFY :
as_warn ( _ ( " emitting simplification relocation " ) ) ;
break ;
default :
as_warn ( _ ( " emitting unknown relocation " ) ) ;
}
}
reloc - > howto = bfd_reloc_type_lookup ( stdoutput , fixp - > fx_r_type ) ;
if ( reloc - > howto = = NULL )
{
@ -5839,24 +5826,6 @@ tc_gen_reloc (asection *section, fixS *fixp)
as_fatal ( _ ( " internal error? cannot generate `%s' relocation " ) ,
bfd_get_reloc_code_name ( fixp - > fx_r_type ) ) ;
/* Write the tentative value of a PC-relative relocation to a local symbol
into the instruction . The value will be ignored by the linker , and it
makes the object file disassembly readable when the linkrelax flag is
set and all branch targets are encoded in relocations . */
if ( linkrelax & & apply_tentative_value & & fixp - > fx_pcrel )
{
valueT val ;
assert ( fixp - > fx_addsy ) ;
if ( S_GET_SEGMENT ( fixp - > fx_addsy ) = = section & & ! fixp - > fx_plt
& & ! S_FORCE_RELOC ( fixp - > fx_addsy , 1 ) )
{
val = ( S_GET_VALUE ( fixp - > fx_addsy ) + fixp - > fx_offset
- md_pcrel_from ( fixp ) ) ;
xg_apply_tentative_value ( fixp , val ) ;
}
}
return reloc ;
}