X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=bfd%2Felf32-arm.c;h=b8abd5844c92cc7fa5a41f6ac4b0b2ee14e3ed70;hb=83b94be54133a44825c4c33975d8fb72e286ed16;hp=4b4ff412eded6bf47282b7e191035747b05344fb;hpb=ab96bf03fd98b6f68cd213ac81f52be3aca9c435;p=deliverable%2Fbinutils-gdb.git diff --git a/bfd/elf32-arm.c b/bfd/elf32-arm.c index 4b4ff412ed..b8abd5844c 100644 --- a/bfd/elf32-arm.c +++ b/bfd/elf32-arm.c @@ -1,12 +1,12 @@ /* 32-bit ELF support for ARM - Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007 - Free Software Foundation, Inc. + Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, + 2008 Free Software Foundation, Inc. This file is part of BFD, the Binary File Descriptor library. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or + the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, @@ -16,10 +16,11 @@ You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, + MA 02110-1301, USA. */ -#include "bfd.h" #include "sysdep.h" +#include "bfd.h" #include "libiberty.h" #include "libbfd.h" #include "elf-bfd.h" @@ -695,8 +696,8 @@ static reloc_howto_type elf32_arm_howto_table_1[] = bfd_elf_generic_reloc, /* special_function */ "R_ARM_MOVW_ABS_NC", /* name */ FALSE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ + 0x000f0fff, /* src_mask */ + 0x000f0fff, /* dst_mask */ FALSE), /* pcrel_offset */ HOWTO (R_ARM_MOVT_ABS, /* type */ @@ -709,8 +710,8 @@ static reloc_howto_type elf32_arm_howto_table_1[] = bfd_elf_generic_reloc, /* special_function */ "R_ARM_MOVT_ABS", /* name */ FALSE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ + 0x000f0fff, /* src_mask */ + 0x000f0fff, /* dst_mask */ FALSE), /* pcrel_offset */ HOWTO (R_ARM_MOVW_PREL_NC, /* type */ @@ -723,8 +724,8 @@ static reloc_howto_type elf32_arm_howto_table_1[] = bfd_elf_generic_reloc, /* special_function */ "R_ARM_MOVW_PREL_NC", /* name */ FALSE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ + 0x000f0fff, /* src_mask */ + 0x000f0fff, /* dst_mask */ TRUE), /* pcrel_offset */ HOWTO (R_ARM_MOVT_PREL, /* type */ @@ -737,8 +738,8 @@ static reloc_howto_type elf32_arm_howto_table_1[] = bfd_elf_generic_reloc, /* special_function */ "R_ARM_MOVT_PREL", /* name */ FALSE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ + 0x000f0fff, /* src_mask */ + 0x000f0fff, /* dst_mask */ TRUE), /* pcrel_offset */ HOWTO (R_ARM_THM_MOVW_ABS_NC, /* type */ @@ -1772,7 +1773,8 @@ static const struct elf32_arm_reloc_map elf32_arm_reloc_map[] = {BFD_RELOC_ARM_LDRS_SB_G2, R_ARM_LDRS_SB_G2}, {BFD_RELOC_ARM_LDC_SB_G0, R_ARM_LDC_SB_G0}, {BFD_RELOC_ARM_LDC_SB_G1, R_ARM_LDC_SB_G1}, - {BFD_RELOC_ARM_LDC_SB_G2, R_ARM_LDC_SB_G2} + {BFD_RELOC_ARM_LDC_SB_G2, R_ARM_LDC_SB_G2}, + {BFD_RELOC_ARM_V4BX, R_ARM_V4BX} }; static reloc_howto_type * @@ -1787,6 +1789,31 @@ elf32_arm_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, return NULL; } +static reloc_howto_type * +elf32_arm_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, + const char *r_name) +{ + unsigned int i; + + for (i = 0; + i < (sizeof (elf32_arm_howto_table_1) + / sizeof (elf32_arm_howto_table_1[0])); + i++) + if (elf32_arm_howto_table_1[i].name != NULL + && strcasecmp (elf32_arm_howto_table_1[i].name, r_name) == 0) + return &elf32_arm_howto_table_1[i]; + + for (i = 0; + i < (sizeof (elf32_arm_howto_table_2) + / sizeof (elf32_arm_howto_table_2[0])); + i++) + if (elf32_arm_howto_table_2[i].name != NULL + && strcasecmp (elf32_arm_howto_table_2[i].name, r_name) == 0) + return &elf32_arm_howto_table_2[i]; + + return NULL; +} + /* Support for core dump NOTE sections */ static bfd_boolean elf32_arm_nabi_grok_prstatus (bfd *abfd, Elf_Internal_Note *note) @@ -1878,6 +1905,9 @@ typedef unsigned short int insn16; #define VFP11_ERRATUM_VENEER_SECTION_NAME ".vfp11_veneer" #define VFP11_ERRATUM_VENEER_ENTRY_NAME "__vfp11_veneer_%x" +#define ARM_BX_GLUE_SECTION_NAME ".v4_bx" +#define ARM_BX_GLUE_ENTRY_NAME "__bx_r%d" + /* The name of the dynamic interpreter. This is put in the .interp section. */ #define ELF_DYNAMIC_INTERPRETER "/usr/lib/ld.so.1" @@ -2039,50 +2069,33 @@ _arm_elf_section_data; /* The size of the thread control block. */ #define TCB_SIZE 8 -#define NUM_KNOWN_ATTRIBUTES 32 - -typedef struct aeabi_attribute -{ - int type; - unsigned int i; - char *s; -} aeabi_attribute; - -typedef struct aeabi_attribute_list -{ - struct aeabi_attribute_list *next; - int tag; - aeabi_attribute attr; -} aeabi_attribute_list; - -struct elf32_arm_obj_tdata +struct elf_arm_obj_tdata { struct elf_obj_tdata root; /* tls_type for each local got entry. */ char *local_got_tls_type; - aeabi_attribute known_eabi_attributes[NUM_KNOWN_ATTRIBUTES]; - aeabi_attribute_list *other_eabi_attributes; + /* Zero to warn when linking objects with incompatible enum sizes. */ + int no_enum_size_warning; }; -#define elf32_arm_tdata(abfd) \ - ((struct elf32_arm_obj_tdata *) (abfd)->tdata.any) +#define elf_arm_tdata(bfd) \ + ((struct elf_arm_obj_tdata *) (bfd)->tdata.any) + +#define elf32_arm_local_got_tls_type(bfd) \ + (elf_arm_tdata (bfd)->local_got_tls_type) -#define elf32_arm_local_got_tls_type(abfd) \ - (elf32_arm_tdata (abfd)->local_got_tls_type) +#define is_arm_elf(bfd) \ + (bfd_get_flavour (bfd) == bfd_target_elf_flavour \ + && elf_tdata (bfd) != NULL \ + && elf_object_id (bfd) == ARM_ELF_TDATA) static bfd_boolean elf32_arm_mkobject (bfd *abfd) { - if (abfd->tdata.any == NULL) - { - bfd_size_type amt = sizeof (struct elf32_arm_obj_tdata); - abfd->tdata.any = bfd_zalloc (abfd, amt); - if (abfd->tdata.any == NULL) - return FALSE; - } - return bfd_elf_mkobject (abfd); + return bfd_elf_allocate_object (abfd, sizeof (struct elf_arm_obj_tdata), + ARM_ELF_TDATA); } /* The ARM linker needs to keep track of the number of relocs that it @@ -2119,6 +2132,10 @@ struct elf32_arm_link_hash_entry so that we can emit the Thumb trampoline only if needed. */ bfd_signed_vma plt_thumb_refcount; + /* Some references from Thumb code may be eliminated by BL->BLX + conversion, so record them separately. */ + bfd_signed_vma plt_maybe_thumb_refcount; + /* Since PLT entries have variable size if the Thumb prologue is used, we need to record the index into .got.plt instead of recomputing it from the PLT offset. */ @@ -2158,6 +2175,13 @@ struct elf32_arm_link_hash_table /* The size in bytes of the section containing the ARM-to-Thumb glue. */ bfd_size_type arm_glue_size; + /* The size in bytes of section containing the ARMv4 BX veneers. */ + bfd_size_type bx_glue_size; + + /* Offsets of ARMv4 BX veneers. Bit1 set if present, and Bit0 set when + veneer has been populated. */ + bfd_vma bx_glue_offset[15]; + /* The size in bytes of the section containing glue for VFP11 erratum veneers. */ bfd_size_type vfp11_erratum_glue_size; @@ -2175,7 +2199,9 @@ struct elf32_arm_link_hash_table /* The relocation to use for R_ARM_TARGET2 relocations. */ int target2_reloc; - /* Nonzero to fix BX instructions for ARMv4 targets. */ + /* 0 = Ignore R_ARM_V4BX. + 1 = Convert BX to MOV PC. + 2 = Generate v4 interworing stubs. */ int fix_v4bx; /* Nonzero if the ARM/Thumb BLX instructions are available for use. */ @@ -2188,6 +2214,9 @@ struct elf32_arm_link_hash_table /* Global counter for the number of fixes we have emitted. */ int num_vfp11_fixes; + /* Nonzero to force PIC branch veneers. */ + int pic_veneer; + /* The number of bytes in the initial entry in the PLT. */ bfd_size_type plt_header_size; @@ -2254,6 +2283,7 @@ elf32_arm_link_hash_newfunc (struct bfd_hash_entry * entry, ret->relocs_copied = NULL; ret->tls_type = GOT_UNKNOWN; ret->plt_thumb_refcount = 0; + ret->plt_maybe_thumb_refcount = 0; ret->plt_got_offset = -1; ret->export_glue = NULL; } @@ -2409,6 +2439,8 @@ elf32_arm_copy_indirect_symbol (struct bfd_link_info *info, /* Copy over PLT info. */ edir->plt_thumb_refcount += eind->plt_thumb_refcount; eind->plt_thumb_refcount = 0; + edir->plt_maybe_thumb_refcount += eind->plt_maybe_thumb_refcount; + eind->plt_maybe_thumb_refcount = 0; if (dir->got.refcount <= 0) { @@ -2450,6 +2482,8 @@ elf32_arm_link_hash_table_create (bfd *abfd) ret->srelplt2 = NULL; ret->thumb_glue_size = 0; ret->arm_glue_size = 0; + ret->bx_glue_size = 0; + memset (ret->bx_glue_offset, 0, sizeof(ret->bx_glue_offset)); ret->vfp11_fix = BFD_ARM_VFP11_FIX_NONE; ret->vfp11_erratum_glue_size = 0; ret->num_vfp11_fixes = 0; @@ -2500,9 +2534,10 @@ find_thumb_glue (struct bfd_link_info *link_info, hash = elf_link_hash_lookup (&(hash_table)->root, tmp_name, FALSE, FALSE, TRUE); - if (hash == NULL) - asprintf (error_message, _("unable to find THUMB glue '%s' for '%s'"), - tmp_name, name); + if (hash == NULL + && asprintf (error_message, _("unable to find THUMB glue '%s' for '%s'"), + tmp_name, name) == -1) + *error_message = (char *) bfd_errmsg (bfd_error_system_call); free (tmp_name); @@ -2533,9 +2568,10 @@ find_arm_glue (struct bfd_link_info *link_info, myh = elf_link_hash_lookup (&(hash_table)->root, tmp_name, FALSE, FALSE, TRUE); - if (myh == NULL) - asprintf (error_message, _("unable to find ARM glue '%s' for '%s'"), - tmp_name, name); + if (myh == NULL + && asprintf (error_message, _("unable to find ARM glue '%s' for '%s'"), + tmp_name, name) == -1) + *error_message = (char *) bfd_errmsg (bfd_error_system_call); free (tmp_name); @@ -2551,6 +2587,13 @@ find_arm_glue (struct bfd_link_info *link_info, __func_addr: .word func @ behave as if you saw a ARM_32 reloc. + (v5t static images) + .arm + __func_from_arm: + ldr pc, __func_addr + __func_addr: + .word func @ behave as if you saw a ARM_32 reloc. + (relocatable images) .arm __func_from_arm: @@ -2566,6 +2609,10 @@ static const insn32 a2t1_ldr_insn = 0xe59fc000; static const insn32 a2t2_bx_r12_insn = 0xe12fff1c; static const insn32 a2t3_func_addr_insn = 0x00000001; +#define ARM2THUMB_V5_STATIC_GLUE_SIZE 8 +static const insn32 a2t1v5_ldr_insn = 0xe51ff004; +static const insn32 a2t2v5_func_addr_insn = 0x00000001; + #define ARM2THUMB_PIC_GLUE_SIZE 16 static const insn32 a2t1p_ldr_insn = 0xe59fc004; static const insn32 a2t2p_add_pc_insn = 0xe08cc00f; @@ -2594,6 +2641,11 @@ static const insn32 t2a3_b_insn = 0xea000000; #define VFP11_ERRATUM_VENEER_SIZE 8 +#define ARM_BX_VENEER_SIZE 12 +static const insn32 armbx1_tst_insn = 0xe3100001; +static const insn32 armbx2_moveq_insn = 0x01a0f000; +static const insn32 armbx3_bx_insn = 0xe12fff10; + #ifndef ELFARM_NABI_C_INCLUDED bfd_boolean bfd_elf32_arm_allocate_interworking_sections (struct bfd_link_info * info) @@ -2652,6 +2704,21 @@ bfd_elf32_arm_allocate_interworking_sections (struct bfd_link_info * info) s->contents = foo; } + if (globals->bx_glue_size != 0) + { + BFD_ASSERT (globals->bfd_of_glue_owner != NULL); + + s = bfd_get_section_by_name (globals->bfd_of_glue_owner, + ARM_BX_GLUE_SECTION_NAME); + + BFD_ASSERT (s != NULL); + + foo = bfd_alloc (globals->bfd_of_glue_owner, globals->bx_glue_size); + + BFD_ASSERT (s->size == globals->bx_glue_size); + s->contents = foo; + } + return TRUE; } @@ -2711,8 +2778,11 @@ record_arm_to_thumb_glue (struct bfd_link_info * link_info, free (tmp_name); - if ((link_info->shared || globals->root.is_relocatable_executable)) + if (link_info->shared || globals->root.is_relocatable_executable + || globals->pic_veneer) size = ARM2THUMB_PIC_GLUE_SIZE; + else if (globals->use_blx) + size = ARM2THUMB_V5_STATIC_GLUE_SIZE; else size = ARM2THUMB_STATIC_GLUE_SIZE; @@ -2800,6 +2870,64 @@ record_thumb_to_arm_glue (struct bfd_link_info *link_info, } +/* Allocate space for ARMv4 BX veneers. */ + +static void +record_arm_bx_glue (struct bfd_link_info * link_info, int reg) +{ + asection * s; + struct elf32_arm_link_hash_table *globals; + char *tmp_name; + struct elf_link_hash_entry *myh; + struct bfd_link_hash_entry *bh; + bfd_vma val; + + /* BX PC does not need a veneer. */ + if (reg == 15) + return; + + globals = elf32_arm_hash_table (link_info); + + BFD_ASSERT (globals != NULL); + BFD_ASSERT (globals->bfd_of_glue_owner != NULL); + + /* Check if this veneer has already been allocated. */ + if (globals->bx_glue_offset[reg]) + return; + + s = bfd_get_section_by_name + (globals->bfd_of_glue_owner, ARM_BX_GLUE_SECTION_NAME); + + BFD_ASSERT (s != NULL); + + /* Add symbol for veneer. */ + tmp_name = bfd_malloc ((bfd_size_type) strlen (ARM_BX_GLUE_ENTRY_NAME) + 1); + + BFD_ASSERT (tmp_name); + + sprintf (tmp_name, ARM_BX_GLUE_ENTRY_NAME, reg); + + myh = elf_link_hash_lookup + (&(globals)->root, tmp_name, FALSE, FALSE, FALSE); + + BFD_ASSERT (myh == NULL); + + bh = NULL; + val = globals->bx_glue_size; + _bfd_generic_link_add_one_symbol (link_info, globals->bfd_of_glue_owner, + tmp_name, BSF_FUNCTION | BSF_LOCAL, s, val, + NULL, TRUE, FALSE, &bh); + + myh = (struct elf_link_hash_entry *) bh; + myh->type = ELF_ST_INFO (STB_LOCAL, STT_FUNC); + myh->forced_local = 1; + + s->size += ARM_BX_VENEER_SIZE; + globals->bx_glue_offset[reg] = globals->bx_glue_size | 2; + globals->bx_glue_size += ARM_BX_VENEER_SIZE; +} + + /* Add an entry to the code/data map for section SEC. */ static void @@ -2820,12 +2948,15 @@ elf32_arm_section_map_add (asection *sec, char type, bfd_vma vma) if (sec_data->mapcount > sec_data->mapsize) { sec_data->mapsize *= 2; - sec_data->map = bfd_realloc (sec_data->map, sec_data->mapsize - * sizeof (elf32_arm_section_map)); + sec_data->map = bfd_realloc_or_free (sec_data->map, sec_data->mapsize + * sizeof (elf32_arm_section_map)); + } + + if (sec_data->map) + { + sec_data->map[newidx].vma = vma; + sec_data->map[newidx].type = type; } - - sec_data->map[newidx].vma = vma; - sec_data->map[newidx].type = type; } @@ -3023,6 +3154,24 @@ bfd_elf32_arm_add_glue_sections_to_bfd (bfd *abfd, sec->gc_mark = 1; } + sec = bfd_get_section_by_name (abfd, ARM_BX_GLUE_SECTION_NAME); + + if (sec == NULL) + { + flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY + | SEC_CODE | SEC_READONLY); + + sec = bfd_make_section_with_flags (abfd, + ARM_BX_GLUE_SECTION_NAME, + flags); + + if (sec == NULL + || !bfd_set_section_alignment (abfd, sec, 2)) + return FALSE; + + sec->gc_mark = 1; + } + return TRUE; } @@ -3058,7 +3207,8 @@ bfd_elf32_arm_get_bfd_for_interworking (bfd *abfd, struct bfd_link_info *info) static void check_use_blx(struct elf32_arm_link_hash_table *globals) { - if (elf32_arm_get_eabi_attr_int (globals->obfd, Tag_CPU_arch) > 2) + if (bfd_elf_get_obj_attr_int (globals->obfd, OBJ_ATTR_PROC, + Tag_CPU_arch) > 2) globals->use_blx = 1; } @@ -3079,13 +3229,13 @@ bfd_elf32_arm_process_before_allocation (bfd *abfd, if (link_info->relocatable) return TRUE; - /* Here we have a bfd that is to be included on the link. We have a hook - to do reloc rummaging, before section sizes are nailed down. */ + /* Here we have a bfd that is to be included on the link. We have a + hook to do reloc rummaging, before section sizes are nailed down. */ globals = elf32_arm_hash_table (link_info); - check_use_blx (globals); BFD_ASSERT (globals != NULL); - BFD_ASSERT (globals->bfd_of_glue_owner != NULL); + + check_use_blx (globals); if (globals->byteswap_code && !bfd_big_endian (abfd)) { @@ -3094,6 +3244,12 @@ bfd_elf32_arm_process_before_allocation (bfd *abfd, return FALSE; } + /* PR 5398: If we have not decided to include any loadable sections in + the output then we will not have a glue owner bfd. This is OK, it + just means that there is nothing else for us to do here. */ + if (globals->bfd_of_glue_owner == NULL) + return TRUE; + /* Rummage around all the relocs and map the glue vectors. */ sec = abfd->sections; @@ -3108,7 +3264,7 @@ bfd_elf32_arm_process_before_allocation (bfd *abfd, if ((sec->flags & SEC_EXCLUDE) != 0) continue; - symtab_hdr = &elf_tdata (abfd)->symtab_hdr; + symtab_hdr = & elf_symtab_hdr (abfd); /* Load the relocs. */ internal_relocs @@ -3134,7 +3290,9 @@ bfd_elf32_arm_process_before_allocation (bfd *abfd, && r_type != R_ARM_PLT32 && r_type != R_ARM_CALL && r_type != R_ARM_JUMP24 - && r_type != R_ARM_THM_CALL) + && r_type != R_ARM_THM_CALL + && r_type != R_ARM_THM_JUMP24 + && (r_type != R_ARM_V4BX || globals->fix_v4bx < 2)) continue; /* Get the section contents if we haven't done so already. */ @@ -3151,6 +3309,15 @@ bfd_elf32_arm_process_before_allocation (bfd *abfd, } } + if (r_type == R_ARM_V4BX) + { + int reg; + + reg = bfd_get_32 (abfd, contents + irel->r_offset) & 0xf; + record_arm_bx_glue (link_info, reg); + continue; + } + /* If the relocation is not against a symbol it cannot concern us. */ h = NULL; @@ -3188,10 +3355,13 @@ bfd_elf32_arm_process_before_allocation (bfd *abfd, break; case R_ARM_THM_CALL: + case R_ARM_THM_JUMP24: /* This one is a call from thumb code. We look up the target of the call. If it is not a thumb target, we insert glue. */ - if (ELF_ST_TYPE (h->type) != STT_ARM_TFUNC && !globals->use_blx) + if (ELF_ST_TYPE (h->type) != STT_ARM_TFUNC + && !(globals->use_blx && r_type == R_ARM_THM_CALL) + && h->root.type != bfd_link_hash_undefweak) record_thumb_to_arm_glue (link_info, h); break; @@ -3238,7 +3408,7 @@ bfd_elf32_arm_init_maps (bfd *abfd) if ((abfd->flags & DYNAMIC) != 0) return; - hdr = &elf_tdata (abfd)->symtab_hdr; + hdr = & elf_symtab_hdr (abfd); localsyms = hdr->sh_info; /* Obtain a buffer full of symbols for this BFD. The hdr->sh_info field @@ -3275,7 +3445,7 @@ void bfd_elf32_arm_set_vfp11_fix (bfd *obfd, struct bfd_link_info *link_info) { struct elf32_arm_link_hash_table *globals = elf32_arm_hash_table (link_info); - aeabi_attribute *out_attr = elf32_arm_tdata (obfd)->known_eabi_attributes; + obj_attribute *out_attr = elf_known_obj_attributes_proc (obfd); /* We assume that ARMv7+ does not need the VFP11 denorm erratum fix. */ if (out_attr[Tag_CPU_arch].i >= TAG_CPU_ARCH_V7) @@ -3611,12 +3781,16 @@ bfd_elf32_arm_vfp11_erratum_scan (bfd *abfd, struct bfd_link_info *link_info) if (link_info->relocatable) return TRUE; + /* Skip if this bfd does not correspond to an ELF image. */ + if (! is_arm_elf (abfd)) + return TRUE; + /* We should have chosen a fix type by the time we get here. */ BFD_ASSERT (globals->vfp11_fix != BFD_ARM_VFP11_FIX_DEFAULT); if (globals->vfp11_fix == BFD_ARM_VFP11_FIX_NONE) return TRUE; - + for (sec = abfd->sections; sec != NULL; sec = sec->next) { unsigned int i, span, first_fmac = 0, veneer_of_insn = 0; @@ -3787,7 +3961,11 @@ bfd_elf32_arm_vfp11_fix_veneer_locations (bfd *abfd, if (link_info->relocatable) return; - + + /* Skip if this bfd does not correspond to an ELF image. */ + if (! is_arm_elf (abfd)) + return; + globals = elf32_arm_hash_table (link_info); tmp_name = bfd_malloc ((bfd_size_type) strlen @@ -3858,12 +4036,14 @@ bfd_elf32_arm_vfp11_fix_veneer_locations (bfd *abfd, /* Set target relocation values needed during linking. */ void -bfd_elf32_arm_set_target_relocs (struct bfd_link_info *link_info, +bfd_elf32_arm_set_target_relocs (struct bfd *output_bfd, + struct bfd_link_info *link_info, int target1_is_rel, char * target2_type, int fix_v4bx, int use_blx, - bfd_arm_vfp11_fix vfp11_fix) + bfd_arm_vfp11_fix vfp11_fix, + int no_enum_warn, int pic_veneer) { struct elf32_arm_link_hash_table *globals; @@ -3884,60 +4064,35 @@ bfd_elf32_arm_set_target_relocs (struct bfd_link_info *link_info, globals->fix_v4bx = fix_v4bx; globals->use_blx |= use_blx; globals->vfp11_fix = vfp11_fix; -} - -/* The thumb form of a long branch is a bit finicky, because the offset - encoding is split over two fields, each in it's own instruction. They - can occur in any order. So given a thumb form of long branch, and an - offset, insert the offset into the thumb branch and return finished - instruction. - - It takes two thumb instructions to encode the target address. Each has - 11 bits to invest. The upper 11 bits are stored in one (identified by - H-0.. see below), the lower 11 bits are stored in the other (identified - by H-1). - - Combine together and shifted left by 1 (it's a half word address) and - there you have it. - - Op: 1111 = F, - H-0, upper address-0 = 000 - Op: 1111 = F, - H-1, lower address-0 = 800 - - They can be ordered either way, but the arm tools I've seen always put - the lower one first. It probably doesn't matter. krk@cygnus.com - - XXX: Actually the order does matter. The second instruction (H-1) - moves the computed address into the PC, so it must be the second one - in the sequence. The problem, however is that whilst little endian code - stores the instructions in HI then LOW order, big endian code does the - reverse. nickc@cygnus.com. */ - -#define LOW_HI_ORDER 0xF800F000 -#define HI_LOW_ORDER 0xF000F800 - -static insn32 -insert_thumb_branch (insn32 br_insn, int rel_off) -{ - unsigned int low_bits; - unsigned int high_bits; - - BFD_ASSERT ((rel_off & 1) != 1); + globals->pic_veneer = pic_veneer; - rel_off >>= 1; /* Half word aligned address. */ - low_bits = rel_off & 0x000007FF; /* The bottom 11 bits. */ - high_bits = (rel_off >> 11) & 0x000007FF; /* The top 11 bits. */ + BFD_ASSERT (is_arm_elf (output_bfd)); + elf_arm_tdata (output_bfd)->no_enum_size_warning = no_enum_warn; +} - if ((br_insn & LOW_HI_ORDER) == LOW_HI_ORDER) - br_insn = LOW_HI_ORDER | (low_bits << 16) | high_bits; - else if ((br_insn & HI_LOW_ORDER) == HI_LOW_ORDER) - br_insn = HI_LOW_ORDER | (high_bits << 16) | low_bits; - else - /* FIXME: abort is probably not the right call. krk@cygnus.com */ - abort (); /* Error - not a valid branch instruction form. */ +/* Replace the target offset of a Thumb bl or b.w instruction. */ - return br_insn; +static void +insert_thumb_branch (bfd *abfd, long int offset, bfd_byte *insn) +{ + bfd_vma upper; + bfd_vma lower; + int reloc_sign; + + BFD_ASSERT ((offset & 1) == 0); + + upper = bfd_get_16 (abfd, insn); + lower = bfd_get_16 (abfd, insn + 2); + reloc_sign = (offset < 0) ? 1 : 0; + upper = (upper & ~(bfd_vma) 0x7ff) + | ((offset >> 12) & 0x3ff) + | (reloc_sign << 10); + lower = (lower & ~(bfd_vma) 0x2fff) + | (((!((offset >> 23) & 1)) ^ reloc_sign) << 13) + | (((!((offset >> 22) & 1)) ^ reloc_sign) << 11) + | ((offset >> 1) & 0x7ff); + bfd_put_16 (abfd, upper, insn); + bfd_put_16 (abfd, lower, insn + 2); } @@ -3986,7 +4141,6 @@ elf32_thumb_to_arm_stub (struct bfd_link_info * info, { asection * s = 0; bfd_vma my_offset; - unsigned long int tmp; long int ret_offset; struct elf_link_hash_entry * myh; struct elf32_arm_link_hash_table * globals; @@ -4067,12 +4221,7 @@ elf32_thumb_to_arm_stub (struct bfd_link_info * info, /* Biassing for PC-relative addressing. */ - 8; - tmp = bfd_get_32 (input_bfd, hit_data - - input_section->vma); - - bfd_put_32 (output_bfd, - (bfd_vma) insert_thumb_branch (tmp, ret_offset), - hit_data - input_section->vma); + insert_thumb_branch (input_bfd, ret_offset, hit_data - input_section->vma); return TRUE; } @@ -4120,7 +4269,8 @@ elf32_arm_create_thumb_stub (struct bfd_link_info * info, --my_offset; myh->root.u.def.value = my_offset; - if ((info->shared || globals->root.is_relocatable_executable)) + if (info->shared || globals->root.is_relocatable_executable + || globals->pic_veneer) { /* For relocatable objects we can't use absolute addresses, so construct the address from a relative offset. */ @@ -4141,6 +4291,15 @@ elf32_arm_create_thumb_stub (struct bfd_link_info * info, bfd_put_32 (output_bfd, ret_offset, s->contents + my_offset + 12); } + else if (globals->use_blx) + { + put_arm_insn (globals, output_bfd, (bfd_vma) a2t1v5_ldr_insn, + s->contents + my_offset); + + /* It's a thumb address. Add the low order bit. */ + bfd_put_32 (output_bfd, val | a2t2v5_func_addr_insn, + s->contents + my_offset + 4); + } else { put_arm_insn (globals, output_bfd, (bfd_vma) a2t1_ldr_insn, @@ -4262,6 +4421,43 @@ elf32_arm_to_thumb_export_stub (struct elf_link_hash_entry *h, void * inf) return TRUE; } +/* Populate ARMv4 BX veneers. Returns the absolute adress of the veneer. */ + +static bfd_vma +elf32_arm_bx_glue (struct bfd_link_info * info, int reg) +{ + bfd_byte *p; + bfd_vma glue_addr; + asection *s; + struct elf32_arm_link_hash_table *globals; + + globals = elf32_arm_hash_table (info); + + BFD_ASSERT (globals != NULL); + BFD_ASSERT (globals->bfd_of_glue_owner != NULL); + + s = bfd_get_section_by_name (globals->bfd_of_glue_owner, + ARM_BX_GLUE_SECTION_NAME); + BFD_ASSERT (s != NULL); + BFD_ASSERT (s->contents != NULL); + BFD_ASSERT (s->output_section != NULL); + + BFD_ASSERT (globals->bx_glue_offset[reg] & 2); + + glue_addr = globals->bx_glue_offset[reg] & ~(bfd_vma)3; + + if ((globals->bx_glue_offset[reg] & 1) == 0) + { + p = s->contents + glue_addr; + bfd_put_32 (globals->obfd, armbx1_tst_insn + (reg << 16), p); + bfd_put_32 (globals->obfd, armbx2_moveq_insn + reg, p + 4); + bfd_put_32 (globals->obfd, armbx3_bx_insn + reg, p + 8); + globals->bx_glue_offset[reg] |= 1; + } + + return glue_addr + s->output_section->vma + s->output_offset; +} + /* Generate Arm stubs for exported Thumb symbols. */ static void elf32_arm_begin_write_processing (bfd *abfd ATTRIBUTE_UNUSED, @@ -4419,7 +4615,8 @@ identify_add_or_sub(bfd_vma insn) static int using_thumb2 (struct elf32_arm_link_hash_table *globals) { - int arch = elf32_arm_get_eabi_attr_int (globals->obfd, Tag_CPU_arch); + int arch = bfd_elf_get_obj_attr_int (globals->obfd, OBJ_ATTR_PROC, + Tag_CPU_arch); return arch == TAG_CPU_ARCH_V6T2 || arch >= TAG_CPU_ARCH_V7; } @@ -4457,7 +4654,9 @@ elf32_arm_final_link_relocate (reloc_howto_type * howto, globals = elf32_arm_hash_table (info); - /* Some relocation type map to different relocations depending on the + BFD_ASSERT (is_arm_elf (input_bfd)); + + /* Some relocation types map to different relocations depending on the target. We pick the right one here. */ r_type = arm_real_reloc_type (globals, r_type); if (r_type != howto->type) @@ -4481,7 +4680,7 @@ elf32_arm_final_link_relocate (reloc_howto_type * howto, sgot = bfd_get_section_by_name (dynobj, ".got"); splt = bfd_get_section_by_name (dynobj, ".plt"); } - symtab_hdr = & elf_tdata (input_bfd)->symtab_hdr; + symtab_hdr = & elf_symtab_hdr (input_bfd); sym_hashes = elf_sym_hashes (input_bfd); local_got_offsets = elf_local_got_offsets (input_bfd); r_symndx = ELF32_R_SYM (rel->r_info); @@ -4553,6 +4752,9 @@ elf32_arm_final_link_relocate (reloc_howto_type * howto, run time. */ if ((info->shared || globals->root.is_relocatable_executable) && (input_section->flags & SEC_ALLOC) + && !(elf32_arm_hash_table (info)->vxworks_p + && strcmp (input_section->output_section->name, + ".tls_vars") == 0) && ((r_type != R_ARM_REL32 && r_type != R_ARM_REL32_NOI) || !SYMBOL_CALLS_LOCAL (info, h)) && (h == NULL @@ -4744,40 +4946,43 @@ elf32_arm_final_link_relocate (reloc_howto_type * howto, signed_addend = value; signed_addend >>= howto->rightshift; - /* It is not an error for an undefined weak reference to be - out of range. Any program that branches to such a symbol - is going to crash anyway, so there is no point worrying - about getting the destination exactly right. */ - if (! h || h->root.type != bfd_link_hash_undefweak) + /* A branch to an undefined weak symbol is turned into a jump to + the next instruction. */ + if (h && h->root.type == bfd_link_hash_undefweak) + { + value = (bfd_get_32 (input_bfd, hit_data) & 0xf0000000) + | 0x0affffff; + } + else { /* Perform a signed range check. */ if ( signed_addend > ((bfd_signed_vma) (howto->dst_mask >> 1)) || signed_addend < - ((bfd_signed_vma) ((howto->dst_mask + 1) >> 1))) return bfd_reloc_overflow; - } - addend = (value & 2); + addend = (value & 2); - value = (signed_addend & howto->dst_mask) - | (bfd_get_32 (input_bfd, hit_data) & (~ howto->dst_mask)); + value = (signed_addend & howto->dst_mask) + | (bfd_get_32 (input_bfd, hit_data) & (~ howto->dst_mask)); - /* Set the H bit in the BLX instruction. */ - if (sym_flags == STT_ARM_TFUNC) - { - if (addend) - value |= (1 << 24); - else - value &= ~(bfd_vma)(1 << 24); - } - if (r_type == R_ARM_CALL) - { - /* Select the correct instruction (BL or BLX). */ + /* Set the H bit in the BLX instruction. */ if (sym_flags == STT_ARM_TFUNC) - value |= (1 << 28); - else { - value &= ~(bfd_vma)(1 << 28); - value |= (1 << 24); + if (addend) + value |= (1 << 24); + else + value &= ~(bfd_vma)(1 << 24); + } + if (r_type == R_ARM_CALL) + { + /* Select the correct instruction (BL or BLX). */ + if (sym_flags == STT_ARM_TFUNC) + value |= (1 << 28); + else + { + value &= ~(bfd_vma)(1 << 28); + value |= (1 << 24); + } } } break; @@ -4940,6 +5145,7 @@ elf32_arm_final_link_relocate (reloc_howto_type * howto, case R_ARM_THM_XPC22: case R_ARM_THM_CALL: + case R_ARM_THM_JUMP24: /* Thumb BL (branch long instruction). */ { bfd_vma relocation; @@ -4954,6 +5160,15 @@ elf32_arm_final_link_relocate (reloc_howto_type * howto, int bitsize; int thumb2 = using_thumb2 (globals); + /* A branch to an undefined weak symbol is turned into a jump to + the next instruction. */ + if (h && h->root.type == bfd_link_hash_undefweak) + { + bfd_put_16 (input_bfd, 0xe000, hit_data); + bfd_put_16 (input_bfd, 0xbf00, hit_data + 2); + return bfd_reloc_ok; + } + /* Fetch the addend. We use the Thumb-2 encoding (backwards compatible with Thumb-1) involving the J1 and J2 bits. */ if (globals->use_rel) @@ -4994,7 +5209,7 @@ elf32_arm_final_link_relocate (reloc_howto_type * howto, && (h == NULL || splt == NULL || h->plt.offset == (bfd_vma) -1)) { - if (globals->use_blx) + if (globals->use_blx && r_type == R_ARM_THM_CALL) { /* Convert BL to BLX. */ lower_insn = (lower_insn & ~0x1000) | 0x0800; @@ -5007,7 +5222,8 @@ elf32_arm_final_link_relocate (reloc_howto_type * howto, else return bfd_reloc_dangerous; } - else if (sym_flags == STT_ARM_TFUNC && globals->use_blx) + else if (sym_flags == STT_ARM_TFUNC && globals->use_blx + && r_type == R_ARM_THM_CALL) { /* Make sure this is a BL. */ lower_insn |= 0x1800; @@ -5020,7 +5236,7 @@ elf32_arm_final_link_relocate (reloc_howto_type * howto, value = (splt->output_section->vma + splt->output_offset + h->plt.offset); - if (globals->use_blx) + if (globals->use_blx && r_type == R_ARM_THM_CALL) { /* If the Thumb BLX instruction is available, convert the BL to a BLX instruction to call the ARM-mode PLT entry. */ @@ -5060,7 +5276,7 @@ elf32_arm_final_link_relocate (reloc_howto_type * howto, if (signed_check > reloc_signed_max || signed_check < reloc_signed_min) overflow = TRUE; - if ((lower_insn & 0x1800) == 0x0800) + if ((lower_insn & 0x5000) == 0x4000) /* For a BLX instruction, make sure that the relocation is rounded up to a word boundary. This follows the semantics of the instruction which specifies that bit 1 of the target address will come from bit @@ -5087,34 +5303,45 @@ elf32_arm_final_link_relocate (reloc_howto_type * howto, } break; - case R_ARM_THM_JUMP24: - /* Thumb32 unconditional branch instruction. */ + case R_ARM_THM_JUMP19: + /* Thumb32 conditional branch instruction. */ { bfd_vma relocation; bfd_boolean overflow = FALSE; bfd_vma upper_insn = bfd_get_16 (input_bfd, hit_data); bfd_vma lower_insn = bfd_get_16 (input_bfd, hit_data + 2); - bfd_signed_vma reloc_signed_max = ((1 << (howto->bitsize - 1)) - 1) >> howto->rightshift; - bfd_signed_vma reloc_signed_min = ~ reloc_signed_max; - bfd_vma check; + bfd_signed_vma reloc_signed_max = 0xffffe; + bfd_signed_vma reloc_signed_min = -0x100000; bfd_signed_vma signed_check; - /* Need to refetch the addend, reconstruct the top three bits, and glue the - two pieces together. */ + /* Need to refetch the addend, reconstruct the top three bits, + and squish the two 11 bit pieces together. */ if (globals->use_rel) { - bfd_vma S = (upper_insn & 0x0400) >> 10; - bfd_vma hi = (upper_insn & 0x03ff); - bfd_vma I1 = (lower_insn & 0x2000) >> 13; - bfd_vma I2 = (lower_insn & 0x0800) >> 11; - bfd_vma lo = (lower_insn & 0x07ff); - - I1 = !(I1 ^ S); - I2 = !(I2 ^ S); - S = !S; - - signed_addend = (S << 24) | (I1 << 23) | (I2 << 22) | (hi << 12) | (lo << 1); - signed_addend -= (1 << 24); /* Sign extend. */ + bfd_vma S = (upper_insn & 0x0400) >> 10; + bfd_vma upper = (upper_insn & 0x003f); + bfd_vma J1 = (lower_insn & 0x2000) >> 13; + bfd_vma J2 = (lower_insn & 0x0800) >> 11; + bfd_vma lower = (lower_insn & 0x07ff); + + upper |= J1 << 6; + upper |= J2 << 7; + upper |= (!S) << 8; + upper -= 0x0100; /* Sign extend. */ + + addend = (upper << 12) | (lower << 1); + signed_addend = addend; + } + + /* Handle calls via the PLT. */ + if (h != NULL && splt != NULL && h->plt.offset != (bfd_vma) -1) + { + value = (splt->output_section->vma + + splt->output_offset + + h->plt.offset); + /* Target the Thumb stub before the ARM PLT entry. */ + value -= PLT_THUMB_STUB_SIZE; + *unresolved_reloc_p = FALSE; } /* ??? Should handle interworking? GCC might someday try to @@ -5124,33 +5351,21 @@ elf32_arm_final_link_relocate (reloc_howto_type * howto, relocation -= (input_section->output_section->vma + input_section->output_offset + rel->r_offset); + signed_check = (bfd_signed_vma) relocation; - check = relocation >> howto->rightshift; - - /* If this is a signed value, the rightshift just dropped - leading 1 bits (assuming twos complement). */ - if ((bfd_signed_vma) relocation >= 0) - signed_check = check; - else - signed_check = check | ~((bfd_vma) -1 >> howto->rightshift); - - /* Assumes two's complement. */ if (signed_check > reloc_signed_max || signed_check < reloc_signed_min) overflow = TRUE; /* Put RELOCATION back into the insn. */ { - bfd_vma S = (relocation & 0x01000000) >> 24; - bfd_vma I1 = (relocation & 0x00800000) >> 23; - bfd_vma I2 = (relocation & 0x00400000) >> 22; - bfd_vma hi = (relocation & 0x003ff000) >> 12; + bfd_vma S = (relocation & 0x00100000) >> 20; + bfd_vma J2 = (relocation & 0x00080000) >> 19; + bfd_vma J1 = (relocation & 0x00040000) >> 18; + bfd_vma hi = (relocation & 0x0003f000) >> 12; bfd_vma lo = (relocation & 0x00000ffe) >> 1; - I1 = !(I1 ^ S); - I2 = !(I2 ^ S); - - upper_insn = (upper_insn & (bfd_vma) 0xf800) | (S << 10) | hi; - lower_insn = (lower_insn & (bfd_vma) 0xd000) | (I1 << 13) | (I2 << 11) | lo; + upper_insn = (upper_insn & 0xfbc0) | (S << 10) | hi; + lower_insn = (lower_insn & 0xd000) | (J1 << 13) | (J2 << 11) | lo; } /* Put the relocated value back in the object file: */ @@ -5160,84 +5375,13 @@ elf32_arm_final_link_relocate (reloc_howto_type * howto, return (overflow ? bfd_reloc_overflow : bfd_reloc_ok); } - case R_ARM_THM_JUMP19: - /* Thumb32 conditional branch instruction. */ + case R_ARM_THM_JUMP11: + case R_ARM_THM_JUMP8: + case R_ARM_THM_JUMP6: + /* Thumb B (branch) instruction). */ { - bfd_vma relocation; - bfd_boolean overflow = FALSE; - bfd_vma upper_insn = bfd_get_16 (input_bfd, hit_data); - bfd_vma lower_insn = bfd_get_16 (input_bfd, hit_data + 2); - bfd_signed_vma reloc_signed_max = ((1 << (howto->bitsize - 1)) - 1) >> howto->rightshift; - bfd_signed_vma reloc_signed_min = ~ reloc_signed_max; - bfd_vma check; - bfd_signed_vma signed_check; - - /* Need to refetch the addend, reconstruct the top three bits, - and squish the two 11 bit pieces together. */ - if (globals->use_rel) - { - bfd_vma S = (upper_insn & 0x0400) >> 10; - bfd_vma upper = (upper_insn & 0x001f); - bfd_vma J1 = (lower_insn & 0x2000) >> 13; - bfd_vma J2 = (lower_insn & 0x0800) >> 11; - bfd_vma lower = (lower_insn & 0x07ff); - - upper |= J2 << 6; - upper |= J1 << 7; - upper |= ~S << 8; - upper -= 0x0100; /* Sign extend. */ - - addend = (upper << 12) | (lower << 1); - signed_addend = addend; - } - - /* ??? Should handle interworking? GCC might someday try to - use this for tail calls. */ - - relocation = value + signed_addend; - relocation -= (input_section->output_section->vma - + input_section->output_offset - + rel->r_offset); - - check = relocation >> howto->rightshift; - - /* If this is a signed value, the rightshift just dropped - leading 1 bits (assuming twos complement). */ - if ((bfd_signed_vma) relocation >= 0) - signed_check = check; - else - signed_check = check | ~((bfd_vma) -1 >> howto->rightshift); - - /* Assumes two's complement. */ - if (signed_check > reloc_signed_max || signed_check < reloc_signed_min) - overflow = TRUE; - - /* Put RELOCATION back into the insn. */ - { - bfd_vma S = (relocation & 0x00100000) >> 20; - bfd_vma J2 = (relocation & 0x00080000) >> 19; - bfd_vma J1 = (relocation & 0x00040000) >> 18; - bfd_vma hi = (relocation & 0x0003f000) >> 12; - bfd_vma lo = (relocation & 0x00000ffe) >> 1; - - upper_insn = (upper_insn & 0xfb30) | (S << 10) | hi; - lower_insn = (lower_insn & 0xd000) | (J1 << 13) | (J2 << 11) | lo; - } - - /* Put the relocated value back in the object file: */ - bfd_put_16 (input_bfd, upper_insn, hit_data); - bfd_put_16 (input_bfd, lower_insn, hit_data + 2); - - return (overflow ? bfd_reloc_overflow : bfd_reloc_ok); - } - - case R_ARM_THM_JUMP11: - case R_ARM_THM_JUMP8: - case R_ARM_THM_JUMP6: - /* Thumb B (branch) instruction). */ - { - bfd_signed_vma relocation; - bfd_signed_vma reloc_signed_max = (1 << (howto->bitsize - 1)) - 1; + bfd_signed_vma relocation; + bfd_signed_vma reloc_signed_max = (1 << (howto->bitsize - 1)) - 1; bfd_signed_vma reloc_signed_min = ~ reloc_signed_max; bfd_signed_vma signed_check; @@ -5695,18 +5839,32 @@ elf32_arm_final_link_relocate (reloc_howto_type * howto, case R_ARM_V4BX: if (globals->fix_v4bx) - { - bfd_vma insn = bfd_get_32 (input_bfd, hit_data); + { + bfd_vma insn = bfd_get_32 (input_bfd, hit_data); - /* Ensure that we have a BX instruction. */ - BFD_ASSERT ((insn & 0x0ffffff0) == 0x012fff10); + /* Ensure that we have a BX instruction. */ + BFD_ASSERT ((insn & 0x0ffffff0) == 0x012fff10); - /* Preserve Rm (lowest four bits) and the condition code - (highest four bits). Other bits encode MOV PC,Rm. */ - insn = (insn & 0xf000000f) | 0x01a0f000; + if (globals->fix_v4bx == 2 && (insn & 0xf) != 0xf) + { + /* Branch to veneer. */ + bfd_vma glue_addr; + glue_addr = elf32_arm_bx_glue (info, insn & 0xf); + glue_addr -= input_section->output_section->vma + + input_section->output_offset + + rel->r_offset + 8; + insn = (insn & 0xf0000000) | 0x0a000000 + | ((glue_addr >> 2) & 0x00ffffff); + } + else + { + /* Preserve Rm (lowest four bits) and the condition code + (highest four bits). Other bits encode MOV PC,Rm. */ + insn = (insn & 0xf000000f) | 0x01a0f000; + } - bfd_put_32 (input_bfd, insn, hit_data); - } + bfd_put_32 (input_bfd, insn, hit_data); + } return bfd_reloc_ok; case R_ARM_MOVW_ABS_NC: @@ -5726,7 +5884,7 @@ elf32_arm_final_link_relocate (reloc_howto_type * howto, if (globals->use_rel) { addend = ((insn >> 4) & 0xf000) | (insn & 0xfff); - signed_addend = (addend ^ 0x10000) - 0x10000; + signed_addend = (addend ^ 0x8000) - 0x8000; } value += signed_addend; @@ -5776,7 +5934,7 @@ elf32_arm_final_link_relocate (reloc_howto_type * howto, | ((insn >> 15) & 0x0800) | ((insn >> 4) & 0x0700) | (insn & 0x00ff); - signed_addend = (addend ^ 0x10000) - 0x10000; + signed_addend = (addend ^ 0x8000) - 0x8000; } value += signed_addend; @@ -6202,194 +6360,6 @@ elf32_arm_final_link_relocate (reloc_howto_type * howto, } } - -static int -uleb128_size (unsigned int i) -{ - int size; - size = 1; - while (i >= 0x80) - { - i >>= 7; - size++; - } - return size; -} - -/* Return TRUE if the attribute has the default value (0/""). */ -static bfd_boolean -is_default_attr (aeabi_attribute *attr) -{ - if ((attr->type & 1) && attr->i != 0) - return FALSE; - if ((attr->type & 2) && attr->s && *attr->s) - return FALSE; - - return TRUE; -} - -/* Return the size of a single attribute. */ -static bfd_vma -eabi_attr_size(int tag, aeabi_attribute *attr) -{ - bfd_vma size; - - if (is_default_attr (attr)) - return 0; - - size = uleb128_size (tag); - if (attr->type & 1) - size += uleb128_size (attr->i); - if (attr->type & 2) - size += strlen ((char *)attr->s) + 1; - return size; -} - -/* Returns the size of the eabi object attributess section. */ -bfd_vma -elf32_arm_eabi_attr_size (bfd *abfd) -{ - bfd_vma size; - aeabi_attribute *attr; - aeabi_attribute_list *list; - int i; - - attr = elf32_arm_tdata (abfd)->known_eabi_attributes; - size = 16; /* 'A' "aeabi" 0x1 . */ - for (i = 4; i < NUM_KNOWN_ATTRIBUTES; i++) - size += eabi_attr_size (i, &attr[i]); - - for (list = elf32_arm_tdata (abfd)->other_eabi_attributes; - list; - list = list->next) - size += eabi_attr_size (list->tag, &list->attr); - - return size; -} - -static bfd_byte * -write_uleb128 (bfd_byte *p, unsigned int val) -{ - bfd_byte c; - do - { - c = val & 0x7f; - val >>= 7; - if (val) - c |= 0x80; - *(p++) = c; - } - while (val); - return p; -} - -/* Write attribute ATTR to butter P, and return a pointer to the following - byte. */ -static bfd_byte * -write_eabi_attribute (bfd_byte *p, int tag, aeabi_attribute *attr) -{ - /* Suppress default entries. */ - if (is_default_attr(attr)) - return p; - - p = write_uleb128 (p, tag); - if (attr->type & 1) - p = write_uleb128 (p, attr->i); - if (attr->type & 2) - { - int len; - - len = strlen (attr->s) + 1; - memcpy (p, attr->s, len); - p += len; - } - - return p; -} - -/* Write the contents of the eabi attributes section to p. */ -void -elf32_arm_set_eabi_attr_contents (bfd *abfd, bfd_byte *contents, bfd_vma size) -{ - bfd_byte *p; - aeabi_attribute *attr; - aeabi_attribute_list *list; - int i; - - p = contents; - *(p++) = 'A'; - bfd_put_32 (abfd, size - 1, p); - p += 4; - memcpy (p, "aeabi", 6); - p += 6; - *(p++) = Tag_File; - bfd_put_32 (abfd, size - 11, p); - p += 4; - - attr = elf32_arm_tdata (abfd)->known_eabi_attributes; - for (i = 4; i < NUM_KNOWN_ATTRIBUTES; i++) - p = write_eabi_attribute (p, i, &attr[i]); - - for (list = elf32_arm_tdata (abfd)->other_eabi_attributes; - list; - list = list->next) - p = write_eabi_attribute (p, list->tag, &list->attr); -} - -/* Override final_link to handle EABI object attribute sections. */ - -static bfd_boolean -elf32_arm_bfd_final_link (bfd *abfd, struct bfd_link_info *info) -{ - asection *o; - struct bfd_link_order *p; - asection *attr_section = NULL; - bfd_byte *contents; - bfd_vma size = 0; - - /* elf32_arm_merge_private_bfd_data will already have merged the - object attributes. Remove the input sections from the link, and set - the contents of the output secton. */ - for (o = abfd->sections; o != NULL; o = o->next) - { - if (strcmp (o->name, ".ARM.attributes") == 0) - { - for (p = o->map_head.link_order; p != NULL; p = p->next) - { - asection *input_section; - - if (p->type != bfd_indirect_link_order) - continue; - input_section = p->u.indirect.section; - /* Hack: reset the SEC_HAS_CONTENTS flag so that - elf_link_input_bfd ignores this section. */ - input_section->flags &= ~SEC_HAS_CONTENTS; - } - - size = elf32_arm_eabi_attr_size (abfd); - bfd_set_section_size (abfd, o, size); - attr_section = o; - /* Skip this section later on. */ - o->map_head.link_order = NULL; - } - } - /* Invoke the ELF linker to do all the work. */ - if (!bfd_elf_final_link (abfd, info)) - return FALSE; - - if (attr_section) - { - contents = bfd_malloc(size); - if (contents == NULL) - return FALSE; - elf32_arm_set_eabi_attr_contents (abfd, contents, size); - bfd_set_section_contents (abfd, attr_section, contents, 0, size); - free (contents); - } - return TRUE; -} - - /* Add INCREMENT to the reloc (of type HOWTO) at ADDRESS. */ static void arm_add_to_rel (bfd * abfd, @@ -6399,7 +6369,8 @@ arm_add_to_rel (bfd * abfd, { bfd_signed_vma addend; - if (howto->type == R_ARM_THM_CALL) + if (howto->type == R_ARM_THM_CALL + || howto->type == R_ARM_THM_JUMP24) { int upper_insn, lower_insn; int upper, lower; @@ -6493,7 +6464,7 @@ elf32_arm_relocate_section (bfd * output_bfd, globals = elf32_arm_hash_table (info); - symtab_hdr = & elf_tdata (input_bfd)->symtab_hdr; + symtab_hdr = & elf_symtab_hdr (input_bfd); sym_hashes = elf_sym_hashes (input_bfd); rel = relocs; @@ -6545,34 +6516,85 @@ elf32_arm_relocate_section (bfd * output_bfd, asection *msec; bfd_vma addend, value; - if (howto->rightshift) + switch (r_type) { - (*_bfd_error_handler) - (_("%B(%A+0x%lx): %s relocation against SEC_MERGE section"), - input_bfd, input_section, - (long) rel->r_offset, howto->name); - return FALSE; - } + case R_ARM_MOVW_ABS_NC: + case R_ARM_MOVT_ABS: + value = bfd_get_32 (input_bfd, contents + rel->r_offset); + addend = ((value & 0xf0000) >> 4) | (value & 0xfff); + addend = (addend ^ 0x8000) - 0x8000; + break; + + case R_ARM_THM_MOVW_ABS_NC: + case R_ARM_THM_MOVT_ABS: + value = bfd_get_16 (input_bfd, contents + rel->r_offset) + << 16; + value |= bfd_get_16 (input_bfd, + contents + rel->r_offset + 2); + addend = ((value & 0xf7000) >> 4) | (value & 0xff) + | ((value & 0x04000000) >> 15); + addend = (addend ^ 0x8000) - 0x8000; + break; - value = bfd_get_32 (input_bfd, contents + rel->r_offset); + default: + if (howto->rightshift + || (howto->src_mask & (howto->src_mask + 1))) + { + (*_bfd_error_handler) + (_("%B(%A+0x%lx): %s relocation against SEC_MERGE section"), + input_bfd, input_section, + (long) rel->r_offset, howto->name); + return FALSE; + } - /* Get the (signed) value from the instruction. */ - addend = value & howto->src_mask; - if (addend & ((howto->src_mask + 1) >> 1)) - { - bfd_signed_vma mask; + value = bfd_get_32 (input_bfd, contents + rel->r_offset); - mask = -1; - mask &= ~ howto->src_mask; - addend |= mask; + /* Get the (signed) value from the instruction. */ + addend = value & howto->src_mask; + if (addend & ((howto->src_mask + 1) >> 1)) + { + bfd_signed_vma mask; + + mask = -1; + mask &= ~ howto->src_mask; + addend |= mask; + } + break; } + msec = sec; addend = _bfd_elf_rel_local_sym (output_bfd, sym, &msec, addend) - relocation; addend += msec->output_section->vma + msec->output_offset; - value = (value & ~ howto->dst_mask) | (addend & howto->dst_mask); - bfd_put_32 (input_bfd, value, contents + rel->r_offset); + + /* Cases here must match those in the preceeding + switch statement. */ + switch (r_type) + { + case R_ARM_MOVW_ABS_NC: + case R_ARM_MOVT_ABS: + value = (value & 0xfff0f000) | ((addend & 0xf000) << 4) + | (addend & 0xfff); + bfd_put_32 (input_bfd, value, contents + rel->r_offset); + break; + + case R_ARM_THM_MOVW_ABS_NC: + case R_ARM_THM_MOVT_ABS: + value = (value & 0xfbf08f00) | ((addend & 0xf700) << 4) + | (addend & 0xff) | ((addend & 0x0800) << 15); + bfd_put_16 (input_bfd, value >> 16, + contents + rel->r_offset); + bfd_put_16 (input_bfd, value, + contents + rel->r_offset + 2); + break; + + default: + value = (value & ~ howto->dst_mask) + | (addend & howto->dst_mask); + bfd_put_32 (input_bfd, value, contents + rel->r_offset); + break; + } } } else @@ -6724,130 +6746,6 @@ elf32_arm_relocate_section (bfd * output_bfd, return TRUE; } -/* Allocate/find an object attribute. */ -static aeabi_attribute * -elf32_arm_new_eabi_attr (bfd *abfd, int tag) -{ - aeabi_attribute *attr; - aeabi_attribute_list *list; - aeabi_attribute_list *p; - aeabi_attribute_list **lastp; - - - if (tag < NUM_KNOWN_ATTRIBUTES) - { - /* Knwon tags are preallocated. */ - attr = &elf32_arm_tdata (abfd)->known_eabi_attributes[tag]; - } - else - { - /* Create a new tag. */ - list = (aeabi_attribute_list *) - bfd_alloc (abfd, sizeof (aeabi_attribute_list)); - memset (list, 0, sizeof (aeabi_attribute_list)); - list->tag = tag; - /* Keep the tag list in order. */ - lastp = &elf32_arm_tdata (abfd)->other_eabi_attributes; - for (p = *lastp; p; p = p->next) - { - if (tag < p->tag) - break; - lastp = &p->next; - } - list->next = *lastp; - *lastp = list; - attr = &list->attr; - } - - return attr; -} - -int -elf32_arm_get_eabi_attr_int (bfd *abfd, int tag) -{ - aeabi_attribute_list *p; - - if (tag < NUM_KNOWN_ATTRIBUTES) - { - /* Knwon tags are preallocated. */ - return elf32_arm_tdata (abfd)->known_eabi_attributes[tag].i; - } - else - { - for (p = elf32_arm_tdata (abfd)->other_eabi_attributes; - p; - p = p->next) - { - if (tag == p->tag) - return p->attr.i; - if (tag < p->tag) - break; - } - return 0; - } -} - -void -elf32_arm_add_eabi_attr_int (bfd *abfd, int tag, unsigned int i) -{ - aeabi_attribute *attr; - - attr = elf32_arm_new_eabi_attr (abfd, tag); - attr->type = 1; - attr->i = i; -} - -static char * -attr_strdup (bfd *abfd, const char * s) -{ - char * p; - int len; - - len = strlen (s) + 1; - p = (char *)bfd_alloc(abfd, len); - return memcpy (p, s, len); -} - -void -elf32_arm_add_eabi_attr_string (bfd *abfd, int tag, const char *s) -{ - aeabi_attribute *attr; - - attr = elf32_arm_new_eabi_attr (abfd, tag); - attr->type = 2; - attr->s = attr_strdup (abfd, s); -} - -void -elf32_arm_add_eabi_attr_compat (bfd *abfd, unsigned int i, const char *s) -{ - aeabi_attribute_list *list; - aeabi_attribute_list *p; - aeabi_attribute_list **lastp; - - list = (aeabi_attribute_list *) - bfd_alloc (abfd, sizeof (aeabi_attribute_list)); - memset (list, 0, sizeof (aeabi_attribute_list)); - list->tag = Tag_compatibility; - list->attr.type = 3; - list->attr.i = i; - list->attr.s = attr_strdup (abfd, s); - - lastp = &elf32_arm_tdata (abfd)->other_eabi_attributes; - for (p = *lastp; p; p = p->next) - { - int cmp; - if (p->tag != Tag_compatibility) - break; - cmp = strcmp(s, p->attr.s); - if (cmp < 0 || (cmp == 0 && i < p->attr.i)) - break; - lastp = &p->next; - } - list->next = *lastp; - *lastp = list; -} - /* Set the right machine number. */ static bfd_boolean @@ -6898,49 +6796,6 @@ elf32_arm_set_private_flags (bfd *abfd, flagword flags) return TRUE; } -/* Copy the eabi object attribute from IBFD to OBFD. */ -static void -copy_eabi_attributes (bfd *ibfd, bfd *obfd) -{ - aeabi_attribute *in_attr; - aeabi_attribute *out_attr; - aeabi_attribute_list *list; - int i; - - in_attr = &elf32_arm_tdata (ibfd)->known_eabi_attributes[4]; - out_attr = &elf32_arm_tdata (obfd)->known_eabi_attributes[4]; - for (i = 4; i < NUM_KNOWN_ATTRIBUTES; i++) - { - out_attr->i = in_attr->i; - if (in_attr->s && *in_attr->s) - out_attr->s = attr_strdup (obfd, in_attr->s); - in_attr++; - out_attr++; - } - - for (list = elf32_arm_tdata (ibfd)->other_eabi_attributes; - list; - list = list->next) - { - in_attr = &list->attr; - switch (in_attr->type) - { - case 1: - elf32_arm_add_eabi_attr_int (obfd, list->tag, in_attr->i); - break; - case 2: - elf32_arm_add_eabi_attr_string (obfd, list->tag, in_attr->s); - break; - case 3: - elf32_arm_add_eabi_attr_compat (obfd, in_attr->i, in_attr->s); - break; - default: - abort(); - } - } -} - - /* Copy backend specific data from one object module to another. */ static bfd_boolean @@ -6949,8 +6804,7 @@ elf32_arm_copy_private_bfd_data (bfd *ibfd, bfd *obfd) flagword in_flags; flagword out_flags; - if ( bfd_get_flavour (ibfd) != bfd_target_elf_flavour - || bfd_get_flavour (obfd) != bfd_target_elf_flavour) + if (! is_arm_elf (ibfd) || ! is_arm_elf (obfd)) return TRUE; in_flags = elf_elfheader (ibfd)->e_flags; @@ -6992,8 +6846,8 @@ elf32_arm_copy_private_bfd_data (bfd *ibfd, bfd *obfd) elf_elfheader (obfd)->e_ident[EI_OSABI] = elf_elfheader (ibfd)->e_ident[EI_OSABI]; - /* Copy EABI object attributes. */ - copy_eabi_attributes (ibfd, obfd); + /* Copy object attributes. */ + _bfd_elf_copy_obj_attributes (ibfd, obfd); return TRUE; } @@ -7025,34 +6879,50 @@ enum AEABI_enum_forced_wide }; +/* Determine whether an object attribute tag takes an integer, a + string or both. */ +static int +elf32_arm_obj_attrs_arg_type (int tag) +{ + if (tag == Tag_compatibility) + return 3; + else if (tag == 4 || tag == 5) + return 2; + else if (tag < 32) + return 1; + else + return (tag & 1) != 0 ? 2 : 1; +} + /* Merge EABI object attributes from IBFD into OBFD. Raise an error if there are conflicting attributes. */ static bfd_boolean elf32_arm_merge_eabi_attributes (bfd *ibfd, bfd *obfd) { - aeabi_attribute *in_attr; - aeabi_attribute *out_attr; - aeabi_attribute_list *in_list; - aeabi_attribute_list *out_list; + obj_attribute *in_attr; + obj_attribute *out_attr; + obj_attribute_list *in_list; /* Some tags have 0 = don't care, 1 = strong requirement, 2 = weak requirement. */ static const int order_312[3] = {3, 1, 2}; + /* For use with Tag_VFP_arch. */ + static const int order_01243[5] = {0, 1, 2, 4, 3}; int i; - if (!elf32_arm_tdata (obfd)->known_eabi_attributes[0].i) + if (!elf_known_obj_attributes_proc (obfd)[0].i) { /* This is the first object. Copy the attributes. */ - copy_eabi_attributes (ibfd, obfd); + _bfd_elf_copy_obj_attributes (ibfd, obfd); /* Use the Tag_null value to indicate the attributes have been initialized. */ - elf32_arm_tdata (obfd)->known_eabi_attributes[0].i = 1; + elf_known_obj_attributes_proc (obfd)[0].i = 1; return TRUE; } - in_attr = elf32_arm_tdata (ibfd)->known_eabi_attributes; - out_attr = elf32_arm_tdata (obfd)->known_eabi_attributes; + in_attr = elf_known_obj_attributes_proc (ibfd); + out_attr = elf_known_obj_attributes_proc (obfd); /* This needs to happen before Tag_ABI_FP_number_model is merged. */ if (in_attr[Tag_ABI_VFP_args].i != out_attr[Tag_ABI_VFP_args].i) { @@ -7068,7 +6938,7 @@ elf32_arm_merge_eabi_attributes (bfd *ibfd, bfd *obfd) } } - for (i = 4; i < NUM_KNOWN_ATTRIBUTES; i++) + for (i = 4; i < NUM_KNOWN_OBJ_ATTRIBUTES; i++) { /* Merge this attribute with existing attributes. */ switch (i) @@ -7080,7 +6950,7 @@ elf32_arm_merge_eabi_attributes (bfd *ibfd, bfd *obfd) name is non-NULL. */ if (in_attr[Tag_CPU_arch].i > out_attr[Tag_CPU_arch].i && in_attr[i].s) - out_attr[i].s = attr_strdup(obfd, in_attr[i].s); + out_attr[i].s = _bfd_elf_attr_strdup (obfd, in_attr[i].s); break; case Tag_ABI_optimization_goals: @@ -7091,7 +6961,6 @@ elf32_arm_merge_eabi_attributes (bfd *ibfd, bfd *obfd) case Tag_CPU_arch: case Tag_ARM_ISA_use: case Tag_THUMB_ISA_use: - case Tag_VFP_arch: case Tag_WMMX_arch: case Tag_NEON_arch: /* ??? Do NEON and WMMX conflict? */ @@ -7119,6 +6988,11 @@ elf32_arm_merge_eabi_attributes (bfd *ibfd, bfd *obfd) if (in_attr[i].i) out_attr[i].i = in_attr[i].i; break; + case Tag_VFP_arch: + if (in_attr[i].i > 4 || out_attr[i].i > 4 + || order_01243[in_attr[i].i] > order_01243[out_attr[i].i]) + out_attr[i].i = in_attr[i].i; + break; case Tag_PCS_config: if (out_attr[i].i == 0) out_attr[i].i = in_attr[i].i; @@ -7193,10 +7067,15 @@ elf32_arm_merge_eabi_attributes (bfd *ibfd, bfd *obfd) out_attr[i].i = in_attr[i].i; } else if (in_attr[i].i != AEABI_enum_forced_wide - && out_attr[i].i != in_attr[i].i) + && out_attr[i].i != in_attr[i].i + && !elf_arm_tdata (obfd)->no_enum_size_warning) { + const char *aeabi_enum_names[] = + { "", "variable-size", "32-bit", "" }; _bfd_error_handler - (_("ERROR: %B: Conflicting enum sizes"), ibfd); + (_("warning: %B uses %s enums yet the output is to use %s enums; use of enum values across objects may fail"), + ibfd, aeabi_enum_names[in_attr[i].i], + aeabi_enum_names[out_attr[i].i]); } } break; @@ -7215,63 +7094,33 @@ elf32_arm_merge_eabi_attributes (bfd *ibfd, bfd *obfd) default: /* All known attributes should be explicitly covered. */ abort (); } - } - in_list = elf32_arm_tdata (ibfd)->other_eabi_attributes; - out_list = elf32_arm_tdata (ibfd)->other_eabi_attributes; - while (in_list && in_list->tag == Tag_compatibility) - { - in_attr = &in_list->attr; - if (in_attr->i == 0) - continue; - if (in_attr->i == 1) - { - _bfd_error_handler - (_("ERROR: %B: Must be processed by '%s' toolchain"), - ibfd, in_attr->s); - return FALSE; - } - if (!out_list || out_list->tag != Tag_compatibility - || strcmp (in_attr->s, out_list->attr.s) != 0) - { - /* Add this compatibility tag to the output. */ - elf32_arm_add_eabi_attr_compat (obfd, in_attr->i, in_attr->s); - continue; - } - out_attr = &out_list->attr; - /* Check all the input tags with the same identifier. */ - for (;;) - { - if (out_list->tag != Tag_compatibility - || in_attr->i != out_attr->i - || strcmp (in_attr->s, out_attr->s) != 0) - { - _bfd_error_handler - (_("ERROR: %B: Incompatible object tag '%s':%d"), - ibfd, in_attr->s, in_attr->i); - return FALSE; - } - in_list = in_list->next; - if (in_list->tag != Tag_compatibility - || strcmp (in_attr->s, in_list->attr.s) != 0) + if (in_attr[i].type && !out_attr[i].type) + switch (in_attr[i].type) + { + case 1: + if (out_attr[i].i) + out_attr[i].type = 1; break; - in_attr = &in_list->attr; - out_list = out_list->next; - if (out_list) - out_attr = &out_list->attr; - } - /* Check the output doesn't have extra tags with this identifier. */ - if (out_list && out_list->tag == Tag_compatibility - && strcmp (in_attr->s, out_list->attr.s) == 0) - { - _bfd_error_handler - (_("ERROR: %B: Incompatible object tag '%s':%d"), - ibfd, in_attr->s, out_list->attr.i); - return FALSE; - } + case 2: + if (out_attr[i].s) + out_attr[i].type = 2; + break; + + default: + abort (); + } } + /* Merge Tag_compatibility attributes and any common GNU ones. */ + _bfd_elf_merge_object_attributes (ibfd, obfd); + + /* Check for any attributes not known on ARM. */ + in_list = elf_other_obj_attributes_proc (ibfd); + while (in_list && in_list->tag == Tag_compatibility) + in_list = in_list->next; + for (; in_list; in_list = in_list->next) { if ((in_list->tag & 128) < 64) @@ -7315,8 +7164,7 @@ elf32_arm_merge_private_bfd_data (bfd * ibfd, bfd * obfd) if (! _bfd_generic_verify_endian_match (ibfd, obfd)) return FALSE; - if ( bfd_get_flavour (ibfd) != bfd_target_elf_flavour - || bfd_get_flavour (obfd) != bfd_target_elf_flavour) + if (! is_arm_elf (ibfd) || ! is_arm_elf (obfd)) return TRUE; if (!elf32_arm_merge_eabi_attributes (ibfd, obfd)) @@ -7703,14 +7551,19 @@ elf32_arm_gc_sweep_hook (bfd * abfd, const Elf_Internal_Rela *rel, *relend; struct elf32_arm_link_hash_table * globals; + if (info->relocatable) + return TRUE; + globals = elf32_arm_hash_table (info); elf_section_data (sec)->local_dynrel = NULL; - symtab_hdr = &elf_tdata (abfd)->symtab_hdr; + symtab_hdr = & elf_symtab_hdr (abfd); sym_hashes = elf_sym_hashes (abfd); local_got_refcounts = elf_local_got_refcounts (abfd); + check_use_blx(globals); + relend = relocs + sec->reloc_count; for (rel = relocs; rel < relend; rel++) { @@ -7761,6 +7614,8 @@ elf32_arm_gc_sweep_hook (bfd * abfd, case R_ARM_JUMP24: case R_ARM_PREL31: case R_ARM_THM_CALL: + case R_ARM_THM_JUMP24: + case R_ARM_THM_JUMP19: case R_ARM_MOVW_ABS_NC: case R_ARM_MOVT_ABS: case R_ARM_MOVW_PREL_NC: @@ -7782,7 +7637,11 @@ elf32_arm_gc_sweep_hook (bfd * abfd, if (h->plt.refcount > 0) { h->plt.refcount -= 1; - if (ELF32_R_TYPE (rel->r_info) == R_ARM_THM_CALL) + if (r_type == R_ARM_THM_CALL) + eh->plt_maybe_thumb_refcount--; + + if (r_type == R_ARM_THM_JUMP24 + || r_type == R_ARM_THM_JUMP19) eh->plt_thumb_refcount--; } @@ -7823,17 +7682,19 @@ elf32_arm_check_relocs (bfd *abfd, struct bfd_link_info *info, { Elf_Internal_Shdr *symtab_hdr; struct elf_link_hash_entry **sym_hashes; - struct elf_link_hash_entry **sym_hashes_end; const Elf_Internal_Rela *rel; const Elf_Internal_Rela *rel_end; bfd *dynobj; asection *sreloc; bfd_vma *local_got_offsets; struct elf32_arm_link_hash_table *htab; + bfd_boolean needs_plt; if (info->relocatable) return TRUE; + BFD_ASSERT (is_arm_elf (abfd)); + htab = elf32_arm_hash_table (info); sreloc = NULL; @@ -7849,13 +7710,8 @@ elf32_arm_check_relocs (bfd *abfd, struct bfd_link_info *info, dynobj = elf_hash_table (info)->dynobj; local_got_offsets = elf_local_got_offsets (abfd); - symtab_hdr = &elf_tdata (abfd)->symtab_hdr; + symtab_hdr = & elf_symtab_hdr (abfd); sym_hashes = elf_sym_hashes (abfd); - sym_hashes_end = sym_hashes - + symtab_hdr->sh_size / sizeof (Elf32_External_Sym); - - if (!elf_bad_symtab (abfd)) - sym_hashes_end -= symtab_hdr->sh_info; rel_end = relocs + sec->reloc_count; for (rel = relocs; rel < rel_end; rel++) @@ -7974,16 +7830,21 @@ elf32_arm_check_relocs (bfd *abfd, struct bfd_link_info *info, break; /* Fall through */ - case R_ARM_ABS32: - case R_ARM_ABS32_NOI: - case R_ARM_REL32: - case R_ARM_REL32_NOI: case R_ARM_PC24: case R_ARM_PLT32: case R_ARM_CALL: case R_ARM_JUMP24: case R_ARM_PREL31: case R_ARM_THM_CALL: + case R_ARM_THM_JUMP24: + case R_ARM_THM_JUMP19: + needs_plt = 1; + goto normal_reloc; + + case R_ARM_ABS32: + case R_ARM_ABS32_NOI: + case R_ARM_REL32: + case R_ARM_REL32_NOI: case R_ARM_MOVW_ABS_NC: case R_ARM_MOVT_ABS: case R_ARM_MOVW_PREL_NC: @@ -7992,6 +7853,9 @@ elf32_arm_check_relocs (bfd *abfd, struct bfd_link_info *info, case R_ARM_THM_MOVT_ABS: case R_ARM_THM_MOVW_PREL_NC: case R_ARM_THM_MOVT_PREL: + needs_plt = 0; + normal_reloc: + /* Should the interworking branches be listed here? */ if (h != NULL) { @@ -8008,17 +7872,22 @@ elf32_arm_check_relocs (bfd *abfd, struct bfd_link_info *info, refers to is in a different object. We can't tell for sure yet, because something later might force the symbol local. */ - if (r_type != R_ARM_ABS32 - && r_type != R_ARM_REL32 - && r_type != R_ARM_ABS32_NOI - && r_type != R_ARM_REL32_NOI) + if (needs_plt) h->needs_plt = 1; /* If we create a PLT entry, this relocation will reference it, even if it's an ABS32 relocation. */ h->plt.refcount += 1; + /* It's too early to use htab->use_blx here, so we have to + record possible blx references separately from + relocs that definitely need a thumb stub. */ + if (r_type == R_ARM_THM_CALL) + eh->plt_maybe_thumb_refcount += 1; + + if (r_type == R_ARM_THM_JUMP24 + || r_type == R_ARM_THM_JUMP19) eh->plt_thumb_refcount += 1; } @@ -8136,7 +8005,9 @@ elf32_arm_check_relocs (bfd *abfd, struct bfd_link_info *info, /* This relocation describes which C++ vtable entries are actually used. Record for later use during GC. */ case R_ARM_GNU_VTENTRY: - if (!bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_offset)) + BFD_ASSERT (h != NULL); + if (h != NULL + && !bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_offset)) return FALSE; break; } @@ -8166,15 +8037,18 @@ elf32_arm_gc_mark_extra_sections(struct bfd_link_info *info, { asection *o; - if (bfd_get_flavour (sub) != bfd_target_elf_flavour) + if (! is_arm_elf (sub)) continue; elf_shdrp = elf_elfsections (sub); for (o = sub->sections; o != NULL; o = o->next) { Elf_Internal_Shdr *hdr; + hdr = &elf_section_data (o)->this_hdr; - if (hdr->sh_type == SHT_ARM_EXIDX && hdr->sh_link + if (hdr->sh_type == SHT_ARM_EXIDX + && hdr->sh_link + && hdr->sh_link < elf_numsections (sub) && !o->gc_mark && elf_shdrp[hdr->sh_link]->bfd_section->gc_mark) { @@ -8335,7 +8209,6 @@ elf32_arm_adjust_dynamic_symbol (struct bfd_link_info * info, { bfd * dynobj; asection * s; - unsigned int power_of_two; struct elf32_arm_link_hash_entry * eh; struct elf32_arm_link_hash_table *globals; @@ -8370,6 +8243,7 @@ elf32_arm_adjust_dynamic_symbol (struct bfd_link_info * info, linkage table, and we can just do a PC24 reloc instead. */ h->plt.offset = (bfd_vma) -1; eh->plt_thumb_refcount = 0; + eh->plt_maybe_thumb_refcount = 0; h->needs_plt = 0; } @@ -8384,6 +8258,7 @@ elf32_arm_adjust_dynamic_symbol (struct bfd_link_info * info, the link may change h->type. So fix it now. */ h->plt.offset = (bfd_vma) -1; eh->plt_thumb_refcount = 0; + eh->plt_maybe_thumb_refcount = 0; } /* If this is a weak symbol, and there is a real definition, the @@ -8448,28 +8323,7 @@ elf32_arm_adjust_dynamic_symbol (struct bfd_link_info * info, h->needs_copy = 1; } - /* We need to figure out the alignment required for this symbol. I - have no idea how ELF linkers handle this. */ - power_of_two = bfd_log2 (h->size); - if (power_of_two > 3) - power_of_two = 3; - - /* Apply the required alignment. */ - s->size = BFD_ALIGN (s->size, (bfd_size_type) (1 << power_of_two)); - if (power_of_two > bfd_get_section_alignment (dynobj, s)) - { - if (! bfd_set_section_alignment (dynobj, s, power_of_two)) - return FALSE; - } - - /* Define the symbol as being at this point in the section. */ - h->root.u.def.section = s; - h->root.u.def.value = s->size; - - /* Increment the section size to make room for the symbol. */ - s->size += h->size; - - return TRUE; + return _bfd_elf_adjust_dynamic_copy (h, s); } /* Allocate space in .plt, .got and associated reloc sections for @@ -8482,6 +8336,7 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf) struct elf32_arm_link_hash_table *htab; struct elf32_arm_link_hash_entry *eh; struct elf32_arm_relocs_copied *p; + bfd_signed_vma thumb_refs; eh = (struct elf32_arm_link_hash_entry *) h; @@ -8523,7 +8378,11 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf) /* If we will insert a Thumb trampoline before this PLT, leave room for it. */ - if (!htab->use_blx && eh->plt_thumb_refcount > 0) + thumb_refs = eh->plt_thumb_refcount; + if (!htab->use_blx) + thumb_refs += eh->plt_maybe_thumb_refcount; + + if (thumb_refs > 0) { h->plt.offset += PLT_THUMB_STUB_SIZE; s->size += PLT_THUMB_STUB_SIZE; @@ -8700,7 +8559,7 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf) if (info->shared || htab->root.is_relocatable_executable) { - /* The only reloc thats uses pc_count are R_ARM_REL32 and + /* The only relocs that use pc_count are R_ARM_REL32 and R_ARM_REL32_NOI, which will appear on something like ".long foo - .". We want calls to protected symbols to resolve directly to the function rather than going via the plt. If people @@ -8721,6 +8580,19 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf) } } + if (elf32_arm_hash_table (info)->vxworks_p) + { + struct elf32_arm_relocs_copied **pp; + + for (pp = &eh->relocs_copied; (p = *pp) != NULL; ) + { + if (strcmp (p->section->output_section->name, ".tls_vars") == 0) + *pp = p->next; + else + pp = &p->next; + } + } + /* Also discard relocs on undefined weak syms with non-default visibility. */ if (eh->relocs_copied != NULL @@ -8872,8 +8744,9 @@ elf32_arm_size_dynamic_sections (bfd * output_bfd ATTRIBUTE_UNUSED, bfd_size_type locsymcount; Elf_Internal_Shdr *symtab_hdr; asection *srel; + bfd_boolean is_vxworks = elf32_arm_hash_table (info)->vxworks_p; - if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour) + if (! is_arm_elf (ibfd)) continue; for (s = ibfd->sections; s != NULL; s = s->next) @@ -8890,6 +8763,13 @@ elf32_arm_size_dynamic_sections (bfd * output_bfd ATTRIBUTE_UNUSED, linker script /DISCARD/, so we'll be discarding the relocs too. */ } + else if (is_vxworks + && strcmp (p->section->output_section->name, + ".tls_vars") == 0) + { + /* Relocations in vxworks .tls_vars sections are + handled specially by the loader. */ + } else if (p->count != 0) { srel = elf_section_data (p->section)->sreloc; @@ -8904,7 +8784,7 @@ elf32_arm_size_dynamic_sections (bfd * output_bfd ATTRIBUTE_UNUSED, if (!local_got) continue; - symtab_hdr = &elf_tdata (ibfd)->symtab_hdr; + symtab_hdr = & elf_symtab_hdr (ibfd); locsymcount = symtab_hdr->sh_info; end_local_got = local_got + locsymcount; local_tls_type = elf32_arm_local_got_tls_type (ibfd); @@ -8950,6 +8830,9 @@ elf32_arm_size_dynamic_sections (bfd * output_bfd ATTRIBUTE_UNUSED, /* Here we rummage through the found bfds to collect glue information. */ for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next) { + if (! is_arm_elf (ibfd)) + continue; + /* Initialise mapping tables for code/data. */ bfd_elf32_arm_init_maps (ibfd); @@ -9081,6 +8964,9 @@ elf32_arm_size_dynamic_sections (bfd * output_bfd ATTRIBUTE_UNUSED, if (!add_dynamic_entry (DT_TEXTREL, 0)) return FALSE; } + if (htab->vxworks_p + && !elf_vxworks_add_dynamic_entries (output_bfd, info)) + return FALSE; } #undef add_dynamic_entry @@ -9197,7 +9083,7 @@ elf32_arm_finish_dynamic_symbol (bfd * output_bfd, struct bfd_link_info * info, unsigned int i; bfd_vma val; - for (i = 0; i != htab->plt_entry_size / 4; i++) + for (i = 0; i != htab->plt_entry_size / 4; i++, ptr += 4) { val = elf32_arm_vxworks_exec_plt_entry[i]; if (i == 2) @@ -9232,6 +9118,7 @@ elf32_arm_finish_dynamic_symbol (bfd * output_bfd, struct bfd_link_info * info, } else { + bfd_signed_vma thumb_refs; /* Calculate the displacement between the PLT slot and the entry in the GOT. The eight-byte offset accounts for the value produced by adding to pc in the first instruction @@ -9240,7 +9127,11 @@ elf32_arm_finish_dynamic_symbol (bfd * output_bfd, struct bfd_link_info * info, BFD_ASSERT ((got_displacement & 0xf0000000) == 0); - if (!htab->use_blx && eh->plt_thumb_refcount > 0) + thumb_refs = eh->plt_thumb_refcount; + if (!htab->use_blx) + thumb_refs += eh->plt_maybe_thumb_refcount; + + if (thumb_refs > 0) { put_thumb_insn (htab, output_bfd, elf32_arm_plt_thumb_stub[0], ptr - 4); @@ -9418,6 +9309,9 @@ elf32_arm_finish_dynamic_sections (bfd * output_bfd, struct bfd_link_info * info unsigned int type; default: + if (htab->vxworks_p + && elf_vxworks_finish_dynamic_entry (output_bfd, &dyn)) + bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon); break; case DT_HASH: @@ -9744,125 +9638,9 @@ elf32_arm_fake_sections (bfd * abfd, Elf_Internal_Shdr * hdr, asection * sec) hdr->sh_type = SHT_ARM_EXIDX; hdr->sh_flags |= SHF_LINK_ORDER; } - else if (strcmp(name, ".ARM.attributes") == 0) - { - hdr->sh_type = SHT_ARM_ATTRIBUTES; - } return TRUE; } -/* Parse an Arm EABI attributes section. */ -static void -elf32_arm_parse_attributes (bfd *abfd, Elf_Internal_Shdr * hdr) -{ - bfd_byte *contents; - bfd_byte *p; - bfd_vma len; - - contents = bfd_malloc (hdr->sh_size); - if (!contents) - return; - if (!bfd_get_section_contents (abfd, hdr->bfd_section, contents, 0, - hdr->sh_size)) - { - free (contents); - return; - } - p = contents; - if (*(p++) == 'A') - { - len = hdr->sh_size - 1; - while (len > 0) - { - int namelen; - bfd_vma section_len; - - section_len = bfd_get_32 (abfd, p); - p += 4; - if (section_len > len) - section_len = len; - len -= section_len; - namelen = strlen ((char *)p) + 1; - section_len -= namelen + 4; - if (strcmp((char *)p, "aeabi") != 0) - { - /* Vendor section. Ignore it. */ - p += namelen + section_len; - } - else - { - p += namelen; - while (section_len > 0) - { - int tag; - unsigned int n; - unsigned int val; - bfd_vma subsection_len; - bfd_byte *end; - - tag = read_unsigned_leb128 (abfd, p, &n); - p += n; - subsection_len = bfd_get_32 (abfd, p); - p += 4; - if (subsection_len > section_len) - subsection_len = section_len; - section_len -= subsection_len; - subsection_len -= n + 4; - end = p + subsection_len; - switch (tag) - { - case Tag_File: - while (p < end) - { - bfd_boolean is_string; - - tag = read_unsigned_leb128 (abfd, p, &n); - p += n; - if (tag == 4 || tag == 5) - is_string = 1; - else if (tag < 32) - is_string = 0; - else - is_string = (tag & 1) != 0; - if (tag == Tag_compatibility) - { - val = read_unsigned_leb128 (abfd, p, &n); - p += n; - elf32_arm_add_eabi_attr_compat (abfd, val, - (char *)p); - p += strlen ((char *)p) + 1; - } - else if (is_string) - { - elf32_arm_add_eabi_attr_string (abfd, tag, - (char *)p); - p += strlen ((char *)p) + 1; - } - else - { - val = read_unsigned_leb128 (abfd, p, &n); - p += n; - elf32_arm_add_eabi_attr_int (abfd, tag, val); - } - } - break; - case Tag_Section: - case Tag_Symbol: - /* Don't have anywhere convenient to attach these. - Fall through for now. */ - default: - /* Ignore things we don't kow about. */ - p += subsection_len; - subsection_len = 0; - break; - } - } - } - } - } - free (contents); -} - /* Handle an ARM specific section when reading an object file. This is called when bfd_section_from_shdr finds a section with an unknown type. */ @@ -9892,8 +9670,6 @@ elf32_arm_section_from_shdr (bfd *abfd, if (! _bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex)) return FALSE; - if (hdr->sh_type == SHT_ARM_ATTRIBUTES) - elf32_arm_parse_attributes(abfd, hdr); return TRUE; } @@ -10003,8 +9779,8 @@ typedef struct { void *finfo; struct bfd_link_info *info; - int plt_shndx; - bfd_vma plt_offset; + asection *sec; + int sec_shndx; bfd_boolean (*func) (void *, const char *, Elf_Internal_Sym *, asection *, struct elf_link_hash_entry *); } output_arch_syminfo; @@ -10029,12 +9805,14 @@ elf32_arm_ouput_plt_map_sym (output_arch_syminfo *osi, Elf_Internal_Sym sym; htab = elf32_arm_hash_table (osi->info); - sym.st_value = osi->plt_offset + offset; + sym.st_value = osi->sec->output_section->vma + + osi->sec->output_offset + + offset; sym.st_size = 0; sym.st_other = 0; sym.st_info = ELF_ST_INFO (STB_LOCAL, STT_NOTYPE); - sym.st_shndx = osi->plt_shndx; - if (!osi->func (osi->finfo, names[type], &sym, htab->splt, NULL)) + sym.st_shndx = osi->sec_shndx; + if (!osi->func (osi->finfo, names[type], &sym, osi->sec, NULL)) return FALSE; return TRUE; } @@ -10086,10 +9864,13 @@ elf32_arm_output_plt_map (struct elf_link_hash_entry *h, void *inf) } else { - bfd_boolean thumb_stub; + bfd_signed_vma thumb_refs; - thumb_stub = eh->plt_thumb_refcount > 0 && !htab->use_blx; - if (thumb_stub) + thumb_refs = eh->plt_thumb_refcount; + if (!htab->use_blx) + thumb_refs += eh->plt_maybe_thumb_refcount; + + if (thumb_refs > 0) { if (!elf32_arm_ouput_plt_map_sym (osi, ARM_MAP_THUMB, addr - 4)) return FALSE; @@ -10103,7 +9884,7 @@ elf32_arm_output_plt_map (struct elf_link_hash_entry *h, void *inf) /* A three-word PLT with no Thumb thunk contains only Arm code, so only need to output a mapping symbol for the first PLT entry and entries with thumb thunks. */ - if (thumb_stub || addr == 20) + if (thumb_refs > 0 || addr == 20) { if (!elf32_arm_ouput_plt_map_sym (osi, ARM_MAP_ARM, addr)) return FALSE; @@ -10115,7 +9896,7 @@ elf32_arm_output_plt_map (struct elf_link_hash_entry *h, void *inf) } -/* Output mapping symbols for the PLT. */ +/* Output mapping symbols for linker generated sections. */ static bfd_boolean elf32_arm_output_arch_local_syms (bfd *output_bfd, @@ -10127,19 +9908,75 @@ elf32_arm_output_arch_local_syms (bfd *output_bfd, { output_arch_syminfo osi; struct elf32_arm_link_hash_table *htab; + bfd_vma offset; + bfd_size_type size; htab = elf32_arm_hash_table (info); - if (!htab->splt || htab->splt->size == 0) - return TRUE; - check_use_blx(htab); + osi.finfo = finfo; osi.info = info; osi.func = func; - osi.plt_shndx = _bfd_elf_section_from_bfd_section (output_bfd, - htab->splt->output_section); - osi.plt_offset = htab->splt->output_section->vma; + + /* ARM->Thumb glue. */ + if (htab->arm_glue_size > 0) + { + osi.sec = bfd_get_section_by_name (htab->bfd_of_glue_owner, + ARM2THUMB_GLUE_SECTION_NAME); + + osi.sec_shndx = _bfd_elf_section_from_bfd_section + (output_bfd, osi.sec->output_section); + if (info->shared || htab->root.is_relocatable_executable + || htab->pic_veneer) + size = ARM2THUMB_PIC_GLUE_SIZE; + else if (htab->use_blx) + size = ARM2THUMB_V5_STATIC_GLUE_SIZE; + else + size = ARM2THUMB_STATIC_GLUE_SIZE; + for (offset = 0; offset < htab->arm_glue_size; offset += size) + { + elf32_arm_ouput_plt_map_sym (&osi, ARM_MAP_ARM, offset); + elf32_arm_ouput_plt_map_sym (&osi, ARM_MAP_DATA, offset + size - 4); + } + } + + /* Thumb->ARM glue. */ + if (htab->thumb_glue_size > 0) + { + osi.sec = bfd_get_section_by_name (htab->bfd_of_glue_owner, + THUMB2ARM_GLUE_SECTION_NAME); + + osi.sec_shndx = _bfd_elf_section_from_bfd_section + (output_bfd, osi.sec->output_section); + size = THUMB2ARM_GLUE_SIZE; + + for (offset = 0; offset < htab->thumb_glue_size; offset += size) + { + elf32_arm_ouput_plt_map_sym (&osi, ARM_MAP_THUMB, offset); + elf32_arm_ouput_plt_map_sym (&osi, ARM_MAP_ARM, offset + 4); + } + } + + /* ARMv4 BX veneers. */ + if (htab->bx_glue_size > 0) + { + osi.sec = bfd_get_section_by_name (htab->bfd_of_glue_owner, + ARM_BX_GLUE_SECTION_NAME); + + osi.sec_shndx = _bfd_elf_section_from_bfd_section + (output_bfd, osi.sec->output_section); + + elf32_arm_ouput_plt_map_sym (&osi, ARM_MAP_ARM, 0); + } + + /* Finally, output mapping symbols for the PLT. */ + if (!htab->splt || htab->splt->size == 0) + return TRUE; + + osi.sec_shndx = _bfd_elf_section_from_bfd_section (output_bfd, + htab->splt->output_section); + osi.sec = htab->splt; /* Output mapping symbols for the plt header. SymbianOS does not have a plt header. */ if (htab->vxworks_p) @@ -10194,8 +10031,22 @@ elf32_arm_new_section_hook (bfd *abfd, asection *sec) static int elf32_arm_compare_mapping (const void * a, const void * b) { - return ((const elf32_arm_section_map *) a)->vma - > ((const elf32_arm_section_map *) b)->vma; + const elf32_arm_section_map *amap = (const elf32_arm_section_map *) a; + const elf32_arm_section_map *bmap = (const elf32_arm_section_map *) b; + + if (amap->vma > bmap->vma) + return 1; + else if (amap->vma < bmap->vma) + return -1; + else if (amap->type > bmap->type) + /* Ensure results do not depend on the host qsort for objects with + multiple mapping symbols at the same address by sorting on type + after vma. */ + return 1; + else if (amap->type < bmap->type) + return -1; + else + return 0; } @@ -10514,6 +10365,13 @@ elf32_arm_additional_program_headers (bfd *abfd, return 0; } +/* We have two function types: STT_FUNC and STT_ARM_TFUNC. */ +static bfd_boolean +elf32_arm_is_function_type (unsigned int type) +{ + return (type == STT_FUNC) || (type == STT_ARM_TFUNC); +} + /* We use this to override swap_symbol_in and swap_symbol_out. */ const struct elf_size_info elf32_arm_size_info = { sizeof (Elf32_External_Ehdr), @@ -10530,6 +10388,7 @@ const struct elf_size_info elf32_arm_size_info = { ELFCLASS32, EV_CURRENT, bfd_elf32_write_out_phdrs, bfd_elf32_write_shdrs_and_ehdr, + bfd_elf32_checksum_contents, bfd_elf32_write_relocs, elf32_arm_swap_symbol_in, elf32_arm_swap_symbol_out, @@ -10561,13 +10420,13 @@ const struct elf_size_info elf32_arm_size_info = { #define bfd_elf32_bfd_print_private_bfd_data elf32_arm_print_private_bfd_data #define bfd_elf32_bfd_link_hash_table_create elf32_arm_link_hash_table_create #define bfd_elf32_bfd_reloc_type_lookup elf32_arm_reloc_type_lookup +#define bfd_elf32_bfd_reloc_name_lookup elf32_arm_reloc_name_lookup #define bfd_elf32_find_nearest_line elf32_arm_find_nearest_line #define bfd_elf32_find_inliner_info elf32_arm_find_inliner_info #define bfd_elf32_new_section_hook elf32_arm_new_section_hook #define bfd_elf32_bfd_is_target_special_symbol elf32_arm_is_target_special_symbol #define bfd_elf32_close_and_cleanup elf32_arm_close_and_cleanup #define bfd_elf32_bfd_free_cached_info elf32_arm_bfd_free_cached_info -#define bfd_elf32_bfd_final_link elf32_arm_bfd_final_link #define elf_backend_get_symbol_type elf32_arm_get_symbol_type #define elf_backend_gc_mark_hook elf32_arm_gc_mark_hook @@ -10599,6 +10458,7 @@ const struct elf_size_info elf32_arm_size_info = { elf32_arm_output_arch_local_syms #define elf_backend_begin_write_processing \ elf32_arm_begin_write_processing +#define elf_backend_is_function_type elf32_arm_is_function_type #define elf_backend_can_refcount 1 #define elf_backend_can_gc_sections 1 @@ -10611,6 +10471,15 @@ const struct elf_size_info elf32_arm_size_info = { #define elf_backend_got_header_size 12 +#undef elf_backend_obj_attrs_vendor +#define elf_backend_obj_attrs_vendor "aeabi" +#undef elf_backend_obj_attrs_section +#define elf_backend_obj_attrs_section ".ARM.attributes" +#undef elf_backend_obj_attrs_arg_type +#define elf_backend_obj_attrs_arg_type elf32_arm_obj_attrs_arg_type +#undef elf_backend_obj_attrs_section_type +#define elf_backend_obj_attrs_section_type SHT_ARM_ATTRIBUTES + #include "elf32-target.h" /* VxWorks Targets */ @@ -10704,8 +10573,8 @@ elf32_arm_symbian_link_hash_table_create (bfd *abfd) = (struct elf32_arm_link_hash_table *)ret; /* There is no PLT header for Symbian OS. */ htab->plt_header_size = 0; - /* The PLT entries are each three instructions. */ - htab->plt_entry_size = 4 * NUM_ELEM (elf32_arm_symbian_plt_entry); + /* The PLT entries are each one instruction and one word. */ + htab->plt_entry_size = 4 * ARRAY_SIZE (elf32_arm_symbian_plt_entry); htab->symbian_p = 1; /* Symbian uses armv5t or above, so use_blx is always true. */ htab->use_blx = 1; @@ -10781,6 +10650,17 @@ elf32_arm_symbian_modify_segment_map (bfd *abfd, return elf32_arm_modify_segment_map (abfd, info); } +/* Return address for Ith PLT stub in section PLT, for relocation REL + or (bfd_vma) -1 if it should not be included. */ + +static bfd_vma +elf32_arm_symbian_plt_sym_val (bfd_vma i, const asection *plt, + const arelent *rel ATTRIBUTE_UNUSED) +{ + return plt->vma + 4 * ARRAY_SIZE (elf32_arm_symbian_plt_entry) * i; +} + + #undef elf32_bed #define elf32_bed elf32_arm_symbian_bed @@ -10817,6 +10697,9 @@ elf32_arm_symbian_modify_segment_map (bfd *abfd, #undef elf_backend_want_got_plt #define elf_backend_want_got_plt 0 +#undef elf_backend_plt_sym_val +#define elf_backend_plt_sym_val elf32_arm_symbian_plt_sym_val + #undef elf_backend_may_use_rel_p #define elf_backend_may_use_rel_p 1 #undef elf_backend_may_use_rela_p