diff options
author | Federico G. Schwindt <fgsch@cvs.openbsd.org> | 2002-05-13 17:07:46 +0000 |
---|---|---|
committer | Federico G. Schwindt <fgsch@cvs.openbsd.org> | 2002-05-13 17:07:46 +0000 |
commit | c866442bb5e16be2b5323fee961ceb1315393514 (patch) | |
tree | f12f495081042abe1a40d83bf05d076ff8aa8a17 /gnu/usr.bin/binutils/bfd/elf32-sparc.c | |
parent | 99d2ba46f95f9f99286b4c66576c4607669b0e7f (diff) |
resolve conflicts.
Diffstat (limited to 'gnu/usr.bin/binutils/bfd/elf32-sparc.c')
-rw-r--r-- | gnu/usr.bin/binutils/bfd/elf32-sparc.c | 229 |
1 files changed, 169 insertions, 60 deletions
diff --git a/gnu/usr.bin/binutils/bfd/elf32-sparc.c b/gnu/usr.bin/binutils/bfd/elf32-sparc.c index 1c8d0ba275a..091cd3917f7 100644 --- a/gnu/usr.bin/binutils/bfd/elf32-sparc.c +++ b/gnu/usr.bin/binutils/bfd/elf32-sparc.c @@ -1,5 +1,5 @@ /* SPARC-specific support for 32-bit ELF - Copyright (C) 1993, 94, 95, 96, 97, 98, 99, 2000 + Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001 Free Software Foundation, Inc. This file is part of BFD, the Binary File Descriptor library. @@ -24,6 +24,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "libbfd.h" #include "elf-bfd.h" #include "elf/sparc.h" +#include "opcode/sparc.h" static reloc_howto_type *elf32_sparc_reloc_type_lookup PARAMS ((bfd *, bfd_reloc_code_real_type)); @@ -36,6 +37,8 @@ static boolean elf32_sparc_adjust_dynamic_symbol PARAMS ((struct bfd_link_info *, struct elf_link_hash_entry *)); static boolean elf32_sparc_size_dynamic_sections PARAMS ((bfd *, struct bfd_link_info *)); +static boolean elf32_sparc_relax_section + PARAMS ((bfd *, asection *, struct bfd_link_info *, boolean *)); static boolean elf32_sparc_relocate_section PARAMS ((bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *, Elf_Internal_Rela *, Elf_Internal_Sym *, asection **)); @@ -82,7 +85,7 @@ reloc_howto_type _bfd_sparc_elf_howto_table[] = HOWTO(R_SPARC_GLOB_DAT, 0,0,00,false,0,complain_overflow_dont, bfd_elf_generic_reloc, "R_SPARC_GLOB_DAT",false,0,0x00000000,true), HOWTO(R_SPARC_JMP_SLOT, 0,0,00,false,0,complain_overflow_dont, bfd_elf_generic_reloc, "R_SPARC_JMP_SLOT",false,0,0x00000000,true), HOWTO(R_SPARC_RELATIVE, 0,0,00,false,0,complain_overflow_dont, bfd_elf_generic_reloc, "R_SPARC_RELATIVE",false,0,0x00000000,true), - HOWTO(R_SPARC_UA32, 0,0,00,false,0,complain_overflow_dont, bfd_elf_generic_reloc, "R_SPARC_UA32", false,0,0x00000000,true), + HOWTO(R_SPARC_UA32, 0,2,32,false,0,complain_overflow_bitfield,bfd_elf_generic_reloc, "R_SPARC_UA32", false,0,0xffffffff,true), HOWTO(R_SPARC_PLT32, 0,0,00,false,0,complain_overflow_dont, sparc_elf_notsupported_reloc, "R_SPARC_PLT32", false,0,0x00000000,true), HOWTO(R_SPARC_HIPLT22, 0,0,00,false,0,complain_overflow_dont, sparc_elf_notsupported_reloc, "R_SPARC_HIPLT22", false,0,0x00000000,true), HOWTO(R_SPARC_LOPLT10, 0,0,00,false,0,complain_overflow_dont, sparc_elf_notsupported_reloc, "R_SPARC_LOPLT10", false,0,0x00000000,true), @@ -117,16 +120,15 @@ reloc_howto_type _bfd_sparc_elf_howto_table[] = HOWTO(R_SPARC_NONE, 0,0, 0,false,0,complain_overflow_dont, bfd_elf_generic_reloc, "R_SPARC_NONE", false,0,0x00000000,true), HOWTO(R_SPARC_NONE, 0,0, 0,false,0,complain_overflow_dont, bfd_elf_generic_reloc, "R_SPARC_NONE", false,0,0x00000000,true), HOWTO(R_SPARC_NONE, 0,0, 0,false,0,complain_overflow_dont, bfd_elf_generic_reloc, "R_SPARC_NONE", false,0,0x00000000,true), - HOWTO(R_SPARC_NONE, 0,0, 0,false,0,complain_overflow_dont, bfd_elf_generic_reloc, "R_SPARC_NONE", false,0,0x00000000,true), - HOWTO(R_SPARC_NONE, 0,0, 0,false,0,complain_overflow_dont, bfd_elf_generic_reloc, "R_SPARC_NONE", false,0,0x00000000,true), - HOWTO(R_SPARC_REV32, 0,2,32,false,0,complain_overflow_bitfield,bfd_elf_generic_reloc, "R_SPARC_REV32", false,0,0xffffffff,true), + HOWTO(R_SPARC_UA64, 0,4,64,false,0,complain_overflow_bitfield,bfd_elf_generic_reloc, "R_SPARC_UA64", false,0,(~ (bfd_vma)0), true), + HOWTO(R_SPARC_UA16, 0,1,16,false,0,complain_overflow_bitfield,bfd_elf_generic_reloc, "R_SPARC_UA16", false,0,0x0000ffff,true), + HOWTO(R_SPARC_REV32, 0,2,32,false,0,complain_overflow_bitfield,bfd_elf_generic_reloc, "R_SPARC_REV32", false,0,0xffffffff,true), }; static reloc_howto_type elf32_sparc_vtinherit_howto = HOWTO (R_SPARC_GNU_VTINHERIT, 0,2,0,false,0,complain_overflow_dont, NULL, "R_SPARC_GNU_VTINHERIT", false,0, 0, false); static reloc_howto_type elf32_sparc_vtentry_howto = HOWTO (R_SPARC_GNU_VTENTRY, 0,2,0,false,0,complain_overflow_dont, _bfd_elf_rel_vtable_reloc_fn,"R_SPARC_GNU_VTENTRY", false,0,0, false); - struct elf_reloc_map { bfd_reloc_code_real_type bfd_reloc_val; unsigned char elf_reloc_val; @@ -157,26 +159,27 @@ static CONST struct elf_reloc_map sparc_reloc_map[] = { BFD_RELOC_SPARC_JMP_SLOT, R_SPARC_JMP_SLOT }, { BFD_RELOC_SPARC_RELATIVE, R_SPARC_RELATIVE }, { BFD_RELOC_SPARC_WDISP22, R_SPARC_WDISP22 }, - /* ??? Doesn't dwarf use this? */ -/*{ BFD_RELOC_SPARC_UA32, R_SPARC_UA32 }, not used?? */ - {BFD_RELOC_SPARC_10, R_SPARC_10}, - {BFD_RELOC_SPARC_11, R_SPARC_11}, - {BFD_RELOC_SPARC_64, R_SPARC_64}, - {BFD_RELOC_SPARC_OLO10, R_SPARC_OLO10}, - {BFD_RELOC_SPARC_HH22, R_SPARC_HH22}, - {BFD_RELOC_SPARC_HM10, R_SPARC_HM10}, - {BFD_RELOC_SPARC_LM22, R_SPARC_LM22}, - {BFD_RELOC_SPARC_PC_HH22, R_SPARC_PC_HH22}, - {BFD_RELOC_SPARC_PC_HM10, R_SPARC_PC_HM10}, - {BFD_RELOC_SPARC_PC_LM22, R_SPARC_PC_LM22}, - {BFD_RELOC_SPARC_WDISP16, R_SPARC_WDISP16}, - {BFD_RELOC_SPARC_WDISP19, R_SPARC_WDISP19}, - {BFD_RELOC_SPARC_7, R_SPARC_7}, - {BFD_RELOC_SPARC_5, R_SPARC_5}, - {BFD_RELOC_SPARC_6, R_SPARC_6}, - {BFD_RELOC_SPARC_REV32, R_SPARC_REV32 }, - {BFD_RELOC_VTABLE_INHERIT, R_SPARC_GNU_VTINHERIT}, - {BFD_RELOC_VTABLE_ENTRY, R_SPARC_GNU_VTENTRY}, + { BFD_RELOC_SPARC_UA16, R_SPARC_UA16 }, + { BFD_RELOC_SPARC_UA32, R_SPARC_UA32 }, + { BFD_RELOC_SPARC_UA64, R_SPARC_UA64 }, + { BFD_RELOC_SPARC_10, R_SPARC_10 }, + { BFD_RELOC_SPARC_11, R_SPARC_11 }, + { BFD_RELOC_SPARC_64, R_SPARC_64 }, + { BFD_RELOC_SPARC_OLO10, R_SPARC_OLO10 }, + { BFD_RELOC_SPARC_HH22, R_SPARC_HH22 }, + { BFD_RELOC_SPARC_HM10, R_SPARC_HM10 }, + { BFD_RELOC_SPARC_LM22, R_SPARC_LM22 }, + { BFD_RELOC_SPARC_PC_HH22, R_SPARC_PC_HH22 }, + { BFD_RELOC_SPARC_PC_HM10, R_SPARC_PC_HM10 }, + { BFD_RELOC_SPARC_PC_LM22, R_SPARC_PC_LM22 }, + { BFD_RELOC_SPARC_WDISP16, R_SPARC_WDISP16 }, + { BFD_RELOC_SPARC_WDISP19, R_SPARC_WDISP19 }, + { BFD_RELOC_SPARC_7, R_SPARC_7 }, + { BFD_RELOC_SPARC_5, R_SPARC_5 }, + { BFD_RELOC_SPARC_6, R_SPARC_6 }, + { BFD_RELOC_SPARC_REV32, R_SPARC_REV32 }, + { BFD_RELOC_VTABLE_INHERIT, R_SPARC_GNU_VTINHERIT }, + { BFD_RELOC_VTABLE_ENTRY, R_SPARC_GNU_VTENTRY }, }; static reloc_howto_type * @@ -185,7 +188,7 @@ elf32_sparc_reloc_type_lookup (abfd, code) bfd_reloc_code_real_type code; { unsigned int i; - + switch (code) { case BFD_RELOC_VTABLE_INHERIT: @@ -549,7 +552,9 @@ elf32_sparc_check_relocs (abfd, info, sec, relocs) case R_SPARC_22: case R_SPARC_13: case R_SPARC_LO10: + case R_SPARC_UA16: case R_SPARC_UA32: + case R_SPARC_UA64: if (h != NULL) h->elf_link_hash_flags |= ELF_LINK_NON_GOT_REF; @@ -1016,7 +1021,12 @@ elf32_sparc_size_dynamic_sections (output_bfd, info) } /* Allocate memory for the section contents. */ - s->contents = (bfd_byte *) bfd_alloc (dynobj, s->_raw_size); + /* FIXME: This should be a call to bfd_alloc not bfd_zalloc. + Unused entries should be reclaimed before the section's contents + are written out, but at the moment this does not happen. Thus in + order to prevent writing out garbage, we initialise the section's + contents to zero. */ + s->contents = (bfd_byte *) bfd_zalloc (dynobj, s->_raw_size); if (s->contents == NULL && s->_raw_size != 0) return false; } @@ -1053,12 +1063,28 @@ elf32_sparc_size_dynamic_sections (output_bfd, info) { if (! bfd_elf32_add_dynamic_entry (info, DT_TEXTREL, 0)) return false; + info->flags |= DF_TEXTREL; } } return true; } +#define SET_SEC_DO_RELAX(section) do { elf_section_data(section)->tdata = (void *)1; } while (0) +#define SEC_DO_RELAX(section) (elf_section_data(section)->tdata == (void *)1) + +static boolean +elf32_sparc_relax_section (abfd, section, link_info, again) + bfd *abfd ATTRIBUTE_UNUSED; + asection *section ATTRIBUTE_UNUSED; + struct bfd_link_info *link_info ATTRIBUTE_UNUSED; + boolean *again; +{ + *again = false; + SET_SEC_DO_RELAX (section); + return true; +} + /* Relocate a SPARC ELF section. */ static boolean @@ -1113,7 +1139,7 @@ elf32_sparc_relocate_section (output_bfd, info, input_bfd, input_section, r_type = ELF32_R_TYPE (rel->r_info); - if (r_type == R_SPARC_GNU_VTINHERIT + if (r_type == R_SPARC_GNU_VTINHERIT || r_type == R_SPARC_GNU_VTENTRY) continue; @@ -1195,7 +1221,9 @@ elf32_sparc_relocate_section (output_bfd, info, input_bfd, input_section, || r_type == R_SPARC_22 || r_type == R_SPARC_13 || r_type == R_SPARC_LO10 + || r_type == R_SPARC_UA16 || r_type == R_SPARC_UA32 + || r_type == R_SPARC_UA64 || ((r_type == R_SPARC_PC10 || r_type == R_SPARC_PC22) && strcmp (h->root.root.string, @@ -1382,7 +1410,9 @@ elf32_sparc_relocate_section (output_bfd, info, input_bfd, input_section, case R_SPARC_22: case R_SPARC_13: case R_SPARC_LO10: + case R_SPARC_UA16: case R_SPARC_UA32: + case R_SPARC_UA64: if (info->shared) { Elf_Internal_Rela outrel; @@ -1518,6 +1548,7 @@ elf32_sparc_relocate_section (output_bfd, info, input_bfd, input_section, break; } + r = bfd_reloc_continue; if (r_type == R_SPARC_WDISP16) { bfd_vma x; @@ -1549,12 +1580,101 @@ elf32_sparc_relocate_section (output_bfd, info, input_bfd, input_section, bfd_putl32 (/*input_bfd,*/ x, contents + rel->r_offset); r = bfd_reloc_ok; } - else + else if ((r_type == R_SPARC_WDISP30 || r_type == R_SPARC_WPLT30) + && SEC_DO_RELAX (input_section) + && rel->r_offset + 4 < input_section->_raw_size) + { +#define G0 0 +#define O7 15 +#define XCC (2 << 20) +#define COND(x) (((x)&0xf)<<25) +#define CONDA COND(0x8) +#define INSN_BPA (F2(0,1) | CONDA | BPRED | XCC) +#define INSN_BA (F2(0,2) | CONDA) +#define INSN_OR F3(2, 0x2, 0) +#define INSN_NOP F2(0,4) + + bfd_vma x, y; + + /* If the instruction is a call with either: + restore + arithmetic instruction with rd == %o7 + where rs1 != %o7 and rs2 if it is register != %o7 + then we can optimize if the call destination is near + by changing the call into a branch always. */ + x = bfd_get_32 (input_bfd, contents + rel->r_offset); + y = bfd_get_32 (input_bfd, contents + rel->r_offset + 4); + if ((x & OP(~0)) == OP(1) && (y & OP(~0)) == OP(2)) + { + if (((y & OP3(~0)) == OP3(0x3d) /* restore */ + || ((y & OP3(0x28)) == 0 /* arithmetic */ + && (y & RD(~0)) == RD(O7))) + && (y & RS1(~0)) != RS1(O7) + && ((y & F3I(~0)) + || (y & RS2(~0)) != RS2(O7))) + { + bfd_vma reloc; + + reloc = relocation + rel->r_addend - rel->r_offset; + reloc -= (input_section->output_section->vma + + input_section->output_offset); + + /* Ensure the reloc fits into simm22. */ + if ((reloc & 3) == 0 + && ((reloc & ~(bfd_vma)0x7fffff) == 0 + || ((reloc | 0x7fffff) == ~(bfd_vma)0))) + { + reloc >>= 2; + + /* Check whether it fits into simm19 on v9. */ + if (((reloc & 0x3c0000) == 0 + || (reloc & 0x3c0000) == 0x3c0000) + && (elf_elfheader (output_bfd)->e_flags & EF_SPARC_32PLUS)) + x = INSN_BPA | (reloc & 0x7ffff); /* ba,pt %xcc */ + else + x = INSN_BA | (reloc & 0x3fffff); /* ba */ + bfd_put_32 (input_bfd, x, contents + rel->r_offset); + r = bfd_reloc_ok; + if (rel->r_offset >= 4 + && (y & (0xffffffff ^ RS1(~0))) + == (INSN_OR | RD(O7) | RS2(G0))) + { + bfd_vma z; + unsigned int reg; + + z = bfd_get_32 (input_bfd, + contents + rel->r_offset - 4); + if ((z & (0xffffffff ^ RD(~0))) + != (INSN_OR | RS1(O7) | RS2(G0))) + break; + + /* The sequence was + or %o7, %g0, %rN + call foo + or %rN, %g0, %o7 + + If call foo was replaced with ba, replace + or %rN, %g0, %o7 with nop. */ + + reg = (y & RS1(~0)) >> 14; + if (reg != ((z & RD(~0)) >> 25) + || reg == G0 || reg == O7) + break; + + bfd_put_32 (input_bfd, INSN_NOP, + contents + rel->r_offset + 4); + } + + } + } + } + } + + if (r == bfd_reloc_continue) r = _bfd_final_link_relocate (howto, input_bfd, input_section, contents, rel->r_offset, relocation, rel->r_addend); - if (r != bfd_reloc_ok) { switch (r) @@ -1646,6 +1766,13 @@ elf32_sparc_finish_dynamic_symbol (output_bfd, info, h, sym) /* Mark the symbol as undefined, rather than as defined in the .plt section. Leave the value alone. */ sym->st_shndx = SHN_UNDEF; + /* If the symbol is weak, we do need to clear the value. + Otherwise, the PLT entry would provide a definition for + the symbol even if the symbol wasn't defined anywhere, + and so the symbol would never be NULL. */ + if ((h->elf_link_hash_flags & ELF_LINK_HASH_REF_REGULAR_NONWEAK) + == 0) + sym->st_value = 0; } } @@ -1842,33 +1969,6 @@ elf32_sparc_merge_private_bfd_data (ibfd, obfd) error = false; -#if 0 - /* ??? The native linker doesn't do this so we can't (otherwise gcc would - have to know which linker is being used). Instead, the native linker - bumps up the architecture level when it has to. However, I still think - warnings like these are good, so it would be nice to have them turned on - by some option. */ - - /* If the output machine is normal sparc, we can't allow v9 input files. */ - if (bfd_get_mach (obfd) == bfd_mach_sparc - && (bfd_get_mach (ibfd) == bfd_mach_sparc_v8plus - || bfd_get_mach (ibfd) == bfd_mach_sparc_v8plusa)) - { - error = true; - (*_bfd_error_handler) - (_("%s: compiled for a v8plus system and target is v8"), - bfd_get_filename (ibfd)); - } - /* If the output machine is v9, we can't allow v9+vis input files. */ - if (bfd_get_mach (obfd) == bfd_mach_sparc_v8plus - && bfd_get_mach (ibfd) == bfd_mach_sparc_v8plusa) - { - error = true; - (*_bfd_error_handler) - (_("%s: compiled for a v8plusa system and target is v8plus"), - bfd_get_filename (ibfd)); - } -#else if (bfd_get_mach (ibfd) >= bfd_mach_sparc_v9) { error = true; @@ -1881,7 +1981,6 @@ elf32_sparc_merge_private_bfd_data (ibfd, obfd) if (bfd_get_mach (obfd) < bfd_get_mach (ibfd)) bfd_set_arch_mach (obfd, bfd_arch_sparc, bfd_get_mach (ibfd)); } -#endif if (((elf_elfheader (ibfd)->e_flags & EF_SPARC_LEDATA) != previous_ibfd_e_flags) @@ -1911,7 +2010,10 @@ elf32_sparc_object_p (abfd) { if (elf_elfheader (abfd)->e_machine == EM_SPARC32PLUS) { - if (elf_elfheader (abfd)->e_flags & EF_SPARC_SUN_US1) + if (elf_elfheader (abfd)->e_flags & EF_SPARC_SUN_US3) + return bfd_default_set_arch_mach (abfd, bfd_arch_sparc, + bfd_mach_sparc_v8plusb); + else if (elf_elfheader (abfd)->e_flags & EF_SPARC_SUN_US1) return bfd_default_set_arch_mach (abfd, bfd_arch_sparc, bfd_mach_sparc_v8plusa); else if (elf_elfheader (abfd)->e_flags & EF_SPARC_32PLUS) @@ -1949,6 +2051,12 @@ elf32_sparc_final_write_processing (abfd, linker) elf_elfheader (abfd)->e_flags &=~ EF_SPARC_32PLUS_MASK; elf_elfheader (abfd)->e_flags |= EF_SPARC_32PLUS | EF_SPARC_SUN_US1; break; + case bfd_mach_sparc_v8plusb : + elf_elfheader (abfd)->e_machine = EM_SPARC32PLUS; + elf_elfheader (abfd)->e_flags &=~ EF_SPARC_32PLUS_MASK; + elf_elfheader (abfd)->e_flags |= EF_SPARC_32PLUS | EF_SPARC_SUN_US1 + | EF_SPARC_SUN_US3; + break; case bfd_mach_sparc_sparclite_le : elf_elfheader (abfd)->e_machine = EM_SPARC; elf_elfheader (abfd)->e_flags |= EF_SPARC_LEDATA; @@ -1967,6 +2075,7 @@ elf32_sparc_final_write_processing (abfd, linker) #define ELF_MAXPAGESIZE 0x10000 #define bfd_elf32_bfd_reloc_type_lookup elf32_sparc_reloc_type_lookup +#define bfd_elf32_bfd_relax_section elf32_sparc_relax_section #define elf_info_to_howto elf32_sparc_info_to_howto #define elf_backend_create_dynamic_sections \ _bfd_elf_create_dynamic_sections |