+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:
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.
bfd_size_type count;
};
-/* arm ELF linker hash entry. */
+/* Arm ELF linker hash entry. */
struct elf32_arm_link_hash_entry
{
/* 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;
};
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;
}
}
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;
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;
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;
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)
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)
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:
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
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
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. */
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)
{
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
#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
#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 */
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 */
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 }
};