/* 32-bit ELF support for ARM
- Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007,
- 2008, 2009, 2010, 2011, 2012, 2013 Free Software Foundation, Inc.
+ Copyright 1998-2013 Free Software Foundation, Inc.
This file is part of BFD, the Binary File Descriptor library.
DATA_WORD (0, R_ARM_REL32, -4), /* dcd R_ARM_REL32(X) */
};
+/* NaCl ARM -> ARM long branch stub. */
+static const insn_sequence elf32_arm_stub_long_branch_arm_nacl[] =
+{
+ ARM_INSN (0xe59fc00c), /* ldr ip, [pc, #12] */
+ ARM_INSN (0xe3ccc13f), /* bic ip, ip, #0xc000000f */
+ ARM_INSN (0xe12fff1c), /* bx ip */
+ ARM_INSN (0xe320f000), /* nop */
+ ARM_INSN (0xe125be70), /* bkpt 0x5be0 */
+ DATA_WORD (0, R_ARM_ABS32, 0), /* dcd R_ARM_ABS32(X) */
+ DATA_WORD (0, R_ARM_NONE, 0), /* .word 0 */
+ DATA_WORD (0, R_ARM_NONE, 0), /* .word 0 */
+};
+
+/* NaCl ARM -> ARM long branch stub, PIC. */
+static const insn_sequence elf32_arm_stub_long_branch_arm_nacl_pic[] =
+{
+ ARM_INSN (0xe59fc00c), /* ldr ip, [pc, #12] */
+ ARM_INSN (0xe08cc00f), /* add ip, ip, pc */
+ ARM_INSN (0xe3ccc13f), /* bic ip, ip, #0xc000000f */
+ ARM_INSN (0xe12fff1c), /* bx ip */
+ ARM_INSN (0xe125be70), /* bkpt 0x5be0 */
+ DATA_WORD (0, R_ARM_REL32, 8), /* dcd R_ARM_REL32(X+8) */
+ DATA_WORD (0, R_ARM_NONE, 0), /* .word 0 */
+ DATA_WORD (0, R_ARM_NONE, 0), /* .word 0 */
+};
+
+
/* Cortex-A8 erratum-workaround stubs. */
/* Stub used for conditional branches (which may be beyond +/-1MB away, so we
DEF_STUB(long_branch_thumb_only_pic) \
DEF_STUB(long_branch_any_tls_pic) \
DEF_STUB(long_branch_v4t_thumb_tls_pic) \
+ DEF_STUB(long_branch_arm_nacl) \
+ DEF_STUB(long_branch_arm_nacl_pic) \
DEF_STUB(a8_veneer_b_cond) \
DEF_STUB(a8_veneer_b) \
DEF_STUB(a8_veneer_bl) \
bfd *stub_bfd;
/* Linker call-backs. */
- asection * (*add_stub_section) (const char *, asection *);
+ asection * (*add_stub_section) (const char *, asection *, unsigned int);
void (*layout_sections_again) (void);
/* Array to keep track of which stub sections have been created, and
r_type = ELF32_R_TYPE (rel->r_info);
+ /* ST_BRANCH_TO_ARM is nonsense to thumb-only targets when we
+ are considering a function call relocation. */
+ if (thumb_only && (r_type == R_ARM_THM_CALL || r_type == R_ARM_THM_JUMP24)
+ && branch_type == ST_BRANCH_TO_ARM)
+ branch_type = ST_BRANCH_TO_THUMB;
+
/* For TLS call relocs, it is the caller's responsibility to provide
the address of the appropriate trampoline. */
if (r_type != R_ARM_TLS_CALL
? (r_type == R_ARM_TLS_CALL
/* TLS PIC Stub */
? arm_stub_long_branch_any_tls_pic
- : arm_stub_long_branch_any_arm_pic)
+ : (globals->nacl_p
+ ? arm_stub_long_branch_arm_nacl_pic
+ : arm_stub_long_branch_any_arm_pic))
/* non-PIC stubs. */
- : arm_stub_long_branch_any_any;
+ : (globals->nacl_p
+ ? arm_stub_long_branch_arm_nacl
+ : arm_stub_long_branch_any_any);
}
}
}
memcpy (s_name, link_sec->name, namelen);
memcpy (s_name + namelen, STUB_SUFFIX, sizeof (STUB_SUFFIX));
- stub_sec = (*htab->add_stub_section) (s_name, link_sec);
+ stub_sec = (*htab->add_stub_section) (s_name, link_sec,
+ htab->nacl_p ? 4 : 3);
if (stub_sec == NULL)
return NULL;
htab->stub_group[link_sec->id].stub_sec = stub_sec;
case arm_stub_a8_veneer_blx:
return 4;
+ case arm_stub_long_branch_arm_nacl:
+ case arm_stub_long_branch_arm_nacl_pic:
+ return 16;
+
default:
abort (); /* Should be unreachable. */
}
arm_build_one_stub (struct bfd_hash_entry *gen_entry,
void * in_arg)
{
-#define MAXRELOCS 2
+#define MAXRELOCS 3
struct elf32_arm_stub_hash_entry *stub_entry;
struct elf32_arm_link_hash_table *globals;
struct bfd_link_info *info;
bfd *stub_bfd,
struct bfd_link_info *info,
bfd_signed_vma group_size,
- asection * (*add_stub_section) (const char *, asection *),
+ asection * (*add_stub_section) (const char *, asection *,
+ unsigned int),
void (*layout_sections_again) (void))
{
bfd_size_type stub_group_size;
ROOT_PLT points to the offset of the PLT entry from the start of its
section (.iplt or .plt). ARM_PLT points to the symbol's ARM-specific
- bookkeeping information. */
+ bookkeeping information.
-static void
+ Returns FALSE if there was a problem. */
+
+static bfd_boolean
elf32_arm_populate_plt_entry (bfd *output_bfd, struct bfd_link_info *info,
union gotplt_union *root_plt,
struct arm_plt_info *arm_plt,
| (tail_displacement & 0x00ffffff),
ptr + 12);
}
+ else if (using_thumb_only (htab))
+ {
+ /* PR ld/16017: Do not generate ARM instructions for
+ the PLT if compiling for a thumb-only target.
+
+ FIXME: We ought to be able to generate thumb PLT instructions... */
+ _bfd_error_handler (_("%B: Warning: thumb mode PLT generation not currently supported"),
+ output_bfd);
+ return FALSE;
+ }
else
{
/* Calculate the displacement between the PLT slot and the
loc = srel->contents + plt_index * RELOC_SIZE (htab);
SWAP_RELOC_OUT (htab) (output_bfd, &rel, loc);
}
+
+ return TRUE;
}
/* Some relocations map to different relocations depending on the
else
addend = signed_addend = rel->r_addend;
+ /* ST_BRANCH_TO_ARM is nonsense to thumb-only targets when we
+ are resolving a function call relocation. */
+ if (using_thumb_only (globals)
+ && (r_type == R_ARM_THM_CALL
+ || r_type == R_ARM_THM_JUMP24)
+ && branch_type == ST_BRANCH_TO_ARM)
+ branch_type = ST_BRANCH_TO_THUMB;
+
/* Record the symbol information that should be used in dynamic
relocations. */
dynreloc_st_type = st_type;
plt_offset--;
else
{
- elf32_arm_populate_plt_entry (output_bfd, info, root_plt, arm_plt,
- -1, dynreloc_value);
- root_plt->offset |= 1;
+ if (elf32_arm_populate_plt_entry (output_bfd, info, root_plt, arm_plt,
+ -1, dynreloc_value))
+ root_plt->offset |= 1;
+ else
+ return bfd_reloc_notsupported;
}
/* Static relocations always resolve to the .iplt entry. */
return bfd_reloc_ok;
case R_ARM_ABS8:
+ /* PR 16202: Refectch the addend using the correct size. */
+ if (globals->use_rel)
+ addend = bfd_get_8 (input_bfd, hit_data);
value += addend;
/* There is no way to tell whether the user intended to use a signed or
return bfd_reloc_ok;
case R_ARM_ABS16:
+ /* PR 16202: Refectch the addend using the correct size. */
+ if (globals->use_rel)
+ addend = bfd_get_16 (input_bfd, hit_data);
value += addend;
/* See comment for R_ARM_ABS8. */
bfd_vma insn = bfd_get_32 (input_bfd, hit_data);
bfd_vma pc = input_section->output_section->vma
+ input_section->output_offset + rel->r_offset;
- /* sb should be the origin of the *segment* containing the symbol.
- It is not clear how to obtain this OS-dependent value, so we
- make an arbitrary choice of zero. */
- bfd_vma sb = 0;
+ /* sb is the origin of the *segment* containing the symbol. */
+ bfd_vma sb = sym_sec ? sym_sec->output_section->vma : 0;
bfd_vma residual;
bfd_vma g_n;
bfd_signed_vma signed_value;
bfd_vma insn = bfd_get_32 (input_bfd, hit_data);
bfd_vma pc = input_section->output_section->vma
+ input_section->output_offset + rel->r_offset;
- bfd_vma sb = 0; /* See note above. */
+ /* sb is the origin of the *segment* containing the symbol. */
+ bfd_vma sb = sym_sec ? sym_sec->output_section->vma : 0;
bfd_vma residual;
bfd_signed_vma signed_value;
int group = 0;
bfd_vma insn = bfd_get_32 (input_bfd, hit_data);
bfd_vma pc = input_section->output_section->vma
+ input_section->output_offset + rel->r_offset;
- bfd_vma sb = 0; /* See note above. */
+ /* sb is the origin of the *segment* containing the symbol. */
+ bfd_vma sb = sym_sec ? sym_sec->output_section->vma : 0;
bfd_vma residual;
bfd_signed_vma signed_value;
int group = 0;
bfd_vma insn = bfd_get_32 (input_bfd, hit_data);
bfd_vma pc = input_section->output_section->vma
+ input_section->output_offset + rel->r_offset;
- bfd_vma sb = 0; /* See note above. */
+ /* sb is the origin of the *segment* containing the symbol. */
+ bfd_vma sb = sym_sec ? sym_sec->output_section->vma : 0;
bfd_vma residual;
bfd_signed_vma signed_value;
int group = 0;
}
else
{
- bfd_boolean warned;
+ bfd_boolean warned, ignored;
RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel,
r_symndx, symtab_hdr, sym_hashes,
h, sec, relocation,
- unresolved_reloc, warned);
+ unresolved_reloc, warned, ignored);
sym_type = h->type;
}
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];
-
- /* Copy object attributes. */
- _bfd_elf_copy_obj_attributes (ibfd, obfd);
-
- return TRUE;
+ return _bfd_elf_copy_private_bfd_data (ibfd, obfd);
}
/* Values for Tag_ABI_PCS_R9_use. */
if (!eh->is_iplt)
{
BFD_ASSERT (h->dynindx != -1);
- elf32_arm_populate_plt_entry (output_bfd, info, &h->plt, &eh->plt,
- h->dynindx, 0);
+ if (! elf32_arm_populate_plt_entry (output_bfd, info, &h->plt, &eh->plt,
+ h->dynindx, 0))
+ return FALSE;
}
if (!h->def_regular)
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;
+ _bfd_elf_post_process_headers (abfd, link_info);
i_ehdrp->e_ident[EI_ABIVERSION] = ARM_ELF_ABI_VERSION;
if (link_info)
&& nacl_modify_segment_map (abfd, info));
}
+static void
+elf32_arm_nacl_final_write_processing (bfd *abfd, bfd_boolean linker)
+{
+ elf32_arm_final_write_processing (abfd, linker);
+ nacl_final_write_processing (abfd, linker);
+}
+
+
#undef elf32_bed
#define elf32_bed elf32_arm_nacl_bed
#undef bfd_elf32_bfd_link_hash_table_create
#define elf_backend_modify_segment_map elf32_arm_nacl_modify_segment_map
#undef elf_backend_modify_program_headers
#define elf_backend_modify_program_headers nacl_modify_program_headers
+#undef elf_backend_final_write_processing
+#define elf_backend_final_write_processing elf32_arm_nacl_final_write_processing
#undef ELF_MAXPAGESIZE
#define ELF_MAXPAGESIZE 0x10000
+#undef ELF_MINPAGESIZE
+#undef ELF_COMMONPAGESIZE
+
#include "elf32-target.h"
#undef elf_backend_modify_segment_map
#define elf_backend_modify_segment_map elf32_arm_modify_segment_map
#undef elf_backend_modify_program_headers
+#undef elf_backend_final_write_processing
+#define elf_backend_final_write_processing elf32_arm_final_write_processing
+#undef ELF_MINPAGESIZE
+#define ELF_MINPAGESIZE 0x1000
+#undef ELF_COMMONPAGESIZE
+#define ELF_COMMONPAGESIZE 0x1000
+
/* VxWorks Targets. */