/* 32-bit ELF support for ARM
- Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
- Free Software Foundation, Inc.
+ Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007,
+ 2008 Free Software Foundation, Inc.
This file is part of BFD, the Binary File Descriptor library.
bfd_elf_generic_reloc, /* special_function */
"R_ARM_MOVW_ABS_NC", /* name */
FALSE, /* partial_inplace */
- 0x0000ffff, /* src_mask */
- 0x0000ffff, /* dst_mask */
+ 0x000f0fff, /* src_mask */
+ 0x000f0fff, /* dst_mask */
FALSE), /* pcrel_offset */
HOWTO (R_ARM_MOVT_ABS, /* type */
bfd_elf_generic_reloc, /* special_function */
"R_ARM_MOVT_ABS", /* name */
FALSE, /* partial_inplace */
- 0x0000ffff, /* src_mask */
- 0x0000ffff, /* dst_mask */
+ 0x000f0fff, /* src_mask */
+ 0x000f0fff, /* dst_mask */
FALSE), /* pcrel_offset */
HOWTO (R_ARM_MOVW_PREL_NC, /* type */
bfd_elf_generic_reloc, /* special_function */
"R_ARM_MOVW_PREL_NC", /* name */
FALSE, /* partial_inplace */
- 0x0000ffff, /* src_mask */
- 0x0000ffff, /* dst_mask */
+ 0x000f0fff, /* src_mask */
+ 0x000f0fff, /* dst_mask */
TRUE), /* pcrel_offset */
HOWTO (R_ARM_MOVT_PREL, /* type */
bfd_elf_generic_reloc, /* special_function */
"R_ARM_MOVT_PREL", /* name */
FALSE, /* partial_inplace */
- 0x0000ffff, /* src_mask */
- 0x0000ffff, /* dst_mask */
+ 0x000f0fff, /* src_mask */
+ 0x000f0fff, /* dst_mask */
TRUE), /* pcrel_offset */
HOWTO (R_ARM_THM_MOVW_ABS_NC, /* type */
{BFD_RELOC_ARM_LDRS_SB_G2, R_ARM_LDRS_SB_G2},
{BFD_RELOC_ARM_LDC_SB_G0, R_ARM_LDC_SB_G0},
{BFD_RELOC_ARM_LDC_SB_G1, R_ARM_LDC_SB_G1},
- {BFD_RELOC_ARM_LDC_SB_G2, R_ARM_LDC_SB_G2}
+ {BFD_RELOC_ARM_LDC_SB_G2, R_ARM_LDC_SB_G2},
+ {BFD_RELOC_ARM_V4BX, R_ARM_V4BX}
};
static reloc_howto_type *
#define VFP11_ERRATUM_VENEER_SECTION_NAME ".vfp11_veneer"
#define VFP11_ERRATUM_VENEER_ENTRY_NAME "__vfp11_veneer_%x"
+#define ARM_BX_GLUE_SECTION_NAME ".v4_bx"
+#define ARM_BX_GLUE_ENTRY_NAME "__bx_r%d"
+
/* The name of the dynamic interpreter. This is put in the .interp
section. */
#define ELF_DYNAMIC_INTERPRETER "/usr/lib/ld.so.1"
/* The size of the thread control block. */
#define TCB_SIZE 8
-struct elf32_arm_obj_tdata
+struct elf_arm_obj_tdata
{
struct elf_obj_tdata root;
int no_enum_size_warning;
};
-#define elf32_arm_tdata(abfd) \
- ((struct elf32_arm_obj_tdata *) (abfd)->tdata.any)
+#define elf_arm_tdata(bfd) \
+ ((struct elf_arm_obj_tdata *) (bfd)->tdata.any)
-#define elf32_arm_local_got_tls_type(abfd) \
- (elf32_arm_tdata (abfd)->local_got_tls_type)
+#define elf32_arm_local_got_tls_type(bfd) \
+ (elf_arm_tdata (bfd)->local_got_tls_type)
+
+#define is_arm_elf(bfd) \
+ (bfd_get_flavour (bfd) == bfd_target_elf_flavour \
+ && elf_tdata (bfd) != NULL \
+ && elf_object_id (bfd) == ARM_ELF_TDATA)
static bfd_boolean
elf32_arm_mkobject (bfd *abfd)
{
- if (abfd->tdata.any == NULL)
- {
- bfd_size_type amt = sizeof (struct elf32_arm_obj_tdata);
- abfd->tdata.any = bfd_zalloc (abfd, amt);
- if (abfd->tdata.any == NULL)
- return FALSE;
- }
- return bfd_elf_mkobject (abfd);
+ return bfd_elf_allocate_object (abfd, sizeof (struct elf_arm_obj_tdata),
+ ARM_ELF_TDATA);
}
/* The ARM linker needs to keep track of the number of relocs that it
/* The size in bytes of the section containing the ARM-to-Thumb glue. */
bfd_size_type arm_glue_size;
+ /* The size in bytes of section containing the ARMv4 BX veneers. */
+ bfd_size_type bx_glue_size;
+
+ /* Offsets of ARMv4 BX veneers. Bit1 set if present, and Bit0 set when
+ veneer has been populated. */
+ bfd_vma bx_glue_offset[15];
+
/* The size in bytes of the section containing glue for VFP11 erratum
veneers. */
bfd_size_type vfp11_erratum_glue_size;
/* The relocation to use for R_ARM_TARGET2 relocations. */
int target2_reloc;
- /* Nonzero to fix BX instructions for ARMv4 targets. */
+ /* 0 = Ignore R_ARM_V4BX.
+ 1 = Convert BX to MOV PC.
+ 2 = Generate v4 interworing stubs. */
int fix_v4bx;
/* Nonzero if the ARM/Thumb BLX instructions are available for use. */
ret->srelplt2 = NULL;
ret->thumb_glue_size = 0;
ret->arm_glue_size = 0;
+ ret->bx_glue_size = 0;
+ memset (ret->bx_glue_offset, 0, sizeof(ret->bx_glue_offset));
ret->vfp11_fix = BFD_ARM_VFP11_FIX_NONE;
ret->vfp11_erratum_glue_size = 0;
ret->num_vfp11_fixes = 0;
#define VFP11_ERRATUM_VENEER_SIZE 8
+#define ARM_BX_VENEER_SIZE 12
+static const insn32 armbx1_tst_insn = 0xe3100001;
+static const insn32 armbx2_moveq_insn = 0x01a0f000;
+static const insn32 armbx3_bx_insn = 0xe12fff10;
+
#ifndef ELFARM_NABI_C_INCLUDED
bfd_boolean
bfd_elf32_arm_allocate_interworking_sections (struct bfd_link_info * info)
s->contents = foo;
}
+ if (globals->bx_glue_size != 0)
+ {
+ BFD_ASSERT (globals->bfd_of_glue_owner != NULL);
+
+ s = bfd_get_section_by_name (globals->bfd_of_glue_owner,
+ ARM_BX_GLUE_SECTION_NAME);
+
+ BFD_ASSERT (s != NULL);
+
+ foo = bfd_alloc (globals->bfd_of_glue_owner, globals->bx_glue_size);
+
+ BFD_ASSERT (s->size == globals->bx_glue_size);
+ s->contents = foo;
+ }
+
return TRUE;
}
}
+/* Allocate space for ARMv4 BX veneers. */
+
+static void
+record_arm_bx_glue (struct bfd_link_info * link_info, int reg)
+{
+ asection * s;
+ struct elf32_arm_link_hash_table *globals;
+ char *tmp_name;
+ struct elf_link_hash_entry *myh;
+ struct bfd_link_hash_entry *bh;
+ bfd_vma val;
+
+ /* BX PC does not need a veneer. */
+ if (reg == 15)
+ return;
+
+ globals = elf32_arm_hash_table (link_info);
+
+ BFD_ASSERT (globals != NULL);
+ BFD_ASSERT (globals->bfd_of_glue_owner != NULL);
+
+ /* Check if this veneer has already been allocated. */
+ if (globals->bx_glue_offset[reg])
+ return;
+
+ s = bfd_get_section_by_name
+ (globals->bfd_of_glue_owner, ARM_BX_GLUE_SECTION_NAME);
+
+ BFD_ASSERT (s != NULL);
+
+ /* Add symbol for veneer. */
+ tmp_name = bfd_malloc ((bfd_size_type) strlen (ARM_BX_GLUE_ENTRY_NAME) + 1);
+
+ BFD_ASSERT (tmp_name);
+
+ sprintf (tmp_name, ARM_BX_GLUE_ENTRY_NAME, reg);
+
+ myh = elf_link_hash_lookup
+ (&(globals)->root, tmp_name, FALSE, FALSE, FALSE);
+
+ BFD_ASSERT (myh == NULL);
+
+ bh = NULL;
+ val = globals->bx_glue_size;
+ _bfd_generic_link_add_one_symbol (link_info, globals->bfd_of_glue_owner,
+ tmp_name, BSF_FUNCTION | BSF_LOCAL, s, val,
+ NULL, TRUE, FALSE, &bh);
+
+ myh = (struct elf_link_hash_entry *) bh;
+ myh->type = ELF_ST_INFO (STB_LOCAL, STT_FUNC);
+ myh->forced_local = 1;
+
+ s->size += ARM_BX_VENEER_SIZE;
+ globals->bx_glue_offset[reg] = globals->bx_glue_size | 2;
+ globals->bx_glue_size += ARM_BX_VENEER_SIZE;
+}
+
+
/* Add an entry to the code/data map for section SEC. */
static void
if (sec_data->mapcount > sec_data->mapsize)
{
sec_data->mapsize *= 2;
- sec_data->map = bfd_realloc (sec_data->map, sec_data->mapsize
- * sizeof (elf32_arm_section_map));
+ sec_data->map = bfd_realloc_or_free (sec_data->map, sec_data->mapsize
+ * sizeof (elf32_arm_section_map));
+ }
+
+ if (sec_data->map)
+ {
+ sec_data->map[newidx].vma = vma;
+ sec_data->map[newidx].type = type;
}
-
- sec_data->map[newidx].vma = vma;
- sec_data->map[newidx].type = type;
}
sec->gc_mark = 1;
}
+ sec = bfd_get_section_by_name (abfd, ARM_BX_GLUE_SECTION_NAME);
+
+ if (sec == NULL)
+ {
+ flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY
+ | SEC_CODE | SEC_READONLY);
+
+ sec = bfd_make_section_with_flags (abfd,
+ ARM_BX_GLUE_SECTION_NAME,
+ flags);
+
+ if (sec == NULL
+ || !bfd_set_section_alignment (abfd, sec, 2))
+ return FALSE;
+
+ sec->gc_mark = 1;
+ }
+
return TRUE;
}
if ((sec->flags & SEC_EXCLUDE) != 0)
continue;
- symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
+ symtab_hdr = & elf_symtab_hdr (abfd);
/* Load the relocs. */
internal_relocs
&& r_type != R_ARM_CALL
&& r_type != R_ARM_JUMP24
&& r_type != R_ARM_THM_CALL
- && r_type != R_ARM_THM_JUMP24)
+ && r_type != R_ARM_THM_JUMP24
+ && (r_type != R_ARM_V4BX || globals->fix_v4bx < 2))
continue;
/* Get the section contents if we haven't done so already. */
}
}
+ if (r_type == R_ARM_V4BX)
+ {
+ int reg;
+
+ reg = bfd_get_32 (abfd, contents + irel->r_offset) & 0xf;
+ record_arm_bx_glue (link_info, reg);
+ continue;
+ }
+
/* If the relocation is not against a symbol it cannot concern us. */
h = NULL;
if ((abfd->flags & DYNAMIC) != 0)
return;
- hdr = &elf_tdata (abfd)->symtab_hdr;
+ hdr = & elf_symtab_hdr (abfd);
localsyms = hdr->sh_info;
/* Obtain a buffer full of symbols for this BFD. The hdr->sh_info field
if (link_info->relocatable)
return TRUE;
+ /* Skip if this bfd does not correspond to an ELF image. */
+ if (! is_arm_elf (abfd))
+ return TRUE;
+
/* We should have chosen a fix type by the time we get here. */
BFD_ASSERT (globals->vfp11_fix != BFD_ARM_VFP11_FIX_DEFAULT);
if (globals->vfp11_fix == BFD_ARM_VFP11_FIX_NONE)
return TRUE;
- /* Skip if this bfd does not correspond to an ELF image. */
- if (bfd_get_flavour (abfd) != bfd_target_elf_flavour)
- return TRUE;
-
for (sec = abfd->sections; sec != NULL; sec = sec->next)
{
unsigned int i, span, first_fmac = 0, veneer_of_insn = 0;
return;
/* Skip if this bfd does not correspond to an ELF image. */
- if (bfd_get_flavour (abfd) != bfd_target_elf_flavour)
+ if (! is_arm_elf (abfd))
return;
globals = elf32_arm_hash_table (link_info);
globals->vfp11_fix = vfp11_fix;
globals->pic_veneer = pic_veneer;
- elf32_arm_tdata (output_bfd)->no_enum_size_warning = no_enum_warn;
+ BFD_ASSERT (is_arm_elf (output_bfd));
+ elf_arm_tdata (output_bfd)->no_enum_size_warning = no_enum_warn;
}
-/* The thumb form of a long branch is a bit finicky, because the offset
- encoding is split over two fields, each in it's own instruction. They
- can occur in any order. So given a thumb form of long branch, and an
- offset, insert the offset into the thumb branch and return finished
- instruction.
-
- It takes two thumb instructions to encode the target address. Each has
- 11 bits to invest. The upper 11 bits are stored in one (identified by
- H-0.. see below), the lower 11 bits are stored in the other (identified
- by H-1).
-
- Combine together and shifted left by 1 (it's a half word address) and
- there you have it.
+/* Replace the target offset of a Thumb bl or b.w instruction. */
- Op: 1111 = F,
- H-0, upper address-0 = 000
- Op: 1111 = F,
- H-1, lower address-0 = 800
-
- They can be ordered either way, but the arm tools I've seen always put
- the lower one first. It probably doesn't matter. krk@cygnus.com
-
- XXX: Actually the order does matter. The second instruction (H-1)
- moves the computed address into the PC, so it must be the second one
- in the sequence. The problem, however is that whilst little endian code
- stores the instructions in HI then LOW order, big endian code does the
- reverse. nickc@cygnus.com. */
-
-#define LOW_HI_ORDER 0xF800F000
-#define HI_LOW_ORDER 0xF000F800
-
-static insn32
-insert_thumb_branch (insn32 br_insn, int rel_off)
+static void
+insert_thumb_branch (bfd *abfd, long int offset, bfd_byte *insn)
{
- unsigned int low_bits;
- unsigned int high_bits;
-
- BFD_ASSERT ((rel_off & 1) != 1);
-
- rel_off >>= 1; /* Half word aligned address. */
- low_bits = rel_off & 0x000007FF; /* The bottom 11 bits. */
- high_bits = (rel_off >> 11) & 0x000007FF; /* The top 11 bits. */
-
- if ((br_insn & LOW_HI_ORDER) == LOW_HI_ORDER)
- br_insn = LOW_HI_ORDER | (low_bits << 16) | high_bits;
- else if ((br_insn & HI_LOW_ORDER) == HI_LOW_ORDER)
- br_insn = HI_LOW_ORDER | (high_bits << 16) | low_bits;
- else
- /* FIXME: abort is probably not the right call. krk@cygnus.com */
- abort (); /* Error - not a valid branch instruction form. */
-
- return br_insn;
+ bfd_vma upper;
+ bfd_vma lower;
+ int reloc_sign;
+
+ BFD_ASSERT ((offset & 1) == 0);
+
+ upper = bfd_get_16 (abfd, insn);
+ lower = bfd_get_16 (abfd, insn + 2);
+ reloc_sign = (offset < 0) ? 1 : 0;
+ upper = (upper & ~(bfd_vma) 0x7ff)
+ | ((offset >> 12) & 0x3ff)
+ | (reloc_sign << 10);
+ lower = (lower & ~(bfd_vma) 0x2fff)
+ | (((!((offset >> 23) & 1)) ^ reloc_sign) << 13)
+ | (((!((offset >> 22) & 1)) ^ reloc_sign) << 11)
+ | ((offset >> 1) & 0x7ff);
+ bfd_put_16 (abfd, upper, insn);
+ bfd_put_16 (abfd, lower, insn + 2);
}
{
asection * s = 0;
bfd_vma my_offset;
- unsigned long int tmp;
long int ret_offset;
struct elf_link_hash_entry * myh;
struct elf32_arm_link_hash_table * globals;
/* Biassing for PC-relative addressing. */
- 8;
- tmp = bfd_get_32 (input_bfd, hit_data
- - input_section->vma);
-
- bfd_put_32 (output_bfd,
- (bfd_vma) insert_thumb_branch (tmp, ret_offset),
- hit_data - input_section->vma);
+ insert_thumb_branch (input_bfd, ret_offset, hit_data - input_section->vma);
return TRUE;
}
return TRUE;
}
+/* Populate ARMv4 BX veneers. Returns the absolute adress of the veneer. */
+
+static bfd_vma
+elf32_arm_bx_glue (struct bfd_link_info * info, int reg)
+{
+ bfd_byte *p;
+ bfd_vma glue_addr;
+ asection *s;
+ struct elf32_arm_link_hash_table *globals;
+
+ globals = elf32_arm_hash_table (info);
+
+ BFD_ASSERT (globals != NULL);
+ BFD_ASSERT (globals->bfd_of_glue_owner != NULL);
+
+ s = bfd_get_section_by_name (globals->bfd_of_glue_owner,
+ ARM_BX_GLUE_SECTION_NAME);
+ BFD_ASSERT (s != NULL);
+ BFD_ASSERT (s->contents != NULL);
+ BFD_ASSERT (s->output_section != NULL);
+
+ BFD_ASSERT (globals->bx_glue_offset[reg] & 2);
+
+ glue_addr = globals->bx_glue_offset[reg] & ~(bfd_vma)3;
+
+ if ((globals->bx_glue_offset[reg] & 1) == 0)
+ {
+ p = s->contents + glue_addr;
+ bfd_put_32 (globals->obfd, armbx1_tst_insn + (reg << 16), p);
+ bfd_put_32 (globals->obfd, armbx2_moveq_insn + reg, p + 4);
+ bfd_put_32 (globals->obfd, armbx3_bx_insn + reg, p + 8);
+ globals->bx_glue_offset[reg] |= 1;
+ }
+
+ return glue_addr + s->output_section->vma + s->output_offset;
+}
+
/* Generate Arm stubs for exported Thumb symbols. */
static void
elf32_arm_begin_write_processing (bfd *abfd ATTRIBUTE_UNUSED,
globals = elf32_arm_hash_table (info);
- /* Some relocation type map to different relocations depending on the
+ BFD_ASSERT (is_arm_elf (input_bfd));
+
+ /* Some relocation types map to different relocations depending on the
target. We pick the right one here. */
r_type = arm_real_reloc_type (globals, r_type);
if (r_type != howto->type)
sgot = bfd_get_section_by_name (dynobj, ".got");
splt = bfd_get_section_by_name (dynobj, ".plt");
}
- symtab_hdr = & elf_tdata (input_bfd)->symtab_hdr;
+ symtab_hdr = & elf_symtab_hdr (input_bfd);
sym_hashes = elf_sym_hashes (input_bfd);
local_got_offsets = elf_local_got_offsets (input_bfd);
r_symndx = ELF32_R_SYM (rel->r_info);
run time. */
if ((info->shared || globals->root.is_relocatable_executable)
&& (input_section->flags & SEC_ALLOC)
+ && !(elf32_arm_hash_table (info)->vxworks_p
+ && strcmp (input_section->output_section->name,
+ ".tls_vars") == 0)
&& ((r_type != R_ARM_REL32 && r_type != R_ARM_REL32_NOI)
|| !SYMBOL_CALLS_LOCAL (info, h))
&& (h == NULL
case R_ARM_V4BX:
if (globals->fix_v4bx)
- {
- bfd_vma insn = bfd_get_32 (input_bfd, hit_data);
+ {
+ bfd_vma insn = bfd_get_32 (input_bfd, hit_data);
- /* Ensure that we have a BX instruction. */
- BFD_ASSERT ((insn & 0x0ffffff0) == 0x012fff10);
+ /* Ensure that we have a BX instruction. */
+ BFD_ASSERT ((insn & 0x0ffffff0) == 0x012fff10);
- /* Preserve Rm (lowest four bits) and the condition code
- (highest four bits). Other bits encode MOV PC,Rm. */
- insn = (insn & 0xf000000f) | 0x01a0f000;
+ if (globals->fix_v4bx == 2 && (insn & 0xf) != 0xf)
+ {
+ /* Branch to veneer. */
+ bfd_vma glue_addr;
+ glue_addr = elf32_arm_bx_glue (info, insn & 0xf);
+ glue_addr -= input_section->output_section->vma
+ + input_section->output_offset
+ + rel->r_offset + 8;
+ insn = (insn & 0xf0000000) | 0x0a000000
+ | ((glue_addr >> 2) & 0x00ffffff);
+ }
+ else
+ {
+ /* Preserve Rm (lowest four bits) and the condition code
+ (highest four bits). Other bits encode MOV PC,Rm. */
+ insn = (insn & 0xf000000f) | 0x01a0f000;
+ }
- bfd_put_32 (input_bfd, insn, hit_data);
- }
+ bfd_put_32 (input_bfd, insn, hit_data);
+ }
return bfd_reloc_ok;
case R_ARM_MOVW_ABS_NC:
if (globals->use_rel)
{
addend = ((insn >> 4) & 0xf000) | (insn & 0xfff);
- signed_addend = (addend ^ 0x10000) - 0x10000;
+ signed_addend = (addend ^ 0x8000) - 0x8000;
}
value += signed_addend;
| ((insn >> 15) & 0x0800)
| ((insn >> 4) & 0x0700)
| (insn & 0x00ff);
- signed_addend = (addend ^ 0x10000) - 0x10000;
+ signed_addend = (addend ^ 0x8000) - 0x8000;
}
value += signed_addend;
globals = elf32_arm_hash_table (info);
- symtab_hdr = & elf_tdata (input_bfd)->symtab_hdr;
+ symtab_hdr = & elf_symtab_hdr (input_bfd);
sym_hashes = elf_sym_hashes (input_bfd);
rel = relocs;
asection *msec;
bfd_vma addend, value;
- if (howto->rightshift)
+ switch (r_type)
{
- (*_bfd_error_handler)
- (_("%B(%A+0x%lx): %s relocation against SEC_MERGE section"),
- input_bfd, input_section,
- (long) rel->r_offset, howto->name);
- return FALSE;
- }
+ case R_ARM_MOVW_ABS_NC:
+ case R_ARM_MOVT_ABS:
+ value = bfd_get_32 (input_bfd, contents + rel->r_offset);
+ addend = ((value & 0xf0000) >> 4) | (value & 0xfff);
+ addend = (addend ^ 0x8000) - 0x8000;
+ break;
- value = bfd_get_32 (input_bfd, contents + rel->r_offset);
+ case R_ARM_THM_MOVW_ABS_NC:
+ case R_ARM_THM_MOVT_ABS:
+ value = bfd_get_16 (input_bfd, contents + rel->r_offset)
+ << 16;
+ value |= bfd_get_16 (input_bfd,
+ contents + rel->r_offset + 2);
+ addend = ((value & 0xf7000) >> 4) | (value & 0xff)
+ | ((value & 0x04000000) >> 15);
+ addend = (addend ^ 0x8000) - 0x8000;
+ break;
- /* Get the (signed) value from the instruction. */
- addend = value & howto->src_mask;
- if (addend & ((howto->src_mask + 1) >> 1))
- {
- bfd_signed_vma mask;
+ default:
+ if (howto->rightshift
+ || (howto->src_mask & (howto->src_mask + 1)))
+ {
+ (*_bfd_error_handler)
+ (_("%B(%A+0x%lx): %s relocation against SEC_MERGE section"),
+ input_bfd, input_section,
+ (long) rel->r_offset, howto->name);
+ return FALSE;
+ }
+
+ value = bfd_get_32 (input_bfd, contents + rel->r_offset);
- mask = -1;
- mask &= ~ howto->src_mask;
- addend |= mask;
+ /* Get the (signed) value from the instruction. */
+ addend = value & howto->src_mask;
+ if (addend & ((howto->src_mask + 1) >> 1))
+ {
+ bfd_signed_vma mask;
+
+ mask = -1;
+ mask &= ~ howto->src_mask;
+ addend |= mask;
+ }
+ break;
}
+
msec = sec;
addend =
_bfd_elf_rel_local_sym (output_bfd, sym, &msec, addend)
- relocation;
addend += msec->output_section->vma + msec->output_offset;
- value = (value & ~ howto->dst_mask) | (addend & howto->dst_mask);
- bfd_put_32 (input_bfd, value, contents + rel->r_offset);
+
+ /* Cases here must match those in the preceeding
+ switch statement. */
+ switch (r_type)
+ {
+ case R_ARM_MOVW_ABS_NC:
+ case R_ARM_MOVT_ABS:
+ value = (value & 0xfff0f000) | ((addend & 0xf000) << 4)
+ | (addend & 0xfff);
+ bfd_put_32 (input_bfd, value, contents + rel->r_offset);
+ break;
+
+ case R_ARM_THM_MOVW_ABS_NC:
+ case R_ARM_THM_MOVT_ABS:
+ value = (value & 0xfbf08f00) | ((addend & 0xf700) << 4)
+ | (addend & 0xff) | ((addend & 0x0800) << 15);
+ bfd_put_16 (input_bfd, value >> 16,
+ contents + rel->r_offset);
+ bfd_put_16 (input_bfd, value,
+ contents + rel->r_offset + 2);
+ break;
+
+ default:
+ value = (value & ~ howto->dst_mask)
+ | (addend & howto->dst_mask);
+ bfd_put_32 (input_bfd, value, contents + rel->r_offset);
+ break;
+ }
}
}
else
flagword in_flags;
flagword out_flags;
- if ( bfd_get_flavour (ibfd) != bfd_target_elf_flavour
- || bfd_get_flavour (obfd) != bfd_target_elf_flavour)
+ if (! is_arm_elf (ibfd) || ! is_arm_elf (obfd))
return TRUE;
in_flags = elf_elfheader (ibfd)->e_flags;
/* Some tags have 0 = don't care, 1 = strong requirement,
2 = weak requirement. */
static const int order_312[3] = {3, 1, 2};
+ /* For use with Tag_VFP_arch. */
+ static const int order_01243[5] = {0, 1, 2, 4, 3};
int i;
if (!elf_known_obj_attributes_proc (obfd)[0].i)
case Tag_CPU_arch:
case Tag_ARM_ISA_use:
case Tag_THUMB_ISA_use:
- case Tag_VFP_arch:
case Tag_WMMX_arch:
case Tag_NEON_arch:
/* ??? Do NEON and WMMX conflict? */
if (in_attr[i].i)
out_attr[i].i = in_attr[i].i;
break;
+ case Tag_VFP_arch:
+ if (in_attr[i].i > 4 || out_attr[i].i > 4
+ || order_01243[in_attr[i].i] > order_01243[out_attr[i].i])
+ out_attr[i].i = in_attr[i].i;
+ break;
case Tag_PCS_config:
if (out_attr[i].i == 0)
out_attr[i].i = in_attr[i].i;
}
else if (in_attr[i].i != AEABI_enum_forced_wide
&& out_attr[i].i != in_attr[i].i
- && !elf32_arm_tdata (obfd)->no_enum_size_warning)
+ && !elf_arm_tdata (obfd)->no_enum_size_warning)
{
const char *aeabi_enum_names[] =
{ "", "variable-size", "32-bit", "" };
if (! _bfd_generic_verify_endian_match (ibfd, obfd))
return FALSE;
- if ( bfd_get_flavour (ibfd) != bfd_target_elf_flavour
- || bfd_get_flavour (obfd) != bfd_target_elf_flavour)
+ if (! is_arm_elf (ibfd) || ! is_arm_elf (obfd))
return TRUE;
if (!elf32_arm_merge_eabi_attributes (ibfd, obfd))
elf_section_data (sec)->local_dynrel = NULL;
- symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
+ symtab_hdr = & elf_symtab_hdr (abfd);
sym_hashes = elf_sym_hashes (abfd);
local_got_refcounts = elf_local_got_refcounts (abfd);
asection *sreloc;
bfd_vma *local_got_offsets;
struct elf32_arm_link_hash_table *htab;
+ bfd_boolean needs_plt;
if (info->relocatable)
return TRUE;
+ BFD_ASSERT (is_arm_elf (abfd));
+
htab = elf32_arm_hash_table (info);
sreloc = NULL;
dynobj = elf_hash_table (info)->dynobj;
local_got_offsets = elf_local_got_offsets (abfd);
- symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
+ symtab_hdr = & elf_symtab_hdr (abfd);
sym_hashes = elf_sym_hashes (abfd);
rel_end = relocs + sec->reloc_count;
break;
/* Fall through */
- case R_ARM_ABS32:
- case R_ARM_ABS32_NOI:
- case R_ARM_REL32:
- case R_ARM_REL32_NOI:
case R_ARM_PC24:
case R_ARM_PLT32:
case R_ARM_CALL:
case R_ARM_THM_CALL:
case R_ARM_THM_JUMP24:
case R_ARM_THM_JUMP19:
+ needs_plt = 1;
+ goto normal_reloc;
+
+ case R_ARM_ABS32:
+ case R_ARM_ABS32_NOI:
+ case R_ARM_REL32:
+ case R_ARM_REL32_NOI:
case R_ARM_MOVW_ABS_NC:
case R_ARM_MOVT_ABS:
case R_ARM_MOVW_PREL_NC:
case R_ARM_THM_MOVT_ABS:
case R_ARM_THM_MOVW_PREL_NC:
case R_ARM_THM_MOVT_PREL:
+ needs_plt = 0;
+ normal_reloc:
+
/* Should the interworking branches be listed here? */
if (h != NULL)
{
refers to is in a different object. We can't tell for
sure yet, because something later might force the
symbol local. */
- if (r_type != R_ARM_ABS32
- && r_type != R_ARM_REL32
- && r_type != R_ARM_ABS32_NOI
- && r_type != R_ARM_REL32_NOI
- && r_type != R_ARM_ABS12)
+ if (needs_plt)
h->needs_plt = 1;
/* If we create a PLT entry, this relocation will reference
{
asection *o;
- if (bfd_get_flavour (sub) != bfd_target_elf_flavour)
+ if (! is_arm_elf (sub))
continue;
elf_shdrp = elf_elfsections (sub);
for (o = sub->sections; o != NULL; o = o->next)
{
Elf_Internal_Shdr *hdr;
+
hdr = &elf_section_data (o)->this_hdr;
- if (hdr->sh_type == SHT_ARM_EXIDX && hdr->sh_link
+ if (hdr->sh_type == SHT_ARM_EXIDX
+ && hdr->sh_link
+ && hdr->sh_link < elf_numsections (sub)
&& !o->gc_mark
&& elf_shdrp[hdr->sh_link]->bfd_section->gc_mark)
{
}
}
+ if (elf32_arm_hash_table (info)->vxworks_p)
+ {
+ struct elf32_arm_relocs_copied **pp;
+
+ for (pp = &eh->relocs_copied; (p = *pp) != NULL; )
+ {
+ if (strcmp (p->section->output_section->name, ".tls_vars") == 0)
+ *pp = p->next;
+ else
+ pp = &p->next;
+ }
+ }
+
/* Also discard relocs on undefined weak syms with non-default
visibility. */
if (eh->relocs_copied != NULL
bfd_size_type locsymcount;
Elf_Internal_Shdr *symtab_hdr;
asection *srel;
+ bfd_boolean is_vxworks = elf32_arm_hash_table (info)->vxworks_p;
- if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour)
+ if (! is_arm_elf (ibfd))
continue;
for (s = ibfd->sections; s != NULL; s = s->next)
linker script /DISCARD/, so we'll be discarding
the relocs too. */
}
+ else if (is_vxworks
+ && strcmp (p->section->output_section->name,
+ ".tls_vars") == 0)
+ {
+ /* Relocations in vxworks .tls_vars sections are
+ handled specially by the loader. */
+ }
else if (p->count != 0)
{
srel = elf_section_data (p->section)->sreloc;
if (!local_got)
continue;
- symtab_hdr = &elf_tdata (ibfd)->symtab_hdr;
+ symtab_hdr = & elf_symtab_hdr (ibfd);
locsymcount = symtab_hdr->sh_info;
end_local_got = local_got + locsymcount;
local_tls_type = elf32_arm_local_got_tls_type (ibfd);
/* Here we rummage through the found bfds to collect glue information. */
for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next)
{
+ if (! is_arm_elf (ibfd))
+ continue;
+
/* Initialise mapping tables for code/data. */
bfd_elf32_arm_init_maps (ibfd);
}
}
+ /* ARMv4 BX veneers. */
+ if (htab->bx_glue_size > 0)
+ {
+ osi.sec = bfd_get_section_by_name (htab->bfd_of_glue_owner,
+ ARM_BX_GLUE_SECTION_NAME);
+
+ osi.sec_shndx = _bfd_elf_section_from_bfd_section
+ (output_bfd, osi.sec->output_section);
+
+ elf32_arm_ouput_plt_map_sym (&osi, ARM_MAP_ARM, 0);
+ }
+
/* Finally, output mapping symbols for the PLT. */
if (!htab->splt || htab->splt->size == 0)
return TRUE;
= (struct elf32_arm_link_hash_table *)ret;
/* There is no PLT header for Symbian OS. */
htab->plt_header_size = 0;
- /* The PLT entries are each three instructions. */
- htab->plt_entry_size = 4 * NUM_ELEM (elf32_arm_symbian_plt_entry);
+ /* The PLT entries are each one instruction and one word. */
+ htab->plt_entry_size = 4 * ARRAY_SIZE (elf32_arm_symbian_plt_entry);
htab->symbian_p = 1;
/* Symbian uses armv5t or above, so use_blx is always true. */
htab->use_blx = 1;
return elf32_arm_modify_segment_map (abfd, info);
}
+/* Return address for Ith PLT stub in section PLT, for relocation REL
+ or (bfd_vma) -1 if it should not be included. */
+
+static bfd_vma
+elf32_arm_symbian_plt_sym_val (bfd_vma i, const asection *plt,
+ const arelent *rel ATTRIBUTE_UNUSED)
+{
+ return plt->vma + 4 * ARRAY_SIZE (elf32_arm_symbian_plt_entry) * i;
+}
+
+
#undef elf32_bed
#define elf32_bed elf32_arm_symbian_bed
#undef elf_backend_want_got_plt
#define elf_backend_want_got_plt 0
+#undef elf_backend_plt_sym_val
+#define elf_backend_plt_sym_val elf32_arm_symbian_plt_sym_val
+
#undef elf_backend_may_use_rel_p
#define elf_backend_may_use_rel_p 1
#undef elf_backend_may_use_rela_p