This is the mail archive of the
binutils@sources.redhat.com
mailing list for the binutils project.
patch applied: fix sh-elf linker relaxation
- From: Joern Rennecke <joern dot rennecke at superh dot com>
- To: gcc-patches at gcc dot gnu dot org, binutils at sources dot redhat dot com
- Date: Mon, 03 Mar 2003 21:20:50 +0000
- Subject: patch applied: fix sh-elf linker relaxation
- Organization: SuperH UK Ltd.
Regression tested on sh-elf and sh-coff.
(There are some regressions, but no new ones).
Note that although the meaning of the R_SH_IND12W for sh-elf
is changed, this should not cause any incompatibilities in
practice, since this relocation is only emitted when assembling
with -relax, and linker relaxation was utterly broken.
--
--------------------------
SuperH (UK) Ltd.
2410 Aztec West / Almondsbury / BRISTOL / BS32 4QX
T:+44 1454 465658
Mon Mar 3 21:11:40 2003 J"orn Rennecke <joern dot rennecke at superh dot com>
Fix sh-elf linker relaxation:
gcc:
* config/sh/sh.h (EXTRA_SPECS): Add subtarget_asm_relax_spec and
subtarget_asm_isa_spec.
(SUBTARGET_ASM_RELAX_SPEC, SUBTARGET_ASM_ISA_SPEC): Define.
(ASM_SPEC): Define as SH_ASM_SPEC.
(SH_ASM_SPEC): New; take the role of ASM_SPEC, but safe from svr4.h.
Use subtarget_asm_relax_spec and subtarget_asm_isa_spec.
* config/sh/elf.h (ASM_SPEC): Use SH_ASM_SPEC.
(SUBTARGET_ASM_ISA_SPEC): Undef / define.
gcc/testsuite:
gcc.dg/sh-relax.c: New test.
include/elf:
* sh.h (EF_SH_MERGE_MACH): Make sure SH2E & SH3/SH3E merge to SH3E,
and SH2E & SH4 merge to SH4, not SH2E.
gas:
* config/tc-sh.c (sh_dsp): Replace with preset_target_arch.
(md_begin): Use preset_target_arch.
(md_longopts): Make isa option unconditional.
(md_parse_option): Make OPTION_DSP and OPTION_ISA sh4 / any
set preset_target_arch.
(md_apply_fix3): If BFD_ASSEMBLER, adjust SWITCH_TABLE fixups
by -S_GET_VALUE (fixP->fx_subsy).
(tc_gen_reloc): For SWITCH_TABLE fixups, the symbol is fixp->fx_subsy,
and the addend is 0.
Adjust addend of R_SH_IND12W relocations by fixp->fx_offset - 4.
* config/tc-sh.h (TC_FORCE_RELOCATION_SUB_LOCAL): Define.
bfd:
elf32-sh.c (sh_elf_howto_tab): Make R_SH_IND12W into an ordinary
relocation (no special function), and make it non-partial_inplace.
(sh_elf_relax_section): When creating a bsr, use a consistent value
no matter if the symbol is extern or not; set addend to -4.
Don't swap load / non-load instructions for SH4.
(sh_elf_relax_delete_bytes): In R_SH_IND12W case, check the offset
rather than if the symbol is external to determine if adjusting the
offset makes sense. Adjust the addend too if appropriate.
(sh_elf_relocate_section): In R_SH_IND12W, don't fiddle with the
relocation.
Index: gcc/config/sh/sh.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/sh/sh.h,v
retrieving revision 1.192
retrieving revision 1.193
diff -p -r1.192 -r1.193
*** gcc/config/sh/sh.h 3 Mar 2003 19:50:38 -0000 1.192
--- gcc/config/sh/sh.h 3 Mar 2003 20:57:17 -0000 1.193
*************** extern int target_flags;
*** 359,367 ****
{ "subtarget_link_emul_suffix", SUBTARGET_LINK_EMUL_SUFFIX }, \
{ "subtarget_link_spec", SUBTARGET_LINK_SPEC }, \
{ "subtarget_asm_endian_spec", SUBTARGET_ASM_ENDIAN_SPEC }, \
SUBTARGET_EXTRA_SPECS
! #define ASM_SPEC "%(subtarget_asm_endian_spec) %{mrelax:-relax}"
#ifndef SUBTARGET_ASM_ENDIAN_SPEC
#if TARGET_ENDIAN_DEFAULT == LITTLE_ENDIAN_BIT
--- 359,379 ----
{ "subtarget_link_emul_suffix", SUBTARGET_LINK_EMUL_SUFFIX }, \
{ "subtarget_link_spec", SUBTARGET_LINK_SPEC }, \
{ "subtarget_asm_endian_spec", SUBTARGET_ASM_ENDIAN_SPEC }, \
+ { "subtarget_asm_relax_spec", SUBTARGET_ASM_RELAX_SPEC }, \
+ { "subtarget_asm_isa_spec", SUBTARGET_ASM_ISA_SPEC }, \
SUBTARGET_EXTRA_SPECS
! #if TARGET_CPU_DEFAULT & HARD_SH4_BIT
! #define SUBTARGET_ASM_RELAX_SPEC "%{!m[1235]*:-isa=sh4}"
! #else
! #define SUBTARGET_ASM_RELAX_SPEC "%{m4*:-isa=sh4}"
! #endif
!
! #define SH_ASM_SPEC \
! "%(subtarget_asm_endian_spec) %{mrelax:-relax %(subtarget_asm_relax_spec)}\
! %(subtarget_asm_isa_spec)"
!
! #define ASM_SPEC SH_ASM_SPEC
#ifndef SUBTARGET_ASM_ENDIAN_SPEC
#if TARGET_ENDIAN_DEFAULT == LITTLE_ENDIAN_BIT
*************** extern int target_flags;
*** 370,375 ****
--- 382,389 ----
#define SUBTARGET_ASM_ENDIAN_SPEC "%{ml:-little} %{!ml:-big}"
#endif
#endif
+
+ #define SUBTARGET_ASM_ISA_SPEC ""
#define LINK_EMUL_PREFIX "sh%{ml:l}"
Index: gcc/config/sh/elf.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/sh/elf.h,v
retrieving revision 1.26
retrieving revision 1.27
diff -p -r1.26 -r1.27
*** gcc/config/sh/elf.h 16 Dec 2002 18:21:53 -0000 1.26
--- gcc/config/sh/elf.h 3 Mar 2003 20:57:17 -0000 1.27
*************** Boston, MA 02111-1307, USA. */
*** 68,76 ****
#undef PTRDIFF_TYPE
#define PTRDIFF_TYPE (TARGET_SH5 ? "long int" : "int")
/* Pass -ml and -mrelax to the assembler and linker. */
#undef ASM_SPEC
! #define ASM_SPEC "%(subtarget_asm_endian_spec) %{mrelax:-relax} \
%{m5-compact:--isa=SHcompact} %{m5-compact-nofpu:--isa=SHcompact} \
%{m5-32media:--isa=SHmedia --abi=32} %{m5-32media-nofpu:--isa=SHmedia --abi=32} \
%{m5-64media:--isa=SHmedia --abi=64} %{m5-64media-nofpu:--isa=SHmedia --abi=64}"
--- 68,79 ----
#undef PTRDIFF_TYPE
#define PTRDIFF_TYPE (TARGET_SH5 ? "long int" : "int")
+
/* Pass -ml and -mrelax to the assembler and linker. */
#undef ASM_SPEC
! #define ASM_SPEC SH_ASM_SPEC
! #undef SUBTARGET_ASM_ISA_SPEC
! #define SUBTARGET_ASM_ISA_SPEC "\
%{m5-compact:--isa=SHcompact} %{m5-compact-nofpu:--isa=SHcompact} \
%{m5-32media:--isa=SHmedia --abi=32} %{m5-32media-nofpu:--isa=SHmedia --abi=32} \
%{m5-64media:--isa=SHmedia --abi=64} %{m5-64media-nofpu:--isa=SHmedia --abi=64}"
*** /dev/null Thu Aug 30 21:30:55 2001
--- gcc/testsuite/gcc.dg/sh-relax.c Thu Feb 27 19:21:03 2003
***************
*** 0 ****
--- 1,40 ----
+ /* Check that -mrelax works. */
+ /* { dg-do run { target sh-*-* sh?-*-* sh64-*-* } } */
+ /* { dg-options "-O1 -mrelax" } */
+
+ extern int qwerty (int);
+
+ int
+ f (int i)
+ {
+ return qwerty (i) + 1;
+ }
+
+ int
+ qwerty (int i)
+ {
+ switch (i)
+ {
+ case 1:
+ return 'q';
+ case 2:
+ return 'w';
+ case 3:
+ return 'e';
+ case 4:
+ return 'r';
+ case 5:
+ return 't';
+ case 6:
+ return 'y';
+ }
+ }
+
+ int
+ main ()
+ {
+ if (f (1) != 'q' + 1 || f (2) != 'w' + 1 || f (3) != 'e' + 1
+ || f(4) != 'r' + 1 || f (5) != 't' + 1 || f (6) != 'y' + 1)
+ abort ();
+ return 0;
+ }
Index: include/elf/sh.h
===================================================================
RCS file: /cvs/src/src/include/elf/sh.h,v
retrieving revision 1.13
retrieving revision 1.14
diff -p -r1.13 -r1.14
*** include/elf/sh.h 23 Jan 2003 18:50:57 -0000 1.13
--- include/elf/sh.h 3 Mar 2003 21:03:58 -0000 1.14
***************
*** 56,62 ****
: (((mach1) == EF_SH3E && (mach2) == EF_SH_UNKNOWN) \
|| ((mach2) == EF_SH3E && (mach1) == EF_SH_UNKNOWN)) \
? EF_SH4 \
! : ((mach1) > (mach2) ? (mach1) : (mach2)))
/* Flags for the st_other symbol field.
Keep away from the STV_ visibility flags (bit 0..1). */
--- 56,63 ----
: (((mach1) == EF_SH3E && (mach2) == EF_SH_UNKNOWN) \
|| ((mach2) == EF_SH3E && (mach1) == EF_SH_UNKNOWN)) \
? EF_SH4 \
! : (((mach1) == EF_SH2E ? 7 : (mach1)) > ((mach2) == EF_SH2E ? 7 : (mach2)) \
! ? (mach1) : (mach2)))
/* Flags for the st_other symbol field.
Keep away from the STV_ visibility flags (bit 0..1). */
Index: gas/config/tc-sh.h
===================================================================
RCS file: /cvs/src/src/gas/config/tc-sh.h,v
retrieving revision 1.25
retrieving revision 1.26
diff -p -r1.25 -r1.26
*** gas/config/tc-sh.h 23 Jan 2003 12:51:05 -0000 1.25
--- gas/config/tc-sh.h 3 Mar 2003 21:04:00 -0000 1.26
*************** extern bfd_boolean sh_fix_adjustable PAR
*** 235,240 ****
--- 235,242 ----
|| (FIX)->fx_r_type == BFD_RELOC_SH_GOTPC \
|| TC_FORCE_RELOCATION (FIX))
+ #define TC_FORCE_RELOCATION_SUB_LOCAL(FIX) (sh_relax && SWITCH_TABLE (FIX))
+
/* This keeps the subtracted symbol around, for use by PLT_PCREL
relocs. */
#define TC_FORCE_RELOCATION_SUB_ABS(FIX) \
Index: gas/config/tc-sh.c
===================================================================
RCS file: /cvs/src/src/gas/config/tc-sh.c,v
retrieving revision 1.80
retrieving revision 1.81
diff -p -r1.80 -r1.81
*** gas/config/tc-sh.c 23 Jan 2003 18:50:57 -0000 1.80
--- gas/config/tc-sh.c 3 Mar 2003 21:04:00 -0000 1.81
*************** int sh_relax; /* set if -relax seen */
*** 163,171 ****
int sh_small;
! /* Whether -dsp was seen. */
! static int sh_dsp;
/* The bit mask of architectures that could
accomodate the insns seen so far. */
--- 163,171 ----
int sh_small;
! /* preset architecture set, if given; zero otherwise. */
! static int preset_target_arch;
/* The bit mask of architectures that could
accomodate the insns seen so far. */
*************** md_begin ()
*** 867,873 ****
char *prev_name = "";
int target_arch;
! target_arch = arch_sh1_up & ~(sh_dsp ? arch_sh3e_up : arch_sh_dsp_up);
valid_arch = target_arch;
#ifdef HAVE_SH64
--- 867,874 ----
char *prev_name = "";
int target_arch;
! target_arch
! = preset_target_arch ? preset_target_arch : arch_sh1_up & ~arch_sh_dsp_up;
valid_arch = target_arch;
#ifdef HAVE_SH64
*************** struct option md_longopts[] =
*** 2593,2612 ****
#define OPTION_LITTLE (OPTION_BIG + 1)
#define OPTION_SMALL (OPTION_LITTLE + 1)
#define OPTION_DSP (OPTION_SMALL + 1)
{"relax", no_argument, NULL, OPTION_RELAX},
{"big", no_argument, NULL, OPTION_BIG},
{"little", no_argument, NULL, OPTION_LITTLE},
{"small", no_argument, NULL, OPTION_SMALL},
{"dsp", no_argument, NULL, OPTION_DSP},
#ifdef HAVE_SH64
- #define OPTION_ISA (OPTION_DSP + 1)
#define OPTION_ABI (OPTION_ISA + 1)
#define OPTION_NO_MIX (OPTION_ABI + 1)
#define OPTION_SHCOMPACT_CONST_CRANGE (OPTION_NO_MIX + 1)
#define OPTION_NO_EXPAND (OPTION_SHCOMPACT_CONST_CRANGE + 1)
#define OPTION_PT32 (OPTION_NO_EXPAND + 1)
- {"isa", required_argument, NULL, OPTION_ISA},
{"abi", required_argument, NULL, OPTION_ABI},
{"no-mix", no_argument, NULL, OPTION_NO_MIX},
{"shcompact-const-crange", no_argument, NULL, OPTION_SHCOMPACT_CONST_CRANGE},
--- 2594,2613 ----
#define OPTION_LITTLE (OPTION_BIG + 1)
#define OPTION_SMALL (OPTION_LITTLE + 1)
#define OPTION_DSP (OPTION_SMALL + 1)
+ #define OPTION_ISA (OPTION_DSP + 1)
{"relax", no_argument, NULL, OPTION_RELAX},
{"big", no_argument, NULL, OPTION_BIG},
{"little", no_argument, NULL, OPTION_LITTLE},
{"small", no_argument, NULL, OPTION_SMALL},
{"dsp", no_argument, NULL, OPTION_DSP},
+ {"isa", required_argument, NULL, OPTION_ISA},
#ifdef HAVE_SH64
#define OPTION_ABI (OPTION_ISA + 1)
#define OPTION_NO_MIX (OPTION_ABI + 1)
#define OPTION_SHCOMPACT_CONST_CRANGE (OPTION_NO_MIX + 1)
#define OPTION_NO_EXPAND (OPTION_SHCOMPACT_CONST_CRANGE + 1)
#define OPTION_PT32 (OPTION_NO_EXPAND + 1)
{"abi", required_argument, NULL, OPTION_ABI},
{"no-mix", no_argument, NULL, OPTION_NO_MIX},
{"shcompact-const-crange", no_argument, NULL, OPTION_SHCOMPACT_CONST_CRANGE},
*************** md_parse_option (c, arg)
*** 2642,2653 ****
break;
case OPTION_DSP:
! sh_dsp = 1;
break;
- #ifdef HAVE_SH64
case OPTION_ISA:
! if (strcasecmp (arg, "shmedia") == 0)
{
if (sh64_isa_mode == sh64_isa_shcompact)
as_bad (_("Invalid combination: --isa=SHcompact with --isa=SHmedia"));
--- 2643,2658 ----
break;
case OPTION_DSP:
! preset_target_arch = arch_sh1_up & ~arch_sh3e_up;
break;
case OPTION_ISA:
! if (strcasecmp (arg, "sh4") == 0)
! preset_target_arch = arch_sh4;
! else if (strcasecmp (arg, "any") == 0)
! preset_target_arch = arch_sh1_up;
! #ifdef HAVE_SH64
! else if (strcasecmp (arg, "shmedia") == 0)
{
if (sh64_isa_mode == sh64_isa_shcompact)
as_bad (_("Invalid combination: --isa=SHcompact with --isa=SHmedia"));
*************** md_parse_option (c, arg)
*** 2661,2670 ****
--- 2666,2677 ----
as_bad (_("Invalid combination: --abi=64 with --isa=SHcompact"));
sh64_isa_mode = sh64_isa_shcompact;
}
+ #endif /* HAVE_SH64 */
else
as_bad ("Invalid argument to --isa option: %s", arg);
break;
+ #ifdef HAVE_SH64
case OPTION_ABI:
if (strcmp (arg, "32") == 0)
{
*************** md_apply_fix3 (fixP, valP, seg)
*** 3381,3387 ****
val -= S_GET_VALUE (fixP->fx_addsy);
#endif
! #ifndef BFD_ASSEMBLER
if (fixP->fx_r_type == 0)
{
if (fixP->fx_size == 2)
--- 3388,3397 ----
val -= S_GET_VALUE (fixP->fx_addsy);
#endif
! #ifdef BFD_ASSEMBLER
! if (SWITCH_TABLE (fixP))
! val -= S_GET_VALUE (fixP->fx_subsy);
! #else
if (fixP->fx_r_type == 0)
{
if (fixP->fx_size == 2)
*************** tc_gen_reloc (section, fixp)
*** 3902,3908 ****
if (SWITCH_TABLE (fixp))
{
! rel->addend = rel->address - S_GET_VALUE (fixp->fx_subsy);
if (r_type == BFD_RELOC_16)
r_type = BFD_RELOC_SH_SWITCH16;
else if (r_type == BFD_RELOC_8)
--- 3912,3919 ----
if (SWITCH_TABLE (fixp))
{
! *rel->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_subsy);
! rel->addend = 0;
if (r_type == BFD_RELOC_16)
r_type = BFD_RELOC_SH_SWITCH16;
else if (r_type == BFD_RELOC_8)
*************** tc_gen_reloc (section, fixp)
*** 3941,3946 ****
--- 3952,3959 ----
rel->addend = 0;
rel->howto = bfd_reloc_type_lookup (stdoutput, r_type);
+ if (rel->howto->type == R_SH_IND12W)
+ rel->addend += fixp->fx_offset - 4;
if (rel->howto == NULL)
{
as_bad_where (fixp->fx_file, fixp->fx_line,
Index: bfd/elf32-sh.c
===================================================================
RCS file: /cvs/src/src/bfd/elf32-sh.c,v
retrieving revision 1.73
retrieving revision 1.74
diff -p -r1.73 -r1.74
*** bfd/elf32-sh.c 19 Feb 2003 14:14:16 -0000 1.73
--- bfd/elf32-sh.c 3 Mar 2003 21:04:01 -0000 1.74
*************** static reloc_howto_type sh_elf_howto_tab
*** 179,184 ****
--- 179,186 ----
TRUE), /* pcrel_offset */
/* 12 bit PC relative branch divided by 2. */
+ /* This cannot be partial_inplace because relaxation can't know the
+ eventual value of a symbol. */
HOWTO (R_SH_IND12W, /* type */
1, /* rightshift */
1, /* size (0 = byte, 1 = short, 2 = long) */
*************** static reloc_howto_type sh_elf_howto_tab
*** 186,195 ****
TRUE, /* pc_relative */
0, /* bitpos */
complain_overflow_signed, /* complain_on_overflow */
! sh_elf_reloc, /* special_function */
"R_SH_IND12W", /* name */
! TRUE, /* partial_inplace */
! 0xfff, /* src_mask */
0xfff, /* dst_mask */
TRUE), /* pcrel_offset */
--- 188,197 ----
TRUE, /* pc_relative */
0, /* bitpos */
complain_overflow_signed, /* complain_on_overflow */
! NULL, /* special_function */
"R_SH_IND12W", /* name */
! FALSE, /* partial_inplace */
! 0x0, /* src_mask */
0xfff, /* dst_mask */
TRUE), /* pcrel_offset */
*************** sh_elf_relax_section (abfd, sec, link_in
*** 2232,2237 ****
--- 2234,2245 ----
/* Change the R_SH_USES reloc into an R_SH_IND12W reloc, and
replace the jsr with a bsr. */
irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irelfn->r_info), R_SH_IND12W);
+ /* We used to test (ELF32_R_SYM (irelfn->r_info) < symtab_hdr->sh_info)
+ here, but that only checks if the symbol is an external symbol,
+ not if the symbol is in a different section. Besides, we need
+ a consistent meaning for the relocation, so we just assume here that
+ the value of the symbol is not available. */
+ #if 0
if (ELF32_R_SYM (irelfn->r_info) < symtab_hdr->sh_info)
{
/* If this needs to be changed because of future relaxing,
*************** sh_elf_relax_section (abfd, sec, link_in
*** 2242,2253 ****
--- 2250,2263 ----
contents + irel->r_offset);
}
else
+ #endif
{
/* We can't fully resolve this yet, because the external
symbol value may be changed by future relaxing. We let
the final link phase handle it. */
bfd_put_16 (abfd, (bfd_vma) 0xb000, contents + irel->r_offset);
}
+ irel->r_addend = -4;
/* See if there is another R_SH_USES reloc referring to the same
register load. */
*************** sh_elf_relax_section (abfd, sec, link_in
*** 2316,2322 ****
/* Look for load and store instructions that we can align on four
byte boundaries. */
! if (have_code)
{
bfd_boolean swapped;
--- 2326,2333 ----
/* Look for load and store instructions that we can align on four
byte boundaries. */
! if ((elf_elfheader (abfd)->e_flags & EF_SH_MACH_MASK) != EF_SH4
! && have_code)
{
bfd_boolean swapped;
*************** sh_elf_relax_delete_bytes (abfd, sec, ad
*** 2542,2555 ****
break;
case R_SH_IND12W:
! if (ELF32_R_SYM (irel->r_info) >= symtab_hdr->sh_info)
! start = stop = addr;
else
{
- off = insn & 0xfff;
if (off & 0x800)
off -= 0x1000;
stop = (bfd_vma) ((bfd_signed_vma) start + 4 + off * 2);
}
break;
--- 2553,2580 ----
break;
case R_SH_IND12W:
! off = insn & 0xfff;
! if (! off)
! {
! /* This has been made by previous relaxation. Since the
! relocation will be against an external symbol, the
! final relocation will just do the right thing. */
! start = stop = addr;
! }
else
{
if (off & 0x800)
off -= 0x1000;
stop = (bfd_vma) ((bfd_signed_vma) start + 4 + off * 2);
+
+ /* The addend will be against the section symbol, thus
+ for adjusting the addend, the relevant start is the
+ start of the section.
+ N.B. If we want to abandom in-place changes here and
+ test directly using symbol + addend, we have to take into
+ account that the addend has already been adjusted by -4. */
+ if (stop > addr && stop < toaddr)
+ irel->r_addend -= count;
}
break;
*************** sh_elf_relocate_section (output_bfd, inf
*** 4811,4817 ****
break;
case R_SH_IND12W:
- relocation -= 4;
goto final_link_relocate;
case R_SH_DIR8WPN:
--- 4836,4841 ----