X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=bfd%2Felf32-arm.c;h=b8abd5844c92cc7fa5a41f6ac4b0b2ee14e3ed70;hb=83b94be54133a44825c4c33975d8fb72e286ed16;hp=ab4755846666c55816aa8399d6e30df55945ed05;hpb=3cfad14c4a2b29ed8939e8e749b2a1c2f2b15f9e;p=deliverable%2Fbinutils-gdb.git diff --git a/bfd/elf32-arm.c b/bfd/elf32-arm.c index ab47558466..b8abd5844c 100644 --- a/bfd/elf32-arm.c +++ b/bfd/elf32-arm.c @@ -1,6 +1,6 @@ /* 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. @@ -696,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 */ @@ -710,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 */ @@ -724,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 */ @@ -738,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 */ @@ -1773,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 * @@ -1904,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" @@ -2065,7 +2069,7 @@ _arm_elf_section_data; /* The size of the thread control block. */ #define TCB_SIZE 8 -struct elf32_arm_obj_tdata +struct elf_arm_obj_tdata { struct elf_obj_tdata root; @@ -2076,23 +2080,22 @@ struct elf32_arm_obj_tdata 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 @@ -2129,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. */ @@ -2168,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; @@ -2185,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. */ @@ -2267,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; } @@ -2422,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) { @@ -2463,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; @@ -2513,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); @@ -2546,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); @@ -2618,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) @@ -2676,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; } @@ -2827,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 @@ -2847,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; } @@ -3050,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; } @@ -3107,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)) { @@ -3122,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; @@ -3136,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 @@ -3162,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. */ @@ -3179,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; @@ -3216,10 +3355,12 @@ 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; @@ -3267,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 @@ -3640,16 +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; - /* Skip if this bfd does not correspond to an ELF image. */ - if (bfd_get_flavour (abfd) != bfd_target_elf_flavour) - return TRUE; - for (sec = abfd->sections; sec != NULL; sec = sec->next) { unsigned int i, span, first_fmac = 0, veneer_of_insn = 0; @@ -3822,7 +3963,7 @@ bfd_elf32_arm_vfp11_fix_veneer_locations (bfd *abfd, return; /* Skip if this bfd does not correspond to an ELF image. */ - if (bfd_get_flavour (abfd) != bfd_target_elf_flavour) + if (! is_arm_elf (abfd)) return; globals = elf32_arm_hash_table (link_info); @@ -3925,61 +4066,33 @@ bfd_elf32_arm_set_target_relocs (struct bfd *output_bfd, globals->vfp11_fix = vfp11_fix; globals->pic_veneer = pic_veneer; - elf32_arm_tdata (output_bfd)->no_enum_size_warning = no_enum_warn; + BFD_ASSERT (is_arm_elf (output_bfd)); + elf_arm_tdata (output_bfd)->no_enum_size_warning = no_enum_warn; } -/* 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 +/* Replace the target offset of a Thumb bl or b.w instruction. */ -static insn32 -insert_thumb_branch (insn32 br_insn, int rel_off) +static void +insert_thumb_branch (bfd *abfd, long int offset, bfd_byte *insn) { - unsigned int low_bits; - unsigned int high_bits; - - BFD_ASSERT ((rel_off & 1) != 1); - - 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. */ - - 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. */ - - return br_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); } @@ -4028,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; @@ -4109,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; } @@ -4314,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, @@ -4510,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) @@ -4534,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); @@ -4606,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 @@ -4996,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; @@ -5059,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; @@ -5072,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; @@ -5085,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. */ @@ -5125,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 @@ -5152,79 +5303,6 @@ elf32_arm_final_link_relocate (reloc_howto_type * howto, } break; - case R_ARM_THM_JUMP24: - /* Thumb32 unconditional 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 glue the - two 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. */ - } - - /* ??? 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 & 0x01000000) >> 24; - bfd_vma I1 = (relocation & 0x00800000) >> 23; - bfd_vma I2 = (relocation & 0x00400000) >> 22; - bfd_vma hi = (relocation & 0x003ff000) >> 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; - } - - /* 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_JUMP19: /* Thumb32 conditional branch instruction. */ { @@ -5255,6 +5333,17 @@ elf32_arm_final_link_relocate (reloc_howto_type * howto, 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 use this for tail calls. */ @@ -5750,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: @@ -5781,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; @@ -5831,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; @@ -6266,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; @@ -6360,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; @@ -6412,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; - value = bfd_get_32 (input_bfd, contents + rel->r_offset); + 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; - /* Get the (signed) value from the instruction. */ - addend = value & howto->src_mask; - if (addend & ((howto->src_mask + 1) >> 1)) - { - bfd_signed_vma mask; + 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; + } - mask = -1; - mask &= ~ howto->src_mask; - addend |= mask; + value = bfd_get_32 (input_bfd, contents + rel->r_offset); + + /* 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 @@ -6649,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; @@ -6751,6 +6905,8 @@ elf32_arm_merge_eabi_attributes (bfd *ibfd, bfd *obfd) /* 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 (!elf_known_obj_attributes_proc (obfd)[0].i) @@ -6805,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? */ @@ -6833,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; @@ -6908,7 +7068,7 @@ elf32_arm_merge_eabi_attributes (bfd *ibfd, bfd *obfd) } else if (in_attr[i].i != AEABI_enum_forced_wide && out_attr[i].i != in_attr[i].i - && !elf32_arm_tdata (obfd)->no_enum_size_warning) + && !elf_arm_tdata (obfd)->no_enum_size_warning) { const char *aeabi_enum_names[] = { "", "variable-size", "32-bit", "" }; @@ -7004,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)) @@ -7392,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++) { @@ -7450,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: @@ -7471,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--; } @@ -7512,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; @@ -7538,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++) @@ -7663,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: @@ -7681,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) { @@ -7697,18 +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 - && r_type != R_ARM_ABS12) + 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; } @@ -7826,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; } @@ -7856,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) { @@ -8059,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; } @@ -8073,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 @@ -8150,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; @@ -8191,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; @@ -8389,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 @@ -8540,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) @@ -8558,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; @@ -8572,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); @@ -8618,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); @@ -8749,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 @@ -8900,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 @@ -8908,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); @@ -9086,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: @@ -9638,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_refs = eh->plt_thumb_refcount; + if (!htab->use_blx) + thumb_refs += eh->plt_maybe_thumb_refcount; - thumb_stub = eh->plt_thumb_refcount > 0 && !htab->use_blx; - if (thumb_stub) + if (thumb_refs > 0) { if (!elf32_arm_ouput_plt_map_sym (osi, ARM_MAP_THUMB, addr - 4)) return FALSE; @@ -9655,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; @@ -9729,6 +9958,18 @@ elf32_arm_output_arch_local_syms (bfd *output_bfd, } } + /* 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; @@ -9790,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; } @@ -10133,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, @@ -10317,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; @@ -10394,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 @@ -10430,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