From 99f2c3cfe1305286b23010becfae98b83aeb90b7 Mon Sep 17 00:00:00 2001 From: Richard Sandiford Date: Mon, 31 Jan 2005 20:39:11 +0000 Subject: [PATCH] * elf-bfd.h (elf_backend_data): Add elf_backend_eh_frame_address_size. (_bfd_elf_eh_frame_address_size): Declare. * elfxx-target.h (elf_backend_eh_frame_address_size): Define a default. (elfNN_bed): Initialize elf_backend_eh_frame_address_size. * elfxx-mips.h (_bfd_mips_elf_eh_frame_address_size): Declare. (elf_backend_eh_frame_address_size): Define. * elfxx-mips.c (_bfd_mips_elf_eh_frame_address_size): New function. * elf-eh-frame.c (_bfd_elf_discard_section_eh_frame): Get the address size from the new backend hook. (_bfd_elf_write_section_eh_frame): Likewise. (_bfd_elf_eh_frame_address_size): New function. --- bfd/ChangeLog | 14 ++++++++++++ bfd/elf-bfd.h | 8 +++++++ bfd/elf-eh-frame.c | 22 +++++++++++++----- bfd/elfxx-mips.c | 66 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ bfd/elfxx-mips.h | 3 +++ bfd/elfxx-target.h | 4 ++++ 6 files changed, 112 insertions(+), 5 deletions(-) diff --git a/bfd/ChangeLog b/bfd/ChangeLog index b0f0666a6e..c76d939b4e 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,17 @@ +2005-01-31 Richard Sandiford + + * elf-bfd.h (elf_backend_data): Add elf_backend_eh_frame_address_size. + (_bfd_elf_eh_frame_address_size): Declare. + * elfxx-target.h (elf_backend_eh_frame_address_size): Define a default. + (elfNN_bed): Initialize elf_backend_eh_frame_address_size. + * elfxx-mips.h (_bfd_mips_elf_eh_frame_address_size): Declare. + (elf_backend_eh_frame_address_size): Define. + * elfxx-mips.c (_bfd_mips_elf_eh_frame_address_size): New function. + * elf-eh-frame.c (_bfd_elf_discard_section_eh_frame): Get the address + size from the new backend hook. + (_bfd_elf_write_section_eh_frame): Likewise. + (_bfd_elf_eh_frame_address_size): New function. + 2005-01-31 Andrew Cagney * configure: Regenerate to track ../gettext.m4. diff --git a/bfd/elf-bfd.h b/bfd/elf-bfd.h index 6645c9a90c..f2a063bfa0 100644 --- a/bfd/elf-bfd.h +++ b/bfd/elf-bfd.h @@ -906,6 +906,12 @@ struct elf_backend_data bfd_boolean (*elf_backend_ignore_discarded_relocs) (asection *); + /* This function returns the width of FDE pointers in bytes, or 0 if + that can't be determined for some reason. The default definition + goes by the bfd's EI_CLASS. */ + unsigned int (*elf_backend_eh_frame_address_size) + (bfd *, asection *); + /* These functions tell elf-eh-frame whether to attempt to turn absolute or lsda encodings into pc-relative ones. The default definition enables these transformations. */ @@ -1381,6 +1387,8 @@ extern void _bfd_elf_sprintf_vma extern void _bfd_elf_fprintf_vma (bfd *, void *, bfd_vma); +extern unsigned int _bfd_elf_eh_frame_address_size + (bfd *, asection *); extern bfd_byte _bfd_elf_encode_eh_address (bfd *abfd, struct bfd_link_info *info, asection *osec, bfd_vma offset, asection *loc_sec, bfd_vma loc_offset, bfd_vma *encoded); diff --git a/bfd/elf-eh-frame.c b/bfd/elf-eh-frame.c index ab316adeab..389f6f3093 100644 --- a/bfd/elf-eh-frame.c +++ b/bfd/elf-eh-frame.c @@ -418,8 +418,10 @@ _bfd_elf_discard_section_eh_frame it (it would need to use 64-bit .eh_frame format anyway). */ REQUIRE (sec->size == (unsigned int) sec->size); - ptr_size = (elf_elfheader (abfd)->e_ident[EI_CLASS] - == ELFCLASS64) ? 8 : 4; + ptr_size = (get_elf_backend_data (abfd) + ->elf_backend_eh_frame_address_size (abfd, sec)); + REQUIRE (ptr_size != 0); + buf = ehbuf; last_cie = NULL; last_cie_inf = NULL; @@ -987,12 +989,14 @@ _bfd_elf_write_section_eh_frame (bfd *abfd, unsigned int ptr_size; struct eh_cie_fde *ent; - ptr_size = (elf_elfheader (sec->owner)->e_ident[EI_CLASS] - == ELFCLASS64) ? 8 : 4; - if (sec->sec_info_type != ELF_INFO_TYPE_EH_FRAME) return bfd_set_section_contents (abfd, sec->output_section, contents, sec->output_offset, sec->size); + + ptr_size = (get_elf_backend_data (abfd) + ->elf_backend_eh_frame_address_size (abfd, sec)); + BFD_ASSERT (ptr_size != 0); + sec_info = elf_section_data (sec)->sec_info; htab = elf_hash_table (info); hdr_info = &htab->eh_info; @@ -1407,6 +1411,14 @@ _bfd_elf_write_section_eh_frame_hdr (bfd *abfd, struct bfd_link_info *info) return retval; } +/* Return the width of FDE addresses. This is the default implementation. */ + +unsigned int +_bfd_elf_eh_frame_address_size (bfd *abfd, asection *sec ATTRIBUTE_UNUSED) +{ + return elf_elfheader (abfd)->e_ident[EI_CLASS] == ELFCLASS64 ? 8 : 4; +} + /* Decide whether we can use a PC-relative encoding within the given EH frame section. This is the default implementation. */ diff --git a/bfd/elfxx-mips.c b/bfd/elfxx-mips.c index 9ec9c86dcb..595c9dfafd 100644 --- a/bfd/elfxx-mips.c +++ b/bfd/elfxx-mips.c @@ -4248,6 +4248,72 @@ _bfd_mips_elf_symbol_processing (bfd *abfd, asymbol *asym) } } +/* Implement elf_backend_eh_frame_address_size. This differs from + the default in the way it handles EABI64. + + EABI64 was originally specified as an LP64 ABI, and that is what + -mabi=eabi normally gives on a 64-bit target. However, gcc has + historically accepted the combination of -mabi=eabi and -mlong32, + and this ILP32 variation has become semi-official over time. + Both forms use elf32 and have pointer-sized FDE addresses. + + If an EABI object was generated by GCC 4.0 or above, it will have + an empty .gcc_compiled_longXX section, where XX is the size of longs + in bits. Unfortunately, ILP32 objects generated by earlier compilers + have no special marking to distinguish them from LP64 objects. + + We don't want users of the official LP64 ABI to be punished for the + existence of the ILP32 variant, but at the same time, we don't want + to mistakenly interpret pre-4.0 ILP32 objects as being LP64 objects. + We therefore take the following approach: + + - If ABFD contains a .gcc_compiled_longXX section, use it to + determine the pointer size. + + - Otherwise check the type of the first relocation. Assume that + the LP64 ABI is being used if the relocation is of type R_MIPS_64. + + - Otherwise punt. + + The second check is enough to detect LP64 objects generated by pre-4.0 + compilers because, in the kind of output generated by those compilers, + the first relocation will be associated with either a CIE personality + routine or an FDE start address. Furthermore, the compilers never + used a special (non-pointer) encoding for this ABI. + + Checking the relocation type should also be safe because there is no + reason to use R_MIPS_64 in an ILP32 object. Pre-4.0 compilers never + did so. */ + +unsigned int +_bfd_mips_elf_eh_frame_address_size (bfd *abfd, asection *sec) +{ + if (elf_elfheader (abfd)->e_ident[EI_CLASS] == ELFCLASS64) + return 8; + if ((elf_elfheader (abfd)->e_flags & EF_MIPS_ABI) == E_MIPS_ABI_EABI64) + { + bfd_boolean long32_p, long64_p; + + long32_p = bfd_get_section_by_name (abfd, ".gcc_compiled_long32") != 0; + long64_p = bfd_get_section_by_name (abfd, ".gcc_compiled_long64") != 0; + if (long32_p && long64_p) + return 0; + if (long32_p) + return 4; + if (long64_p) + return 8; + + if (sec->reloc_count > 0 + && elf_section_data (sec)->relocs != NULL + && (ELF32_R_TYPE (elf_section_data (sec)->relocs[0].r_info) + == R_MIPS_64)) + return 8; + + return 0; + } + return 4; +} + /* There appears to be a bug in the MIPSpro linker that causes GOT_DISP relocations against two unnamed section symbols to resolve to the same address. For example, if we have code like: diff --git a/bfd/elfxx-mips.h b/bfd/elfxx-mips.h index 0a684d9086..de48c63be8 100644 --- a/bfd/elfxx-mips.h +++ b/bfd/elfxx-mips.h @@ -24,6 +24,8 @@ extern bfd_boolean _bfd_mips_elf_new_section_hook (bfd *, asection *); extern void _bfd_mips_elf_symbol_processing (bfd *, asymbol *); +extern unsigned int _bfd_mips_elf_eh_frame_address_size + (bfd *, asection *); extern bfd_boolean _bfd_mips_elf_name_local_section_symbols (bfd *); extern bfd_boolean _bfd_mips_elf_section_processing @@ -124,3 +126,4 @@ extern struct bfd_elf_special_section const _bfd_mips_elf_special_sections[]; #define elf_backend_name_local_section_symbols \ _bfd_mips_elf_name_local_section_symbols #define elf_backend_special_sections _bfd_mips_elf_special_sections +#define elf_backend_eh_frame_address_size _bfd_mips_elf_eh_frame_address_size diff --git a/bfd/elfxx-target.h b/bfd/elfxx-target.h index a9d49c3b65..baad96d4ba 100644 --- a/bfd/elfxx-target.h +++ b/bfd/elfxx-target.h @@ -442,6 +442,9 @@ #ifndef elf_backend_ignore_discarded_relocs #define elf_backend_ignore_discarded_relocs NULL #endif +#ifndef elf_backend_eh_frame_address_size +#define elf_backend_eh_frame_address_size _bfd_elf_eh_frame_address_size +#endif #ifndef elf_backend_can_make_relative_eh_frame #define elf_backend_can_make_relative_eh_frame _bfd_elf_can_make_relative #endif @@ -573,6 +576,7 @@ static const struct elf_backend_data elfNN_bed = elf_backend_reloc_type_class, elf_backend_discard_info, elf_backend_ignore_discarded_relocs, + elf_backend_eh_frame_address_size, elf_backend_can_make_relative_eh_frame, elf_backend_can_make_lsda_relative_eh_frame, elf_backend_encode_eh_address, -- 2.11.0