Commit ba96a88f authored by Nick Clifton's avatar Nick Clifton
Browse files

Fix implementation of R_ARM_PC24 and R_ARM_THM_PC22 relocs to conform to spec.

parent 7ca69e9e
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:
......
......@@ -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 *));
......
......@@ -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 *));
......
......@@ -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
......
......@@ -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;
......
......@@ -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 }
};
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment