/* 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;
#endif
+/* An initial stub used if the PLT entry is referenced from Thumb code. */
+#define PLT_THUMB_STUB_SIZE 4
+static const bfd_vma elf32_arm_plt_thumb_stub [] =
+ {
+ 0x4778, /* bx pc */
+ 0x46c0 /* nop */
+ };
+
/* The entries in a PLT when using a DLL-based target with multiple
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) */
};
/* Number of PC relative relocs copied for this symbol. */
struct elf32_arm_relocs_copied * relocs_copied;
+
+ /* We reference count Thumb references to a PLT entry separately,
+ so that we can emit the Thumb trampoline only if needed. */
+ bfd_signed_vma plt_thumb_refcount;
+
+ /* Since PLT entries have variable size if the Thumb prologue is
+ used, we need to record the index into .got.plt instead of
+ recomputing it from the PLT offset. */
+ bfd_signed_vma plt_got_offset;
};
/* Traverse an arm ELF linker hash table. */
#define elf32_arm_link_hash_traverse(table, func, info) \
(elf_link_hash_traverse \
(&(table)->root, \
- (bfd_boolean (*) (struct elf_link_hash_entry *, void *))) (func), \
+ (bfd_boolean (*) (struct elf_link_hash_entry *, void *)) (func), \
(info)))
/* Get the ARM elf linker hash table from a link_info structure. */
/* An arbitrary 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;
-
/* Nonzero to output a BE8 image. */
int byteswap_code;
/* 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;
/* Small local sym to section mapping cache. */
struct sym_sec_cache sym_sec;
+
+ /* For convenience in allocate_dynrelocs. */
+ bfd * obfd;
};
/* Create an entry in an ARM ELF linker hash table. */
_bfd_elf_link_hash_newfunc ((struct bfd_hash_entry *) ret,
table, string));
if (ret != NULL)
- ret->relocs_copied = NULL;
+ {
+ ret->relocs_copied = NULL;
+ ret->plt_thumb_refcount = 0;
+ ret->plt_got_offset = -1;
+ }
return (struct bfd_hash_entry *) ret;
}
eind->relocs_copied = NULL;
}
+ /* If the direct symbol already has an associated PLT entry, the
+ indirect symbol should not. If it doesn't, swap refcount information
+ from the indirect symbol. */
+ if (edir->plt_thumb_refcount == 0)
+ {
+ edir->plt_thumb_refcount = eind->plt_thumb_refcount;
+ eind->plt_thumb_refcount = 0;
+ }
+ else
+ BFD_ASSERT (eind->plt_thumb_refcount == 0);
+
_bfd_elf_link_hash_copy_indirect (bed, dir, ind);
}
ret->thumb_glue_size = 0;
ret->arm_glue_size = 0;
ret->bfd_of_glue_owner = NULL;
- ret->no_pipeline_knowledge = 0;
ret->byteswap_code = 0;
ret->target1_is_rel = 0;
ret->target2_reloc = R_ARM_NONE;
ret->plt_entry_size = 12;
#endif
ret->symbian_p = 0;
+ ret->use_rel = 1;
ret->sym_sec.abfd = NULL;
+ ret->obfd = abfd;
return &ret->root.root;
}
tmp_name, BSF_GLOBAL, 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;
+
free (tmp_name);
globals->arm_glue_size += ARM2THUMB_GLUE_SIZE;
struct elf_link_hash_entry *myh;
struct bfd_link_hash_entry *bh;
struct elf32_arm_link_hash_table *hash_table;
- char bind;
bfd_vma val;
hash_table = elf32_arm_hash_table (link_info);
/* If we mark it 'Thumb', the disassembler will do a better job. */
myh = (struct elf_link_hash_entry *) bh;
- bind = ELF_ST_BIND (myh->type);
- myh->type = ELF_ST_INFO (bind, STT_ARM_TFUNC);
+ myh->type = ELF_ST_INFO (STB_LOCAL, STT_ARM_TFUNC);
+ myh->forced_local = 1;
free (tmp_name);
if (info->relocatable)
return TRUE;
+ /* Make sure we don't attach the glue sections to a dynamic object. */
+ BFD_ASSERT (!(abfd->flags & DYNAMIC));
+
globals = elf32_arm_hash_table (info);
BFD_ASSERT (globals != NULL);
bfd_boolean
bfd_elf32_arm_process_before_allocation (bfd *abfd,
struct bfd_link_info *link_info,
- int no_pipeline_knowledge,
int byteswap_code)
{
Elf_Internal_Shdr *symtab_hdr;
BFD_ASSERT (globals != NULL);
BFD_ASSERT (globals->bfd_of_glue_owner != NULL);
- globals->no_pipeline_knowledge = no_pipeline_knowledge;
-
if (byteswap_code && !bfd_big_endian (abfd))
{
_bfd_error_handler (_("%B: BE8 images only valid in big-endian mode."),
/* These are the only relocation types we care about. */
if ( r_type != R_ARM_PC24
+ && r_type != R_ARM_PLT32
#ifndef OLD_ARM_ABI
&& r_type != R_ARM_CALL
&& r_type != R_ARM_JUMP24
if (h == NULL)
continue;
+ /* If the call will go through a PLT entry then we do not need
+ glue. */
+ if (globals->splt != NULL && h->plt.offset != (bfd_vma) -1)
+ continue;
+
switch (r_type)
{
case R_ARM_PC24:
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)
{
will use the symbol's value, which may point to a PLT entry, but we
don't need to handle that here. If we created a PLT entry, all
branches in this object should go to it. */
- if ((r_type != R_ARM_ABS32 && r_type != R_ARM_REL32
-#ifndef OLD_ARM_ABI
- && r_type != R_ARM_PREL31
-#endif
- )
+ if ((r_type != R_ARM_ABS32 && r_type != R_ARM_REL32)
&& h != NULL
&& splt != NULL
&& h->plt.offset != (bfd_vma) -1)
(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
-#ifndef OLD_ARM_ABI
- && r_type != R_ARM_PREL31
-#endif
- ) || !SYMBOL_CALLS_LOCAL (info, h))
+ && (r_type != R_ARM_REL32
+ || !SYMBOL_CALLS_LOCAL (info, h))
&& (h == NULL
|| ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
|| h->root.type != bfd_link_hash_undefweak)
#ifndef OLD_ARM_ABI
&& r_type != R_ARM_CALL
&& r_type != R_ARM_JUMP24
+ && r_type != R_ARM_PREL31
#endif
&& r_type != R_ARM_PLT32)
{
/* This symbol is local, or marked to become local. */
relocate = TRUE;
+ if (sym_flags == STT_ARM_TFUNC)
+ value |= 1;
if (globals->symbian_p)
{
/* On Symbian OS, the data segment and text segement
}
}
- 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;
- }
+ /* 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;
+ if (globals->use_rel)
+ value += (signed_addend << howto->size);
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;
- }
- }
+ /* 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)
{
{
/* If it is not a call to Thumb, assume call to Arm.
If it is a call relative to a section name, then it is not a
- function call at all, but rather a long jump. */
- if (sym_flags != STT_ARM_TFUNC && sym_flags != STT_SECTION)
+ function call at all, but rather a long jump. Calls through
+ the PLT do not require stubs. */
+ if (sym_flags != STT_ARM_TFUNC && sym_flags != STT_SECTION
+ && (h == NULL || splt == NULL
+ || h->plt.offset == (bfd_vma) -1))
{
if (elf32_thumb_to_arm_stub
(info, sym_name, input_bfd, output_bfd, input_section,
}
}
+ /* Handle calls via the PLT. */
+ if (h != NULL && splt != NULL && h->plt.offset != (bfd_vma) -1)
+ {
+ value = (splt->output_section->vma
+ + splt->output_offset
+ + h->plt.offset);
+ /* Target the Thumb stub before the ARM PLT entry. */
+ value -= 4;
+ }
+
relocation = value + signed_addend;
relocation -= (input_section->output_section->vma
+ 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
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
off &= ~1;
else
{
+ /* If we are addressing a Thumb function, we need to
+ adjust the address by one, so that attempts to
+ call the function pointer will correctly
+ interpret it as Thumb code. */
+ if (sym_flags == STT_ARM_TFUNC)
+ value |= 1;
+
bfd_put_32 (output_bfd, value, sgot->contents + off);
if (info->shared)
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
Elf_Internal_Rela *rel;
Elf_Internal_Rela *relend;
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
symtab_hdr = & elf_tdata (input_bfd)->symtab_hdr;
sym_hashes = elf_sym_hashes (input_bfd);
r_symndx = ELF32_R_SYM (rel->r_info);
r_type = ELF32_R_TYPE (rel->r_info);
+ r_type = arm_real_reloc_type (globals, r_type);
if ( r_type == R_ARM_GNU_VTENTRY
|| r_type == R_ARM_GNU_VTINHERIT)
continue;
- elf32_arm_info_to_howto (input_bfd, & bfd_reloc, rel);
+ 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;
+
+ 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;
+ }
- value = bfd_get_32 (input_bfd, contents + rel->r_offset);
+ value = bfd_get_32 (input_bfd, contents + rel->r_offset);
- /* Get the (signed) value from the instruction. */
- addend = value & howto->src_mask;
- if (addend & ((howto->src_mask + 1) >> 1))
- {
- bfd_signed_vma 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;
+ 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
{
#ifndef OLD_ARM_ABI
case R_ARM_CALL:
case R_ARM_JUMP24:
+ case R_ARM_PREL31:
#endif
case R_ARM_ABS32:
case R_ARM_THM_PC22:
elf_elfheader (obfd)->e_flags = in_flags;
elf_flags_init (obfd) = TRUE;
+ /* Also copy the EI_OSABI field. */
+ elf_elfheader (obfd)->e_ident[EI_OSABI] =
+ elf_elfheader (ibfd)->e_ident[EI_OSABI];
+
return TRUE;
}
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_JUMP24:
case R_ARM_PREL31:
#endif
- r_symndx = ELF32_R_SYM (rel->r_info);
- if (r_symndx >= symtab_hdr->sh_info)
+ case R_ARM_THM_PC22:
+ /* Should the interworking branches be here also? */
+
+ 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)
- h->plt.refcount -= 1;
+ {
+ h->plt.refcount -= 1;
+ if (ELF32_R_TYPE (rel->r_info) == R_ARM_THM_PC22)
+ eh->plt_thumb_refcount--;
+ }
if (r_type == R_ARM_ABS32
-#ifndef OLD_ARM_ABI
- || r_type == R_ARM_PREL31
-#endif
|| r_type == R_ARM_REL32)
{
- eh = (struct elf32_arm_link_hash_entry *) h;
-
for (pp = &eh->relocs_copied; (p = *pp) != NULL;
pp = &p->next)
if (p->section == sec)
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);
for (rel = relocs; rel < rel_end; rel++)
{
struct elf_link_hash_entry *h;
+ struct elf32_arm_link_hash_entry *eh;
unsigned long r_symndx;
int r_type;
else
h = sym_hashes[r_symndx - symtab_hdr->sh_info];
+ eh = (struct elf32_arm_link_hash_entry *) h;
+
switch (r_type)
{
case R_ARM_GOT32:
case R_ARM_JUMP24:
case R_ARM_PREL31:
#endif
+ case R_ARM_THM_PC22:
+ /* Should the interworking branches be listed here? */
if (h != NULL)
{
/* If this reloc is in a read-only section, we might
#ifndef OLD_ARM_ABI
|| r_type == R_ARM_CALL
|| r_type == R_ARM_JUMP24
+ || r_type == R_ARM_PREL31
#endif
- || r_type == R_ARM_PLT32)
+ || r_type == R_ARM_PLT32
+ || r_type == R_ARM_THM_PC22)
h->needs_plt = 1;
/* If we create a PLT entry, this relocation will reference
it, even if it's an ABS32 relocation. */
h->plt.refcount += 1;
+
+ if (r_type == R_ARM_THM_PC22)
+ 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
&& r_type != R_ARM_JUMP24
&& r_type != R_ARM_PREL31
#endif
- && r_type != R_ARM_REL32)
+ && r_type != R_ARM_REL32
+ && r_type != R_ARM_THM_PC22)
|| (h != NULL
&& (! info->symbolic
|| !h->def_regular))))
}
if (r_type == R_ARM_ABS32
-#ifndef OLD_ARM_ABI
- || r_type == R_ARM_PREL31
-#endif
|| r_type == R_ARM_REL32)
p->count += 1;
}
bfd * dynobj;
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. */
&& h->ref_regular
&& !h->def_regular)));
+ eh = (struct elf32_arm_link_hash_entry *) h;
+
/* If this is a function, put it in the procedure linkage table. We
will fill in the contents of the procedure linkage table later,
when we know the address of the .got section. */
- if (h->type == STT_FUNC
+ if (h->type == STT_FUNC || h->type == STT_ARM_TFUNC
|| h->needs_plt)
{
if (h->plt.refcount <= 0
such a case, we don't actually need to build a procedure
linkage table, and we can just do a PC24 reloc instead. */
h->plt.offset = (bfd_vma) -1;
+ eh->plt_thumb_refcount = 0;
h->needs_plt = 0;
}
return TRUE;
}
else
- /* It's possible that we incorrectly decided a .plt reloc was
- needed for an R_ARM_PC24 or similar reloc to a non-function sym
- in check_relocs. We can't decide accurately between function
- and non-function syms in check-relocs; Objects loaded later in
- the link may change h->type. So fix it now. */
- h->plt.offset = (bfd_vma) -1;
+ {
+ /* It's possible that we incorrectly decided a .plt reloc was
+ needed for an R_ARM_PC24 or similar reloc to a non-function sym
+ in check_relocs. We can't decide accurately between function
+ and non-function syms in check-relocs; Objects loaded later in
+ the link may change h->type. So fix it now. */
+ h->plt.offset = (bfd_vma) -1;
+ eh->plt_thumb_refcount = 0;
+ }
/* If this is a weak symbol, and there is a real definition, the
processor independent code will have arranged for us to see the
/* 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
struct elf32_arm_link_hash_entry *eh;
struct elf32_arm_relocs_copied *p;
+ eh = (struct elf32_arm_link_hash_entry *) h;
+
if (h->root.type == bfd_link_hash_indirect)
return TRUE;
h->plt.offset = s->size;
+ /* If we will insert a Thumb trampoline before this PLT, leave room
+ for it. */
+ if (!htab->symbian_p && eh->plt_thumb_refcount > 0)
+ {
+ h->plt.offset += PLT_THUMB_STUB_SIZE;
+ s->size += PLT_THUMB_STUB_SIZE;
+ }
+
/* If this symbol is not defined in a regular file, and we are
not generating a shared library, then set the symbol to this
location in the .plt. This is required to make function
{
h->root.u.def.section = s;
h->root.u.def.value = h->plt.offset;
+
+ /* Make sure the function is not marked as Thumb, in case
+ it is the target of an ABS32 relocation, which will
+ point to the PLT entry. */
+ if (ELF_ST_TYPE (h->type) == STT_ARM_TFUNC)
+ h->type = ELF_ST_INFO (ELF_ST_BIND (h->type), STT_FUNC);
}
/* Make room for this entry. */
s->size += htab->plt_entry_size;
if (!htab->symbian_p)
- /* We also need to make an entry in the .got.plt section, which
- will be placed in the .got section by the linker script. */
- htab->sgotplt->size += 4;
+ {
+ /* We also need to make an entry in the .got.plt section, which
+ will be placed in the .got section by the linker script. */
+ eh->plt_got_offset = htab->sgotplt->size;
+ htab->sgotplt->size += 4;
+ }
/* We also need to make an entry in the .rel.plt section. */
htab->srelplt->size += sizeof (Elf32_External_Rel);
else
h->got.offset = (bfd_vma) -1;
- eh = (struct elf32_arm_link_hash_entry *) h;
if (eh->relocs_copied == NULL)
return TRUE;
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
{
{
bfd * dynobj;
struct elf32_arm_link_hash_table *htab;
+ struct elf32_arm_link_hash_entry *eh;
dynobj = elf_hash_table (info)->dynobj;
htab = elf32_arm_hash_table (info);
+ eh = (struct elf32_arm_link_hash_entry *) h;
if (h->plt.offset != (bfd_vma) -1)
{
srel = bfd_get_section_by_name (dynobj, ".rel.plt");
BFD_ASSERT (splt != NULL && srel != NULL);
- /* Get the index in the procedure linkage table which
- corresponds to this symbol. This is the index of this symbol
- in all the symbols for which we are making plt entries. The
- first entry in the procedure linkage table is reserved. */
- plt_index = ((h->plt.offset - htab->plt_header_size)
- / htab->plt_entry_size);
-
/* Fill in the entry in the procedure linkage table. */
if (htab->symbian_p)
{
+ splt->output_offset
+ h->plt.offset + 4 * (i - 1));
rel.r_info = ELF32_R_INFO (h->dynindx, R_ARM_GLOB_DAT);
+
+ /* Get the index in the procedure linkage table which
+ corresponds to this symbol. This is the index of this symbol
+ in all the symbols for which we are making plt entries. The
+ first entry in the procedure linkage table is reserved. */
+ plt_index = ((h->plt.offset - htab->plt_header_size)
+ / htab->plt_entry_size);
}
else
{
sgot = bfd_get_section_by_name (dynobj, ".got.plt");
BFD_ASSERT (sgot != NULL);
- /* Get the offset into the .got table of the entry that
- corresponds to this function. Each .got entry is 4 bytes.
- The first three are reserved. */
- got_offset = (plt_index + 3) * 4;
+ /* Get the offset into the .got.plt table of the entry that
+ corresponds to this function. */
+ got_offset = eh->plt_got_offset;
+
+ /* Get the index in the procedure linkage table which
+ corresponds to this symbol. This is the index of this symbol
+ in all the symbols for which we are making plt entries. The
+ first three entries in .got.plt are reserved; after that
+ symbols appear in the same order as in .plt. */
+ plt_index = (got_offset - 12) / 4;
/* Calculate the displacement between the PLT slot and the
- entry in the GOT. */
+ entry in the GOT. The eight-byte offset accounts for the
+ value produced by adding to pc in the first instruction
+ of the PLT stub. */
got_displacement = (sgot->output_section->vma
+ sgot->output_offset
+ got_offset
BFD_ASSERT ((got_displacement & 0xf0000000) == 0);
+ if (eh->plt_thumb_refcount > 0)
+ {
+ bfd_put_16 (output_bfd, elf32_arm_plt_thumb_stub[0],
+ splt->contents + h->plt.offset - 4);
+ bfd_put_16 (output_bfd, elf32_arm_plt_thumb_stub[1],
+ splt->contents + h->plt.offset - 2);
+ }
+
bfd_put_32 (output_bfd, elf32_arm_plt_entry[0] | ((got_displacement & 0x0ff00000) >> 20),
splt->contents + h->plt.offset + 0);
bfd_put_32 (output_bfd, elf32_arm_plt_entry[1] | ((got_displacement & 0x000ff000) >> 12),
if (dyn.d_tag == DT_RELSZ
|| dyn.d_tag == DT_RELASZ)
dyn.d_un.d_val += hdr->sh_size;
- else if (dyn.d_un.d_val == 0
- || hdr->sh_offset < dyn.d_un.d_val)
+ else if ((ufile_ptr) hdr->sh_offset
+ <= dyn.d_un.d_val - 1)
dyn.d_un.d_val = hdr->sh_offset;
}
}
i_ehdrp = elf_elfheader (abfd);
- i_ehdrp->e_ident[EI_OSABI] = ARM_ELF_OS_ABI_VERSION;
+ if (EF_ARM_EABI_VERSION (i_ehdrp->e_flags) == EF_ARM_EABI_UNKNOWN)
+ i_ehdrp->e_ident[EI_OSABI] = ELFOSABI_ARM;
+ else
+ i_ehdrp->e_ident[EI_OSABI] = 0;
i_ehdrp->e_ident[EI_ABIVERSION] = ARM_ELF_ABI_VERSION;
if (link_info)
return FALSE;
}
+/* Display STT_ARM_TFUNC symbols as functions. */
+
+static void
+elf32_arm_symbol_processing (bfd *abfd ATTRIBUTE_UNUSED,
+ asymbol *asym)
+{
+ elf_symbol_type *elfsym = (elf_symbol_type *) asym;
+
+ if (ELF_ST_TYPE (elfsym->internal_elf_sym.st_info) == STT_ARM_TFUNC)
+ elfsym->symbol.flags |= BSF_FUNCTION;
+}
+
+
+/* Mangle thumb function symbols as we read them in. */
+
+static void
+elf32_arm_swap_symbol_in (bfd * abfd,
+ const void *psrc,
+ const void *pshn,
+ Elf_Internal_Sym *dst)
+{
+ bfd_elf32_swap_symbol_in (abfd, psrc, pshn, dst);
+
+ /* New EABI objects mark thumb function symbols by setting the low bit of
+ the address. Turn these into STT_ARM_TFUNC. */
+ if (ELF_ST_TYPE (dst->st_info) == STT_FUNC
+ && (dst->st_value & 1))
+ {
+ dst->st_info = ELF_ST_INFO (ELF_ST_BIND (dst->st_info), STT_ARM_TFUNC);
+ dst->st_value &= ~(bfd_vma) 1;
+ }
+}
+
+
+/* Mangle thumb function symbols as we write them out. */
+
+static void
+elf32_arm_swap_symbol_out (bfd *abfd,
+ const Elf_Internal_Sym *src,
+ void *cdst,
+ void *shndx)
+{
+ Elf_Internal_Sym newsym;
+
+ /* We convert STT_ARM_TFUNC symbols into STT_FUNC with the low bit
+ of the address set, as per the new EABI. We do this unconditionally
+ because objcopy does not set the elf header flags until after
+ it writes out the symbol table. */
+ if (ELF_ST_TYPE (src->st_info) == STT_ARM_TFUNC)
+ {
+ newsym = *src;
+ newsym.st_info = ELF_ST_INFO (ELF_ST_BIND (src->st_info), STT_FUNC);
+ newsym.st_value |= 1;
+
+ src = &newsym;
+ }
+ bfd_elf32_swap_symbol_out (abfd, src, cdst, shndx);
+}
+
+/* We use this to override swap_symbol_in and swap_symbol_out. */
+const struct elf_size_info elf32_arm_size_info = {
+ sizeof (Elf32_External_Ehdr),
+ sizeof (Elf32_External_Phdr),
+ sizeof (Elf32_External_Shdr),
+ sizeof (Elf32_External_Rel),
+ sizeof (Elf32_External_Rela),
+ sizeof (Elf32_External_Sym),
+ sizeof (Elf32_External_Dyn),
+ sizeof (Elf_External_Note),
+ 4,
+ 1,
+ 32, 2,
+ ELFCLASS32, EV_CURRENT,
+ bfd_elf32_write_out_phdrs,
+ bfd_elf32_write_shdrs_and_ehdr,
+ bfd_elf32_write_relocs,
+ elf32_arm_swap_symbol_in,
+ elf32_arm_swap_symbol_out,
+ bfd_elf32_slurp_reloc_table,
+ bfd_elf32_slurp_symbol_table,
+ bfd_elf32_swap_dyn_in,
+ bfd_elf32_swap_dyn_out,
+ bfd_elf32_swap_reloc_in,
+ bfd_elf32_swap_reloc_out,
+ bfd_elf32_swap_reloca_in,
+ bfd_elf32_swap_reloca_out
+};
+
#define ELF_ARCH bfd_arch_arm
#define ELF_MACHINE_CODE EM_ARM
#ifdef __QNXTARGET__
#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_section_from_shdr elf32_arm_section_from_shdr
#define elf_backend_final_write_processing elf32_arm_final_write_processing
#define elf_backend_copy_indirect_symbol elf32_arm_copy_indirect_symbol
+#define elf_backend_symbol_processing elf32_arm_symbol_processing
+#define elf_backend_size_info elf32_arm_size_info
#define elf_backend_can_refcount 1
#define elf_backend_can_gc_sections 1
#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
-#include "elf32-target.h"
+#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"