X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=bfd%2Felf32-arm.h;h=0cf2f9ce4436588be868ec8436f8930e0891f6cc;hb=ba96a88f080f2b56a2cbe113ac9e287bfd21ef97;hp=d4e97d6b9bf26ef4278d6009deb09d8ab9559bef;hpb=5b64ad42d36e6d487e1f7287d37fbc243a178e72;p=deliverable%2Fbinutils-gdb.git diff --git a/bfd/elf32-arm.h b/bfd/elf32-arm.h index d4e97d6b9b..0cf2f9ce44 100644 --- a/bfd/elf32-arm.h +++ b/bfd/elf32-arm.h @@ -34,7 +34,9 @@ static int elf32_arm_get_symbol_type static struct bfd_link_hash_table *elf32_arm_link_hash_table_create PARAMS ((bfd *)); static bfd_reloc_status_type elf32_arm_final_link_relocate - PARAMS ((reloc_howto_type *, bfd *, bfd *, asection *, bfd_byte *, Elf_Internal_Rela *, bfd_vma, struct bfd_link_info *, asection *, const char *, unsigned char)); + PARAMS ((reloc_howto_type *, bfd *, bfd *, asection *, bfd_byte *, + Elf_Internal_Rela *, bfd_vma, struct bfd_link_info *, asection *, + const char *, unsigned char, struct elf_link_hash_entry *)); static insn32 insert_thumb_branch PARAMS ((insn32, int)); @@ -46,6 +48,8 @@ static void record_arm_to_thumb_glue PARAMS ((struct bfd_link_info *, struct elf_link_hash_entry *)); static void record_thumb_to_arm_glue PARAMS ((struct bfd_link_info *, struct elf_link_hash_entry *)); +static void elf32_arm_post_process_headers + PARAMS ((bfd *, struct bfd_link_info *)); /* The linker script knows the section names for placement. The entry_names are used to do simple name mangling on the stubs. @@ -113,7 +117,7 @@ struct elf32_arm_pcrel_relocs_copied bfd_size_type count; }; -/* arm ELF linker hash entry. */ +/* Arm ELF linker hash entry. */ struct elf32_arm_link_hash_entry { @@ -154,9 +158,43 @@ struct elf32_arm_link_hash_table /* An arbitary input BFD chosen to hold the glue sections. */ bfd * bfd_of_glue_owner; + + /* A boolean indicating whether knowledge of the ARM's pipeline + length should be applied by the linker. */ + int no_pipeline_knowledge; }; +/* Create an entry in an ARM ELF linker hash table. */ + +static struct bfd_hash_entry * +elf32_arm_link_hash_newfunc (entry, table, string) + struct bfd_hash_entry * entry; + struct bfd_hash_table * table; + const char * string; +{ + struct elf32_arm_link_hash_entry * ret = + (struct elf32_arm_link_hash_entry *) entry; + + /* Allocate the structure if it has not already been allocated by a + subclass. */ + if (ret == (struct elf32_arm_link_hash_entry *) NULL) + ret = ((struct elf32_arm_link_hash_entry *) + bfd_hash_allocate (table, + sizeof (struct elf32_arm_link_hash_entry))); + if (ret == (struct elf32_arm_link_hash_entry *) NULL) + return (struct bfd_hash_entry *) ret; + + /* Call the allocation method of the superclass. */ + ret = ((struct elf32_arm_link_hash_entry *) + _bfd_elf_link_hash_newfunc ((struct bfd_hash_entry *) ret, + table, string)); + if (ret != (struct elf32_arm_link_hash_entry *) NULL) + ret->pcrel_relocs_copied = NULL; + + return (struct bfd_hash_entry *) ret; +} + /* Create an ARM elf linker hash table */ static struct bfd_link_hash_table * @@ -171,7 +209,7 @@ elf32_arm_link_hash_table_create (abfd) return NULL; if (!_bfd_elf_link_hash_table_init (&ret->root, abfd, - _bfd_elf_link_hash_newfunc)) + elf32_arm_link_hash_newfunc)) { bfd_release (abfd, ret); return NULL; @@ -180,6 +218,7 @@ elf32_arm_link_hash_table_create (abfd) ret->thumb_glue_size = 0; ret->arm_glue_size = 0; ret->bfd_of_glue_owner = NULL; + ret->no_pipeline_knowledge = 0; return &ret->root.root; } @@ -531,9 +570,10 @@ bfd_elf32_arm_get_bfd_for_interworking (abfd, info) } boolean -bfd_elf32_arm_process_before_allocation (abfd, link_info) +bfd_elf32_arm_process_before_allocation (abfd, link_info, no_pipeline_knowledge) bfd *abfd; struct bfd_link_info *link_info; + int no_pipeline_knowledge; { Elf_Internal_Shdr *symtab_hdr; Elf_Internal_Rela *free_relocs = NULL; @@ -559,6 +599,8 @@ bfd_elf32_arm_process_before_allocation (abfd, link_info) BFD_ASSERT (globals != NULL); BFD_ASSERT (globals->bfd_of_glue_owner != NULL); + globals->no_pipeline_knowledge = no_pipeline_knowledge; + /* Rummage around all the relocs and map the glue vectors. */ sec = abfd->sections; @@ -591,7 +633,7 @@ bfd_elf32_arm_process_before_allocation (abfd, link_info) r_index = ELF32_R_SYM (irel->r_info); /* These are the only relocation types we care about */ - if (r_type != R_ARM_PC24 + if ( r_type != R_ARM_PC24 && r_type != R_ARM_THM_PC22) continue; @@ -943,7 +985,7 @@ elf32_arm_to_thumb_stub (info, name, input_bfd, output_bfd, input_section, static bfd_reloc_status_type elf32_arm_final_link_relocate (howto, input_bfd, output_bfd, input_section, contents, rel, value, - info, sym_sec, sym_name, sym_flags) + info, sym_sec, sym_name, sym_flags, h) reloc_howto_type * howto; bfd * input_bfd; bfd * output_bfd; @@ -955,6 +997,7 @@ elf32_arm_final_link_relocate (howto, input_bfd, output_bfd, asection * sym_sec; const char * sym_name; unsigned char sym_flags; + struct elf_link_hash_entry * h; { unsigned long r_type = howto->type; unsigned long r_symndx; @@ -966,8 +1009,11 @@ elf32_arm_final_link_relocate (howto, input_bfd, output_bfd, asection * sgot = NULL; asection * splt = NULL; asection * sreloc = NULL; - struct elf_link_hash_entry * h = NULL; bfd_vma addend; + bfd_signed_vma signed_addend; + struct elf32_arm_link_hash_table * globals; + + globals = elf32_arm_hash_table (info); dynobj = elf_hash_table (info)->dynobj; if (dynobj) @@ -981,9 +1027,18 @@ elf32_arm_final_link_relocate (howto, input_bfd, output_bfd, r_symndx = ELF32_R_SYM (rel->r_info); #ifdef USE_REL - addend = (bfd_get_32 (input_bfd, hit_data) & howto->src_mask); + addend = bfd_get_32 (input_bfd, hit_data) & howto->src_mask; + + if (addend & ((howto->src_mask + 1) >> 1)) + { + signed_addend = -1; + signed_addend &= ~ howto->src_mask; + signed_addend |= addend; + } + else + signed_addend = addend; #else - addend = rel->r_addend; + addend = signed_addend = rel->r_addend; #endif switch (r_type) @@ -1112,15 +1167,66 @@ elf32_arm_final_link_relocate (howto, input_bfd, output_bfd, input_section, hit_data, sym_sec, rel->r_offset, addend, value); return bfd_reloc_ok; } + + if ( strcmp (bfd_get_target (input_bfd), "elf32-littlearm-oabi") == 0 + || strcmp (bfd_get_target (input_bfd), "elf32-bigarm-oabi") == 0) + { + /* The old way of doing things. Trearing the addend as a + byte sized field and adding in the pipeline offset. */ + + value -= (input_section->output_section->vma + + input_section->output_offset); + value -= rel->r_offset; + value += addend; + + if (! globals->no_pipeline_knowledge) + value -= 8; + } + else + { + /* The ARM ELF ABI says that this reloc is computed as: S - P + A + where: + S is the address of the symbol in the relocation. + P is address of the instruction being relocated. + A is the addend (extracted from the instruction) in bytes. + + S is held in 'value'. + P is the base address of the section containing the instruction + plus the offset of the reloc into that section, ie: + (input_section->output_section->vma + + input_section->output_offset + + rel->r_offset). + A is the addend, converted into bytes, ie: + (signed_addend * 4) + + Note: None of these operations have knowledge of the pipeline + size of the processor, thus it is up to the assembler to encode + this information into the addend. */ + + value -= (input_section->output_section->vma + + input_section->output_offset); + value -= rel->r_offset; + value += (signed_addend << howto->size); + + /* Previous versions of this code also used to add in the pipeline + offset here. This is wrong because the linker is not supposed + to know about such things, and one day it might change. In order + to support old binaries that need the old behaviour however, so + we attempt to detect which ABI was used to create the reloc. */ + if (! globals->no_pipeline_knowledge) + { + Elf_Internal_Ehdr * i_ehdrp; /* Elf file header, internal form */ + + i_ehdrp = elf_elfheader (input_bfd); + + if (i_ehdrp->e_ident[EI_OSABI] == 0) + value -= 8; + } + } - value = value + addend; - value -= (input_section->output_section->vma - + input_section->output_offset + 8); - value -= rel->r_offset; - value = value >> howto->rightshift; - - value &= 0xffffff; - value |= (bfd_get_32 (input_bfd, hit_data) & 0xff000000); + value >>= howto->rightshift; + value &= howto->dst_mask; + value |= (bfd_get_32 (input_bfd, hit_data) & (~ howto->dst_mask)); break; case R_ARM_ABS32: @@ -1190,26 +1296,25 @@ elf32_arm_final_link_relocate (howto, input_bfd, output_bfd, case R_ARM_THM_PC22: /* Thumb BL (branch long instruction). */ { - bfd_vma relocation; - 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_vma src_mask = 0x007FFFFE; + bfd_vma relocation; + 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_vma src_mask = 0x007FFFFE; bfd_signed_vma reloc_signed_max = (1 << (howto->bitsize - 1)) - 1; - bfd_signed_vma reloc_signed_min = ~reloc_signed_max; - bfd_vma check; + bfd_signed_vma reloc_signed_min = ~ reloc_signed_max; + bfd_vma check; bfd_signed_vma signed_check; - bfd_vma add; - bfd_signed_vma signed_add; #ifdef USE_REL /* Need to refetch the addend and squish the two 11 bit pieces together. */ { - bfd_vma upper = bfd_get_16 (input_bfd, hit_data) & 0x7ff; - bfd_vma lower = bfd_get_16 (input_bfd, hit_data + 2) & 0x7ff; + bfd_vma upper = upper_insn & 0x7ff; + bfd_vma lower = lower_insn & 0x7ff; upper = (upper ^ 0x400) - 0x400; /* sign extend */ addend = (upper << 12) | (lower << 1); + signed_addend = addend; } #endif @@ -1223,13 +1328,30 @@ elf32_arm_final_link_relocate (howto, input_bfd, output_bfd, else return bfd_reloc_dangerous; } - - /* +4: pc is offset by 4 */ - relocation = value + addend + 4; + + relocation = value + signed_addend; + relocation -= (input_section->output_section->vma - + input_section->output_offset); - relocation -= rel->r_offset; - + + input_section->output_offset + + rel->r_offset); + + if (! globals->no_pipeline_knowledge) + { + Elf_Internal_Ehdr * i_ehdrp; /* Elf file header, internal form */ + + i_ehdrp = elf_elfheader (input_bfd); + + /* Previous versions of this code also used to add in the pipline + offset here. This is wrong because the linker is not supposed + to know about such things, and one day it might change. In order + to support old binaries that need the old behaviour however, so + we attempt to detect which ABI was used to create the reloc. */ + if ( strcmp (bfd_get_target (input_bfd), "elf32-littlearm-oabi") == 0 + || strcmp (bfd_get_target (input_bfd), "elf32-bigarm-oabi") == 0 + || i_ehdrp->e_ident[EI_OSABI] == 0) + relocation += 4; + } + check = relocation >> howto->rightshift; /* If this is a signed value, the rightshift just dropped @@ -1239,17 +1361,8 @@ elf32_arm_final_link_relocate (howto, input_bfd, output_bfd, else signed_check = check | ~((bfd_vma) -1 >> howto->rightshift); - add = ((upper_insn & 0x7ff) << 12) | ((lower_insn & 0x7ff) << 1); - /* sign extend */ - signed_add = (add ^ 0x400000) - 0x400000; - - /* Add the value from the object file. */ - signed_check += signed_add; - relocation += signed_add; - /* Assumes two's complement. */ - if (signed_check > reloc_signed_max - || signed_check < reloc_signed_min) + if (signed_check > reloc_signed_max || signed_check < reloc_signed_min) overflow = true; /* Put RELOCATION back into the insn. */ @@ -1483,25 +1596,25 @@ elf32_arm_relocate_section (output_bfd, info, input_bfd, input_section, relend = relocs + input_section->reloc_count; for (; rel < relend; rel++) { - int r_type; - reloc_howto_type * howto; - unsigned long r_symndx; - Elf_Internal_Sym * sym; - asection * sec; + int r_type; + reloc_howto_type * howto; + unsigned long r_symndx; + Elf_Internal_Sym * sym; + asection * sec; struct elf_link_hash_entry * h; - bfd_vma relocation; - bfd_reloc_status_type r; - + bfd_vma relocation; + bfd_reloc_status_type r; + arelent bfd_reloc; + r_symndx = ELF32_R_SYM (rel->r_info); - r_type = ELF32_R_TYPE (rel->r_info); + r_type = ELF32_R_TYPE (rel->r_info); - if (r_type == R_ARM_GNU_VTENTRY - || r_type == R_ARM_GNU_VTINHERIT ) + if ( r_type == R_ARM_GNU_VTENTRY + || r_type == R_ARM_GNU_VTINHERIT) continue; - /* ScottB: range check r_type here. */ - - howto = elf32_arm_howto_table + r_type; + elf32_arm_info_to_howto (input_bfd, & bfd_reloc, rel); + howto = bfd_reloc.howto; if (info->relocateable) { @@ -1519,7 +1632,7 @@ elf32_arm_relocate_section (output_bfd, info, input_bfd, input_section, { bfd_vma val; val = bfd_get_32 (input_bfd, contents + rel->r_offset); - val += (sec->output_offset + sym->st_value) >> howto->rightshift; + val += (sec->output_offset + sym->st_value); bfd_put_32 (input_bfd, val, contents + rel->r_offset); } #else @@ -1553,11 +1666,9 @@ elf32_arm_relocate_section (output_bfd, info, input_bfd, input_section, if (h->root.type == bfd_link_hash_defined || h->root.type == bfd_link_hash_defweak) { - sec = h->root.u.def.section; + int relocation_needed = 1; - relocation = (h->root.u.def.value - + sec->output_section->vma - + sec->output_offset); + sec = h->root.u.def.section; /* In these cases, we don't need the relocation value. We check specially because in some obscure cases @@ -1569,15 +1680,15 @@ elf32_arm_relocate_section (output_bfd, info, input_bfd, input_section, if (info->shared && ( (!info->symbolic && h->dynindx != -1) - || (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR == 0) + || (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0 ) && ((input_section->flags & SEC_ALLOC) != 0) ) - relocation = 0; + relocation_needed = 0; break; case R_ARM_GOTPC: - relocation = 0; + relocation_needed = 0; break; case R_ARM_GOT32: @@ -1587,12 +1698,12 @@ elf32_arm_relocate_section (output_bfd, info, input_bfd, input_section, || (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0 ) ) - relocation = 0; + relocation_needed = 0; break; case R_ARM_PLT32: if (h->plt.offset != (bfd_vma)-1) - relocation = 0; + relocation_needed = 0; break; default: @@ -1602,9 +1713,16 @@ elf32_arm_relocate_section (output_bfd, info, input_bfd, input_section, (_("%s: warning: unresolvable relocation against symbol `%s' from %s section"), bfd_get_filename (input_bfd), h->root.root.string, bfd_get_section_name (input_bfd, input_section)); - relocation = 0; + relocation_needed = 0; } } + + if (relocation_needed) + relocation = h->root.u.def.value + + sec->output_section->vma + + sec->output_offset; + else + relocation = 0; } else if (h->root.type == bfd_link_hash_undefweak) relocation = 0; @@ -1632,7 +1750,7 @@ elf32_arm_relocate_section (output_bfd, info, input_bfd, input_section, input_section, contents, rel, relocation, info, sec, name, (h ? ELF_ST_TYPE (h->type) : - ELF_ST_TYPE (sym->st_info))); + ELF_ST_TYPE (sym->st_info)), h); if (r != bfd_reloc_ok) { @@ -1957,6 +2075,8 @@ elf32_arm_gc_mark_hook (abfd, info, rel, h, sym) return NULL; } +/* Update the got entry reference counts for the section being removed. */ + static boolean elf32_arm_gc_sweep_hook (abfd, info, sec, relocs) bfd *abfd; @@ -1964,14 +2084,12 @@ elf32_arm_gc_sweep_hook (abfd, info, sec, relocs) asection *sec; const Elf_Internal_Rela *relocs; { - /* we don't use got and plt entries for armelf */ + /* We don't support garbage collection of GOT and PLT relocs yet. */ return true; } -/* Look through the relocs for a section during the first phase. - Since we don't do .gots or .plts, we just need to consider the - virtual table relocs for gc. */ - +/* Look through the relocs for a section during the first phase. */ + static boolean elf32_arm_check_relocs (abfd, info, sec, relocs) bfd * abfd; @@ -2978,6 +3096,20 @@ elf32_arm_finish_dynamic_sections (output_bfd, info) return true; } +static void +elf32_arm_post_process_headers (abfd, link_info) + bfd * abfd; + struct bfd_link_info * link_info; +{ + Elf_Internal_Ehdr * i_ehdrp; /* Elf file header, internal form */ + + i_ehdrp = elf_elfheader (abfd); + + i_ehdrp->e_ident[EI_OSABI] = ARM_ELF_OS_ABI_VERSION; + i_ehdrp->e_ident[EI_ABIVERSION] = ARM_ELF_ABI_VERSION; +} + + #define ELF_ARCH bfd_arch_arm #define ELF_MACHINE_CODE EM_ARM #define ELF_MAXPAGE_SIZE 0x8000 @@ -3001,6 +3133,7 @@ elf32_arm_finish_dynamic_sections (output_bfd, info) #define elf_backend_finish_dynamic_symbol elf32_arm_finish_dynamic_symbol #define elf_backend_finish_dynamic_sections elf32_arm_finish_dynamic_sections #define elf_backend_size_dynamic_sections elf32_arm_size_dynamic_sections +#define elf_backend_post_process_headers elf32_arm_post_process_headers #define elf_backend_can_gc_sections 1 #define elf_backend_plt_readonly 1