aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNick Clifton <nickc@redhat.com>1999-05-29 11:05:22 +0000
committerNick Clifton <nickc@redhat.com>1999-05-29 11:05:22 +0000
commitba96a88f080f2b56a2cbe113ac9e287bfd21ef97 (patch)
tree7480432b5a432fed735ba4cfad8bc15b5a06d974
parent7ca69e9e10ef290eb3dd62a1e6bebbe4c87fa202 (diff)
downloadfsf-binutils-gdb-ba96a88f080f2b56a2cbe113ac9e287bfd21ef97.zip
fsf-binutils-gdb-ba96a88f080f2b56a2cbe113ac9e287bfd21ef97.tar.gz
fsf-binutils-gdb-ba96a88f080f2b56a2cbe113ac9e287bfd21ef97.tar.bz2
Fix implementation of R_ARM_PC24 and R_ARM_THM_PC22 relocs to conform to spec.
-rw-r--r--bfd/ChangeLog48
-rw-r--r--bfd/bfd-in.h2
-rw-r--r--bfd/bfd-in2.h2
-rw-r--r--bfd/elf32-arm.h204
-rw-r--r--bfd/elfarm-nabi.c6
-rw-r--r--bfd/elfarm-oabi.c31
6 files changed, 221 insertions, 72 deletions
diff --git a/bfd/ChangeLog b/bfd/ChangeLog
index 621fa91..73d0c51 100644
--- a/bfd/ChangeLog
+++ b/bfd/ChangeLog
@@ -1,3 +1,51 @@
+1999-05-29 Nick Clifton <nickc@cygnus.com>
+
+ * 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 <nickc@cygnus.com>
* elf-bfd.h (struct elf_backend_data): Add new field:
diff --git a/bfd/bfd-in.h b/bfd/bfd-in.h
index 46085d0..7c18ce7 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 044e1a5..7e915e9 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 120b387..0cf2f9c 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 5952e74..87cfada 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 8496075..911d83e 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 }
};