along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
-
typedef unsigned long int insn32;
typedef unsigned short int insn16;
PARAMS ((reloc_howto_type *, bfd *, bfd *, asection *, bfd_byte *,
Elf_Internal_Rela *, bfd_vma, struct bfd_link_info *, asection *,
const char *, unsigned char, struct elf_link_hash_entry *));
-
static insn32 insert_thumb_branch
PARAMS ((insn32, int));
static struct elf_link_hash_entry *find_thumb_glue
PARAMS ((struct bfd_link_info *, const char *, bfd *, bfd *, asection *,
bfd_byte *, asection *, bfd_vma, bfd_signed_vma, bfd_vma));
+#define INTERWORK_FLAG(abfd) (elf_elfheader (abfd)->e_flags & EF_INTERWORK)
+
/* The linker script knows the section names for placement.
The entry_names are used to do simple name mangling on the stubs.
Given a function name, and its type, the stub can be found. The
- name can be changed. The only requirement is the %s be present.
- */
-
-#define INTERWORK_FLAG( abfd ) (elf_elfheader (abfd)->e_flags & EF_INTERWORK)
-
+ name can be changed. The only requirement is the %s be present. */
#define THUMB2ARM_GLUE_SECTION_NAME ".glue_7t"
#define THUMB2ARM_GLUE_ENTRY_NAME "__%s_from_thumb"
#define ELF_DYNAMIC_INTERPRETER "/usr/lib/ld.so.1"
/* The size in bytes of an entry in the procedure linkage table. */
-
#define PLT_ENTRY_SIZE 16
/* 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 calls the dynamic
- linker first */
-
+ linker first. */
static const bfd_byte elf32_arm_plt0_entry [PLT_ENTRY_SIZE] =
{
0x04, 0xe0, 0x2d, 0xe5, /* str lr, [sp, #-4]! */
/* Subsequent entries in a procedure linkage table look like
this. */
-
static const bfd_byte elf32_arm_plt_entry [PLT_ENTRY_SIZE] =
{
0x04, 0xc0, 0x9f, 0xe5, /* ldr ip, [pc, #4] */
0x00, 0x00, 0x00, 0x00 /* offset to symbol in got */
};
-
/* The ARM linker needs to keep track of the number of relocs that it
decides to copy in check_relocs for each symbol. This is so that
it can discard PC relative relocs if it doesn't need them when
/* This structure keeps track of the number of PC relative relocs we
have copied for a given symbol. */
-
struct elf32_arm_pcrel_relocs_copied
{
/* Next section. */
};
/* Arm ELF linker hash entry. */
-
struct elf32_arm_link_hash_entry
{
struct elf_link_hash_entry root;
};
/* Declare this now that the above structures are defined. */
-
static boolean elf32_arm_discard_copies
PARAMS ((struct elf32_arm_link_hash_entry *, PTR));
/* Traverse an arm ELF linker hash table. */
-
#define elf32_arm_link_hash_traverse(table, func, info) \
(elf_link_hash_traverse \
(&(table)->root, \
#define elf32_arm_hash_table(info) \
((struct elf32_arm_link_hash_table *) ((info)->hash))
-/* ARM ELF linker hash table */
+/* ARM ELF linker hash table. */
struct elf32_arm_link_hash_table
- {
- /* The main hash table. */
- struct elf_link_hash_table root;
-
- /* The size in bytes of the section containg the Thumb-to-ARM glue. */
- long int thumb_glue_size;
+{
+ /* The main hash table. */
+ struct elf_link_hash_table root;
- /* The size in bytes of the section containg the ARM-to-Thumb glue. */
- long int arm_glue_size;
+ /* The size in bytes of the section containg the Thumb-to-ARM glue. */
+ long int thumb_glue_size;
- /* An arbitary input BFD chosen to hold the glue sections. */
- bfd * bfd_of_glue_owner;
+ /* The size in bytes of the section containg the ARM-to-Thumb glue. */
+ long int arm_glue_size;
- /* A boolean indicating whether knowledge of the ARM's pipeline
- length should be applied by the linker. */
- int no_pipeline_knowledge;
- };
+ /* An arbitary 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;
+};
/* Create an entry in an ARM ELF linker hash table. */
return (struct bfd_hash_entry *) ret;
}
-/* Create an ARM elf linker hash table */
+/* Create an ARM elf linker hash table. */
static struct bfd_link_hash_table *
elf32_arm_link_hash_table_create (abfd)
return &ret->root.root;
}
+/* Locate the Thumb encoded calling stub for NAME. */
+
static struct elf_link_hash_entry *
find_thumb_glue (link_info, name, input_bfd)
struct bfd_link_info *link_info;
/* We need a pointer to the armelf specific hash table. */
hash_table = elf32_arm_hash_table (link_info);
-
tmp_name = ((char *)
bfd_malloc (strlen (name) + strlen (THUMB2ARM_GLUE_ENTRY_NAME) + 1));
if (hash == NULL)
/* xgettext:c-format */
- _bfd_error_handler (_ ("%s: unable to find THUMB glue '%s' for `%s'"),
+ _bfd_error_handler (_("%s: unable to find THUMB glue '%s' for `%s'"),
bfd_get_filename (input_bfd), tmp_name, name);
free (tmp_name);
return hash;
}
+/* Locate the ARM encoded calling stub for NAME. */
+
static struct elf_link_hash_entry *
find_arm_glue (link_info, name, input_bfd)
struct bfd_link_info *link_info;
if (myh == NULL)
/* xgettext:c-format */
- _bfd_error_handler (_ ("%s: unable to find ARM glue '%s' for `%s'"),
+ _bfd_error_handler (_("%s: unable to find ARM glue '%s' for `%s'"),
bfd_get_filename (input_bfd), tmp_name, name);
free (tmp_name);
return myh;
}
-/*
- ARM->Thumb glue:
+/* ARM->Thumb glue:
.arm
__func_from_arm:
ldr r12, __func_addr
bx r12
__func_addr:
- .word func @ behave as if you saw a ARM_32 reloc
- */
+ .word func @ behave as if you saw a ARM_32 reloc. */
#define ARM2THUMB_GLUE_SIZE 12
static const insn32 a2t1_ldr_insn = 0xe59fc000;
static const insn32 a2t2_bx_r12_insn = 0xe12fff1c;
static const insn32 a2t3_func_addr_insn = 0x00000001;
-/*
- Thumb->ARM: Thumb->(non-interworking aware) ARM
+/* Thumb->ARM: Thumb->(non-interworking aware) ARM
.thumb .thumb
.align 2 .align 2
ldmia r13! {r6, lr}
bx lr
__func_addr:
- .word func
- */
+ .word func */
#define THUMB2ARM_GLUE_SIZE 8
static const insn16 t2a1_bx_pc_insn = 0x4778;
s = bfd_get_section_by_name
(globals->bfd_of_glue_owner, ARM2THUMB_GLUE_SECTION_NAME);
-
BFD_ASSERT (s != NULL);
tmp_name = ((char *)
if (myh != NULL)
{
+ /* We've already seen this guy. */
free (tmp_name);
- return; /* we've already seen this guy */
+ return;
}
/* The only trick here is using hash_table->arm_glue_size as the value. Even
though the section isn't allocated yet, this is where we will be putting
it. */
-
_bfd_generic_link_add_one_symbol (link_info, globals->bfd_of_glue_owner, tmp_name,
BSF_GLOBAL,
s, globals->arm_glue_size + 1,
if (myh != NULL)
{
+ /* We've already seen this guy. */
free (tmp_name);
- return; /* we've already seen this guy */
+ return;
}
_bfd_generic_link_add_one_symbol (link_info, hash_table->bfd_of_glue_owner, tmp_name,
NULL, true, false,
(struct bfd_link_hash_entry **) &myh);
- /* If we mark it 'thumb', the disassembler will do a better job. */
+ /* If we mark it 'Thumb', the disassembler will do a better job. */
bind = ELF_ST_BIND (myh->type);
myh->type = ELF_ST_INFO (bind, STT_ARM_TFUNC);
free (tmp_name);
- /* Allocate another symbol to mark where we switch to arm mode. */
-
#define CHANGE_TO_ARM "__%s_change_to_arm"
#define BACK_FROM_ARM "__%s_back_from_arm"
+ /* Allocate another symbol to mark where we switch to Arm mode. */
tmp_name = (char *) bfd_malloc (strlen (name) + strlen (CHANGE_TO_ARM) + 1);
BFD_ASSERT (tmp_name);
/* Select a BFD to be used to hold the sections used by the glue code.
This function is called from the linker scripts in ld/emultempl/
{armelf/pe}.em */
+
boolean
bfd_elf32_arm_get_bfd_for_interworking (abfd, info)
bfd *abfd;
|| !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;
|| !bfd_set_section_flags (abfd, sec, flags)
|| !bfd_set_section_alignment (abfd, sec, 2))
return false;
-
+
sec->gc_mark = 1;
}
/* Here we have a bfd that is to be included on the link. We have a hook
to do reloc rummaging, before section sizes are nailed down. */
-
globals = elf32_arm_hash_table (link_info);
BFD_ASSERT (globals != NULL);
continue;
symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
- /* Load the relocs. */
+ /* Load the relocs. */
irel = (_bfd_elf32_link_read_relocs (abfd, sec, (PTR) NULL,
(Elf_Internal_Rela *) NULL, false));
r_type = ELF32_R_TYPE (irel->r_info);
r_index = ELF32_R_SYM (irel->r_info);
- /* These are the only relocation types we care about */
+ /* These are the only relocation types we care about. */
if ( r_type != R_ARM_PC24
&& r_type != R_ARM_THM_PC22)
continue;
contents = (bfd_byte *) bfd_malloc (sec->_raw_size);
if (contents == NULL)
goto error_return;
+
free_contents = contents;
if (!bfd_get_section_contents (abfd, sec, contents,
bfd_malloc (symtab_hdr->sh_size));
if (extsyms == NULL)
goto error_return;
+
free_extsyms = extsyms;
+
if (bfd_seek (abfd, symtab_hdr->sh_offset, SEEK_SET) != 0
|| (bfd_read (extsyms, 1, symtab_hdr->sh_size, abfd)
!= symtab_hdr->sh_size))
}
}
- /* If the relocation is not against a symbol it cannot concern us. */
-
+ /* If the relocation is not against a symbol it cannot concern us. */
h = NULL;
- /* We don't care about local symbols */
+ /* We don't care about local symbols. */
if (r_index < symtab_hdr->sh_info)
continue;
- /* This is an external symbol */
+ /* This is an external symbol. */
r_index -= symtab_hdr->sh_info;
h = (struct elf_link_hash_entry *)
elf_sym_hashes (abfd)[r_index];
/* 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. */
-
if (ELF_ST_TYPE(h->type) == STT_ARM_TFUNC)
record_arm_to_thumb_glue (link_info, h);
break;
/* 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. */
-
if (ELF_ST_TYPE (h->type) != STT_ARM_TFUNC)
record_thumb_to_arm_glue (link_info, h);
break;
}
return true;
-
+
error_return:
if (free_relocs != NULL)
free (free_relocs);
free (free_contents);
if (free_extsyms != NULL)
free (free_extsyms);
-
+
return false;
}
unsigned int low_bits;
unsigned int high_bits;
-
BFD_ASSERT ((rel_off & 1) != 1);
rel_off >>= 1; /* Half word aligned address. */
else if ((br_insn & HI_LOW_ORDER) == HI_LOW_ORDER)
br_insn = HI_LOW_ORDER | (high_bits << 16) | low_bits;
else
- abort (); /* error - not a valid branch instruction form */
+ /* FIXME: abort is probably not the right call. krk@cygnus.com */
+ abort (); /* error - not a valid branch instruction form. */
- /* FIXME: abort is probably not the right call. krk@cygnus.com */
-
return br_insn;
}
-/* Thumb code calling an ARM function */
+/* Thumb code calling an ARM function. */
+
static int
elf32_thumb_to_arm_stub (info, name, input_bfd, output_bfd, input_section,
hit_data, sym_sec, offset, addend, val)
&& !INTERWORK_FLAG (sym_sec->owner))
{
_bfd_error_handler
- (_ ("%s(%s): warning: interworking not enabled."),
+ (_("%s(%s): warning: interworking not enabled."),
bfd_get_filename (sym_sec->owner), name);
_bfd_error_handler
- (_ (" first occurrence: %s: thumb call to arm"),
+ (_(" first occurrence: %s: thumb call to arm"),
bfd_get_filename (input_bfd));
return false;
s->contents + my_offset + 2);
ret_offset =
- ((bfd_signed_vma) val) /* Address of destination of the stub */
+ /* Address of destination of the stub. */
+ ((bfd_signed_vma) val)
- ((bfd_signed_vma)
- (s->output_offset /* Offset from the start of the current section to the start of the stubs. */
- + my_offset /* Offset of the start of this stub from the start of the stubs. */
- + s->output_section->vma) /* Address of the start of the current section. */
- + 4 /* The branch instruction is 4 bytes into the stub. */
- + 8); /* ARM branches work from the pc of the instruction + 8. */
+ /* Offset from the start of the current section to the start of the stubs. */
+ (s->output_offset
+ /* Offset of the start of this stub from the start of the stubs. */
+ + my_offset
+ /* Address of the start of the current section. */
+ + s->output_section->vma)
+ /* The branch instruction is 4 bytes into the stub. */
+ + 4
+ /* ARM branches work from the pc of the instruction + 8. */
+ + 8);
bfd_put_32 (output_bfd,
t2a3_b_insn | ((ret_offset >> 2) & 0x00FFFFFF),
return true;
}
-/* Arm code calling a Thumb function */
+/* Arm code calling a Thumb function. */
+
static int
elf32_arm_to_thumb_stub (info, name, input_bfd, output_bfd, input_section,
hit_data, sym_sec, offset, addend, val)
&& !INTERWORK_FLAG (sym_sec->owner))
{
_bfd_error_handler
- (_ ("%s(%s): warning: interworking not enabled."),
+ (_("%s(%s): warning: interworking not enabled."),
bfd_get_filename (sym_sec->owner), name);
_bfd_error_handler
- (_ (" first occurrence: %s: arm call to thumb"),
+ (_(" first occurrence: %s: arm call to thumb"),
bfd_get_filename (input_bfd));
}
+
--my_offset;
myh->root.u.def.value = my_offset;
tmp = bfd_get_32 (input_bfd, hit_data);
tmp = tmp & 0xFF000000;
- /* Somehow these are both 4 too far, so subtract 8. */
+ /* Somehow these are both 4 too far, so subtract 8. */
ret_offset = s->output_offset
+ my_offset
+ s->output_section->vma
+ input_section->output_section->vma
+ offset + addend)
- 8;
-
+
tmp = tmp | ((ret_offset >> 2) & 0x00FFFFFF);
bfd_put_32 (output_bfd, tmp, hit_data
}
/* Perform a relocation as part of a final link. */
+
static bfd_reloc_status_type
elf32_arm_final_link_relocate (howto, input_bfd, output_bfd,
input_section, contents, rel, value,
case R_ARM_XPC25:
#endif
/* When generating a shared object, these relocations are copied
- into the output file to be resolved at run time. */
-
+ into the output file to be resolved at run time. */
if (info->shared
&& (r_type != R_ARM_PC24
|| (h != NULL
sreloc->contents)
+ sreloc->reloc_count));
++sreloc->reloc_count;
-
+
/* If this reloc is against an external symbol, we do not want to
fiddle with the addend. Otherwise, we need to include the symbol
- value so that it becomes an addend for the dynamic reloc. */
+ value so that it becomes an addend for the dynamic reloc. */
if (! relocate)
return bfd_reloc_ok;
-
return _bfd_final_link_relocate (howto, input_bfd, input_section,
contents, rel->r_offset, value,
(bfd_vma) 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;
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;
}
}
+ signed_addend = value;
+ signed_addend >>= howto->rightshift;
+
/* 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. */
+ 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))
+ 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));
+
+#ifndef OLD_ARM_ABI
+ /* If necessary set the H bit in the BLX instruction. */
+ if (r_type == R_ARM_XPC25 && ((value & 2) == 2))
+ value = (signed_addend & howto->dst_mask)
+ | (bfd_get_32 (input_bfd, hit_data) & (~ howto->dst_mask))
+ | (1 << 24);
+ else
+#endif
+ value = (signed_addend & howto->dst_mask)
+ | (bfd_get_32 (input_bfd, hit_data) & (~ howto->dst_mask));
break;
case R_ARM_ABS32:
return bfd_reloc_ok;
case R_ARM_THM_ABS5:
- /* Support ldr and str instructions for the thumb. */
+ /* Support ldr and str instructions for the thumb. */
#ifdef USE_REL
/* Need to refetch addend. */
addend = bfd_get_16 (input_bfd, hit_data) & howto->src_mask;
{
bfd_vma upper = upper_insn & 0x7ff;
bfd_vma lower = lower_insn & 0x7ff;
- upper = (upper ^ 0x400) - 0x400; /* sign extend */
+ upper = (upper ^ 0x400) - 0x400; /* Sign extend. */
addend = (upper << 12) | (lower << 1);
signed_addend = 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 */
-
+ 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
BFD_ASSERT (sgot != NULL);
if (sgot == NULL)
return bfd_reloc_notsupported;
-
+
/* Note that sgot->output_offset is not involved in this
calculation. We always want the start of .got. If we
define _GLOBAL_OFFSET_TABLE in a different way, as is
permitted by the ABI, we might have to change this
- calculation. */
-
+ calculation. */
value -= sgot->output_section->vma;
return _bfd_final_link_relocate (howto, input_bfd, input_section,
contents, rel->r_offset, value,
(bfd_vma) 0);
case R_ARM_GOTPC:
- /* Use global offset table as symbol value. */
-
+ /* Use global offset table as symbol value. */
BFD_ASSERT (sgot != NULL);
if (sgot == NULL)
case R_ARM_GOT32:
/* Relocation is to the entry for this symbol in the
- global offset table. */
+ global offset table. */
if (sgot == NULL)
return bfd_reloc_notsupported;
When doing a dynamic link, we create a .rel.got relocation
entry to initialize the value. This is done in the
- finish_dynamic_symbol routine. */
-
+ finish_dynamic_symbol routine. */
if ((off & 1) != 0)
off &= ~1;
else
/* The offset must always be a multiple of 4. We use the
least significant bit to record whether we have already
- generated the necessary reloc. */
+ generated the necessary reloc. */
if ((off & 1) != 0)
off &= ~1;
else
value = sgot->output_offset + off;
}
-
+
return _bfd_final_link_relocate (howto, input_bfd, input_section,
contents, rel->r_offset, value,
(bfd_vma) 0);
procedure linkage table. */
/* Resolve a PLT32 reloc against a local symbol directly,
- without using the procedure linkage table. */
+ without using the procedure linkage table. */
if (h == NULL)
return _bfd_final_link_relocate (howto, input_bfd, input_section,
contents, rel->r_offset, value,
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))
+ if (howto->type == R_ARM_THM_PC22)
{
- bfd_signed_vma mask;
-
- mask = -1;
- mask &= ~ howto->src_mask;
- addend |= mask;
- }
+ int upper_insn, lower_insn;
+ int upper, lower;
- /* Add in the increment, (which is a byte value). */
- switch (howto->type)
- {
- case R_ARM_THM_PC22:
- default:
+ upper_insn = bfd_get_16 (abfd, address);
+ lower_insn = bfd_get_16 (abfd, address + 2);
+ upper = upper_insn & 0x7ff;
+ lower = lower_insn & 0x7ff;
+
+ addend = (upper << 12) | (lower << 1);
addend += increment;
- break;
-
- case R_ARM_PC24:
- addend <<= howto->size;
- addend += increment;
-
- /* Should we check for overflow here ? */
+ addend >>= 1;
- /* Drop any undesired bits. */
- addend >>= howto->rightshift;
- break;
+ upper_insn = (upper_insn & 0xf800) | ((addend >> 11) & 0x7ff);
+ lower_insn = (lower_insn & 0xf800) | (addend & 0x7ff);
+
+ bfd_put_16 (abfd, upper_insn, address);
+ bfd_put_16 (abfd, lower_insn, address + 2);
+ }
+ else
+ {
+ bfd_vma contents;
+
+ 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)
+ {
+ 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);
}
-
- contents = (contents & ~ howto->dst_mask) | (addend & howto->dst_mask);
-
- bfd_put_32 (abfd, contents, address);
}
#endif /* USE_REL */
h = NULL;
sym = NULL;
sec = NULL;
+
if (r_symndx < symtab_hdr->sh_info)
{
sym = local_syms + r_symndx;
else
{
h = sym_hashes[r_symndx - symtab_hdr->sh_info];
- while (h->root.type == bfd_link_hash_indirect
+
+ 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;
- if (h->root.type == bfd_link_hash_defined
+
+ if ( h->root.type == bfd_link_hash_defined
|| h->root.type == bfd_link_hash_defweak)
{
int relocation_needed = 1;
/* In these cases, we don't need the relocation value.
We check specially because in some obscure cases
- sec->output_section will be NULL. */
+ sec->output_section will be NULL. */
switch (r_type)
{
case R_ARM_PC24:
(!info->symbolic && h->dynindx != -1)
|| (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0
)
- && ((input_section->flags & SEC_ALLOC) != 0)
+ && ((input_section->flags & SEC_ALLOC) != 0
+ /* DWARF will emit R_ARM_ABS32 relocations in its
+ sections against symbols defined externally
+ 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))
)
relocation_needed = 0;
break;
switch (r)
{
case bfd_reloc_overflow:
- if (!((*info->callbacks->reloc_overflow)
- (info, name, howto->name, (bfd_vma) 0,
- input_bfd, input_section, rel->r_offset)))
- return false;
+ /* If the overflowing reloc was to an undefined symbol,
+ we have already printed one error message and there
+ is no point complaining again. */
+ 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))))
+ return false;
break;
case bfd_reloc_undefined:
break;
case bfd_reloc_outofrange:
- msg = _ ("internal error: out of range error");
+ msg = _("internal error: out of range error");
goto common_error;
case bfd_reloc_notsupported:
- msg = _ ("internal error: unsupported relocation error");
+ msg = _("internal error: unsupported relocation error");
goto common_error;
case bfd_reloc_dangerous:
- msg = _ ("internal error: dangerous error");
+ msg = _("internal error: dangerous error");
goto common_error;
default:
- msg = _ ("internal error: unknown error");
+ msg = _("internal error: unknown error");
/* fall through */
common_error:
if (EF_ARM_EABI_VERSION (flags) == EF_ARM_EABI_UNKNOWN)
{
if (flags & EF_INTERWORK)
- _bfd_error_handler (_ ("\
+ _bfd_error_handler (_("\
Warning: Not setting interwork flag of %s since it has already been specified as non-interworking"),
bfd_get_filename (abfd));
else
- _bfd_error_handler (_ ("\
+ _bfd_error_handler (_("\
Warning: Clearing the interwork flag of %s due to outside request"),
bfd_get_filename (abfd));
}
}
/* Copy backend specific data from one object module to another. */
+
static boolean
elf32_arm_copy_private_bfd_data (ibfd, obfd)
bfd *ibfd;
&& EF_ARM_EABI_VERSION (out_flags) == EF_ARM_EABI_UNKNOWN
&& in_flags != out_flags)
{
- /* Cannot mix PIC and non-PIC code. */
- if ((in_flags & EF_PIC) != (out_flags & EF_PIC))
- return false;
-
/* Cannot mix APCS26 and APCS32 code. */
if ((in_flags & EF_APCS_26) != (out_flags & EF_APCS_26))
return false;
if ((in_flags & EF_INTERWORK) != (out_flags & EF_INTERWORK))
{
if (out_flags & EF_INTERWORK)
- _bfd_error_handler (_ ("\
+ _bfd_error_handler (_("\
Warning: Clearing the interwork flag in %s because non-interworking code in %s has been linked with it"),
bfd_get_filename (obfd), bfd_get_filename (ibfd));
in_flags &= ~EF_INTERWORK;
}
+
+ /* Likewise for PIC, though don't warn for this case. */
+ if ((in_flags & EF_PIC) != (out_flags & EF_PIC))
+ in_flags &= ~EF_PIC;
}
elf_elfheader (obfd)->e_flags = in_flags;
/* Merge backend specific data from an object file to the output
object file when linking. */
+
static boolean
elf32_arm_merge_private_bfd_data (ibfd, obfd)
bfd * ibfd;
{
flagword out_flags;
flagword in_flags;
+ boolean flags_compatible = true;
+ boolean null_input_bfd = true;
+ asection *sec;
- /* Check if we have the same endianess */
+ /* Check if we have the same endianess. */
if (_bfd_generic_verify_endian_match (ibfd, obfd) == false)
return false;
/* The input BFD must have had its flags initialised. */
/* The following seems bogus to me -- The flags are initialized in
the assembler but I don't think an elf_flags_init field is
- written into the object */
+ written into the object. */
/* BFD_ASSERT (elf_flags_init (ibfd)); */
in_flags = elf_elfheader (ibfd)->e_flags;
if (!elf_flags_init (obfd))
{
- /* If the input is the default architecture then do not
- bother setting the flags for the output architecture,
- instead allow future merges to do this. If no future
- merges ever set these flags then they will retain their
- unitialised values, which surprise surprise, correspond
+ /* If the input is the default architecture and had the default
+ flags then do not bother setting the flags for the output
+ architecture, instead allow future merges to do this. If no
+ future merges ever set these flags then they will retain their
+ uninitialised values, which surprise surprise, correspond
to the default values. */
- if (bfd_get_arch_info (ibfd)->the_default)
+ if (bfd_get_arch_info (ibfd)->the_default
+ && elf_elfheader (ibfd)->e_flags == 0)
return true;
elf_flags_init (obfd) = true;
return true;
}
- /* Check flag compatibility. */
+ /* Identical flags must be compatible. */
if (in_flags == out_flags)
return true;
+ /* Check to see if the input BFD actually contains any sections.
+ If not, its flags may not have been initialised either, but it cannot
+ actually cause any incompatibility. */
+ for (sec = ibfd->sections; sec != NULL; sec = sec->next)
+ {
+ /* Ignore synthetic glue sections. */
+ if (strcmp (sec->name, ".glue_7")
+ && strcmp (sec->name, ".glue_7t"))
+ {
+ null_input_bfd = false;
+ break;
+ }
+ }
+ if (null_input_bfd)
+ return true;
+
/* Complain about various flag mismatches. */
if (EF_ARM_EABI_VERSION (in_flags) != EF_ARM_EABI_VERSION (out_flags))
{
(in_flags & EF_ARM_EABIMASK) >> 24,
bfd_get_filename (obfd),
(out_flags & EF_ARM_EABIMASK) >> 24);
+ return false;
}
- else if (EF_ARM_EABI_VERSION (in_flags) != EF_ARM_EABI_UNKNOWN)
- /* Not sure what needs to be checked for EABI versions >= 1. */
- return true;
- if ((in_flags & EF_APCS_26) != (out_flags & EF_APCS_26))
- _bfd_error_handler (_ ("\
+ /* Not sure what needs to be checked for EABI versions >= 1. */
+ if (EF_ARM_EABI_VERSION (in_flags) == EF_ARM_EABI_UNKNOWN)
+ {
+ if ((in_flags & EF_APCS_26) != (out_flags & EF_APCS_26))
+ {
+ _bfd_error_handler (_("\
Error: %s compiled for APCS-%d, whereas %s is compiled for APCS-%d"),
bfd_get_filename (ibfd),
in_flags & EF_APCS_26 ? 26 : 32,
bfd_get_filename (obfd),
out_flags & EF_APCS_26 ? 26 : 32);
+ flags_compatible = false;
+ }
- if ((in_flags & EF_APCS_FLOAT) != (out_flags & EF_APCS_FLOAT))
- _bfd_error_handler (_ ("\
+ if ((in_flags & EF_APCS_FLOAT) != (out_flags & EF_APCS_FLOAT))
+ {
+ _bfd_error_handler (_("\
Error: %s passes floats in %s registers, whereas %s passes them in %s registers"),
bfd_get_filename (ibfd),
- in_flags & EF_APCS_FLOAT ? _ ("float") : _ ("integer"),
+ in_flags & EF_APCS_FLOAT ? _("float") : _("integer"),
bfd_get_filename (obfd),
- out_flags & EF_APCS_26 ? _ ("float") : _ ("integer"));
+ out_flags & EF_APCS_26 ? _("float") : _("integer"));
+ flags_compatible = false;
+ }
- if ((in_flags & EF_PIC) != (out_flags & EF_PIC))
- _bfd_error_handler (_ ("\
-Error: %s is compiled as position %s code, whereas %s is not"),
- bfd_get_filename (ibfd),
- in_flags & EF_PIC ? _ ("independent") : _ ("dependent"),
- bfd_get_filename (obfd));
+#ifdef EF_SOFT_FLOAT
+ if ((in_flags & EF_SOFT_FLOAT) != (out_flags & EF_SOFT_FLOAT))
+ {
+ _bfd_error_handler (_ ("\
+Error: %s uses %s floating point, whereas %s uses %s floating point"),
+ bfd_get_filename (ibfd),
+ in_flags & EF_SOFT_FLOAT ? _("soft") : _("hard"),
+ bfd_get_filename (obfd),
+ out_flags & EF_SOFT_FLOAT ? _("soft") : _("hard"));
+ flags_compatible = false;
+ }
+#endif
- /* Interworking mismatch is only a warning. */
- if ((in_flags & EF_INTERWORK) != (out_flags & EF_INTERWORK))
- {
- _bfd_error_handler (_ ("\
+ /* Interworking mismatch is only a warning. */
+ if ((in_flags & EF_INTERWORK) != (out_flags & EF_INTERWORK))
+ _bfd_error_handler (_("\
Warning: %s %s interworking, whereas %s %s"),
bfd_get_filename (ibfd),
- in_flags & EF_INTERWORK ? _ ("supports") : _ ("does not support"),
+ in_flags & EF_INTERWORK ? _("supports") : _("does not support"),
bfd_get_filename (obfd),
- out_flags & EF_INTERWORK ? _ ("does not") : _ ("does"));
- return true;
+ out_flags & EF_INTERWORK ? _("does not") : _("does"));
}
- return false;
+ return flags_compatible;
}
-/* Display the flags field */
+/* Display the flags field. */
+
static boolean
elf32_arm_print_private_bfd_data (abfd, ptr)
bfd *abfd;
_bfd_elf_print_private_bfd_data (abfd, ptr);
flags = elf_elfheader (abfd)->e_flags;
- /* Ignore init flag - it may not be set, despite the flags field containing valid data. */
+ /* Ignore init flag - it may not be set, despite the flags field
+ containing valid data. */
/* xgettext:c-format */
- fprintf (file, _ ("private flags = %lx:"), elf_elfheader (abfd)->e_flags);
+ fprintf (file, _("private flags = %lx:"), elf_elfheader (abfd)->e_flags);
switch (EF_ARM_EABI_VERSION (flags))
{
official ARM ELF extended ABI. Hence they are only decoded if
the EABI version is not set. */
if (flags & EF_INTERWORK)
- fprintf (file, _ (" [interworking enabled]"));
-
+ fprintf (file, _(" [interworking enabled]"));
+
if (flags & EF_APCS_26)
- fprintf (file, _ (" [APCS-26]"));
+ fprintf (file, _(" [APCS-26]"));
else
- fprintf (file, _ (" [APCS-32]"));
-
+ fprintf (file, _(" [APCS-32]"));
+
if (flags & EF_APCS_FLOAT)
- fprintf (file, _ (" [floats passed in float registers]"));
-
+ fprintf (file, _(" [floats passed in float registers]"));
+
if (flags & EF_PIC)
- fprintf (file, _ (" [position independent]"));
+ fprintf (file, _(" [position independent]"));
if (flags & EF_NEW_ABI)
- fprintf (file, _ (" [new ABI]"));
-
+ fprintf (file, _(" [new ABI]"));
+
if (flags & EF_OLD_ABI)
- fprintf (file, _ (" [old ABI]"));
-
+ fprintf (file, _(" [old ABI]"));
+
if (flags & EF_SOFT_FLOAT)
- fprintf (file, _ (" [software FP]"));
-
+ fprintf (file, _(" [software FP]"));
+
flags &= ~(EF_INTERWORK | EF_APCS_26 | EF_APCS_FLOAT | EF_PIC
| EF_NEW_ABI | EF_OLD_ABI | EF_SOFT_FLOAT);
break;
-
+
case EF_ARM_EABI_VER1:
- fprintf (file, _ (" [Version1 EABI]"));
-
+ fprintf (file, _(" [Version1 EABI]"));
+
if (flags & EF_ARM_SYMSARESORTED)
- fprintf (file, _ (" [sorted symbol table]"));
+ fprintf (file, _(" [sorted symbol table]"));
else
- fprintf (file, _ (" [unsorted symbol table]"));
-
+ fprintf (file, _(" [unsorted symbol table]"));
+
flags &= ~ EF_ARM_SYMSARESORTED;
break;
-
+
default:
- fprintf (file, _ (" <EABI version unrecognised>"));
+ fprintf (file, _(" <EABI version unrecognised>"));
break;
}
flags &= ~ EF_ARM_EABIMASK;
if (flags & EF_ARM_RELEXEC)
- fprintf (file, _ (" [relocatable executable]"));
+ fprintf (file, _(" [relocatable executable]"));
if (flags & EF_ARM_HASENTRY)
- fprintf (file, _ (" [has entry point]"));
+ fprintf (file, _(" [has entry point]"));
flags &= ~ (EF_ARM_RELEXEC | EF_ARM_HASENTRY);
if (flags)
- fprintf (file, _ ("<Unrecognised flag bits set>"));
-
+ fprintf (file, _("<Unrecognised flag bits set>"));
+
fputc ('\n', file);
return true;
if (type != STT_OBJECT)
return ELF_ST_TYPE (elf_sym->st_info);
break;
-
+
default:
break;
}
bfd * dynobj;
asection * sgot, *srelgot, *sreloc;
bfd_vma * local_got_offsets;
-
+
if (info->relocateable)
return true;
-
+
sgot = srelgot = sreloc = NULL;
-
+
dynobj = elf_hash_table (info)->dynobj;
local_got_offsets = elf_local_got_offsets (abfd);
symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
sym_hashes = elf_sym_hashes (abfd);
- sym_hashes_end = sym_hashes + symtab_hdr->sh_size/sizeof(Elf32_External_Sym);
+ sym_hashes_end = sym_hashes
+ + symtab_hdr->sh_size / sizeof (Elf32_External_Sym);
+
if (!elf_bad_symtab (abfd))
sym_hashes_end -= symtab_hdr->sh_info;
-
+
rel_end = relocs + sec->reloc_count;
for (rel = relocs; rel < rel_end; rel++)
{
struct elf_link_hash_entry *h;
unsigned long r_symndx;
-
+
r_symndx = ELF32_R_SYM (rel->r_info);
if (r_symndx < symtab_hdr->sh_info)
h = NULL;
else
h = sym_hashes[r_symndx - symtab_hdr->sh_info];
-
+
/* Some relocs require a global offset table. */
if (dynobj == NULL)
{
&& (h != NULL || info->shared))
{
srelgot = bfd_get_section_by_name (dynobj, ".rel.got");
-
+
/* If no got relocation section, make one and initialize. */
if (srelgot == NULL)
{
if (!_bfd_elf32_gc_record_vtinherit (abfd, sec, h, rel->r_offset))
return false;
break;
-
+
/* This relocation describes which C++ vtable entries are actually
used. Record for later use during GC. */
case R_ARM_GNU_VTENTRY:
return true;
}
-
/* Find the nearest line to a particular section and offset, for error
reporting. This code is a duplicate of the code in elf.c, except
- that it also accepts STT_ARM_TFUNC as a symbol that names a function. */
+ that it also accepts STT_ARM_TFUNC as a symbol that names a function. */
static boolean
elf32_arm_find_nearest_line
/* We also need to make an entry in the .got.plt section, which
will be placed in the .got section by the linker script. */
-
s = bfd_get_section_by_name (dynobj, ".got.plt");
BFD_ASSERT (s != NULL);
s->_raw_size += 4;
determine the address it must put in the global offset table, so
both the dynamic object and the regular object will refer to the
same memory location for the variable. */
-
s = bfd_get_section_by_name (dynobj, ".dynbss");
BFD_ASSERT (s != NULL);
outname = bfd_get_section_name (output_bfd,
s->output_section);
target = bfd_get_section_by_name (output_bfd, outname + 4);
-
+
if (target != NULL
&& (target->flags & SEC_READONLY) != 0
&& (target->flags & SEC_ALLOC) != 0)
if (plt)
{
- if (! bfd_elf32_add_dynamic_entry (info, DT_PLTGOT, 0)
+ if ( ! bfd_elf32_add_dynamic_entry (info, DT_PLTGOT, 0)
|| ! bfd_elf32_add_dynamic_entry (info, DT_PLTRELSZ, 0)
|| ! bfd_elf32_add_dynamic_entry (info, DT_PLTREL, DT_REL)
|| ! bfd_elf32_add_dynamic_entry (info, DT_JMPREL, 0))
if (relocs)
{
- if (! bfd_elf32_add_dynamic_entry (info, DT_REL, 0)
+ if ( ! bfd_elf32_add_dynamic_entry (info, DT_REL, 0)
|| ! bfd_elf32_add_dynamic_entry (info, DT_RELSZ, 0)
|| ! bfd_elf32_add_dynamic_entry (info, DT_RELENT,
sizeof (Elf32_External_Rel)))
/* This symbol has an entry in the global offset table. Set it
up. */
-
sgot = bfd_get_section_by_name (dynobj, ".got");
srel = bfd_get_section_by_name (dynobj, ".rel.got");
BFD_ASSERT (sgot != NULL && srel != NULL);
Elf_Internal_Rel rel;
/* This symbol needs a copy reloc. Set it up. */
-
BFD_ASSERT (h->dynindx != -1
&& (h->root.type == bfd_link_hash_defined
|| h->root.type == bfd_link_hash_defweak));
dyncon = (Elf32_External_Dyn *) sdyn->contents;
dynconend = (Elf32_External_Dyn *) (sdyn->contents + sdyn->_raw_size);
+
for (; dyncon < dynconend; dyncon++)
{
Elf_Internal_Dyn dyn;
bfd * abfd;
struct bfd_link_info * link_info ATTRIBUTE_UNUSED;
{
- Elf_Internal_Ehdr * i_ehdrp; /* Elf file header, internal form */
+ Elf_Internal_Ehdr * i_ehdrp; /* ELF file header, internal form. */
i_ehdrp = elf_elfheader (abfd);
i_ehdrp->e_ident[EI_ABIVERSION] = ARM_ELF_ABI_VERSION;
}
-
#define ELF_ARCH bfd_arch_arm
#define ELF_MACHINE_CODE EM_ARM
#define ELF_MAXPAGESIZE 0x8000
-
#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 bfd_elf32_bfd_set_private_flags elf32_arm_set_private_flags