From: Tristan Gingold Date: Wed, 18 Nov 2015 14:43:27 +0000 (+0100) Subject: mach-o: use a per-target reloc canonicalize function. X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=bcb51645d3ef1211efbce59f0935f5f0223602a3;p=binutils-gdb.git mach-o: use a per-target reloc canonicalize function. bfd/ * mach-o.h (bfd_mach_o_swap_in_non_scattered_reloc) (bfd_mach_o_canonicalize_non_scattered_reloc) (bfd_mach_o_pre_canonicalize_one_reloc): Declare. (bfd_mach_o_backend_data): Rename field _bfd_mach_o_swap_reloc_in to _bfd_mach_o_canonicalize_one_reloc. * mach-o.c (bfd_mach_o_swap_in_non_scattered_reloc): Now public. (bfd_mach_o_canonicalize_non_scattered_reloc): Renames from bfd_mach_o_canonicalize_one_reloc. (bfd_mach_o_pre_canonicalize_one_reloc): New function. (bfd_mach_o_canonicalize_relocs): Adjust. (bfd_mach_o_canonicalize_relocs): Rename define from bfd_mach_o_swap_reloc_in. * mach-o-target.c (TARGET_NAME_BACKEND): Use bfd_mach_o_canonicalize_one_reloc instead of bfd_mach_o_swap_reloc_in. * mach-o-i386.c (bfd_mach_o_i386_canonicalize_one_reloc): Renames from bfd_mach_o_i386_swap_reloc_in and adjust. (bfd_mach_o_canonicalize_one_reloc): Renames from bfd_mach_o_i386_canonicalize_one_reloc. * mach-o-x86_64.c (bfd_mach_o_x86_64_canonicalize_one_reloc): Renames from bfd_mach_o_x86_64_swap_reloc_in and adjust. (bfd_mach_o_canonicalize_one_reloc): Renames from bfd_mach_o_x86_64_canonicalize_one_reloc. --- diff --git a/bfd/ChangeLog b/bfd/ChangeLog index b70456dceef..b580b89c708 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -5,6 +5,32 @@ backward file movement via "negative" sizes. * coff-alpha.c (alpha_ecoff_openr_next_archived_file): Likewise. +2015-11-18 Tristan Gingold + + * mach-o.h (bfd_mach_o_swap_in_non_scattered_reloc) + (bfd_mach_o_canonicalize_non_scattered_reloc) + (bfd_mach_o_pre_canonicalize_one_reloc): Declare. + (bfd_mach_o_backend_data): Rename field + _bfd_mach_o_swap_reloc_in to _bfd_mach_o_canonicalize_one_reloc. + * mach-o.c (bfd_mach_o_swap_in_non_scattered_reloc): Now public. + (bfd_mach_o_canonicalize_non_scattered_reloc): Renames from + bfd_mach_o_canonicalize_one_reloc. + (bfd_mach_o_pre_canonicalize_one_reloc): New function. + (bfd_mach_o_canonicalize_relocs): Adjust. + (bfd_mach_o_canonicalize_relocs): Rename define from + bfd_mach_o_swap_reloc_in. + * mach-o-target.c (TARGET_NAME_BACKEND): Use + bfd_mach_o_canonicalize_one_reloc instead of + bfd_mach_o_swap_reloc_in. + * mach-o-i386.c (bfd_mach_o_i386_canonicalize_one_reloc): Renames + from bfd_mach_o_i386_swap_reloc_in and adjust. + (bfd_mach_o_canonicalize_one_reloc): Renames from + bfd_mach_o_i386_canonicalize_one_reloc. + * mach-o-x86_64.c (bfd_mach_o_x86_64_canonicalize_one_reloc): Renames + from bfd_mach_o_x86_64_swap_reloc_in and adjust. + (bfd_mach_o_canonicalize_one_reloc): Renames from + bfd_mach_o_x86_64_canonicalize_one_reloc. + 2015-11-18 Tristan Gingold * mach-o.h (struct mach_o_data_struct): Add hdr_offset field. diff --git a/bfd/mach-o-i386.c b/bfd/mach-o-i386.c index b409022d324..41b2976f847 100644 --- a/bfd/mach-o-i386.c +++ b/bfd/mach-o-i386.c @@ -112,20 +112,27 @@ static reloc_howto_type i386_howto_table[]= }; static bfd_boolean -bfd_mach_o_i386_swap_reloc_in (arelent *res, bfd_mach_o_reloc_info *reloc) +bfd_mach_o_i386_canonicalize_one_reloc (bfd *abfd, + struct mach_o_reloc_info_external *raw, + arelent *res, asymbol **syms) { - if (reloc->r_scattered) + bfd_mach_o_reloc_info reloc; + + if (!bfd_mach_o_pre_canonicalize_one_reloc (abfd, raw, &reloc, res, syms)) + return FALSE; + + if (reloc.r_scattered) { - switch (reloc->r_type) + switch (reloc.r_type) { case BFD_MACH_O_GENERIC_RELOC_PAIR: - if (reloc->r_length == 2) + if (reloc.r_length == 2) { res->howto = &i386_howto_table[7]; res->address = res[-1].address; return TRUE; } - else if (reloc->r_length == 1) + else if (reloc.r_length == 1) { res->howto = &i386_howto_table[10]; res->address = res[-1].address; @@ -133,24 +140,24 @@ bfd_mach_o_i386_swap_reloc_in (arelent *res, bfd_mach_o_reloc_info *reloc) } return FALSE; case BFD_MACH_O_GENERIC_RELOC_SECTDIFF: - if (reloc->r_length == 2) + if (reloc.r_length == 2) { res->howto = &i386_howto_table[5]; return TRUE; } - else if (reloc->r_length == 1) + else if (reloc.r_length == 1) { res->howto = &i386_howto_table[8]; return TRUE; } return FALSE; case BFD_MACH_O_GENERIC_RELOC_LOCAL_SECTDIFF: - if (reloc->r_length == 2) + if (reloc.r_length == 2) { res->howto = &i386_howto_table[6]; return TRUE; } - else if (reloc->r_length == 1) + else if (reloc.r_length == 1) { res->howto = &i386_howto_table[9]; return TRUE; @@ -162,10 +169,10 @@ bfd_mach_o_i386_swap_reloc_in (arelent *res, bfd_mach_o_reloc_info *reloc) } else { - switch (reloc->r_type) + switch (reloc.r_type) { case BFD_MACH_O_GENERIC_RELOC_VANILLA: - switch ((reloc->r_length << 1) | reloc->r_pcrel) + switch ((reloc.r_length << 1) | reloc.r_pcrel) { case 0: /* len = 0, pcrel = 0 */ res->howto = &i386_howto_table[2]; @@ -384,7 +391,7 @@ const mach_o_segment_name_xlat mach_o_i386_segsec_names_xlat[] = { NULL, NULL } }; -#define bfd_mach_o_swap_reloc_in bfd_mach_o_i386_swap_reloc_in +#define bfd_mach_o_canonicalize_one_reloc bfd_mach_o_i386_canonicalize_one_reloc #define bfd_mach_o_swap_reloc_out bfd_mach_o_i386_swap_reloc_out #define bfd_mach_o_print_thread bfd_mach_o_i386_print_thread diff --git a/bfd/mach-o-target.c b/bfd/mach-o-target.c index 3915dc07e68..9977db1e2a2 100644 --- a/bfd/mach-o-target.c +++ b/bfd/mach-o-target.c @@ -104,7 +104,7 @@ static const bfd_mach_o_backend_data TARGET_NAME_BACKEND = { TARGET_ARCHITECTURE, TARGET_PAGESIZE, - bfd_mach_o_swap_reloc_in, + bfd_mach_o_canonicalize_one_reloc, bfd_mach_o_swap_reloc_out, bfd_mach_o_print_thread, bfd_mach_o_tgt_seg_table, diff --git a/bfd/mach-o-x86-64.c b/bfd/mach-o-x86-64.c index b0eef2c1dc6..5914ae8b1c2 100644 --- a/bfd/mach-o-x86-64.c +++ b/bfd/mach-o-x86-64.c @@ -120,18 +120,25 @@ static reloc_howto_type x86_64_howto_table[]= }; static bfd_boolean -bfd_mach_o_x86_64_swap_reloc_in (arelent *res, bfd_mach_o_reloc_info *reloc) +bfd_mach_o_x86_64_canonicalize_one_reloc (bfd *abfd, + struct mach_o_reloc_info_external *raw, + arelent *res, asymbol **syms) { + bfd_mach_o_reloc_info reloc; + + if (!bfd_mach_o_pre_canonicalize_one_reloc (abfd, raw, &reloc, res, syms)) + return FALSE; + /* On x86-64, scattered relocs are not used. */ - if (reloc->r_scattered) + if (reloc.r_scattered) return FALSE; - switch (reloc->r_type) + switch (reloc.r_type) { case BFD_MACH_O_X86_64_RELOC_UNSIGNED: - if (reloc->r_pcrel) + if (reloc.r_pcrel) return FALSE; - switch (reloc->r_length) + switch (reloc.r_length) { case 2: res->howto = &x86_64_howto_table[1]; @@ -143,16 +150,16 @@ bfd_mach_o_x86_64_swap_reloc_in (arelent *res, bfd_mach_o_reloc_info *reloc) return FALSE; } case BFD_MACH_O_X86_64_RELOC_SIGNED: - if (reloc->r_length == 2 && reloc->r_pcrel) + if (reloc.r_length == 2 && reloc.r_pcrel) { res->howto = &x86_64_howto_table[2]; return TRUE; } break; case BFD_MACH_O_X86_64_RELOC_BRANCH: - if (!reloc->r_pcrel) + if (!reloc.r_pcrel) return FALSE; - switch (reloc->r_length) + switch (reloc.r_length) { case 2: res->howto = &x86_64_howto_table[6]; @@ -162,23 +169,23 @@ bfd_mach_o_x86_64_swap_reloc_in (arelent *res, bfd_mach_o_reloc_info *reloc) } break; case BFD_MACH_O_X86_64_RELOC_GOT_LOAD: - if (reloc->r_length == 2 && reloc->r_pcrel && reloc->r_extern) + if (reloc.r_length == 2 && reloc.r_pcrel && reloc.r_extern) { res->howto = &x86_64_howto_table[7]; return TRUE; } break; case BFD_MACH_O_X86_64_RELOC_GOT: - if (reloc->r_length == 2 && reloc->r_pcrel && reloc->r_extern) + if (reloc.r_length == 2 && reloc.r_pcrel && reloc.r_extern) { res->howto = &x86_64_howto_table[10]; return TRUE; } break; case BFD_MACH_O_X86_64_RELOC_SUBTRACTOR: - if (reloc->r_pcrel) + if (reloc.r_pcrel) return FALSE; - switch (reloc->r_length) + switch (reloc.r_length) { case 2: res->howto = &x86_64_howto_table[8]; @@ -191,21 +198,21 @@ bfd_mach_o_x86_64_swap_reloc_in (arelent *res, bfd_mach_o_reloc_info *reloc) } break; case BFD_MACH_O_X86_64_RELOC_SIGNED_1: - if (reloc->r_length == 2 && reloc->r_pcrel) + if (reloc.r_length == 2 && reloc.r_pcrel) { res->howto = &x86_64_howto_table[3]; return TRUE; } break; case BFD_MACH_O_X86_64_RELOC_SIGNED_2: - if (reloc->r_length == 2 && reloc->r_pcrel) + if (reloc.r_length == 2 && reloc.r_pcrel) { res->howto = &x86_64_howto_table[4]; return TRUE; } break; case BFD_MACH_O_X86_64_RELOC_SIGNED_4: - if (reloc->r_length == 2 && reloc->r_pcrel) + if (reloc.r_length == 2 && reloc.r_pcrel) { res->howto = &x86_64_howto_table[5]; return TRUE; @@ -344,7 +351,7 @@ const mach_o_segment_name_xlat mach_o_x86_64_segsec_names_xlat[] = { NULL, NULL } }; -#define bfd_mach_o_swap_reloc_in bfd_mach_o_x86_64_swap_reloc_in +#define bfd_mach_o_canonicalize_one_reloc bfd_mach_o_x86_64_canonicalize_one_reloc #define bfd_mach_o_swap_reloc_out bfd_mach_o_x86_64_swap_reloc_out #define bfd_mach_o_bfd_reloc_type_lookup bfd_mach_o_x86_64_bfd_reloc_type_lookup diff --git a/bfd/mach-o.c b/bfd/mach-o.c index b1bac05009e..bbd8d1e8628 100644 --- a/bfd/mach-o.c +++ b/bfd/mach-o.c @@ -1299,7 +1299,7 @@ bfd_mach_o_get_reloc_upper_bound (bfd *abfd ATTRIBUTE_UNUSED, /* In addition to the need to byte-swap the symbol number, the bit positions of the fields in the relocation information vary per target endian-ness. */ -static void +void bfd_mach_o_swap_in_non_scattered_reloc (bfd *abfd, bfd_mach_o_reloc_info *rel, unsigned char *fields) { @@ -1325,17 +1325,87 @@ bfd_mach_o_swap_in_non_scattered_reloc (bfd *abfd, bfd_mach_o_reloc_info *rel, } } -static int -bfd_mach_o_canonicalize_one_reloc (bfd *abfd, - struct mach_o_reloc_info_external *raw, - arelent *res, asymbol **syms) +/* Set syms_ptr_ptr and addend of RES. */ + +bfd_boolean +bfd_mach_o_canonicalize_non_scattered_reloc (bfd *abfd, + bfd_mach_o_reloc_info *reloc, + arelent *res, asymbol **syms) { bfd_mach_o_data_struct *mdata = bfd_mach_o_get_data (abfd); - bfd_mach_o_backend_data *bed = bfd_mach_o_get_backend_data (abfd); - bfd_mach_o_reloc_info reloc; - bfd_vma addr; + unsigned int num; asymbol **sym; + /* Non-scattered relocation. */ + reloc->r_scattered = 0; + res->addend = 0; + + num = reloc->r_value; + + if (reloc->r_extern) + { + /* PR 17512: file: 8396-1185-0.004. */ + if (num >= (unsigned) bfd_mach_o_count_symbols (abfd)) + sym = bfd_und_section_ptr->symbol_ptr_ptr; + else if (syms == NULL) + sym = bfd_und_section_ptr->symbol_ptr_ptr; + else + /* An external symbol number. */ + sym = syms + num; + } + else if (num == 0x00ffffff || num == 0) + { + /* The 'symnum' in a non-scattered PAIR is 0x00ffffff. But as this + is generic code, we don't know wether this is really a PAIR. + This value is almost certainly not a valid section number, hence + this specific case to avoid an assertion failure. + Target specific swap_reloc_in routine should adjust that. */ + sym = bfd_abs_section_ptr->symbol_ptr_ptr; + } + else + { + /* PR 17512: file: 006-2964-0.004. */ + if (num > mdata->nsects) + return FALSE; + + /* A section number. */ + sym = mdata->sections[num - 1]->bfdsection->symbol_ptr_ptr; + /* For a symbol defined in section S, the addend (stored in the + binary) contains the address of the section. To comply with + bfd convention, subtract the section address. + Use the address from the header, so that the user can modify + the vma of the section. */ + res->addend = -mdata->sections[num - 1]->addr; + } + + /* Note: Pairs for PPC LO/HI/HA are not scattered, but contain the offset + in the lower 16bits of the address value. So we have to find the + 'symbol' from the preceding reloc. We do this even though the + section symbol is probably not needed here, because NULL symbol + values cause an assert in generic BFD code. This must be done in + the PPC swap_reloc_in routine. */ + res->sym_ptr_ptr = sym; + + return TRUE; +} + +/* Do most of the work for canonicalize_relocs on RAW: create internal + representation RELOC and set most fields of RES using symbol table SYMS. + Each target still has to set the howto of RES and possibly adjust other + fields. + Previously the Mach-O hook point was simply swap_in, but some targets + (like arm64) don't follow the generic rules (symnum is a value for the + non-scattered relocation ADDEND). */ + +bfd_boolean +bfd_mach_o_pre_canonicalize_one_reloc (bfd *abfd, + struct mach_o_reloc_info_external *raw, + bfd_mach_o_reloc_info *reloc, + arelent *res, asymbol **syms) +{ + bfd_mach_o_data_struct *mdata = bfd_mach_o_get_data (abfd); + bfd_vma addr; + addr = bfd_get_32 (abfd, raw->r_address); res->sym_ptr_ptr = NULL; res->addend = 0; @@ -1346,11 +1416,11 @@ bfd_mach_o_canonicalize_one_reloc (bfd *abfd, bfd_vma symnum = bfd_get_32 (abfd, raw->r_symbolnum); /* Scattered relocation, can't be extern. */ - reloc.r_scattered = 1; - reloc.r_extern = 0; + reloc->r_scattered = 1; + reloc->r_extern = 0; /* Extract section and offset from r_value (symnum). */ - reloc.r_value = symnum; + reloc->r_value = symnum; /* FIXME: This breaks when a symbol in a reloc exactly follows the end of the data for the section (e.g. in a calculation of section data length). At present, the symbol will end up associated with @@ -1368,81 +1438,33 @@ bfd_mach_o_canonicalize_one_reloc (bfd *abfd, } /* Extract the info and address fields from r_address. */ - reloc.r_type = BFD_MACH_O_GET_SR_TYPE (addr); - reloc.r_length = BFD_MACH_O_GET_SR_LENGTH (addr); - reloc.r_pcrel = addr & BFD_MACH_O_SR_PCREL; - reloc.r_address = BFD_MACH_O_GET_SR_TYPE (addr); + reloc->r_type = BFD_MACH_O_GET_SR_TYPE (addr); + reloc->r_length = BFD_MACH_O_GET_SR_LENGTH (addr); + reloc->r_pcrel = addr & BFD_MACH_O_SR_PCREL; + reloc->r_address = BFD_MACH_O_GET_SR_TYPE (addr); res->address = BFD_MACH_O_GET_SR_ADDRESS (addr); } else { - unsigned int num; - /* Non-scattered relocation. */ - reloc.r_scattered = 0; + reloc->r_scattered = 0; + reloc->r_address = addr; + res->address = addr; /* The value and info fields have to be extracted dependent on target endian-ness. */ - bfd_mach_o_swap_in_non_scattered_reloc (abfd, &reloc, raw->r_symbolnum); - num = reloc.r_value; + bfd_mach_o_swap_in_non_scattered_reloc (abfd, reloc, raw->r_symbolnum); - if (reloc.r_extern) - { - /* PR 17512: file: 8396-1185-0.004. */ - if (num >= (unsigned) bfd_mach_o_count_symbols (abfd)) - sym = bfd_und_section_ptr->symbol_ptr_ptr; - else if (syms == NULL) - sym = bfd_und_section_ptr->symbol_ptr_ptr; - else - /* An external symbol number. */ - sym = syms + num; - } - else if (num == 0x00ffffff || num == 0) - { - /* The 'symnum' in a non-scattered PAIR is 0x00ffffff. But as this - is generic code, we don't know wether this is really a PAIR. - This value is almost certainly not a valid section number, hence - this specific case to avoid an assertion failure. - Target specific swap_reloc_in routine should adjust that. */ - sym = bfd_abs_section_ptr->symbol_ptr_ptr; - } - else - { - /* PR 17512: file: 006-2964-0.004. */ - if (num > mdata->nsects) - return -1; - - /* A section number. */ - sym = mdata->sections[num - 1]->bfdsection->symbol_ptr_ptr; - /* For a symbol defined in section S, the addend (stored in the - binary) contains the address of the section. To comply with - bfd convention, subtract the section address. - Use the address from the header, so that the user can modify - the vma of the section. */ - res->addend = -mdata->sections[num - 1]->addr; - } - /* Note: Pairs for PPC LO/HI/HA are not scattered, but contain the offset - in the lower 16bits of the address value. So we have to find the - 'symbol' from the preceding reloc. We do this even though the - section symbol is probably not needed here, because NULL symbol - values cause an assert in generic BFD code. This must be done in - the PPC swap_reloc_in routine. */ - res->sym_ptr_ptr = sym; - - /* The 'address' is just r_address. - ??? maybe this should be masked with 0xffffff for safety. */ - res->address = addr; - reloc.r_address = addr; + if (!bfd_mach_o_canonicalize_non_scattered_reloc (abfd, reloc, + res, syms)) + return FALSE; } /* We have set up a reloc with all the information present, so the swapper can modify address, value and addend fields, if necessary, to convey information in the generic BFD reloc that is mach-o specific. */ - if (!(*bed->_bfd_mach_o_swap_reloc_in)(res, &reloc)) - return -1; - - return 0; + return TRUE; } static int @@ -1450,6 +1472,7 @@ bfd_mach_o_canonicalize_relocs (bfd *abfd, unsigned long filepos, unsigned long count, arelent *res, asymbol **syms) { + bfd_mach_o_backend_data *bed = bfd_mach_o_get_backend_data (abfd); unsigned long i; struct mach_o_reloc_info_external *native_relocs; bfd_size_type native_size; @@ -1472,8 +1495,8 @@ bfd_mach_o_canonicalize_relocs (bfd *abfd, unsigned long filepos, for (i = 0; i < count; i++) { - if (bfd_mach_o_canonicalize_one_reloc (abfd, &native_relocs[i], - &res[i], syms) < 0) + if (!(*bed->_bfd_mach_o_canonicalize_one_reloc)(abfd, &native_relocs[i], + &res[i], syms)) goto err; } free (native_relocs); @@ -1495,7 +1518,7 @@ bfd_mach_o_canonicalize_reloc (bfd *abfd, asection *asect, return 0; /* No need to go further if we don't know how to read relocs. */ - if (bed->_bfd_mach_o_swap_reloc_in == NULL) + if (bed->_bfd_mach_o_canonicalize_one_reloc == NULL) return 0; if (asect->relocation == NULL) @@ -1550,7 +1573,7 @@ bfd_mach_o_canonicalize_dynamic_reloc (bfd *abfd, arelent **rels, return 0; /* No need to go further if we don't know how to read relocs. */ - if (bed->_bfd_mach_o_swap_reloc_in == NULL) + if (bed->_bfd_mach_o_canonicalize_one_reloc == NULL) return 0; if (mdata->dyn_reloc_cache == NULL) @@ -5807,7 +5830,7 @@ bfd_boolean bfd_mach_o_free_cached_info (bfd *abfd) #define bfd_mach_o_bfd_reloc_type_lookup _bfd_norelocs_bfd_reloc_type_lookup #define bfd_mach_o_bfd_reloc_name_lookup _bfd_norelocs_bfd_reloc_name_lookup -#define bfd_mach_o_swap_reloc_in NULL +#define bfd_mach_o_canonicalize_one_reloc NULL #define bfd_mach_o_swap_reloc_out NULL #define bfd_mach_o_print_thread NULL #define bfd_mach_o_tgt_seg_table NULL diff --git a/bfd/mach-o.h b/bfd/mach-o.h index 1b62c0f0bc9..5ea6d4a26c1 100644 --- a/bfd/mach-o.h +++ b/bfd/mach-o.h @@ -704,6 +704,11 @@ bfd_boolean bfd_mach_o_read_symtab_strtab (bfd *abfd); bfd_vma bfd_mach_o_get_base_address (bfd *); +void bfd_mach_o_swap_in_non_scattered_reloc (bfd *, bfd_mach_o_reloc_info *, + unsigned char *); +bfd_boolean bfd_mach_o_canonicalize_non_scattered_reloc (bfd *, bfd_mach_o_reloc_info *, arelent *, asymbol **); +bfd_boolean bfd_mach_o_pre_canonicalize_one_reloc (bfd *, struct mach_o_reloc_info_external *, bfd_mach_o_reloc_info *, arelent *, asymbol **); + /* A placeholder in case we need to suppress emitting the dysymtab for some reason (e.g. compatibility with older system versions). */ #define bfd_mach_o_should_emit_dysymtab(x) TRUE @@ -740,7 +745,8 @@ typedef struct bfd_mach_o_backend_data { enum bfd_architecture arch; bfd_vma page_size; - bfd_boolean (*_bfd_mach_o_swap_reloc_in)(arelent *, bfd_mach_o_reloc_info *); + bfd_boolean (*_bfd_mach_o_canonicalize_one_reloc) + (bfd *, struct mach_o_reloc_info_external *, arelent *, asymbol **); bfd_boolean (*_bfd_mach_o_swap_reloc_out)(arelent *, bfd_mach_o_reloc_info *); bfd_boolean (*_bfd_mach_o_print_thread)(bfd *, bfd_mach_o_thread_flavour *, void *, char *);