diff options
Diffstat (limited to 'bfd')
-rw-r--r-- | bfd/ChangeLog | 14 | ||||
-rw-r--r-- | bfd/bfd-in2.h | 2 | ||||
-rw-r--r-- | bfd/elf32-sh.c | 201 | ||||
-rw-r--r-- | bfd/libbfd.h | 2 | ||||
-rw-r--r-- | bfd/reloc.c | 4 |
5 files changed, 202 insertions, 21 deletions
diff --git a/bfd/ChangeLog b/bfd/ChangeLog index 2a8ec71..c7714f1 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,17 @@ +Wed Apr 5 22:04:20 2000 J"orn Rennecke <amylaar@cygnus.co.uk> + + * reloc.c (_bfd_relocate_contents): Add BFD_RELOC_SH_LOOP_START and + BFD_RELOC_SH_LOOP_END. + * elf32-sh.c (sh_elf_howto_tab): Change special_func to + sh_elf_ignore_reloc for all entries that sh_elf_reloc used to ignore. + Add entries for R_SH_LOOP_START and R_SH_LOOP_END. + (sh_elf_reloc_loop): New function. + (sh_elf_reloc): No need to test for always-to-be-ignored relocs + any more. + (sh_rel): Add entries for BFD_RELOC_SH_LOOP_{START,END}. + (sh_elf_relocate_section): Handle BFD_RELOC_SH_LOOP_{START,END}. + * bfd-in2.h, libbfd.h: Regenerate. + 2000-04-04 Alan Modra <alan@linuxcare.com.au> * po/bfd.pot: Regenerate. diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h index fa1c5b9..abbf203 100644 --- a/bfd/bfd-in2.h +++ b/bfd/bfd-in2.h @@ -2086,6 +2086,8 @@ not stored in the instruction. */ BFD_RELOC_SH_CODE, BFD_RELOC_SH_DATA, BFD_RELOC_SH_LABEL, + BFD_RELOC_SH_LOOP_START, + BFD_RELOC_SH_LOOP_END, /* Thumb 23-, 12- and 9-bit pc-relative branches. The lowest bit must be zero and is not stored in the instruction. */ diff --git a/bfd/elf32-sh.c b/bfd/elf32-sh.c index ad60e07..6913fa4 100644 --- a/bfd/elf32-sh.c +++ b/bfd/elf32-sh.c @@ -66,7 +66,7 @@ static reloc_howto_type sh_elf_howto_table[] = false, /* pc_relative */ 0, /* bitpos */ complain_overflow_dont, /* complain_on_overflow */ - sh_elf_reloc, /* special_function */ + sh_elf_ignore_reloc, /* special_function */ "R_SH_NONE", /* name */ false, /* partial_inplace */ 0, /* src_mask */ @@ -97,7 +97,7 @@ static reloc_howto_type sh_elf_howto_table[] = true, /* pc_relative */ 0, /* bitpos */ complain_overflow_signed, /* complain_on_overflow */ - sh_elf_reloc, /* special_function */ + sh_elf_ignore_reloc, /* special_function */ "R_SH_REL32", /* name */ false, /* partial_inplace */ 0, /* src_mask */ @@ -112,7 +112,7 @@ static reloc_howto_type sh_elf_howto_table[] = true, /* pc_relative */ 0, /* bitpos */ complain_overflow_signed, /* complain_on_overflow */ - sh_elf_reloc, /* special_function */ + sh_elf_ignore_reloc, /* special_function */ "R_SH_DIR8WPN", /* name */ true, /* partial_inplace */ 0xff, /* src_mask */ @@ -142,7 +142,7 @@ static reloc_howto_type sh_elf_howto_table[] = true, /* pc_relative */ 0, /* bitpos */ complain_overflow_unsigned, /* complain_on_overflow */ - sh_elf_reloc, /* special_function */ + sh_elf_ignore_reloc, /* special_function */ "R_SH_DIR8WPL", /* name */ true, /* partial_inplace */ 0xff, /* src_mask */ @@ -157,7 +157,7 @@ static reloc_howto_type sh_elf_howto_table[] = true, /* pc_relative */ 0, /* bitpos */ complain_overflow_unsigned, /* complain_on_overflow */ - sh_elf_reloc, /* special_function */ + sh_elf_ignore_reloc, /* special_function */ "R_SH_DIR8WPZ", /* name */ true, /* partial_inplace */ 0xff, /* src_mask */ @@ -174,7 +174,7 @@ static reloc_howto_type sh_elf_howto_table[] = false, /* pc_relative */ 0, /* bitpos */ complain_overflow_unsigned, /* complain_on_overflow */ - sh_elf_reloc, /* special_function */ + sh_elf_ignore_reloc, /* special_function */ "R_SH_DIR8BP", /* name */ false, /* partial_inplace */ 0, /* src_mask */ @@ -191,7 +191,7 @@ static reloc_howto_type sh_elf_howto_table[] = false, /* pc_relative */ 0, /* bitpos */ complain_overflow_unsigned, /* complain_on_overflow */ - sh_elf_reloc, /* special_function */ + sh_elf_ignore_reloc, /* special_function */ "R_SH_DIR8W", /* name */ false, /* partial_inplace */ 0, /* src_mask */ @@ -208,7 +208,7 @@ static reloc_howto_type sh_elf_howto_table[] = false, /* pc_relative */ 0, /* bitpos */ complain_overflow_unsigned, /* complain_on_overflow */ - sh_elf_reloc, /* special_function */ + sh_elf_ignore_reloc, /* special_function */ "R_SH_DIR8L", /* name */ false, /* partial_inplace */ 0, /* src_mask */ @@ -420,9 +420,147 @@ static reloc_howto_type sh_elf_howto_table[] = 0, /* dst_mask */ false), /* pcrel_offset */ + /* 8 bit PC relative divided by 2 - but specified in a very odd way. */ + HOWTO (R_SH_LOOP_START, /* type */ + 1, /* rightshift */ + 1, /* size (0 = byte, 1 = short, 2 = long) */ + 8, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + sh_elf_ignore_reloc, /* special_function */ + "R_SH_LOOP_START", /* name */ + true, /* partial_inplace */ + 0xff, /* src_mask */ + 0xff, /* dst_mask */ + true), /* pcrel_offset */ + + /* 8 bit PC relative divided by 2 - but specified in a very odd way. */ + HOWTO (R_SH_LOOP_END, /* type */ + 1, /* rightshift */ + 1, /* size (0 = byte, 1 = short, 2 = long) */ + 8, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + sh_elf_ignore_reloc, /* special_function */ + "R_SH_LOOP_END", /* name */ + true, /* partial_inplace */ + 0xff, /* src_mask */ + 0xff, /* dst_mask */ + true), /* pcrel_offset */ + }; -/* This function is used for normal relocs. This is like the COFF +static bfd_reloc_status_type +sh_elf_reloc_loop (r_type, input_bfd, input_section, contents, addr, + symbol_section, start, end) + int r_type; + bfd *input_bfd; + asection *input_section; + bfd_byte *contents; + bfd_vma addr; + asection *symbol_section; + bfd_vma start, end; +{ + static bfd_vma last_addr; + asection *last_symbol_section; + bfd_byte *free_contents = NULL; + bfd_byte *start_ptr, *ptr, *last_ptr; + int diff, cum_diff; + bfd_signed_vma x; + int insn; + + /* Sanity check the address. */ + if (addr > input_section->_raw_size) + return bfd_reloc_outofrange; + + /* We require the start and end relocations to be processed consecutively - + although we allow then to be processed forwards or backwards. */ + if (! last_addr) + { + last_addr = addr; + last_symbol_section = symbol_section; + return bfd_reloc_ok; + } + if (last_addr != addr) + abort (); + last_addr = 0; + + if (! symbol_section || last_symbol_section != symbol_section || end < start) + return bfd_reloc_outofrange; + + /* Get the symbol_section contents. */ + if (symbol_section != input_section) + { + if (elf_section_data (symbol_section)->this_hdr.contents != NULL) + contents = elf_section_data (symbol_section)->this_hdr.contents; + else + { + free_contents = contents + = (bfd_byte *) bfd_malloc (symbol_section->_raw_size); + if (contents == NULL) + return bfd_reloc_outofrange; + if (! bfd_get_section_contents (input_bfd, symbol_section, contents, + (file_ptr) 0, + symbol_section->_raw_size)) + { + free (contents); + return bfd_reloc_outofrange; + } + } + } +#define IS_PPI(PTR) ((bfd_get_16 (input_bfd, (PTR)) & 0xfc00) == 0xf800) + start_ptr = contents + start; + for (cum_diff = -6, ptr = contents + end; cum_diff < 0 && ptr > start_ptr;) + { + for (last_ptr = ptr, ptr -= 4; ptr >= start_ptr && IS_PPI (ptr);) + ptr -= 2; + ptr += 2; + diff = last_ptr - ptr >> 1; + cum_diff += diff & 1; + cum_diff += diff; + } + /* Calculate the start / end values to load into rs / re minus four - + so that will cancel out the four we would otherwise have to add to + addr to get the value to subtract in order to get relative addressing. */ + if (cum_diff >= 0) + { + start -= 4; + end = (ptr + cum_diff * 2) - contents; + } + else + { + bfd_vma start0 = start - 4; + + while (start0 >= 0 && IS_PPI (contents + start0)) + start0 -= 2; + start0 = start - 2 - ((start - start0) & 2); + start = start0 - cum_diff - 2; + end = start0; + } + + if (free_contents) + free (free_contents); + + insn = bfd_get_16 (input_bfd, contents + addr); + + x = (insn & 0x200 ? end : start) - addr; + if (input_section != symbol_section) + x += ((symbol_section->output_section->vma + symbol_section->output_offset) + - (input_section->output_section->vma + + input_section->output_offset)); + x >>= 1; + if (x < -128 || x > 127) + return bfd_reloc_overflow; + + x = insn & ~0xff | x & 0xff; + bfd_put_16 (input_bfd, x, contents + addr); + + return bfd_reloc_ok; +} + +/* This function is used for normal relocs. This used to be like the COFF function, and is almost certainly incorrect for other ELF targets. */ static bfd_reloc_status_type @@ -453,9 +591,7 @@ sh_elf_reloc (abfd, reloc_entry, symbol_in, data, input_section, output_bfd, /* Almost all relocs have to do with relaxing. If any work must be done for them, it has been done in sh_relax_section. */ - if (r_type != R_SH_DIR32 - && (r_type != R_SH_IND12W - || (symbol_in->flags & BSF_LOCAL) != 0)) + if (r_type == R_SH_IND12W && (symbol_in->flags & BSF_LOCAL) != 0) return bfd_reloc_ok; if (symbol_in != NULL @@ -549,6 +685,8 @@ static const struct elf_reloc_map sh_reloc_map[] = { BFD_RELOC_SH_LABEL, R_SH_LABEL }, { BFD_RELOC_VTABLE_INHERIT, R_SH_GNU_VTINHERIT }, { BFD_RELOC_VTABLE_ENTRY, R_SH_GNU_VTENTRY }, + { BFD_RELOC_SH_LOOP_START, R_SH_LOOP_START }, + { BFD_RELOC_SH_LOOP_END, R_SH_LOOP_END }, }; /* Given a BFD reloc code, return the howto structure for the @@ -1734,11 +1872,13 @@ sh_elf_relocate_section (output_bfd, info, input_bfd, input_section, /* Many of the relocs are only used for relaxing, and are handled entirely by the relaxation code. */ - if (r_type > (int) R_SH_LAST_INVALID_RELOC) + if (r_type > (int) R_SH_LAST_INVALID_RELOC + && r_type < (int) R_SH_LOOP_START) continue; if (r_type < 0 - || r_type >= (int) R_SH_FIRST_INVALID_RELOC) + || (r_type >= (int) R_SH_FIRST_INVALID_RELOC + && r_type <= (int) R_SH_LAST_INVALID_RELOC)) { bfd_set_error (bfd_error_bad_value); return false; @@ -1747,7 +1887,9 @@ sh_elf_relocate_section (output_bfd, info, input_bfd, input_section, /* FIXME: This is certainly incorrect. However, it is how the COFF linker works. */ if (r_type != (int) R_SH_DIR32 - && r_type != (int) R_SH_IND12W) + && r_type != (int) R_SH_IND12W + && r_type != (int) R_SH_LOOP_START + && r_type != (int) R_SH_LOOP_END) continue; howto = sh_elf_howto_table + r_type; @@ -1803,15 +1945,32 @@ sh_elf_relocate_section (output_bfd, info, input_bfd, input_section, { case (int)R_SH_DIR32: addend = rel->r_addend; + /* Fall through. */ + default: + /* COFF relocs don't use the addend. The addend is used for + R_SH_DIR32 to be compatible with other compilers. */ + r = _bfd_final_link_relocate (howto, input_bfd, input_section, + contents, rel->r_offset, + relocation, addend); break; + case R_SH_LOOP_START: + { + static bfd_vma start, end; + + start = (relocation + rel->r_addend + - (sec->output_section->vma + sec->output_offset)); + r = sh_elf_reloc_loop (r_type, input_bfd, input_section, contents, + rel->r_offset, sec, start, end); + break; + case R_SH_LOOP_END: + end = (relocation + rel->r_addend + - (sec->output_section->vma + sec->output_offset)); + r = sh_elf_reloc_loop (r_type, input_bfd, input_section, contents, + rel->r_offset, sec, start, end); + break; + } } - /* COFF relocs don't use the addend. The addend is used for R_SH_DIR32 - to be compatible with other compilers. */ - r = _bfd_final_link_relocate (howto, input_bfd, input_section, - contents, rel->r_offset, - relocation, addend); - if (r != bfd_reloc_ok) { switch (r) diff --git a/bfd/libbfd.h b/bfd/libbfd.h index f9baf5a..774cfc3 100644 --- a/bfd/libbfd.h +++ b/bfd/libbfd.h @@ -809,6 +809,8 @@ static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@", "BFD_RELOC_SH_CODE", "BFD_RELOC_SH_DATA", "BFD_RELOC_SH_LABEL", + "BFD_RELOC_SH_LOOP_START", + "BFD_RELOC_SH_LOOP_END", "BFD_RELOC_THUMB_PCREL_BRANCH9", "BFD_RELOC_THUMB_PCREL_BRANCH12", "BFD_RELOC_THUMB_PCREL_BRANCH23", diff --git a/bfd/reloc.c b/bfd/reloc.c index a3318e6..3b1a00f 100644 --- a/bfd/reloc.c +++ b/bfd/reloc.c @@ -2293,6 +2293,10 @@ ENUMX BFD_RELOC_SH_DATA ENUMX BFD_RELOC_SH_LABEL +ENUMX + BFD_RELOC_SH_LOOP_START +ENUMX + BFD_RELOC_SH_LOOP_END ENUMDOC Hitachi SH relocs. Not all of these appear in object files. |