diff options
Diffstat (limited to 'bfd/elf32-cris.c')
-rw-r--r-- | bfd/elf32-cris.c | 454 |
1 files changed, 394 insertions, 60 deletions
diff --git a/bfd/elf32-cris.c b/bfd/elf32-cris.c index ad93071..d043111 100644 --- a/bfd/elf32-cris.c +++ b/bfd/elf32-cris.c @@ -33,6 +33,9 @@ static reloc_howto_type * cris_reloc_type_lookup static void cris_info_to_howto_rela PARAMS ((bfd *, arelent *, Elf_Internal_Rela *)); +static bfd_reloc_status_type cris_elf_pcrel_reloc + PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **)); + static bfd_boolean cris_elf_grok_prstatus PARAMS ((bfd *abfd, Elf_Internal_Note *note)); @@ -59,9 +62,13 @@ static bfd_boolean cris_elf_object_p PARAMS ((bfd *)); static void cris_elf_final_write_processing PARAMS ((bfd *, bfd_boolean)); +static bfd_boolean cris_elf_set_mach_from_flags + PARAMS ((bfd *, unsigned long int)); + static bfd_boolean cris_elf_print_private_bfd_data PARAMS ((bfd *, PTR)); static bfd_boolean cris_elf_merge_private_bfd_data PARAMS ((bfd *, bfd *)); +static bfd_boolean cris_elf_copy_private_bfd_data PARAMS ((bfd *, bfd *)); struct elf_cris_link_hash_entry; static bfd_boolean elf_cris_discard_excess_dso_dynamics @@ -164,7 +171,7 @@ static reloc_howto_type cris_elf_howto_table [] = TRUE, /* pc_relative */ 0, /* bitpos */ complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ + cris_elf_pcrel_reloc, /* special_function */ "R_CRIS_8_PCREL", /* name */ FALSE, /* partial_inplace */ 0x0000, /* src_mask */ @@ -179,7 +186,7 @@ static reloc_howto_type cris_elf_howto_table [] = TRUE, /* pc_relative */ 0, /* bitpos */ complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ + cris_elf_pcrel_reloc, /* special_function */ "R_CRIS_16_PCREL", /* name */ FALSE, /* partial_inplace */ 0x00000000, /* src_mask */ @@ -194,7 +201,7 @@ static reloc_howto_type cris_elf_howto_table [] = TRUE, /* pc_relative */ 0, /* bitpos */ complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ + cris_elf_pcrel_reloc, /* special_function */ "R_CRIS_32_PCREL", /* name */ FALSE, /* partial_inplace */ 0x00000000, /* src_mask */ @@ -398,7 +405,7 @@ static reloc_howto_type cris_elf_howto_table [] = TRUE, /* pc_relative */ 0, /* bitpos */ complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ + cris_elf_pcrel_reloc, /* special_function */ "R_CRIS_32_PLT_PCREL", /* name */ FALSE, /* partial_inplace */ 0, /* src_mask */ @@ -466,8 +473,39 @@ cris_info_to_howto_rela (abfd, cache_ptr, dst) BFD_ASSERT (r_type < (unsigned int) R_CRIS_max); cache_ptr->howto = & cris_elf_howto_table [r_type]; } + +bfd_reloc_status_type +cris_elf_pcrel_reloc (abfd, reloc_entry, symbol, data, input_section, + output_bfd, error_message) + bfd *abfd ATTRIBUTE_UNUSED; + arelent *reloc_entry; + asymbol *symbol; + PTR data ATTRIBUTE_UNUSED; + asection *input_section; + bfd *output_bfd; + char **error_message ATTRIBUTE_UNUSED; +{ + /* By default (using only bfd_elf_generic_reloc when linking to + non-ELF formats) PC-relative relocs are relative to the beginning + of the reloc. CRIS PC-relative relocs are relative to the position + *after* the reloc because that's what pre-CRISv32 PC points to + after reading an insn field with that reloc. (For CRISv32, PC is + actually relative to the start of the insn, but we keep the old + definition.) Still, we use as much generic machinery as we can. + + Only adjust when doing a final link. */ + if (output_bfd == (bfd *) NULL) + reloc_entry->addend -= 1 << reloc_entry->howto->size; + + return + bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data, + input_section, output_bfd, error_message); +} -/* Support for core dump NOTE sections. */ +/* Support for core dump NOTE sections. + The slightly unintuitive code layout is an attempt to keep at least + some similarities with other ports, hoping to simplify general + changes, while still keeping Linux/CRIS and Linux/CRISv32 code apart. */ static bfd_boolean cris_elf_grok_prstatus (abfd, note) @@ -477,8 +515,28 @@ cris_elf_grok_prstatus (abfd, note) int offset; size_t size; - switch (note->descsz) - { + if (bfd_get_mach (abfd) == bfd_mach_cris_v32) + switch (note->descsz) + { + default: + return FALSE; + + case 202: /* Linux/CRISv32 */ + /* pr_cursig */ + elf_tdata (abfd)->core_signal = bfd_get_16 (abfd, note->descdata + 12); + + /* pr_pid */ + elf_tdata (abfd)->core_pid = bfd_get_32 (abfd, note->descdata + 22); + + /* pr_reg */ + offset = 70; + size = 128; + + break; + } + else + switch (note->descsz) + { default: return FALSE; @@ -494,7 +552,7 @@ cris_elf_grok_prstatus (abfd, note) size = 140; break; - } + } /* Make a ".reg/999" section. */ return _bfd_elfcore_make_pseudosection (abfd, ".reg", @@ -506,17 +564,30 @@ cris_elf_grok_psinfo (abfd, note) bfd *abfd; Elf_Internal_Note *note; { - switch (note->descsz) - { + if (bfd_get_mach (abfd) == bfd_mach_cris_v32) + switch (note->descsz) + { + default: + return FALSE; + + case 124: /* Linux/CRISv32 elf_prpsinfo */ + elf_tdata (abfd)->core_program + = _bfd_elfcore_strndup (abfd, note->descdata + 28, 16); + elf_tdata (abfd)->core_command + = _bfd_elfcore_strndup (abfd, note->descdata + 44, 80); + } + else + switch (note->descsz) + { default: return FALSE; case 124: /* Linux/CRIS elf_prpsinfo */ elf_tdata (abfd)->core_program - = _bfd_elfcore_strndup (abfd, note->descdata + 28, 16); + = _bfd_elfcore_strndup (abfd, note->descdata + 28, 16); elf_tdata (abfd)->core_command - = _bfd_elfcore_strndup (abfd, note->descdata + 44, 80); - } + = _bfd_elfcore_strndup (abfd, note->descdata + 44, 80); + } /* Note that for some reason, a spurious space is tacked onto the end of the args in some (at least one anyway) @@ -541,6 +612,7 @@ cris_elf_grok_psinfo (abfd, note) /* The size in bytes of an entry in the procedure linkage table. */ #define PLT_ENTRY_SIZE 20 +#define PLT_ENTRY_SIZE_V32 26 /* The first entry in an absolute procedure linkage table looks like this. */ @@ -553,7 +625,21 @@ static const bfd_byte elf_cris_plt0_entry[PLT_ENTRY_SIZE] = 0x30, 0x7a, /* move [...],mof */ 0x7f, 0x0d, /* (dip [pc+]) */ 0, 0, 0, 0, /* Replaced with address of .got + 8. */ - 0x30, 0x09, /* jump [...] */ + 0x30, 0x09 /* jump [...] */ +}; + +static const bfd_byte elf_cris_plt0_entry_v32[PLT_ENTRY_SIZE_V32] = +{ + 0x84, 0xe2, /* subq 4,$sp */ + 0x6f, 0xfe, /* move.d 0,$acr */ + 0, 0, 0, 0, /* Replaced by address of .got + 4. */ + 0x7e, 0x7a, /* move $mof,[$sp] */ + 0x3f, 0x7a, /* move [$acr],$mof */ + 0x04, 0xf2, /* addq 4,acr */ + 0x6f, 0xfa, /* move.d [$acr],$acr */ + 0xbf, 0x09, /* jump $acr */ + 0xb0, 0x05, /* nop */ + 0, 0 /* Pad out to 26 bytes. */ }; /* Subsequent entries in an absolute procedure linkage table look like @@ -571,6 +657,20 @@ static const bfd_byte elf_cris_plt_entry[PLT_ENTRY_SIZE] = 0xff, 0xff /* Replaced with offset to start of .plt. */ }; +static const bfd_byte elf_cris_plt_entry_v32[PLT_ENTRY_SIZE_V32] = +{ + 0x6f, 0xfe, /* move.d 0,$acr */ + 0, 0, 0, 0, /* Replaced with address of this symbol in .got. */ + 0x6f, 0xfa, /* move.d [$acr],$acr */ + 0xbf, 0x09, /* jump $acr */ + 0xb0, 0x05, /* nop */ + 0x3f, 0x7e, /* move 0,mof */ + 0, 0, 0, 0, /* Replaced with offset into relocation table. */ + 0xbf, 0x0e, /* ba start_of_plt0_entry */ + 0, 0, 0, 0, /* Replaced with offset to plt0 entry. */ + 0xb0, 0x05 /* nop */ +}; + /* The first entry in a PIC procedure linkage table looks like this. */ static const bfd_byte elf_cris_pic_plt0_entry[PLT_ENTRY_SIZE] = @@ -581,6 +681,21 @@ static const bfd_byte elf_cris_pic_plt0_entry[PLT_ENTRY_SIZE] = 0, 0, 0, 0, 0, 0, 0, 0, /* Pad out to 20 bytes. */ }; +static const bfd_byte elf_cris_pic_plt0_entry_v32[PLT_ENTRY_SIZE_V32] = +{ + 0x84, 0xe2, /* subq 4,$sp */ + 0x04, 0x01, /* addoq 4,$r0,$acr */ + 0x7e, 0x7a, /* move $mof,[$sp] */ + 0x3f, 0x7a, /* move [$acr],$mof */ + 0x04, 0xf2, /* addq 4,$acr */ + 0x6f, 0xfa, /* move.d [$acr],$acr */ + 0xbf, 0x09, /* jump $acr */ + 0xb0, 0x05, /* nop */ + 0, 0, /* Pad out to 26 bytes. */ + 0, 0, 0, 0, + 0, 0, 0, 0 +}; + /* Subsequent entries in a PIC procedure linkage table look like this. */ static const bfd_byte elf_cris_pic_plt_entry[PLT_ENTRY_SIZE] = @@ -594,6 +709,20 @@ static const bfd_byte elf_cris_pic_plt_entry[PLT_ENTRY_SIZE] = 0xec, 0xff, /* Replaced with offset to start of .plt. */ 0xff, 0xff }; + +static const bfd_byte elf_cris_pic_plt_entry_v32[PLT_ENTRY_SIZE_V32] = +{ + 0x6f, 0x0d, /* addo.d 0,$r0,$acr */ + 0, 0, 0, 0, /* Replaced with offset of this symbol in .got. */ + 0x6f, 0xfa, /* move.d [$acr],$acr */ + 0xbf, 0x09, /* jump $acr */ + 0xb0, 0x05, /* nop */ + 0x3f, 0x7e, /* move relocoffs,$mof */ + 0, 0, 0, 0, /* Replaced with offset into relocation table. */ + 0xbf, 0x0e, /* ba start_of_plt */ + 0, 0, 0, 0, /* Replaced with offset to start of .plt. */ + 0xb0, 0x05 /* nop */ +}; /* We copy elf32-m68k.c and elf32-i386.c for the basic linker hash bits (and most other PIC/shlib stuff). Check that we don't drift away @@ -917,7 +1046,7 @@ cris_elf_relocate_section (output_bfd, info, input_bfd, input_section, else if (unresolved_reloc) { _bfd_error_handler - (_("%B(%A): unresolvable relocation %s against symbol `%s'"), + (_("%B, section %A: unresolvable relocation %s against symbol `%s'"), input_bfd, input_section, cris_elf_howto_table[r_type].name, @@ -972,9 +1101,9 @@ cris_elf_relocate_section (output_bfd, info, input_bfd, input_section, { (*_bfd_error_handler) ((h->got.offset == (bfd_vma) -1) - ? _("%B(%A): No PLT nor GOT for relocation %s" + ? _("%B, section %A: No PLT nor GOT for relocation %s" " against symbol `%s'") - : _("%B(%A): No PLT for relocation %s" + : _("%B, section %A: No PLT for relocation %s" " against symbol `%s'"), input_bfd, input_section, @@ -1098,7 +1227,7 @@ cris_elf_relocate_section (output_bfd, info, input_bfd, input_section, allowed to pass us these kinds of things. */ if (h == NULL) (*_bfd_error_handler) - (_("%B(%A): relocation %s with non-zero addend %d" + (_("%B, section %A: relocation %s with non-zero addend %d" " against local symbol"), input_bfd, input_section, @@ -1106,7 +1235,7 @@ cris_elf_relocate_section (output_bfd, info, input_bfd, input_section, rel->r_addend); else (*_bfd_error_handler) - (_("%B(%A): relocation %s with non-zero addend %d" + (_("%B, section %A: relocation %s with non-zero addend %d" " against symbol `%s'"), input_bfd, input_section, @@ -1132,7 +1261,8 @@ cris_elf_relocate_section (output_bfd, info, input_bfd, input_section, && h->root.type == bfd_link_hash_undefweak)))) { (*_bfd_error_handler) - (_("%B(%A): relocation %s is not allowed for global symbol: `%s'"), + (_("%B, section %A: relocation %s is" + " not allowed for global symbol: `%s'"), input_bfd, input_section, cris_elf_howto_table[r_type].name, @@ -1147,7 +1277,7 @@ cris_elf_relocate_section (output_bfd, info, input_bfd, input_section, if (sgot == NULL) { (*_bfd_error_handler) - (_("%B: relocation %s in section %A with no GOT created"), + (_("%B, section %A: relocation %s with no GOT created"), input_bfd, input_section, cris_elf_howto_table[r_type].name); @@ -1407,8 +1537,33 @@ elf_cris_finish_dynamic_symbol (output_bfd, info, h, sym) Elf_Internal_Sym *sym; { bfd *dynobj; + + /* Where in the plt entry to put values. */ int plt_off1 = 2, plt_off2 = 10, plt_off3 = 16; + /* What offset to add to the distance to the first PLT entry for the + value at plt_off3. */ + int plt_off3_value_bias = 4; + + /* Where in the PLT entry the call-dynlink-stub is (happens to be same + for PIC and non-PIC for v32 and pre-v32). */ + int plt_stub_offset = 8; + int plt_entry_size = PLT_ENTRY_SIZE; + const bfd_byte *plt_entry = elf_cris_plt_entry; + const bfd_byte *plt_pic_entry = elf_cris_pic_plt_entry; + + /* Adjust the various PLT entry offsets. */ + if (bfd_get_mach (output_bfd) == bfd_mach_cris_v32) + { + plt_off2 = 14; + plt_off3 = 20; + plt_off3_value_bias = -2; + plt_stub_offset = 12; + plt_entry_size = PLT_ENTRY_SIZE_V32; + plt_entry = elf_cris_plt_entry_v32; + plt_pic_entry = elf_cris_pic_plt_entry_v32; + } + dynobj = elf_hash_table (info)->dynobj; if (h->plt.offset != (bfd_vma) -1) @@ -1460,8 +1615,8 @@ elf_cris_finish_dynamic_symbol (output_bfd, info, h, sym) /* Fill in the entry in the procedure linkage table. */ if (! info->shared) { - memcpy (splt->contents + h->plt.offset, elf_cris_plt_entry, - PLT_ENTRY_SIZE); + memcpy (splt->contents + h->plt.offset, plt_entry, + plt_entry_size); /* We need to enter the absolute address of the GOT entry here. */ bfd_put_32 (output_bfd, got_base + got_offset, @@ -1469,8 +1624,8 @@ elf_cris_finish_dynamic_symbol (output_bfd, info, h, sym) } else { - memcpy (splt->contents + h->plt.offset, elf_cris_pic_plt_entry, - PLT_ENTRY_SIZE); + memcpy (splt->contents + h->plt.offset, plt_pic_entry, + plt_entry_size); bfd_put_32 (output_bfd, got_offset, splt->contents + h->plt.offset + plt_off1); } @@ -1479,13 +1634,14 @@ elf_cris_finish_dynamic_symbol (output_bfd, info, h, sym) PLT entry. */ if (has_gotplt) { - /* Fill in the offset into the reloc table. */ + /* Fill in the offset to the reloc table. */ bfd_put_32 (output_bfd, gotplt_index * sizeof (Elf32_External_Rela), splt->contents + h->plt.offset + plt_off2); /* Fill in the offset to the first PLT entry, where to "jump". */ - bfd_put_32 (output_bfd, - (h->plt.offset + plt_off3 + 4), + bfd_put_32 (output_bfd, + - (h->plt.offset + plt_off3 + plt_off3_value_bias), splt->contents + h->plt.offset + plt_off3); /* Fill in the entry in the global offset table with the address of @@ -1494,7 +1650,7 @@ elf_cris_finish_dynamic_symbol (output_bfd, info, h, sym) (splt->output_section->vma + splt->output_offset + h->plt.offset - + 8), + + plt_stub_offset), sgotplt->contents + got_offset); /* Fill in the entry in the .rela.plt section. */ @@ -1695,20 +1851,45 @@ elf_cris_finish_dynamic_sections (output_bfd, info) /* Fill in the first entry in the procedure linkage table. */ if (splt->size > 0) { - if (info->shared) - memcpy (splt->contents, elf_cris_pic_plt0_entry, PLT_ENTRY_SIZE); + if (bfd_get_mach (output_bfd) == bfd_mach_cris_v32) + { + if (info->shared) + memcpy (splt->contents, elf_cris_pic_plt0_entry_v32, + PLT_ENTRY_SIZE_V32); + else + { + memcpy (splt->contents, elf_cris_plt0_entry_v32, + PLT_ENTRY_SIZE_V32); + bfd_put_32 (output_bfd, + sgot->output_section->vma + + sgot->output_offset + 4, + splt->contents + 4); + + elf_section_data (splt->output_section)->this_hdr.sh_entsize + = PLT_ENTRY_SIZE_V32; + } + } else - { - memcpy (splt->contents, elf_cris_plt0_entry, PLT_ENTRY_SIZE); - bfd_put_32 (output_bfd, - sgot->output_section->vma + sgot->output_offset + 4, - splt->contents + 6); - bfd_put_32 (output_bfd, - sgot->output_section->vma + sgot->output_offset + 8, - splt->contents + 14); - - elf_section_data (splt->output_section)->this_hdr.sh_entsize - = PLT_ENTRY_SIZE; + { + if (info->shared) + memcpy (splt->contents, elf_cris_pic_plt0_entry, + PLT_ENTRY_SIZE); + else + { + memcpy (splt->contents, elf_cris_plt0_entry, + PLT_ENTRY_SIZE); + bfd_put_32 (output_bfd, + sgot->output_section->vma + + sgot->output_offset + 4, + splt->contents + 6); + bfd_put_32 (output_bfd, + sgot->output_section->vma + + sgot->output_offset + 8, + splt->contents + 14); + + elf_section_data (splt->output_section)->this_hdr.sh_entsize + = PLT_ENTRY_SIZE; + } } } } @@ -2018,6 +2199,7 @@ elf_cris_adjust_dynamic_symbol (info, h) bfd *dynobj; asection *s; unsigned int power_of_two; + bfd_size_type plt_entry_size; dynobj = elf_hash_table (info)->dynobj; @@ -2029,6 +2211,10 @@ elf_cris_adjust_dynamic_symbol (info, h) && h->ref_regular && !h->def_regular))); + plt_entry_size + = (bfd_get_mach (dynobj) == bfd_mach_cris_v32 + ? PLT_ENTRY_SIZE_V32 : PLT_ENTRY_SIZE); + /* If this is a function, put it in the procedure linkage table. We will fill in the contents of the procedure linkage table later, when we know the address of the .got section. */ @@ -2089,7 +2275,7 @@ elf_cris_adjust_dynamic_symbol (info, h) /* If this is the first .plt entry, make room for the special first entry. */ if (s->size == 0) - s->size += PLT_ENTRY_SIZE; + s->size += plt_entry_size; /* If this symbol is not defined in a regular file, and we are not generating a shared library, then set the symbol to this @@ -2113,8 +2299,8 @@ elf_cris_adjust_dynamic_symbol (info, h) /* Mark the PLT offset to use the GOT entry by setting the low bit in the plt offset; it is always a multiple of - pointer-size. */ - BFD_ASSERT ((s->size & 3) == 0); + plt_entry_size (which is at least a multiple of 2). */ + BFD_ASSERT ((s->size % plt_entry_size) == 0); /* Change the PLT refcount to an offset. */ h->plt.offset = s->size; @@ -2125,7 +2311,7 @@ elf_cris_adjust_dynamic_symbol (info, h) h)->gotplt_offset == 0); /* Make room for this entry. */ - s->size += PLT_ENTRY_SIZE; + s->size += plt_entry_size; return TRUE; } @@ -2134,7 +2320,7 @@ elf_cris_adjust_dynamic_symbol (info, h) h->plt.offset = s->size; /* Make room for this entry. */ - s->size += PLT_ENTRY_SIZE; + s->size += plt_entry_size; /* We also need to make an entry in the .got.plt section, which will be placed in the .got section by the linker script. */ @@ -2305,6 +2491,18 @@ cris_elf_check_relocs (abfd, info, sec, relocs) { elf_hash_table (info)->dynobj = dynobj = abfd; + /* We could handle this if we can get a handle on the + output bfd in elf_cris_adjust_dynamic_symbol. Failing + that, we must insist on dynobj being a specific mach. */ + if (bfd_get_mach (dynobj) == bfd_mach_cris_v10_v32) + { + (*_bfd_error_handler) + (_("%B, section %A:\n v10/v32 compatible object %s" + " must not contain a PIC relocation"), + abfd, sec); + return FALSE; + } + /* Create the .got section, so we can assume it's always present whenever there's a dynobj. */ if (!_bfd_elf_create_got_section (dynobj, info)) @@ -2486,7 +2684,8 @@ cris_elf_check_relocs (abfd, info, sec, relocs) { /* FIXME: How do we make this optionally a warning only? */ (*_bfd_error_handler) - (_("%B, section %A:\n relocation %s should not be used in a shared object; recompile with -fPIC"), + (_("%B, section %A:\n relocation %s should not" + " be used in a shared object; recompile with -fPIC"), abfd, sec, cris_elf_howto_table[r_type].name); @@ -2548,6 +2747,17 @@ cris_elf_check_relocs (abfd, info, sec, relocs) && h->root.type != bfd_link_hash_defweak && h->def_regular) break; + + if ((sec->flags & SEC_READONLY) != 0) + { + /* FIXME: How do we make this optionally a warning only? */ + (*_bfd_error_handler) + (_("%B, section %A:\n relocation %s should not be used" + " in a shared object; recompile with -fPIC"), + abfd, + sec, + cris_elf_howto_table[r_type].name); + } } /* We create a reloc section in dynobj and make room for this @@ -2932,23 +3142,81 @@ static bfd_boolean cris_elf_object_p (abfd) bfd *abfd; { + if (! cris_elf_set_mach_from_flags (abfd, elf_elfheader (abfd)->e_flags)) + return FALSE; + if ((elf_elfheader (abfd)->e_flags & EF_CRIS_UNDERSCORE)) return (bfd_get_symbol_leading_char (abfd) == '_'); else return (bfd_get_symbol_leading_char (abfd) == 0); } -/* Mark presence or absence of leading underscore. */ +/* Mark presence or absence of leading underscore. Set machine type + flags from mach type. */ static void cris_elf_final_write_processing (abfd, linker) bfd *abfd; bfd_boolean linker ATTRIBUTE_UNUSED; { + unsigned long e_flags = elf_elfheader (abfd)->e_flags; + + e_flags &= ~EF_CRIS_UNDERSCORE; if (bfd_get_symbol_leading_char (abfd) == '_') - elf_elfheader (abfd)->e_flags |= EF_CRIS_UNDERSCORE; - else - elf_elfheader (abfd)->e_flags &= ~EF_CRIS_UNDERSCORE; + e_flags |= EF_CRIS_UNDERSCORE; + + switch (bfd_get_mach (abfd)) + { + case bfd_mach_cris_v0_v10: + e_flags |= EF_CRIS_VARIANT_ANY_V0_V10; + break; + + case bfd_mach_cris_v10_v32: + e_flags |= EF_CRIS_VARIANT_COMMON_V10_V32; + break; + + case bfd_mach_cris_v32: + e_flags |= EF_CRIS_VARIANT_V32; + break; + + default: + _bfd_abort (__FILE__, __LINE__, + _("Unexpected machine number")); + } + + elf_elfheader (abfd)->e_flags = e_flags; +} + +/* Set the mach type from e_flags value. */ + +static bfd_boolean +cris_elf_set_mach_from_flags (abfd, flags) + bfd *abfd; + unsigned long flags; +{ + switch (flags & EF_CRIS_VARIANT_MASK) + { + case EF_CRIS_VARIANT_ANY_V0_V10: + bfd_default_set_arch_mach (abfd, bfd_arch_cris, bfd_mach_cris_v0_v10); + break; + + case EF_CRIS_VARIANT_V32: + bfd_default_set_arch_mach (abfd, bfd_arch_cris, bfd_mach_cris_v32); + break; + + case EF_CRIS_VARIANT_COMMON_V10_V32: + bfd_default_set_arch_mach (abfd, bfd_arch_cris, bfd_mach_cris_v10_v32); + break; + + default: + /* Since we don't recognize them, we obviously can't support them + with this code; we'd have to require that all future handling + would be optional. */ + bfd_set_error (bfd_error_wrong_format); + return FALSE; + } + + return TRUE; } /* Display the flags field. */ @@ -2968,6 +3236,12 @@ cris_elf_print_private_bfd_data (abfd, ptr) if (elf_elfheader (abfd)->e_flags & EF_CRIS_UNDERSCORE) fprintf (file, _(" [symbols have a _ prefix]")); + if ((elf_elfheader (abfd)->e_flags & EF_CRIS_VARIANT_MASK) + == EF_CRIS_VARIANT_COMMON_V10_V32) + fprintf (file, _(" [v10 and v32]")); + if ((elf_elfheader (abfd)->e_flags & EF_CRIS_VARIANT_MASK) + == EF_CRIS_VARIANT_V32) + fprintf (file, _(" [v32]")); fputc ('\n', file); return TRUE; @@ -2980,7 +3254,7 @@ cris_elf_merge_private_bfd_data (ibfd, obfd) bfd *ibfd; bfd *obfd; { - flagword old_flags, new_flags; + int imach, omach; if (! _bfd_generic_verify_endian_match (ibfd, obfd)) return FALSE; @@ -2989,23 +3263,29 @@ cris_elf_merge_private_bfd_data (ibfd, obfd) || bfd_get_flavour (obfd) != bfd_target_elf_flavour) return TRUE; + imach = bfd_get_mach (ibfd); + if (! elf_flags_init (obfd)) { /* This happens when ld starts out with a 'blank' output file. */ elf_flags_init (obfd) = TRUE; - /* Set flags according to current bfd_target. */ - cris_elf_final_write_processing (obfd, FALSE); + /* We ignore the linker-set mach, and instead set it according to + the first input file. This would also happen if we could + somehow filter out the OUTPUT_ARCH () setting from elf.sc. + This allows us to keep the same linker config across + cris(v0..v10) and crisv32. The drawback is that we can't force + the output type, which might be a sane thing to do for a + v10+v32 compatibility object. */ + if (! bfd_set_arch_mach (obfd, bfd_arch_cris, imach)) + return FALSE; } - old_flags = elf_elfheader (obfd)->e_flags; - new_flags = elf_elfheader (ibfd)->e_flags; - - /* Is this good or bad? We'll follow with other excluding flags. */ - if ((old_flags & EF_CRIS_UNDERSCORE) != (new_flags & EF_CRIS_UNDERSCORE)) + if (bfd_get_symbol_leading_char (ibfd) + != bfd_get_symbol_leading_char (obfd)) { (*_bfd_error_handler) - ((new_flags & EF_CRIS_UNDERSCORE) + (bfd_get_symbol_leading_char (ibfd) == '_' ? _("%B: uses _-prefixed symbols, but writing file with non-prefixed symbols") : _("%B: uses non-prefixed symbols, but writing file with _-prefixed symbols"), ibfd); @@ -3013,9 +3293,61 @@ cris_elf_merge_private_bfd_data (ibfd, obfd) return FALSE; } + omach = bfd_get_mach (obfd); + + if (imach != omach) + { + /* We can get an incompatible combination only if either is + bfd_mach_cris_v32, and the other one isn't compatible. */ + if ((imach == bfd_mach_cris_v32 + && omach != bfd_mach_cris_v10_v32) + || (omach == bfd_mach_cris_v32 + && imach != bfd_mach_cris_v10_v32)) + { + (*_bfd_error_handler) + ((imach == bfd_mach_cris_v32) + ? _("%B contains CRIS v32 code, incompatible" + " with previous objects") + : _("%B contains non-CRIS-v32 code, incompatible" + " with previous objects"), + ibfd); + bfd_set_error (bfd_error_bad_value); + return FALSE; + } + + /* We don't have to check the case where the input is compatible + with v10 and v32, because the output is already known to be set + to the other (compatible) mach. */ + if (omach == bfd_mach_cris_v10_v32 + && ! bfd_set_arch_mach (obfd, bfd_arch_cris, imach)) + return FALSE; + } + return TRUE; } +/* Do side-effects of e_flags copying to obfd. */ + +static bfd_boolean +cris_elf_copy_private_bfd_data (ibfd, obfd) + bfd *ibfd; + bfd *obfd; +{ + /* Call the base function. */ + if (!_bfd_elf_copy_private_bfd_data (ibfd, obfd)) + return FALSE; + + /* If output is big-endian for some obscure reason, stop here. */ + if (_bfd_generic_verify_endian_match (ibfd, obfd) == FALSE) + return FALSE; + + if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour + || bfd_get_flavour (obfd) != bfd_target_elf_flavour) + return TRUE; + + /* Do what we really came here for. */ + return bfd_set_arch_mach (obfd, bfd_arch_cris, bfd_get_mach (ibfd)); +} static enum elf_reloc_type_class elf_cris_reloc_type_class (rela) @@ -3061,6 +3393,8 @@ elf_cris_reloc_type_class (rela) cris_elf_print_private_bfd_data #define bfd_elf32_bfd_merge_private_bfd_data \ cris_elf_merge_private_bfd_data +#define bfd_elf32_bfd_copy_private_bfd_data \ + cris_elf_copy_private_bfd_data #define bfd_elf32_bfd_reloc_type_lookup cris_reloc_type_lookup |