PARAMS ((struct bfd_link_info *, struct elf_link_hash_entry *));
static void elf32_arm_post_process_headers
PARAMS ((bfd *, struct bfd_link_info *));
+static int elf32_arm_to_thumb_stub
+ PARAMS ((struct bfd_link_info *, const char *, bfd *, bfd *, asection *,
+ bfd_byte *, asection *, bfd_vma, bfd_signed_vma, bfd_vma));
+static int elf32_thumb_to_arm_stub
+ PARAMS ((struct bfd_link_info *, const char *, bfd *, bfd *, asection *,
+ bfd_byte *, asection *, bfd_vma, bfd_signed_vma, bfd_vma));
/* The linker script knows the section names for placement.
The entry_names are used to do simple name mangling on the stubs.
/* The first entry in a procedure linkage table looks like
this. It is set up so that any shared library function that is
- called before the relocation has been set up calles the dynamic
+ called before the relocation has been set up calls the dynamic
linker first */
static const bfd_byte elf32_arm_plt0_entry [PLT_ENTRY_SIZE] =
0x04, 0xe0, 0x2d, 0xe5, /* str lr, [sp, #-4]! */
0x10, 0xe0, 0x9f, 0xe5, /* ldr lr, [pc, #16] */
0x0e, 0xe0, 0x8f, 0xe0, /* adr lr, pc, lr */
- 0x08, 0xf0, 0xbe, 0xe5 /* ldr pc, [lr, #-4] */
+ 0x08, 0xf0, 0xbe, 0xe5 /* ldr pc, [lr, #8]! */
};
/* Subsequent entries in a procedure linkage table look like
if (sec == NULL)
{
+ /* Note: we do not include the flag SEC_LINKER_CREATED, as this
+ will prevent elf_link_input_bfd() from processing the contents
+ of this section. */
flags = SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY;
sec = bfd_make_section (abfd, ARM2THUMB_GLUE_SECTION_NAME);
|| !bfd_set_section_flags (abfd, sec, flags)
|| !bfd_set_section_alignment (abfd, sec, 2))
return false;
+
+ /* Set the gc mark to prevent the section from being removed by garbage
+ collection, despite the fact that no relocs refer to this section. */
+ sec->gc_mark = 1;
}
sec = bfd_get_section_by_name (abfd, THUMB2ARM_GLUE_SECTION_NAME);
|| !bfd_set_section_flags (abfd, sec, flags)
|| !bfd_set_section_alignment (abfd, sec, 2))
return false;
+
+ sec->gc_mark = 1;
}
/* Save the bfd for later use. */
{
long r_type;
unsigned long r_index;
- unsigned char code;
struct elf_link_hash_entry *h;
case R_ARM_THM_PC22:
/* This one is a call from thumb code. We look
up the target of the call. If it is not a thumb
- target, we insert glue. */
+ target, we insert glue. */
if (ELF_ST_TYPE (h->type) != STT_ARM_TFUNC)
record_thumb_to_arm_glue (link_info, h);
static int
elf32_thumb_to_arm_stub (info, name, input_bfd, output_bfd, input_section,
hit_data, sym_sec, offset, addend, val)
- struct bfd_link_info *info;
- char *name;
- bfd *input_bfd;
- bfd *output_bfd;
- asection *input_section;
- bfd_byte *hit_data;
- asection *sym_sec;
- int offset;
- int addend;
- bfd_vma val;
+ struct bfd_link_info * info;
+ const char * name;
+ bfd * input_bfd;
+ bfd * output_bfd;
+ asection * input_section;
+ bfd_byte * hit_data;
+ asection * sym_sec;
+ bfd_vma offset;
+ bfd_signed_vma addend;
+ bfd_vma val;
{
- asection *s = 0;
+ asection * s = 0;
long int my_offset;
unsigned long int tmp;
long int ret_offset;
- struct elf_link_hash_entry *myh;
- struct elf32_arm_link_hash_table *globals;
+ struct elf_link_hash_entry * myh;
+ struct elf32_arm_link_hash_table * globals;
myh = find_thumb_glue (info, name, input_bfd);
if (myh == NULL)
static int
elf32_arm_to_thumb_stub (info, name, input_bfd, output_bfd, input_section,
hit_data, sym_sec, offset, addend, val)
-
- struct bfd_link_info *info;
- char *name;
- bfd *input_bfd;
- bfd *output_bfd;
- asection *input_section;
- bfd_byte *hit_data;
- asection *sym_sec;
- int offset;
- int addend;
- bfd_vma val;
+ struct bfd_link_info * info;
+ const char * name;
+ bfd * input_bfd;
+ bfd * output_bfd;
+ asection * input_section;
+ bfd_byte * hit_data;
+ asection * sym_sec;
+ bfd_vma offset;
+ bfd_signed_vma addend;
+ bfd_vma val;
{
unsigned long int tmp;
long int my_offset;
- asection *s;
+ asection * s;
long int ret_offset;
- struct elf_link_hash_entry *myh;
- struct elf32_arm_link_hash_table *globals;
+ struct elf_link_hash_entry * myh;
+ struct elf32_arm_link_hash_table * globals;
myh = find_arm_glue (info, name, input_bfd);
if (myh == NULL)
+ input_section->output_section->vma
+ offset + addend)
- 8;
-
+
tmp = tmp | ((ret_offset >> 2) & 0x00FFFFFF);
bfd_put_32 (output_bfd, tmp, hit_data
- input_section->vma);
-
return true;
}
if (sym_flags == STT_ARM_TFUNC)
{
elf32_arm_to_thumb_stub (info, sym_name, input_bfd, output_bfd,
- input_section, hit_data, sym_sec, rel->r_offset, addend, value);
+ input_section, hit_data, sym_sec, rel->r_offset,
+ signed_addend, value);
return bfd_reloc_ok;
}
value -= 8;
}
}
-
- value >>= howto->rightshift;
- value &= howto->dst_mask;
- value |= (bfd_get_32 (input_bfd, hit_data) & (~ howto->dst_mask));
+
+ /* It is not an error for an undefined weak reference to be
+ out of range. Any program that branches to such a symbol
+ is going to crash anyway, so there is no point worrying
+ about getting the destination exactly right. */
+ if (! h || h->root.type != bfd_link_hash_undefweak)
+ {
+ /* Perform a signed range check. */
+ signed_addend = value;
+ signed_addend >>= howto->rightshift;
+ if (signed_addend > ((bfd_signed_vma)(howto->dst_mask >> 1))
+ || signed_addend < - ((bfd_signed_vma) ((howto->dst_mask + 1) >> 1)))
+ return bfd_reloc_overflow;
+ }
+
+ value = (signed_addend & howto->dst_mask)
+ | (bfd_get_32 (input_bfd, hit_data) & (~ howto->dst_mask));
break;
case R_ARM_ABS32:
boolean overflow = false;
bfd_vma upper_insn = bfd_get_16 (input_bfd, hit_data);
bfd_vma lower_insn = bfd_get_16 (input_bfd, hit_data + 2);
- bfd_vma src_mask = 0x007FFFFE;
bfd_signed_vma reloc_signed_max = (1 << (howto->bitsize - 1)) - 1;
bfd_signed_vma reloc_signed_min = ~ reloc_signed_max;
bfd_vma check;
}
#endif
- /* If it's not a call to thumb, assume call to arm */
- if (sym_flags != STT_ARM_TFUNC)
+ /* 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)
{
if (elf32_thumb_to_arm_stub
(info, sym_name, input_bfd, output_bfd, input_section,
- hit_data, sym_sec, rel->r_offset, addend, value))
+ hit_data, sym_sec, rel->r_offset, signed_addend, value))
return bfd_reloc_ok;
else
return bfd_reloc_dangerous;
}
}
+#ifdef USE_REL
+/* Add INCREMENT to the reloc (of type HOWTO) at ADDRESS. */
+static void
+arm_add_to_rel (abfd, address, howto, increment)
+ bfd * abfd;
+ bfd_byte * address;
+ reloc_howto_type * howto;
+ bfd_signed_vma increment;
+{
+ bfd_vma contents;
+ bfd_signed_vma addend;
+
+ contents = bfd_get_32 (abfd, address);
+
+ /* Get the (signed) value from the instruction. */
+ addend = contents & howto->src_mask;
+ if (addend & ((howto->src_mask + 1) >> 1))
+ {
+ bfd_signed_vma mask;
+
+ mask = -1;
+ mask &= ~ howto->src_mask;
+ addend |= mask;
+ }
+
+ /* Add in the increment, (which is a byte value). */
+ switch (howto->type)
+ {
+ case R_ARM_THM_PC22:
+ default:
+ addend += increment;
+ break;
+
+ case R_ARM_PC24:
+ addend <<= howto->size;
+ addend += increment;
+
+ /* Should we check for overflow here ? */
+
+ /* Drop any undesired bits. */
+ addend >>= howto->rightshift;
+ break;
+ }
+
+ contents = (contents & ~ howto->dst_mask) | (addend & howto->dst_mask);
+
+ bfd_put_32 (abfd, contents, address);
+}
+#endif /* USE_REL */
/* Relocate an ARM ELF section. */
static boolean
{
sec = local_sections[r_symndx];
#ifdef USE_REL
- {
- bfd_vma val;
- bfd_vma insn;
-
- insn = bfd_get_32 (input_bfd, contents + rel->r_offset);
- val = insn + ((sec->output_offset + sym->st_value)
- >> howto->rightshift);
- val &= howto->dst_mask;
- val |= insn & ~(howto->dst_mask);
-
- bfd_put_32 (input_bfd, val, contents + rel->r_offset);
- }
+ arm_add_to_rel (input_bfd, contents + rel->r_offset,
+ howto, sec->output_offset + sym->st_value);
#else
rel->r_addend += (sec->output_offset + sym->st_value)
>> howto->rightshift;
}
else if (h->root.type == bfd_link_hash_undefweak)
relocation = 0;
+ else if (info->shared && !info->symbolic && !info->no_undefined)
+ relocation = 0;
else
{
if (!((*info->callbacks->undefined_symbol)
static asection *
elf32_arm_gc_mark_hook (abfd, info, rel, h, sym)
bfd *abfd;
- struct bfd_link_info *info;
+ struct bfd_link_info *info ATTRIBUTE_UNUSED;
Elf_Internal_Rela *rel;
struct elf_link_hash_entry *h;
Elf_Internal_Sym *sym;
case bfd_link_hash_common:
return h->root.u.c.p->section;
+
+ default:
+ break;
}
}
}
static boolean
elf32_arm_gc_sweep_hook (abfd, info, sec, relocs)
- bfd *abfd;
- struct bfd_link_info *info;
- asection *sec;
- const Elf_Internal_Rela *relocs;
+ bfd *abfd ATTRIBUTE_UNUSED;
+ struct bfd_link_info *info ATTRIBUTE_UNUSED;
+ asection *sec ATTRIBUTE_UNUSED;
+ const Elf_Internal_Rela *relocs ATTRIBUTE_UNUSED;
{
/* We don't support garbage collection of GOT and PLT relocs yet. */
return true;
/* This relocation describes which C++ vtable entries are actually
used. Record for later use during GC. */
case R_ARM_GNU_VTENTRY:
- if (!_bfd_elf32_gc_record_vtentry (abfd, sec, h, rel->r_addend))
+ if (!_bfd_elf32_gc_record_vtentry (abfd, sec, h, rel->r_offset))
return false;
break;
}
if (_bfd_dwarf2_find_nearest_line (abfd, section, symbols, offset,
filename_ptr, functionname_ptr,
- line_ptr))
+ line_ptr, 0))
return true;
if (! _bfd_stab_section_find_nearest_line (abfd, symbols, section, offset,
static boolean
elf32_arm_discard_copies (h, ignore)
struct elf32_arm_link_hash_entry * h;
- PTR ignore;
+ PTR ignore ATTRIBUTE_UNUSED;
{
struct elf32_arm_pcrel_relocs_copied * s;
static void
elf32_arm_post_process_headers (abfd, link_info)
bfd * abfd;
- struct bfd_link_info * link_info;
+ struct bfd_link_info * link_info ATTRIBUTE_UNUSED;
{
Elf_Internal_Ehdr * i_ehdrp; /* Elf file header, internal form */
#define elf_backend_want_got_plt 1
#define elf_backend_want_plt_sym 0
+#define elf_backend_got_header_size 12
+#define elf_backend_plt_header_size PLT_ENTRY_SIZE
+
#include "elf32-target.h"