typedef unsigned long int insn32;
typedef unsigned short int insn16;
-/* In leiu of proper flags, assume all EABIv3 objects are interworkable. */
+/* In lieu of proper flags, assume all EABIv4 objects are interworkable. */
#define INTERWORK_FLAG(abfd) \
- (EF_ARM_EABI_VERSION (elf_elfheader (abfd)->e_flags) == EF_ARM_EABI_VER3 \
+ (EF_ARM_EABI_VERSION (elf_elfheader (abfd)->e_flags) == EF_ARM_EABI_VER4 \
|| (elf_elfheader (abfd)->e_flags & EF_ARM_INTERWORK))
/* The linker script knows the section names for placement.
/* Nonzero to output a BE8 image. */
int byteswap_code;
+ /* Zero if R_ARM_TARGET1 means R_ARM_ABS32.
+ Nonzero if R_ARM_TARGET1 means R_ARM_ABS32. */
+ int target1_is_rel;
+
+ /* The relocation to use for R_ARM_TARGET2 relocations. */
+ int target2_reloc;
+
/* The number of bytes in the initial entry in the PLT. */
bfd_size_type plt_header_size;
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;
#ifdef FOUR_WORD_PLT
ret->plt_header_size = 16;
ret->plt_entry_size = 16;
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
+#ifndef OLD_ARM_ABI
+ && r_type != R_ARM_CALL
+ && r_type != R_ARM_JUMP24
+#endif
&& r_type != R_ARM_THM_PC22)
continue;
switch (r_type)
{
case R_ARM_PC24:
+#ifndef OLD_ARM_ABI
+ case R_ARM_CALL:
+ case R_ARM_JUMP24:
+#endif
/* This one is a call from arm code. We need to look up
the target of the call. If it is a thumb target, we
insert glue. */
}
#endif
+
+#ifndef OLD_ARM_ABI
+/* Set target relocation values needed during linking. */
+
+void
+bfd_elf32_arm_set_target_relocs (struct bfd_link_info *link_info,
+ int target1_is_rel,
+ char * target2_type)
+{
+ struct elf32_arm_link_hash_table *globals;
+
+ globals = elf32_arm_hash_table (link_info);
+
+ globals->target1_is_rel = target1_is_rel;
+ if (strcmp (target2_type, "rel") == 0)
+ globals->target2_reloc = R_ARM_REL32;
+ else if (strcmp (target2_type, "abs") == 0)
+ globals->target2_reloc = R_ARM_ABS32;
+ else if (strcmp (target2_type, "got-rel") == 0)
+ globals->target2_reloc = R_ARM_GOT_PREL;
+ else
+ {
+ _bfd_error_handler (_("Invalid TARGET2 relocation type '%s'."),
+ target2_type);
+ }
+}
+#endif
+
/* 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
return TRUE;
}
+
+#ifndef OLD_ARM_ABI
+/* Some relocations map to different relocations depending on the
+ target. Return the real relocation. */
+static int
+arm_real_reloc_type (struct elf32_arm_link_hash_table * globals,
+ int r_type)
+{
+ switch (r_type)
+ {
+ case R_ARM_TARGET1:
+ if (globals->target1_is_rel)
+ return R_ARM_REL32;
+ else
+ return R_ARM_ABS32;
+
+ case R_ARM_TARGET2:
+ return globals->target2_reloc;
+
+ default:
+ return r_type;
+ }
+}
+#endif /* OLD_ARM_ABI */
+
+
/* Perform a relocation as part of a final link. */
static bfd_reloc_status_type
bfd_signed_vma signed_addend;
struct elf32_arm_link_hash_table * globals;
+ globals = elf32_arm_hash_table (info);
+
+#ifndef OLD_ARM_ABI
+ /* Some relocation type 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)
+ howto = elf32_arm_howto_from_type (r_type);
+#endif /* OLD_ARM_ABI */
+
/* If the start address has been set, then set the EF_ARM_HASENTRY
flag. Setting this more than once is redundant, but the cost is
not too high, and it keeps the code simple.
if (bfd_get_start_address (output_bfd) != 0)
elf_elfheader (output_bfd)->e_flags |= EF_ARM_HASENTRY;
- globals = elf32_arm_hash_table (info);
-
dynobj = elf_hash_table (info)->dynobj;
if (dynobj)
{
case R_ARM_ABS32:
case R_ARM_REL32:
#ifndef OLD_ARM_ABI
+ case R_ARM_CALL:
+ case R_ARM_JUMP24:
case R_ARM_XPC25:
+ case R_ARM_PREL31:
#endif
case R_ARM_PLT32:
/* r_symndx will be zero only for relocs against symbols
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)
+ if ((r_type != R_ARM_ABS32 && r_type != R_ARM_REL32
+#ifndef OLD_ARM_ABI
+ && r_type != R_ARM_PREL31
+#endif
+ )
&& h != NULL
&& splt != NULL
&& h->plt.offset != (bfd_vma) -1)
into the output file to be resolved at run time. */
if (info->shared
&& (input_section->flags & SEC_ALLOC)
- && (r_type != R_ARM_REL32
- || !SYMBOL_CALLS_LOCAL (info, h))
+ && ((r_type != R_ARM_REL32
+#ifndef OLD_ARM_ABI
+ && r_type != R_ARM_PREL31
+#endif
+ ) || !SYMBOL_CALLS_LOCAL (info, h))
&& (h == NULL
|| ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
|| h->root.type != bfd_link_hash_undefweak)
&& r_type != R_ARM_PC24
+#ifndef OLD_ARM_ABI
+ && r_type != R_ARM_CALL
+ && r_type != R_ARM_JUMP24
+#endif
&& r_type != R_ARM_PLT32)
{
Elf_Internal_Rela outrel;
&& h->dynindx != -1
&& (!info->shared
|| !info->symbolic
- || (h->elf_link_hash_flags
- & ELF_LINK_HASH_DEF_REGULAR) == 0))
+ || !h->def_regular))
outrel.r_info = ELF32_R_INFO (h->dynindx, r_type);
else
{
{
#ifndef OLD_ARM_ABI
case R_ARM_XPC25: /* Arm BLX instruction. */
+ case R_ARM_CALL:
+ case R_ARM_JUMP24:
#endif
case R_ARM_PC24: /* Arm B/BL instruction */
case R_ARM_PLT32:
+ input_section->output_offset + rel->r_offset);
value += addend;
break;
+
+#ifndef OLD_ARM_ABI
+ case R_ARM_PREL31:
+ value -= (input_section->output_section->vma
+ + input_section->output_offset + rel->r_offset);
+ value += signed_addend;
+ if (! h || h->root.type != bfd_link_hash_undefweak)
+ {
+ /* Check for overflow */
+ if ((value ^ (value >> 1)) & (1 << 30))
+ return bfd_reloc_overflow;
+ }
+ value &= 0x7fffffff;
+ value |= (bfd_get_32 (input_bfd, hit_data) & 0x80000000);
+ if (sym_flags == STT_ARM_TFUNC)
+ value |= 1;
+ break;
+#endif
}
bfd_put_32 (input_bfd, value, hit_data);
(bfd_vma) 0);
case R_ARM_GOT32:
+#ifndef OLD_ARM_ABI
+ case R_ARM_GOT_PREL:
+#endif
/* Relocation is to the entry for this symbol in the
global offset table. */
if (sgot == NULL)
value = sgot->output_offset + off;
}
+ if (r_type != R_ARM_GOT32)
+ value += sgot->output_section->vma;
return _bfd_final_link_relocate (howto, input_bfd, input_section,
contents, rel->r_offset, value,
break;
case R_ARM_PC24:
+#ifndef OLD_ARM_ABI
+ case R_ARM_CALL:
+ case R_ARM_JUMP24:
+#endif
addend <<= howto->size;
addend += increment;
switch (r_type)
{
case R_ARM_PC24:
+#ifndef OLD_ARM_ABI
+ case R_ARM_CALL:
+ case R_ARM_JUMP24:
+#endif
case R_ARM_ABS32:
case R_ARM_THM_PC22:
case R_ARM_PLT32:
if (info->shared
- && (
- (!info->symbolic && h->dynindx != -1)
- || (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0
- )
+ && ((!info->symbolic && h->dynindx != -1)
+ || !h->def_regular)
&& ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
&& ((input_section->flags & SEC_ALLOC) != 0
/* DWARF will emit R_ARM_ABS32 relocations in its
in shared libraries. We can't do anything
with them here. */
|| ((input_section->flags & SEC_DEBUGGING) != 0
- && (h->elf_link_hash_flags
- & ELF_LINK_HASH_DEF_DYNAMIC) != 0))
+ && h->def_dynamic))
)
relocation = 0;
break;
break;
case R_ARM_GOT32:
+#ifndef OLD_ARM_ABI
+ case R_ARM_GOT_PREL:
+#endif
if ((WILL_CALL_FINISH_DYNAMIC_SYMBOL
(elf_hash_table (info)->dynamic_sections_created,
info->shared, h))
&& (!info->shared
|| (!info->symbolic && h->dynindx != -1)
- || (h->elf_link_hash_flags
- & ELF_LINK_HASH_DEF_REGULAR) == 0))
+ || !h->def_regular))
relocation = 0;
break;
if ((! h ||
h->root.type != bfd_link_hash_undefined)
&& (!((*info->callbacks->reloc_overflow)
- (info, name, howto->name, (bfd_vma) 0,
- input_bfd, input_section, rel->r_offset))))
+ (info, (h ? &h->root : NULL), name, howto->name,
+ (bfd_vma) 0, input_bfd, input_section,
+ rel->r_offset))))
return FALSE;
break;
}
/* Function to keep ARM specific flags in the ELF header. */
+
static bfd_boolean
elf32_arm_set_private_flags (bfd *abfd, flagword flags)
{
if (EF_ARM_EABI_VERSION (in_flags) != EF_ARM_EABI_VERSION (out_flags))
{
_bfd_error_handler
- (_("ERROR: %B is compiled for EABI version %d, whereas %B is compiled for version %d"),
+ (_("ERROR: Source object %B has EABI version %d, but target %B has EABI version %d"),
ibfd, obfd,
(in_flags & EF_ARM_EABIMASK) >> 24,
(out_flags & EF_ARM_EABIMASK) >> 24);
case EF_ARM_EABI_VER3:
fprintf (file, _(" [Version3 EABI]"));
+ break;
+
+ case EF_ARM_EABI_VER4:
+ fprintf (file, _(" [Version4 EABI]"));
if (flags & EF_ARM_BE8)
fprintf (file, _(" [BE8]"));
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);
elf_section_data (sec)->local_dynrel = NULL;
relend = relocs + sec->reloc_count;
for (rel = relocs; rel < relend; rel++)
- switch (ELF32_R_TYPE (rel->r_info))
- {
- case R_ARM_GOT32:
- r_symndx = ELF32_R_SYM (rel->r_info);
- if (r_symndx >= symtab_hdr->sh_info)
- {
- h = sym_hashes[r_symndx - symtab_hdr->sh_info];
- if (h->got.refcount > 0)
- h->got.refcount -= 1;
- }
- else if (local_got_refcounts != NULL)
- {
- if (local_got_refcounts[r_symndx] > 0)
- local_got_refcounts[r_symndx] -= 1;
- }
- break;
-
- case R_ARM_ABS32:
- case R_ARM_REL32:
- case R_ARM_PC24:
- case R_ARM_PLT32:
- r_symndx = ELF32_R_SYM (rel->r_info);
- if (r_symndx >= symtab_hdr->sh_info)
- {
- struct elf32_arm_link_hash_entry *eh;
- struct elf32_arm_relocs_copied **pp;
- struct elf32_arm_relocs_copied *p;
+ {
+ int r_type;
+
+ r_type = ELF32_R_TYPE (rel->r_info);
+#ifndef OLD_ARM_ABI
+ r_type = arm_real_reloc_type (globals, r_type);
+#endif
+ switch (r_type)
+ {
+ case R_ARM_GOT32:
+#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)
+ {
+ h = sym_hashes[r_symndx - symtab_hdr->sh_info];
+ if (h->got.refcount > 0)
+ h->got.refcount -= 1;
+ }
+ else if (local_got_refcounts != NULL)
+ {
+ if (local_got_refcounts[r_symndx] > 0)
+ local_got_refcounts[r_symndx] -= 1;
+ }
+ break;
+
+ case R_ARM_ABS32:
+ case R_ARM_REL32:
+ case R_ARM_PC24:
+ case R_ARM_PLT32:
+#ifndef OLD_ARM_ABI
+ case R_ARM_CALL:
+ case R_ARM_JUMP24:
+ case R_ARM_PREL31:
+#endif
+ r_symndx = ELF32_R_SYM (rel->r_info);
+ if (r_symndx >= symtab_hdr->sh_info)
+ {
+ 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];
+ h = sym_hashes[r_symndx - symtab_hdr->sh_info];
- if (h->plt.refcount > 0)
- h->plt.refcount -= 1;
+ if (h->plt.refcount > 0)
+ h->plt.refcount -= 1;
- if (ELF32_R_TYPE (rel->r_info) == R_ARM_ABS32
- || ELF32_R_TYPE (rel->r_info) == R_ARM_REL32)
- {
- eh = (struct elf32_arm_link_hash_entry *) h;
+ 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)
- {
- p->count -= 1;
- if (p->count == 0)
- *pp = p->next;
- break;
- }
- }
- }
- break;
+ for (pp = &eh->relocs_copied; (p = *pp) != NULL;
+ pp = &p->next)
+ if (p->section == sec)
+ {
+ p->count -= 1;
+ if (p->count == 0)
+ *pp = p->next;
+ break;
+ }
+ }
+ }
+ break;
- default:
- break;
- }
+ default:
+ break;
+ }
+ }
return TRUE;
}
{
struct elf_link_hash_entry *h;
unsigned long r_symndx;
+ int r_type;
r_symndx = ELF32_R_SYM (rel->r_info);
+ r_type = ELF32_R_TYPE (rel->r_info);
+#ifndef OLD_ARM_ABI
+ r_type = arm_real_reloc_type (htab, r_type);
+#endif
if (r_symndx < symtab_hdr->sh_info)
h = NULL;
else
h = sym_hashes[r_symndx - symtab_hdr->sh_info];
- switch (ELF32_R_TYPE (rel->r_info))
+ switch (r_type)
{
case R_ARM_GOT32:
+#ifndef OLD_ARM_ABI
+ case R_ARM_GOT_PREL:
+#endif
/* This symbol requires a global offset table entry. */
if (h != NULL)
{
}
local_got_refcounts[r_symndx] += 1;
}
- break;
+ if (r_type == R_ARM_GOT32)
+ break;
+ /* Fall through. */
case R_ARM_GOTOFF:
case R_ARM_GOTPC:
case R_ARM_REL32:
case R_ARM_PC24:
case R_ARM_PLT32:
+#ifndef OLD_ARM_ABI
+ case R_ARM_CALL:
+ case R_ARM_JUMP24:
+ case R_ARM_PREL31:
+#endif
if (h != NULL)
{
/* If this reloc is in a read-only section, we might
Tentatively set the flag for now, and correct in
adjust_dynamic_symbol. */
if (!info->shared)
- h->elf_link_hash_flags |= ELF_LINK_NON_GOT_REF;
+ h->non_got_ref = 1;
/* We may need a .plt entry if the function this reloc
refers to is in a different object. We can't tell for
sure yet, because something later might force the
symbol local. */
- if (ELF32_R_TYPE (rel->r_info) == R_ARM_PC24
- || ELF32_R_TYPE (rel->r_info) == R_ARM_PLT32)
- h->elf_link_hash_flags |= ELF_LINK_HASH_NEEDS_PLT;
+ if (r_type == R_ARM_PC24
+#ifndef OLD_ARM_ABI
+ || r_type == R_ARM_CALL
+ || r_type == R_ARM_JUMP24
+#endif
+ || r_type == R_ARM_PLT32)
+ h->needs_plt = 1;
/* If we create a PLT entry, this relocation will reference
it, even if it's an ABS32 relocation. */
relocs_copied field of the hash table entry. */
if (info->shared
&& (sec->flags & SEC_ALLOC) != 0
- && ((ELF32_R_TYPE (rel->r_info) != R_ARM_PC24
- && ELF32_R_TYPE (rel->r_info) != R_ARM_PLT32
- && ELF32_R_TYPE (rel->r_info) != R_ARM_REL32)
+ && ((r_type != R_ARM_PC24
+ && r_type != R_ARM_PLT32
+#ifndef OLD_ARM_ABI
+ && r_type != R_ARM_CALL
+ && r_type != R_ARM_JUMP24
+ && r_type != R_ARM_PREL31
+#endif
+ && r_type != R_ARM_REL32)
|| (h != NULL
&& (! info->symbolic
- || (h->elf_link_hash_flags
- & ELF_LINK_HASH_DEF_REGULAR) == 0))))
+ || !h->def_regular))))
{
struct elf32_arm_relocs_copied *p, **head;
p->count = 0;
}
- if (ELF32_R_TYPE (rel->r_info) == R_ARM_ABS32
- || ELF32_R_TYPE (rel->r_info) == R_ARM_REL32)
+ if (r_type == R_ARM_ABS32
+#ifndef OLD_ARM_ABI
+ || r_type == R_ARM_PREL31
+#endif
+ || r_type == R_ARM_REL32)
p->count += 1;
}
break;
&& (name[2] == 0);
}
+/* Treat mapping symbols as special target symbols. */
+
+static bfd_boolean
+elf32_arm_is_target_special_symbol (bfd * abfd ATTRIBUTE_UNUSED, asymbol * sym)
+{
+ return is_arm_mapping_symbol_name (sym->name);
+}
+
/* This is a copy of elf_find_function() from elf.c except that
ARM mapping symbols are ignored when looking for function names
and STT_ARM_TFUNC is considered to a function type. */
q = (elf_symbol_type *) *p;
- if (bfd_get_section (&q->symbol) != section)
- continue;
-
switch (ELF_ST_TYPE (q->internal_elf_sym.st_info))
{
default:
continue;
/* Fall through. */
case STT_NOTYPE:
- if (q->symbol.section == section
+ if (bfd_get_section (&q->symbol) == section
&& q->symbol.value >= low_func
&& q->symbol.value <= offset)
{
/* Make sure we know what is going on here. */
BFD_ASSERT (dynobj != NULL
- && ((h->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_PLT)
- || h->weakdef != NULL
- || ((h->elf_link_hash_flags
- & ELF_LINK_HASH_DEF_DYNAMIC) != 0
- && (h->elf_link_hash_flags
- & ELF_LINK_HASH_REF_REGULAR) != 0
- && (h->elf_link_hash_flags
- & ELF_LINK_HASH_DEF_REGULAR) == 0)));
+ && (h->needs_plt
+ || h->u.weakdef != NULL
+ || (h->def_dynamic
+ && h->ref_regular
+ && !h->def_regular)));
/* 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
- || (h->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_PLT) != 0)
+ || h->needs_plt)
{
if (h->plt.refcount <= 0
|| SYMBOL_CALLS_LOCAL (info, h)
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;
- h->elf_link_hash_flags &= ~ELF_LINK_HASH_NEEDS_PLT;
+ h->needs_plt = 0;
}
return TRUE;
}
else
/* It's possible that we incorrectly decided a .plt reloc was
- needed for an R_ARM_PC24 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
+ 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;
/* If this is a weak symbol, and there is a real definition, the
processor independent code will have arranged for us to see the
real definition first, and we can just use the same value. */
- if (h->weakdef != NULL)
+ if (h->u.weakdef != NULL)
{
- BFD_ASSERT (h->weakdef->root.type == bfd_link_hash_defined
- || h->weakdef->root.type == bfd_link_hash_defweak);
- h->root.u.def.section = h->weakdef->root.u.def.section;
- h->root.u.def.value = h->weakdef->root.u.def.value;
+ BFD_ASSERT (h->u.weakdef->root.type == bfd_link_hash_defined
+ || h->u.weakdef->root.type == bfd_link_hash_defweak);
+ h->root.u.def.section = h->u.weakdef->root.u.def.section;
+ h->root.u.def.value = h->u.weakdef->root.u.def.value;
return TRUE;
}
srel = bfd_get_section_by_name (dynobj, ".rel.bss");
BFD_ASSERT (srel != NULL);
srel->size += sizeof (Elf32_External_Rel);
- h->elf_link_hash_flags |= ELF_LINK_HASH_NEEDS_COPY;
+ h->needs_copy = 1;
}
/* We need to figure out the alignment required for this symbol. I
/* Make sure this symbol is output as a dynamic symbol.
Undefined weak syms won't yet be marked as dynamic. */
if (h->dynindx == -1
- && (h->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) == 0)
+ && !h->forced_local)
{
if (! bfd_elf_link_record_dynamic_symbol (info, h))
return FALSE;
pointers compare as equal between the normal executable and
the shared library. */
if (! info->shared
- && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0)
+ && !h->def_regular)
{
h->root.u.def.section = s;
h->root.u.def.value = h->plt.offset;
else
{
h->plt.offset = (bfd_vma) -1;
- h->elf_link_hash_flags &= ~ELF_LINK_HASH_NEEDS_PLT;
+ h->needs_plt = 0;
}
}
else
{
h->plt.offset = (bfd_vma) -1;
- h->elf_link_hash_flags &= ~ELF_LINK_HASH_NEEDS_PLT;
+ h->needs_plt = 0;
}
if (h->got.refcount > 0)
/* Make sure this symbol is output as a dynamic symbol.
Undefined weak syms won't yet be marked as dynamic. */
if (h->dynindx == -1
- && (h->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) == 0)
+ && !h->forced_local)
{
if (! bfd_elf_link_record_dynamic_symbol (info, h))
return FALSE;
symbols which turn out to need copy relocs or are not
dynamic. */
- if ((h->elf_link_hash_flags & ELF_LINK_NON_GOT_REF) == 0
- && (((h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) != 0
- && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0)
+ if (!h->non_got_ref
+ && ((h->def_dynamic
+ && !h->def_regular)
|| (htab->root.dynamic_sections_created
&& (h->root.type == bfd_link_hash_undefweak
|| h->root.type == bfd_link_hash_undefined))))
/* Make sure this symbol is output as a dynamic symbol.
Undefined weak syms won't yet be marked as dynamic. */
if (h->dynindx == -1
- && (h->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) == 0)
+ && !h->forced_local)
{
if (! bfd_elf_link_record_dynamic_symbol (info, h))
return FALSE;
splt->contents + h->plt.offset + 4 * i);
/* Fill in the entry in the .rel.plt section. */
- rel.r_offset = (splt->output_offset
+ rel.r_offset = (splt->output_section->vma
+ + splt->output_offset
+ h->plt.offset + 4 * (i - 1));
rel.r_info = ELF32_R_INFO (h->dynindx, R_ARM_GLOB_DAT);
}
loc = srel->contents + plt_index * sizeof (Elf32_External_Rel);
bfd_elf32_swap_reloc_out (output_bfd, &rel, loc);
- if ((h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0)
+ if (!h->def_regular)
{
/* Mark the symbol as undefined, rather than as defined in
the .plt section. Leave the value alone. */
Otherwise, the PLT entry would provide a definition for
the symbol even if the symbol wasn't defined anywhere,
and so the symbol would never be NULL. */
- if ((h->elf_link_hash_flags & ELF_LINK_HASH_REF_REGULAR_NONWEAK)
- == 0)
+ if (!h->ref_regular_nonweak)
sym->st_value = 0;
}
}
bfd_elf32_swap_reloc_out (output_bfd, &rel, loc);
}
- if ((h->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_COPY) != 0)
+ if (h->needs_copy)
{
asection * s;
Elf_Internal_Rela rel;
dynobj = elf_hash_table (info)->dynobj;
sgot = bfd_get_section_by_name (dynobj, ".got.plt");
- BFD_ASSERT (sgot != NULL);
+ BFD_ASSERT (elf32_arm_hash_table (info)->symbian_p || sgot != NULL);
sdyn = bfd_get_section_by_name (dynobj, ".dynamic");
if (elf_hash_table (info)->dynamic_sections_created)
{
asection *splt;
Elf32_External_Dyn *dyncon, *dynconend;
+ struct elf32_arm_link_hash_table *htab;
+ htab = elf32_arm_hash_table (info);
splt = bfd_get_section_by_name (dynobj, ".plt");
BFD_ASSERT (splt != NULL && sdyn != NULL);
switch (dyn.d_tag)
{
+ unsigned int type;
+
default:
break;
+ case DT_HASH:
+ name = ".hash";
+ goto get_vma_if_bpabi;
+ case DT_STRTAB:
+ name = ".dynstr";
+ goto get_vma_if_bpabi;
+ case DT_SYMTAB:
+ name = ".dynsym";
+ goto get_vma_if_bpabi;
+ case DT_VERSYM:
+ name = ".gnu.version";
+ goto get_vma_if_bpabi;
+ case DT_VERDEF:
+ name = ".gnu.version_d";
+ goto get_vma_if_bpabi;
+ case DT_VERNEED:
+ name = ".gnu.version_r";
+ goto get_vma_if_bpabi;
+
case DT_PLTGOT:
name = ".got";
goto get_vma;
get_vma:
s = bfd_get_section_by_name (output_bfd, name);
BFD_ASSERT (s != NULL);
- dyn.d_un.d_ptr = s->vma;
+ if (!htab->symbian_p)
+ dyn.d_un.d_ptr = s->vma;
+ else
+ /* In the BPABI, tags in the PT_DYNAMIC section point
+ at the file offset, not the memory address, for the
+ convenience of the post linker. */
+ dyn.d_un.d_ptr = s->filepos;
bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon);
break;
+ get_vma_if_bpabi:
+ if (htab->symbian_p)
+ goto get_vma;
+ break;
+
case DT_PLTRELSZ:
s = bfd_get_section_by_name (output_bfd, ".rel.plt");
BFD_ASSERT (s != NULL);
dyn.d_un.d_val = s->size;
bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon);
break;
-
+
case DT_RELSZ:
- /* My reading of the SVR4 ABI indicates that the
- procedure linkage table relocs (DT_JMPREL) should be
- included in the overall relocs (DT_REL). This is
- what Solaris does. However, UnixWare can not handle
- that case. Therefore, we override the DT_RELSZ entry
- here to make it not include the JMPREL relocs. Since
- the linker script arranges for .rel.plt to follow all
- other relocation sections, we don't have to worry
- about changing the DT_REL entry. */
- s = bfd_get_section_by_name (output_bfd, ".rel.plt");
- if (s != NULL)
- dyn.d_un.d_val -= s->size;
- bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon);
+ if (!htab->symbian_p)
+ {
+ /* My reading of the SVR4 ABI indicates that the
+ procedure linkage table relocs (DT_JMPREL) should be
+ included in the overall relocs (DT_REL). This is
+ what Solaris does. However, UnixWare can not handle
+ that case. Therefore, we override the DT_RELSZ entry
+ here to make it not include the JMPREL relocs. Since
+ the linker script arranges for .rel.plt to follow all
+ other relocation sections, we don't have to worry
+ about changing the DT_REL entry. */
+ s = bfd_get_section_by_name (output_bfd, ".rel.plt");
+ if (s != NULL)
+ dyn.d_un.d_val -= s->size;
+ bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon);
+ break;
+ }
+ /* Fall through */
+
+ case DT_REL:
+ case DT_RELA:
+ case DT_RELASZ:
+ /* In the BPABI, the DT_REL tag must point at the file
+ offset, not the VMA, of the first relocation
+ section. So, we use code similar to that in
+ elflink.c, but do not check for SHF_ALLOC on the
+ relcoation section, since relocations sections are
+ never allocated under the BPABI. The comments above
+ about Unixware notwithstanding, we include all of the
+ relocations here. */
+ if (htab->symbian_p)
+ {
+ unsigned int i;
+ type = ((dyn.d_tag == DT_REL || dyn.d_tag == DT_RELSZ)
+ ? SHT_REL : SHT_RELA);
+ dyn.d_un.d_val = 0;
+ for (i = 1; i < elf_numsections (output_bfd); i++)
+ {
+ Elf_Internal_Shdr *hdr
+ = elf_elfsections (output_bfd)[i];
+ if (hdr->sh_type == type)
+ {
+ 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)
+ dyn.d_un.d_val = hdr->sh_offset;
+ }
+ }
+ bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon);
+ }
break;
/* Set the bottom bit of DT_INIT/FINI if the
}
/* Fill in the first three entries in the global offset table. */
- if (sgot->size > 0)
+ if (sgot)
{
- if (sdyn == NULL)
- bfd_put_32 (output_bfd, (bfd_vma) 0, sgot->contents);
- else
- bfd_put_32 (output_bfd,
- sdyn->output_section->vma + sdyn->output_offset,
- sgot->contents);
- bfd_put_32 (output_bfd, (bfd_vma) 0, sgot->contents + 4);
- bfd_put_32 (output_bfd, (bfd_vma) 0, sgot->contents + 8);
- }
+ if (sgot->size > 0)
+ {
+ if (sdyn == NULL)
+ bfd_put_32 (output_bfd, (bfd_vma) 0, sgot->contents);
+ else
+ bfd_put_32 (output_bfd,
+ sdyn->output_section->vma + sdyn->output_offset,
+ sgot->contents);
+ bfd_put_32 (output_bfd, (bfd_vma) 0, sgot->contents + 4);
+ bfd_put_32 (output_bfd, (bfd_vma) 0, sgot->contents + 8);
+ }
- elf_section_data (sgot->output_section)->this_hdr.sh_entsize = 4;
+ elf_section_data (sgot->output_section)->this_hdr.sh_entsize = 4;
+ }
return TRUE;
}
}
}
-static bfd_boolean elf32_arm_section_flags (flagword *, const Elf_Internal_Shdr *);
-static void elf32_arm_final_write_processing (bfd *, bfd_boolean);
-
/* Set the right machine number for an Arm ELF file. */
static bfd_boolean
bfd_arm_update_notes (abfd, ARM_NOTE_SECTION);
}
+/* Return TRUE if this is an unwinding table entry. */
+
+static bfd_boolean
+is_arm_elf_unwind_section_name (bfd * abfd ATTRIBUTE_UNUSED, const char * name)
+{
+ size_t len1, len2;
+
+ len1 = sizeof (ELF_STRING_ARM_unwind) - 1;
+ len2 = sizeof (ELF_STRING_ARM_unwind_once) - 1;
+ return (strncmp (name, ELF_STRING_ARM_unwind, len1) == 0
+ || strncmp (name, ELF_STRING_ARM_unwind_once, len2) == 0);
+}
+
+
+/* Set the type and flags for an ARM section. We do this by
+ the section name, which is a hack, but ought to work. */
+
+static bfd_boolean
+elf32_arm_fake_sections (bfd * abfd, Elf_Internal_Shdr * hdr, asection * sec)
+{
+ const char * name;
+
+ name = bfd_get_section_name (abfd, sec);
+
+ if (is_arm_elf_unwind_section_name (abfd, name))
+ {
+ hdr->sh_type = SHT_ARM_EXIDX;
+ hdr->sh_flags |= SHF_LINK_ORDER;
+ }
+ return TRUE;
+}
+
+/* Handle an ARM specific section when reading an object file.
+ This is called when elf.c finds a section with an unknown type. */
+
+static bfd_boolean
+elf32_arm_section_from_shdr (bfd *abfd,
+ Elf_Internal_Shdr * hdr,
+ const char *name)
+{
+ /* There ought to be a place to keep ELF backend specific flags, but
+ at the moment there isn't one. We just keep track of the
+ sections by their name, instead. Fortunately, the ABI gives
+ names for all the ARM specific sections, so we will probably get
+ away with this. */
+ switch (hdr->sh_type)
+ {
+ case SHT_ARM_EXIDX:
+ break;
+
+ default:
+ return FALSE;
+ }
+
+ if (! _bfd_elf_make_section_from_shdr (abfd, hdr, name))
+ return FALSE;
+
+ return TRUE;
+}
/* Called for each symbol. Builds a section map based on mapping symbols.
Does not alter any of the symbols. */
#define bfd_elf32_bfd_reloc_type_lookup elf32_arm_reloc_type_lookup
#define bfd_elf32_find_nearest_line elf32_arm_find_nearest_line
#define bfd_elf32_new_section_hook elf32_arm_new_section_hook
+#define bfd_elf32_bfd_is_target_special_symbol elf32_arm_is_target_special_symbol
#define elf_backend_get_symbol_type elf32_arm_get_symbol_type
#define elf_backend_gc_mark_hook elf32_arm_gc_mark_hook
#define elf_backend_reloc_type_class elf32_arm_reloc_type_class
#define elf_backend_object_p elf32_arm_object_p
#define elf_backend_section_flags elf32_arm_section_flags
+#define elf_backend_fake_sections elf32_arm_fake_sections
+#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