From ba96a88f080f2b56a2cbe113ac9e287bfd21ef97 Mon Sep 17 00:00:00 2001 From: Nick Clifton Date: Sat, 29 May 1999 11:05:22 +0000 Subject: [PATCH] Fix implementation of R_ARM_PC24 and R_ARM_THM_PC22 relocs to conform to spec. --- bfd/ChangeLog | 48 +++++++++++ bfd/bfd-in.h | 2 +- bfd/bfd-in2.h | 2 +- bfd/elf32-arm.h | 204 ++++++++++++++++++++++++++++++++++------------ bfd/elfarm-nabi.c | 6 +- bfd/elfarm-oabi.c | 31 +++---- 6 files changed, 221 insertions(+), 72 deletions(-) diff --git a/bfd/ChangeLog b/bfd/ChangeLog index 621fa91a2a..73d0c51232 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,51 @@ +1999-05-29 Nick Clifton + + * bfd-in.h: Amend prototype for + bfd_elf32_arm_process_before_allocation . + * bfd-in.h: Regenerate. + + * elfarm-oabi.c (NUM_ELEM): New macro: Compute the number of + elements in a fixed sized array. + (ARM_ELF_ABI_VERSION): Define. + (ARM_ELF_OS_ABI_VERSION): Define. + (R_ARM_THM_ABS5): Fix rightshift and size. + (R_ARM_THM_PC22): Fix size. + (R_ARM_PLT32): Define Howto. + (find_howto): New function: Locate a howto based on a reloc + number. + (elf32_arm_info_to_howto): Use find_howto if necessary. + (elf32_arm_reloc_map): Change type of field bfd_reloc_val to + bfd_reloc_code_real_type. + (elf32_arm_reloc_map[]): Add entries for BFD_RELOC_VTABLE_INHERIT + and BFD_RELOC_VTABLE_ENTRY. + (elf32_arm_reloc_type_lookup): Use find_howto if necessary. + + * elfarm-nabi.c (NUM_ELEM): New macro: Compute the number of + elements in a fixed sized array. + (ARM_ELF_ABI_VERSION): Define. + (ARM_ELF_OS_ABI_VERSION): Define. + (R_ARM_THM_ABS5): Fix rightshift and size. + (R_ARM_THM_PC22): Fix size. + (elf32_arm_info_to_howto_rel): Rename to elf32_arm_info_to_howto. + (elf32_arm_reloc_map): Change type of field bfd_reloc_val to + bfd_reloc_code_real_type. + + * elf32-arm.h (struct elf32_arm_link_hash_table): Add new field: + no_pipeline_knowledge. + (elf32_arm_link_hash_create): Initialise new field to zero. + (bfd_elf32_arm_process_before_allocation): Add new paraemter: + no_pipeline_knowledge. Use this parameter to initialise the field + in the globals data structure. + (elf32_arm_final_link_relocate): Only add in pipeline offset if + no_pipeline_knowledge is false and the binary is from an old + toolchain. + (elf32_arm_merge_private_data): Generate an error if an attempt is + made to linl together big endian and little endian code. + (elf32_arm_post_process_headers): New function: Initialise the + EI_OSABI and EI_ABIVERSION fields of the newly created ELF program + header. + (elf_backend_post_process_headers): Define. + 1999-05-28 Nick Clifton * elf-bfd.h (struct elf_backend_data): Add new field: diff --git a/bfd/bfd-in.h b/bfd/bfd-in.h index 46085d0e41..7c18ce79da 100644 --- a/bfd/bfd-in.h +++ b/bfd/bfd-in.h @@ -725,7 +725,7 @@ extern boolean bfd_arm_get_bfd_for_interworking /* ELF ARM Interworking support. Called from linker. */ extern boolean bfd_elf32_arm_allocate_interworking_sections - PARAMS ((struct bfd_link_info *)); + PARAMS ((struct bfd_link_info *, int)); extern boolean bfd_elf32_arm_process_before_allocation PARAMS ((bfd *, struct bfd_link_info *)); diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h index 044e1a5543..7e915e994f 100644 --- a/bfd/bfd-in2.h +++ b/bfd/bfd-in2.h @@ -728,7 +728,7 @@ extern boolean bfd_arm_get_bfd_for_interworking PARAMS ((struct bfd_link_info *)); extern boolean bfd_elf32_arm_process_before_allocation - PARAMS ((bfd *, struct bfd_link_info *)); + PARAMS ((bfd *, struct bfd_link_info *, int)); extern boolean bfd_elf32_arm_get_bfd_for_interworking PARAMS ((bfd *, struct bfd_link_info *)); diff --git a/bfd/elf32-arm.h b/bfd/elf32-arm.h index 120b387a50..0cf2f9ce44 100644 --- a/bfd/elf32-arm.h +++ b/bfd/elf32-arm.h @@ -48,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. @@ -115,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 { @@ -156,6 +158,10 @@ 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; }; @@ -212,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; } @@ -563,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; @@ -591,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; @@ -623,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; @@ -1000,6 +1010,10 @@ elf32_arm_final_link_relocate (howto, input_bfd, output_bfd, asection * splt = NULL; asection * sreloc = 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) @@ -1013,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) @@ -1144,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: @@ -1222,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 @@ -1255,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 @@ -1271,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. */ @@ -1515,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) { @@ -3015,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 @@ -3038,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 diff --git a/bfd/elfarm-nabi.c b/bfd/elfarm-nabi.c index 5952e74e5e..87cfada113 100644 --- a/bfd/elfarm-nabi.c +++ b/bfd/elfarm-nabi.c @@ -35,8 +35,10 @@ #define TARGET_BIG_NAME "elf32-bigarm" #define elf_info_to_howto 0 -#define elf_info_to_howto_rel elf32_arm_info_to_howto_rel +#define elf_info_to_howto_rel elf32_arm_info_to_howto +#define ARM_ELF_ABI_VERSION 0 +#define ARM_ELF_OS_ABI_VERSION ELFOSABI_ARM static reloc_howto_type * elf32_arm_reloc_type_lookup PARAMS ((bfd * abfd, bfd_reloc_code_real_type code)); @@ -574,7 +576,7 @@ static reloc_howto_type elf32_arm_thm_pc9_howto = static void -elf32_arm_info_to_howto_rel (abfd, bfd_reloc, elf_reloc) +elf32_arm_info_to_howto (abfd, bfd_reloc, elf_reloc) bfd * abfd; arelent * bfd_reloc; Elf32_Internal_Rel * elf_reloc; diff --git a/bfd/elfarm-oabi.c b/bfd/elfarm-oabi.c index 84960758a6..911d83e727 100644 --- a/bfd/elfarm-oabi.c +++ b/bfd/elfarm-oabi.c @@ -37,6 +37,9 @@ #define elf_info_to_howto elf32_arm_info_to_howto #define elf_info_to_howto_rel 0 +#define ARM_ELF_ABI_VERSION 0 +#define ARM_ELF_OS_ABI_VERSION 0 + static reloc_howto_type elf32_arm_howto_table[] = { /* No relocation */ @@ -177,7 +180,7 @@ static reloc_howto_type elf32_arm_howto_table[] = 0, /* bitsize */ false, /* pc_relative */ 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ + complain_overflow_dont,/* complain_on_overflow */ bfd_elf_generic_reloc, /* special_function */ "R_ARM_SBREL32", /* name */ false, /* partial_inplace */ @@ -373,19 +376,19 @@ struct elf32_arm_reloc_map static const struct elf32_arm_reloc_map elf32_arm_reloc_map[] = { - {BFD_RELOC_NONE, R_ARM_NONE,}, - {BFD_RELOC_ARM_PCREL_BRANCH, R_ARM_PC24,}, - {BFD_RELOC_32, R_ARM_ABS32,}, - {BFD_RELOC_32_PCREL, R_ARM_REL32,}, - {BFD_RELOC_8, R_ARM_ABS8,}, - {BFD_RELOC_16, R_ARM_ABS16,}, - {BFD_RELOC_ARM_OFFSET_IMM, R_ARM_ABS12,}, - {BFD_RELOC_ARM_THUMB_OFFSET, R_ARM_THM_ABS5,}, - {BFD_RELOC_THUMB_PCREL_BRANCH23, R_ARM_THM_PC22,}, - {BFD_RELOC_NONE, R_ARM_SBREL32,}, - {BFD_RELOC_NONE, R_ARM_AMP_VCALL9,}, - {BFD_RELOC_THUMB_PCREL_BRANCH12, R_ARM_THM_PC11,}, - {BFD_RELOC_THUMB_PCREL_BRANCH9, R_ARM_THM_PC9,}, + {BFD_RELOC_NONE, R_ARM_NONE }, + {BFD_RELOC_ARM_PCREL_BRANCH, R_ARM_PC24 }, + {BFD_RELOC_32, R_ARM_ABS32 }, + {BFD_RELOC_32_PCREL, R_ARM_REL32 }, + {BFD_RELOC_8, R_ARM_ABS8 }, + {BFD_RELOC_16, R_ARM_ABS16 }, + {BFD_RELOC_ARM_OFFSET_IMM, R_ARM_ABS12 }, + {BFD_RELOC_ARM_THUMB_OFFSET, R_ARM_THM_ABS5 }, + {BFD_RELOC_THUMB_PCREL_BRANCH23, R_ARM_THM_PC22 }, + {BFD_RELOC_NONE, R_ARM_SBREL32 }, + {BFD_RELOC_NONE, R_ARM_AMP_VCALL9 }, + {BFD_RELOC_THUMB_PCREL_BRANCH12, R_ARM_THM_PC11 }, + {BFD_RELOC_THUMB_PCREL_BRANCH9, R_ARM_THM_PC9 }, {BFD_RELOC_VTABLE_INHERIT, R_ARM_GNU_VTINHERIT }, {BFD_RELOC_VTABLE_ENTRY, R_ARM_GNU_VTENTRY } }; -- 2.34.1