/* 32-bit ELF support for ARM
- Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004
+ Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
Free Software Foundation, Inc.
This file is part of BFD, the Binary File Descriptor library.
#define NUM_ELEM(a) (sizeof (a) / (sizeof (a)[0]))
#endif
-#define USE_REL 1
-
#define elf_info_to_howto 0
#define elf_info_to_howto_rel elf32_arm_info_to_howto
#define elf_backend_grok_prstatus elf32_arm_nabi_grok_prstatus
#define elf_backend_grok_psinfo elf32_arm_nabi_grok_psinfo
-#ifndef USE_REL
-#define USE_REL 0
-#endif
-
typedef unsigned long int insn32;
typedef unsigned short int insn16;
address spaces. */
static const bfd_vma elf32_arm_symbian_plt_entry [] =
{
- 0xe51ff004, /* ldr pr, [pc, #-4] */
+ 0xe51ff004, /* ldr pc, [pc, #-4] */
0x00000000, /* dcd R_ARM_GLOB_DAT(X) */
};
/* The relocation to use for R_ARM_TARGET2 relocations. */
int target2_reloc;
+ /* Nonzero to fix BX instructions for ARMv4 targets. */
+ int fix_v4bx;
+
/* The number of bytes in the initial entry in the PLT. */
bfd_size_type plt_header_size;
/* True if the target system is Symbian OS. */
int symbian_p;
+ /* True if the target uses REL relocations. */
+ int use_rel;
+
/* Short-cuts to get to dynamic linker sections. */
asection *sgot;
asection *sgotplt;
ret->plt_entry_size = 12;
#endif
ret->symbian_p = 0;
+ ret->use_rel = 1;
ret->sym_sec.abfd = NULL;
ret->obfd = abfd;
void
bfd_elf32_arm_set_target_relocs (struct bfd_link_info *link_info,
int target1_is_rel,
- char * target2_type)
+ char * target2_type,
+ int fix_v4bx)
{
struct elf32_arm_link_hash_table *globals;
_bfd_error_handler (_("Invalid TARGET2 relocation type '%s'."),
target2_type);
}
+ globals->fix_v4bx = fix_v4bx;
}
#endif
local_got_offsets = elf_local_got_offsets (input_bfd);
r_symndx = ELF32_R_SYM (rel->r_info);
-#if USE_REL
- addend = bfd_get_32 (input_bfd, hit_data) & howto->src_mask;
-
- if (addend & ((howto->src_mask + 1) >> 1))
+ if (globals->use_rel)
{
- signed_addend = -1;
- signed_addend &= ~ howto->src_mask;
- signed_addend |= addend;
+ 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
- signed_addend = addend;
-#else
- addend = signed_addend = rel->r_addend;
-#endif
+ addend = signed_addend = rel->r_addend;
switch (r_type)
{
(bfd_vma) 0);
}
- /* When generating a shared object, these relocations are copied
- into the output file to be resolved at run time. */
- if (info->shared
+ /* When generating a shared object or relocatable executable, these
+ relocations are copied into the output file to be resolved at
+ run time. */
+ if ((info->shared || globals->root.is_relocatable_executable)
&& (input_section->flags & SEC_ALLOC)
&& (r_type != R_ARM_REL32
|| !SYMBOL_CALLS_LOCAL (info, h))
value -= (input_section->output_section->vma
+ input_section->output_offset);
value -= rel->r_offset;
- value += (signed_addend << howto->size);
+ if (globals->use_rel)
+ value += (signed_addend << howto->size);
+ else
+ /* RELA addends do not have to be adjusted by howto->size. */
+ value += signed_addend;
signed_addend = value;
signed_addend >>= howto->rightshift;
case R_ARM_THM_ABS5:
/* Support ldr and str instructions for the thumb. */
-#if USE_REL
- /* Need to refetch addend. */
- addend = bfd_get_16 (input_bfd, hit_data) & howto->src_mask;
- /* ??? Need to determine shift amount from operand size. */
- addend >>= howto->rightshift;
-#endif
+ if (globals->use_rel)
+ {
+ /* Need to refetch addend. */
+ addend = bfd_get_16 (input_bfd, hit_data) & howto->src_mask;
+ /* ??? Need to determine shift amount from operand size. */
+ addend >>= howto->rightshift;
+ }
value += addend;
/* ??? Isn't value unsigned? */
bfd_vma check;
bfd_signed_vma signed_check;
-#if USE_REL
/* Need to refetch the addend and squish the two 11 bit pieces
together. */
- {
- 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
+ if (globals->use_rel)
+ {
+ 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;
+ }
#ifndef OLD_ARM_ABI
if (r_type == R_ARM_THM_XPC22)
{
break;
case R_ARM_THM_PC11:
+ case R_ARM_THM_PC9:
/* Thumb B (branch) instruction). */
{
bfd_signed_vma relocation;
bfd_signed_vma reloc_signed_min = ~ reloc_signed_max;
bfd_signed_vma signed_check;
-#if USE_REL
- /* Need to refetch addend. */
- addend = bfd_get_16 (input_bfd, hit_data) & howto->src_mask;
- if (addend & ((howto->src_mask + 1) >> 1))
+ if (globals->use_rel)
{
- signed_addend = -1;
- signed_addend &= ~ howto->src_mask;
- signed_addend |= addend;
+ /* Need to refetch addend. */
+ addend = bfd_get_16 (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;
+ /* The value in the insn has been right shifted. We need to
+ undo this, so that we can perform the address calculation
+ in terms of bytes. */
+ signed_addend <<= howto->rightshift;
}
- else
- signed_addend = addend;
- /* The value in the insn has been right shifted. We need to
- undo this, so that we can perform the address calculation
- in terms of bytes. */
- signed_addend <<= howto->rightshift;
-#endif
relocation = value + signed_addend;
relocation -= (input_section->output_section->vma
bfd_vma relocation;
insn = bfd_get_32 (input_bfd, hit_data);
-#if USE_REL
- /* Extract the addend. */
- addend = (insn & 0xff) << ((insn & 0xf00) >> 7);
- signed_addend = addend;
-#endif
+ if (globals->use_rel)
+ {
+ /* Extract the addend. */
+ addend = (insn & 0xff) << ((insn & 0xf00) >> 7);
+ signed_addend = addend;
+ }
relocation = value + signed_addend;
relocation -= (input_section->output_section->vma
case R_ARM_RBASE:
return bfd_reloc_notsupported;
+ case R_ARM_V4BX:
+ if (globals->fix_v4bx)
+ {
+ bfd_vma insn = bfd_get_32 (input_bfd, hit_data);
+
+ /* 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;
+
+ bfd_put_32 (input_bfd, insn, hit_data);
+ }
+ return bfd_reloc_ok;
+
default:
return bfd_reloc_notsupported;
}
}
-#if USE_REL
/* Add INCREMENT to the reloc (of type HOWTO) at ADDRESS. */
static void
arm_add_to_rel (bfd * abfd,
bfd_put_32 (abfd, contents, address);
}
}
-#endif /* USE_REL */
/* Relocate an ARM ELF section. */
static bfd_boolean
const char *name;
struct elf32_arm_link_hash_table * globals;
-#if !USE_REL
- if (info->relocatable)
+ globals = elf32_arm_hash_table (info);
+ if (info->relocatable && !globals->use_rel)
return TRUE;
-#endif
- globals = elf32_arm_hash_table (info);
symtab_hdr = & elf_tdata (input_bfd)->symtab_hdr;
sym_hashes = elf_sym_hashes (input_bfd);
bfd_reloc.howto = elf32_arm_howto_from_type (r_type);
howto = bfd_reloc.howto;
-#if USE_REL
- if (info->relocatable)
+ if (info->relocatable && globals->use_rel)
{
/* This is a relocatable link. We don't have to change
anything, unless the reloc is against a section symbol,
continue;
}
-#endif
/* This is a final link. */
h = NULL;
{
sym = local_syms + r_symndx;
sec = local_sections[r_symndx];
-#if USE_REL
- relocation = (sec->output_section->vma
- + sec->output_offset
- + sym->st_value);
- if ((sec->flags & SEC_MERGE)
- && ELF_ST_TYPE (sym->st_info) == STT_SECTION)
+ if (globals->use_rel)
{
- asection *msec;
- bfd_vma addend, value;
-
- if (howto->rightshift)
+ relocation = (sec->output_section->vma
+ + sec->output_offset
+ + sym->st_value);
+ if ((sec->flags & SEC_MERGE)
+ && ELF_ST_TYPE (sym->st_info) == STT_SECTION)
{
- (*_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;
- }
+ asection *msec;
+ bfd_vma addend, value;
- value = bfd_get_32 (input_bfd, contents + rel->r_offset);
+ if (howto->rightshift)
+ {
+ (*_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;
+ }
- /* Get the (signed) value from the instruction. */
- addend = value & howto->src_mask;
- if (addend & ((howto->src_mask + 1) >> 1))
- {
- bfd_signed_vma mask;
+ 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;
+ }
+ 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);
}
- 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);
}
-#else
- relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel);
-#endif
+ else
+ relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel);
}
else
{
struct elf_link_hash_entry **sym_hashes;
bfd_signed_vma *local_got_refcounts;
const Elf_Internal_Rela *rel, *relend;
- unsigned long r_symndx;
- struct elf_link_hash_entry *h;
struct elf32_arm_link_hash_table * globals;
globals = elf32_arm_hash_table (info);
relend = relocs + sec->reloc_count;
for (rel = relocs; rel < relend; rel++)
{
+ unsigned long r_symndx;
+ struct elf_link_hash_entry *h = NULL;
int r_type;
+ r_symndx = ELF32_R_SYM (rel->r_info);
+ if (r_symndx >= symtab_hdr->sh_info)
+ {
+ h = sym_hashes[r_symndx - symtab_hdr->sh_info];
+ while (h->root.type == bfd_link_hash_indirect
+ || h->root.type == bfd_link_hash_warning)
+ h = (struct elf_link_hash_entry *) h->root.u.i.link;
+ }
+
r_type = ELF32_R_TYPE (rel->r_info);
#ifndef OLD_ARM_ABI
r_type = arm_real_reloc_type (globals, r_type);
#ifndef OLD_ARM_ABI
case R_ARM_GOT_PREL:
#endif
- r_symndx = ELF32_R_SYM (rel->r_info);
- if (r_symndx >= symtab_hdr->sh_info)
+ if (h != NULL)
{
- h = sym_hashes[r_symndx - symtab_hdr->sh_info];
if (h->got.refcount > 0)
h->got.refcount -= 1;
}
case R_ARM_THM_PC22:
/* Should the interworking branches be here also? */
- r_symndx = ELF32_R_SYM (rel->r_info);
- if (r_symndx >= symtab_hdr->sh_info)
+ if (h != NULL)
{
struct elf32_arm_link_hash_entry *eh;
struct elf32_arm_relocs_copied **pp;
struct elf32_arm_relocs_copied *p;
- h = sym_hashes[r_symndx - symtab_hdr->sh_info];
eh = (struct elf32_arm_link_hash_entry *) h;
if (h->plt.refcount > 0)
htab = elf32_arm_hash_table (info);
sreloc = NULL;
+ /* Create dynamic sections for relocatable executables so that we can
+ copy relocations. */
+ if (htab->root.is_relocatable_executable
+ && ! htab->root.dynamic_sections_created)
+ {
+ if (! _bfd_elf_link_create_dynamic_sections (abfd, info))
+ return FALSE;
+ }
+
dynobj = elf_hash_table (info)->dynobj;
local_got_offsets = elf_local_got_offsets (abfd);
eh->plt_thumb_refcount += 1;
}
- /* If we are creating a shared library, and this is a reloc
- against a global symbol, or a non PC relative reloc
- against a local symbol, then we need to copy the reloc
- into the shared library. However, if we are linking with
- -Bsymbolic, we do not need to copy a reloc against a
+ /* If we are creating a shared library or relocatable executable,
+ and this is a reloc against a global symbol, or a non PC
+ relative reloc against a local symbol, then we need to copy
+ the reloc into the shared library. However, if we are linking
+ with -Bsymbolic, we do not need to copy a reloc against a
global symbol which is defined in an object we are
including in the link (i.e., DEF_REGULAR is set). At
this point we have not seen all the input files, so it is
later (it is never cleared). We account for that
possibility below by storing information in the
relocs_copied field of the hash table entry. */
- if (info->shared
+ if ((info->shared || htab->root.is_relocatable_executable)
&& (sec->flags & SEC_ALLOC) != 0
&& ((r_type != R_ARM_PC24
&& r_type != R_ARM_PLT32
asection * s;
unsigned int power_of_two;
struct elf32_arm_link_hash_entry * eh;
+ struct elf32_arm_link_hash_table *globals;
+ globals = elf32_arm_hash_table (info);
dynobj = elf_hash_table (info)->dynobj;
/* Make sure we know what is going on here. */
/* If we are creating a shared library, we must presume that the
only references to the symbol are via the global offset table.
For such cases we need not do anything here; the relocations will
- be handled correctly by relocate_section. */
- if (info->shared)
+ be handled correctly by relocate_section. Relocatable executables
+ can reference data in shared objects directly, so we don't need to
+ do anything here. */
+ if (info->shared || globals->root.is_relocatable_executable)
return TRUE;
/* We must allocate the symbol in our .dynbss section, which will
space for pc-relative relocs that have become local due to symbol
visibility changes. */
- if (info->shared)
+ if (info->shared || htab->root.is_relocatable_executable)
{
/* Discard relocs on undefined weak syms with non-default
visibility. */
if (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT
&& h->root.type == bfd_link_hash_undefweak)
eh->relocs_copied = NULL;
+ else if (htab->root.is_relocatable_executable && h->dynindx == -1
+ && h->root.type == bfd_link_hash_new)
+ {
+ /* Output absolute symbols so that we can create relocations
+ against them. For normal symbols we output a relocation
+ against the section that contains them. */
+ if (! bfd_elf_link_record_dynamic_symbol (info, h))
+ return FALSE;
+ }
+
}
else
{
#else
#define ELF_MAXPAGESIZE 0x8000
#endif
+#define ELF_MINPAGESIZE 0x1000
#define bfd_elf32_bfd_copy_private_bfd_data elf32_arm_copy_private_bfd_data
#define bfd_elf32_bfd_merge_private_bfd_data elf32_arm_merge_private_bfd_data
#define elf_backend_plt_readonly 1
#define elf_backend_want_got_plt 1
#define elf_backend_want_plt_sym 0
-#if !USE_REL
-#define elf_backend_rela_normal 1
-#endif
+#define elf_backend_may_use_rel_p 1
+#define elf_backend_may_use_rela_p 0
+#define elf_backend_default_use_rela_p 0
+#define elf_backend_rela_normal 0
#define elf_backend_got_header_size 12
#include "elf32-target.h"
+/* VxWorks Targets */
+
+#undef TARGET_LITTLE_SYM
+#define TARGET_LITTLE_SYM bfd_elf32_littlearm_vxworks_vec
+#undef TARGET_LITTLE_NAME
+#define TARGET_LITTLE_NAME "elf32-littlearm-vxworks"
+#undef TARGET_BIG_SYM
+#define TARGET_BIG_SYM bfd_elf32_bigarm_vxworks_vec
+#undef TARGET_BIG_NAME
+#define TARGET_BIG_NAME "elf32-bigarm-vxworks"
+
+/* Like elf32_arm_link_hash_table_create -- but overrides
+ appropriately for VxWorks. */
+static struct bfd_link_hash_table *
+elf32_arm_vxworks_link_hash_table_create (bfd *abfd)
+{
+ struct bfd_link_hash_table *ret;
+
+ ret = elf32_arm_link_hash_table_create (abfd);
+ if (ret)
+ {
+ struct elf32_arm_link_hash_table *htab
+ = (struct elf32_arm_link_hash_table *)ret;
+ htab->use_rel = 0;
+ }
+ return ret;
+}
+
+#undef elf32_bed
+#define elf32_bed elf32_arm_vxworks_bed
+
+#undef bfd_elf32_bfd_link_hash_table_create
+#define bfd_elf32_bfd_link_hash_table_create \
+ elf32_arm_vxworks_link_hash_table_create
+
+#undef elf_backend_may_use_rel_p
+#define elf_backend_may_use_rel_p 0
+#undef elf_backend_may_use_rela_p
+#define elf_backend_may_use_rela_p 1
+#undef elf_backend_default_use_rela_p
+#define elf_backend_default_use_rela_p 1
+#undef elf_backend_rela_normal
+#define elf_backend_rela_normal 1
+
+#include "elf32-target.h"
+
+
/* Symbian OS Targets */
#undef TARGET_LITTLE_SYM
/* The PLT entries are each three instructions. */
htab->plt_entry_size = 4 * NUM_ELEM (elf32_arm_symbian_plt_entry);
htab->symbian_p = 1;
+ htab->root.is_relocatable_executable = 1;
}
return ret;
}
-/* In a BPABI executable, the dynamic linking sections do not go in
- the loadable read-only segment. The post-linker may wish to refer
- to these sections, but they are not part of the final program
- image. */
static struct bfd_elf_special_section const
elf32_arm_symbian_special_sections[]=
{
+ /* In a BPABI executable, the dynamic linking sections do not go in
+ the loadable read-only segment. The post-linker may wish to
+ refer to these sections, but they are not part of the final
+ program image. */
{ ".dynamic", 8, 0, SHT_DYNAMIC, 0 },
{ ".dynstr", 7, 0, SHT_STRTAB, 0 },
{ ".dynsym", 7, 0, SHT_DYNSYM, 0 },
{ ".got", 4, 0, SHT_PROGBITS, 0 },
{ ".hash", 5, 0, SHT_HASH, 0 },
+ /* These sections do not need to be writable as the SymbianOS
+ postlinker will arrange things so that no dynamic relocation is
+ required. */
+ { ".init_array", 11, 0, SHT_INIT_ARRAY, SHF_ALLOC },
+ { ".fini_array", 11, 0, SHT_FINI_ARRAY, SHF_ALLOC },
+ { ".preinit_array", 14, 0, SHT_PREINIT_ARRAY, SHF_ALLOC },
{ NULL, 0, 0, 0, 0 }
};
#undef elf_backend_want_got_plt
#define elf_backend_want_got_plt 0
+#undef elf_backend_may_use_rel_p
+#define elf_backend_may_use_rel_p 1
+#undef elf_backend_may_use_rela_p
+#define elf_backend_may_use_rela_p 0
+#undef elf_backend_default_use_rela_p
+#define elf_backend_default_use_rela_p 0
+#undef elf_backend_rela_normal
+#define elf_backend_rela_normal 0
+
#include "elf32-target.h"