From bdfaef528f42e9c07279aab2f37e3b888a08fc22 Mon Sep 17 00:00:00 2001 From: Joern Rennecke Date: Mon, 3 Mar 2003 21:04:01 +0000 Subject: [PATCH] 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. --- bfd/ChangeLog | 13 +++++++++++++ bfd/elf32-sh.c | 40 ++++++++++++++++++++++++++++++++-------- gas/ChangeLog | 14 ++++++++++++++ gas/config/tc-sh.c | 33 +++++++++++++++++++++++---------- gas/config/tc-sh.h | 2 ++ include/elf/ChangeLog | 5 +++++ include/elf/sh.h | 3 ++- 7 files changed, 91 insertions(+), 19 deletions(-) diff --git a/bfd/ChangeLog b/bfd/ChangeLog index 393ab0f9839..9387ce2da47 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,16 @@ +Mon Mar 3 20:48:23 2003 J"orn Rennecke + + * 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. + 2003-03-03 Nick Clifton * po/da.po: Installed latest translation. diff --git a/bfd/elf32-sh.c b/bfd/elf32-sh.c index 20dc7d10af4..c9167bc4e87 100644 --- a/bfd/elf32-sh.c +++ b/bfd/elf32-sh.c @@ -179,6 +179,8 @@ static reloc_howto_type sh_elf_howto_table[] = 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) */ @@ -186,10 +188,10 @@ static reloc_howto_type sh_elf_howto_table[] = TRUE, /* pc_relative */ 0, /* bitpos */ complain_overflow_signed, /* complain_on_overflow */ - sh_elf_reloc, /* special_function */ + NULL, /* special_function */ "R_SH_IND12W", /* name */ - TRUE, /* partial_inplace */ - 0xfff, /* src_mask */ + FALSE, /* partial_inplace */ + 0x0, /* src_mask */ 0xfff, /* dst_mask */ TRUE), /* pcrel_offset */ @@ -2232,6 +2234,12 @@ sh_elf_relax_section (abfd, sec, link_info, again) /* 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, @@ -2242,12 +2250,14 @@ sh_elf_relax_section (abfd, sec, link_info, again) 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. */ @@ -2316,7 +2326,8 @@ sh_elf_relax_section (abfd, sec, link_info, again) /* Look for load and store instructions that we can align on four byte boundaries. */ - if (have_code) + if ((elf_elfheader (abfd)->e_flags & EF_SH_MACH_MASK) != EF_SH4 + && have_code) { bfd_boolean swapped; @@ -2542,14 +2553,28 @@ sh_elf_relax_delete_bytes (abfd, sec, addr, count) break; case R_SH_IND12W: - if (ELF32_R_SYM (irel->r_info) >= symtab_hdr->sh_info) - start = stop = addr; + 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 { - off = insn & 0xfff; 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; @@ -4811,7 +4836,6 @@ sh_elf_relocate_section (output_bfd, info, input_bfd, input_section, break; case R_SH_IND12W: - relocation -= 4; goto final_link_relocate; case R_SH_DIR8WPN: diff --git a/gas/ChangeLog b/gas/ChangeLog index dc46fb38dbf..e2253a2b10d 100644 --- a/gas/ChangeLog +++ b/gas/ChangeLog @@ -1,3 +1,17 @@ +Mon Mar 3 20:36:47 2003 J"orn Rennecke + + * 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. + 2003-03-02 Thiemo Seufer * config/tc-mips.c (append_insn): Add handling of diff --git a/gas/config/tc-sh.c b/gas/config/tc-sh.c index d3a6ac34301..c73b81ff821 100644 --- a/gas/config/tc-sh.c +++ b/gas/config/tc-sh.c @@ -163,9 +163,9 @@ int sh_relax; /* set if -relax seen */ int sh_small; -/* Whether -dsp was seen. */ +/* preset architecture set, if given; zero otherwise. */ -static int sh_dsp; +static int preset_target_arch; /* The bit mask of architectures that could accomodate the insns seen so far. */ @@ -867,7 +867,8 @@ md_begin () char *prev_name = ""; int target_arch; - target_arch = arch_sh1_up & ~(sh_dsp ? arch_sh3e_up : arch_sh_dsp_up); + target_arch + = preset_target_arch ? preset_target_arch : arch_sh1_up & ~arch_sh_dsp_up; valid_arch = target_arch; #ifdef HAVE_SH64 @@ -2593,20 +2594,20 @@ struct option md_longopts[] = #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_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}, @@ -2642,12 +2643,16 @@ md_parse_option (c, arg) break; case OPTION_DSP: - sh_dsp = 1; + preset_target_arch = arch_sh1_up & ~arch_sh3e_up; break; -#ifdef HAVE_SH64 case OPTION_ISA: - if (strcasecmp (arg, "shmedia") == 0) + 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")); @@ -2661,10 +2666,12 @@ md_parse_option (c, arg) 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) { @@ -3381,7 +3388,10 @@ md_apply_fix3 (fixP, valP, seg) val -= S_GET_VALUE (fixP->fx_addsy); #endif -#ifndef BFD_ASSEMBLER +#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) @@ -3902,7 +3912,8 @@ tc_gen_reloc (section, fixp) if (SWITCH_TABLE (fixp)) { - rel->addend = rel->address - S_GET_VALUE (fixp->fx_subsy); + *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) @@ -3941,6 +3952,8 @@ tc_gen_reloc (section, fixp) 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, diff --git a/gas/config/tc-sh.h b/gas/config/tc-sh.h index 6537a6dda33..b1c9bc0b2df 100644 --- a/gas/config/tc-sh.h +++ b/gas/config/tc-sh.h @@ -235,6 +235,8 @@ extern bfd_boolean sh_fix_adjustable PARAMS ((struct fix *)); || (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) \ diff --git a/include/elf/ChangeLog b/include/elf/ChangeLog index beb85a7f278..e87cdd2e045 100644 --- a/include/elf/ChangeLog +++ b/include/elf/ChangeLog @@ -1,3 +1,8 @@ +Mon Mar 3 20:35:58 2003 J"orn Rennecke + + * sh.h (EF_SH_MERGE_MACH): Make sure SH2E & SH3/SH3E merge to SH3E, + and SH2E & SH4 merge to SH4, not SH2E. + 2003-02-21 Ian Wienand * ia64.h (SHT_IA_64_LOPSREG, SHT_IA_64_HIPSREG, diff --git a/include/elf/sh.h b/include/elf/sh.h index 41bf0bf6967..00a5f2adce2 100644 --- a/include/elf/sh.h +++ b/include/elf/sh.h @@ -56,7 +56,8 @@ : (((mach1) == EF_SH3E && (mach2) == EF_SH_UNKNOWN) \ || ((mach2) == EF_SH3E && (mach1) == EF_SH_UNKNOWN)) \ ? EF_SH4 \ - : ((mach1) > (mach2) ? (mach1) : (mach2))) + : (((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). */ -- 2.30.2