+ if (symndx == -1)
+ {
+ sec = bfd_abs_section_ptr;
+ val = 0;
+ }
+ else
+ {
+ sec = sections[symndx];
+ val = (sec->output_section->vma
+ + sec->output_offset
+ + sym->n_value
+ - sec->vma);
+ }
+ }
+ else
+ {
+#if 1 /* THUMBEXTENSION */
+ /* We don't output the stubs if we are generating a
+ relocatable output file, since we may as well leave the
+ stub generation to the final linker pass. If we fail to
+ verify that the name is defined, we'll try to build stubs
+ for an undefined name... */
+ if (! info->relocateable
+ && ( h->root.type == bfd_link_hash_defined
+ || h->root.type == bfd_link_hash_defweak))
+ {
+ asection * sec;
+ asection * h_sec = h->root.u.def.section;
+ const char * name = h->root.root.string;
+
+ /* h locates the symbol referenced in the reloc. */
+ h_val = (h->root.u.def.value
+ + h_sec->output_section->vma
+ + h_sec->output_offset);
+
+ if (howto->type == ARM_26)
+ {
+ if ( h->class == C_THUMBSTATFUNC
+ || h->class == C_THUMBEXTFUNC)
+ {
+ /* Arm code calling a Thumb function */
+ signed long int final_disp;
+ unsigned long int tmp;
+ long int my_offset;
+ long int offset;
+ asection * s = 0;
+ unsigned long int return_address;
+ long int ret_offset;
+ long int disp;
+ struct coff_link_hash_entry * myh;
+
+ myh = find_arm_glue (info, name, input_bfd);
+ if (myh == NULL)
+ return false;
+
+ my_offset = myh->root.u.def.value;
+
+ s = bfd_get_section_by_name (bfd_of_glue_owner,
+ ARM2THUMB_GLUE_SECTION_NAME);
+ BFD_ASSERT (s != NULL);
+ BFD_ASSERT (s->contents != NULL);
+
+ if ((my_offset & 0x01) == 0x01)
+ {
+ if (INTERWORK_SET (h_sec->owner) && ! INTERWORK_FLAG (h_sec->owner))
+ _bfd_error_handler ("%s: warning: interworking not enabled.",
+ bfd_get_filename (h_sec->owner));
+
+ --my_offset;
+ myh->root.u.def.value = my_offset;
+
+ bfd_put_32 (output_bfd, a2t1_ldr_insn, s->contents + my_offset);
+
+ bfd_put_32 (output_bfd, a2t2_bx_r12_insn, s->contents + my_offset + 4);
+
+ /* It's a thumb address. Add the low order bit. */
+ bfd_put_32 (output_bfd, h_val | a2t3_func_addr_insn, s->contents + my_offset + 8);
+ }
+
+ BFD_ASSERT (my_offset <= global_arm_glue_size);
+
+ tmp = bfd_get_32 (input_bfd, contents + rel->r_vaddr - input_section->vma);
+
+ tmp = tmp & 0xFF000000;
+
+ /* Somehow these are both 4 too far, so subtract 8. */
+ ret_offset =
+ s->output_offset
+ + my_offset
+ + s->output_section->vma
+ - (input_section->output_offset
+ + input_section->output_section->vma
+ + rel->r_vaddr)
+ - 8;
+
+ tmp = tmp | ((ret_offset >> 2) & 0x00FFFFFF);
+
+ bfd_put_32 (output_bfd, tmp, contents + rel->r_vaddr - input_section->vma);
+
+ done = 1;
+ }
+ }
+
+ /* Note: We used to check for ARM_THUMB9 and ARM_THUMB12 */
+ else if (howto->type == ARM_THUMB23)
+ {
+ if ( h->class == C_EXT
+ || h->class == C_STAT
+ || h->class == C_LABEL)
+ {
+ /* Thumb code calling an ARM function */
+ unsigned long int return_address;
+ signed long int final_disp;
+ asection * s = 0;
+ long int my_offset;
+ unsigned long int tmp;
+ long int ret_offset;
+ struct coff_link_hash_entry * myh;
+
+ myh = find_thumb_glue (info, name, input_bfd);
+ if (myh == NULL)
+ return false;
+
+ my_offset = myh->root.u.def.value;
+
+ s = bfd_get_section_by_name (bfd_of_glue_owner,
+ THUMB2ARM_GLUE_SECTION_NAME);
+
+ BFD_ASSERT (s != NULL);
+ BFD_ASSERT (s->contents != NULL);
+
+ if ((my_offset & 0x01) == 0x01)
+ {
+ if (INTERWORK_SET (h_sec->owner) && ! INTERWORK_FLAG (h_sec->owner))
+ _bfd_error_handler ("%s: warning: interworking not enabled.",
+ bfd_get_filename (h_sec->owner));
+
+ -- my_offset;
+ myh->root.u.def.value = my_offset;
+
+ bfd_put_16 (output_bfd, t2a1_bx_pc_insn,
+ s->contents + my_offset);
+
+ bfd_put_16 (output_bfd, t2a2_noop_insn,
+ s->contents + my_offset + 2);
+
+ ret_offset =
+ ((signed)h_val) -
+ ((signed)(s->output_offset
+ + my_offset
+ + s->output_section->vma))
+ - 12;
+
+ t2a3_b_insn |= ((ret_offset >> 2) & 0x00FFFFFF);
+
+ bfd_put_32 (output_bfd, t2a3_b_insn, s->contents + my_offset + 4);
+ }
+
+ BFD_ASSERT (my_offset <= global_thumb_glue_size);
+
+ /* Now go back and fix up the original bl insn to point here. */
+ ret_offset =
+ s->output_offset
+ + my_offset
+ - (input_section->output_offset
+ + rel->r_vaddr)
+ -4;
+
+ tmp = bfd_get_32 (input_bfd, contents + rel->r_vaddr - input_section->vma);
+
+ bfd_put_32 (output_bfd,
+ insert_thumb_branch (tmp, ret_offset),
+ contents + rel->r_vaddr - input_section->vma);
+
+ done = 1;
+ }
+ }
+ }
+
+ /* If the relocation type and destination symbol does not
+ fall into one of the above categories, then we can just
+ perform a direct link. */
+
+ if (done)
+ rstat = bfd_reloc_ok;
+ else
+#endif /* THUMBEXTENSION */
+ if ( h->root.type == bfd_link_hash_defined
+ || h->root.type == bfd_link_hash_defweak)
+ {
+ asection *sec;
+
+ sec = h->root.u.def.section;
+ val = (h->root.u.def.value
+ + sec->output_section->vma
+ + sec->output_offset);
+ }
+
+ else if (! info->relocateable)
+ {
+ if (! ((*info->callbacks->undefined_symbol)
+ (info, h->root.root.string, input_bfd, input_section,
+ rel->r_vaddr - input_section->vma)))
+ return false;
+ }
+ }
+
+ if (info->base_file)
+ {
+ /* Emit a reloc if the backend thinks it needs it. */
+ if (sym && pe_data(output_bfd)->in_reloc_p(output_bfd, howto))
+ {
+ /* relocation to a symbol in a section which
+ isn't absolute - we output the address here
+ to a file */
+ bfd_vma addr = rel->r_vaddr
+ - input_section->vma
+ + input_section->output_offset
+ + input_section->output_section->vma;
+ if (coff_data(output_bfd)->pe)
+ addr -= pe_data(output_bfd)->pe_opthdr.ImageBase;
+ /* FIXME: Shouldn't 4 be sizeof (addr)? */
+ fwrite (&addr, 1,4, (FILE *) info->base_file);
+ }
+ }
+
+#if 1 /* THUMBEXTENSION */
+ if (done)
+ ;
+ /* Only perform this fix during the final link, not a relocatable link. nickc@cygnus.com */
+ else if (! info->relocateable
+ && howto->type == ARM_THUMB23)
+ {
+ /* This is pretty much a copy of what the default
+ _bfd_final_link_relocate and _bfd_relocate_contents
+ routines do to perform a relocation, with special
+ processing for the split addressing of the Thumb BL
+ instruction. Again, it would probably be simpler adding a
+ ThumbBRANCH23 specific macro expansion into the default
+ code. */
+
+ bfd_vma address = rel->r_vaddr - input_section->vma;
+
+ if (address > input_section->_raw_size)
+ rstat = bfd_reloc_outofrange;
+ else
+ {
+ bfd_vma relocation = val + addend;
+ int size = bfd_get_reloc_size (howto);
+ boolean overflow = false;
+ bfd_byte * location = contents + address;
+ bfd_vma x = bfd_get_32 (input_bfd, location);
+ 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;
+ bfd_signed_vma signed_check;
+ bfd_vma add;
+ bfd_signed_vma signed_add;
+
+ BFD_ASSERT (size == 4);
+
+ /* howto->pc_relative should be TRUE for type 14 BRANCH23 */
+ relocation -= (input_section->output_section->vma
+ + input_section->output_offset);
+
+ /* howto->pcrel_offset should be TRUE for type 14 BRANCH23 */
+ relocation -= address;
+
+ /* No need to negate the relocation with BRANCH23. */
+ /* howto->complain_on_overflow == complain_overflow_signed for BRANCH23. */
+ /* howto->rightshift == 1 */
+ /* Drop unwanted bits from the value we are relocating to. */
+
+ check = relocation >> howto->rightshift;
+
+ /* If this is a signed value, the rightshift just dropped
+ leading 1 bits (assuming twos complement). */
+ if ((bfd_signed_vma) relocation >= 0)
+ signed_check = check;
+ else
+ signed_check = (check
+ | ((bfd_vma) - 1
+ & ~((bfd_vma) - 1 >> howto->rightshift)));
+
+ /* Get the value from the object file. */
+ if (bfd_big_endian (input_bfd))
+ {
+ add = (((x) & 0x07ff0000) >> 4) | (((x) & 0x7ff) << 1);
+ }
+ else
+ {
+ add = ((((x) & 0x7ff) << 12) | (((x) & 0x07ff0000) >> 15));
+ }
+
+ /* Get the value from the object file with an appropriate sign.
+ The expression involving howto->src_mask isolates the upper
+ bit of src_mask. If that bit is set in the value we are
+ adding, it is negative, and we subtract out that number times
+ two. If src_mask includes the highest possible bit, then we
+ can not get the upper bit, but that does not matter since
+ signed_add needs no adjustment to become negative in that
+ case. */
+
+ signed_add = add;
+
+ if ((add & (((~ src_mask) >> 1) & src_mask)) != 0)
+ signed_add -= (((~ src_mask) >> 1) & src_mask) << 1;
+
+ /* Add the value from the object file, shifted so that it is a
+ straight number. */
+ /* howto->bitpos == 0 */
+
+ signed_check += signed_add;
+ relocation += signed_add;
+
+ BFD_ASSERT (howto->complain_on_overflow == complain_overflow_signed);
+
+ /* Assumes two's complement. */
+ if ( signed_check > reloc_signed_max
+ || signed_check < reloc_signed_min)
+ overflow = true;
+
+ /* Put RELOCATION into the correct bits: */
+
+ if (bfd_big_endian (input_bfd))
+ {
+ relocation = (((relocation & 0xffe) >> 1) | ((relocation << 4) & 0x07ff0000));
+ }
+ else
+ {
+ relocation = (((relocation & 0xffe) << 15) | ((relocation >> 12) & 0x7ff));
+ }
+
+ /* Add RELOCATION to the correct bits of X: */
+ x = ((x & ~howto->dst_mask) | relocation);
+
+ /* Put the relocated value back in the object file: */
+ bfd_put_32 (input_bfd, x, location);
+
+ rstat = overflow ? bfd_reloc_overflow : bfd_reloc_ok;
+ }
+ }
+ else
+#endif /* THUMBEXTENSION */
+ rstat = _bfd_final_link_relocate (howto, input_bfd, input_section,
+ contents,
+ rel->r_vaddr - input_section->vma,
+ val, addend);
+#if 1 /* THUMBEXTENSION */
+ /* FIXME:
+ Is this the best way to fix up thumb addresses? krk@cygnus.com
+ Probably not, but it works, and if it works it don't need fixing! nickc@cygnus.com */
+ /* Only perform this fix during the final link, not a relocatable link. nickc@cygnus.com */
+ if (! info->relocateable
+ && rel->r_type == ARM_32)
+ {
+ /* Determine if we need to set the bottom bit of a relocated address
+ because the address is the address of a Thumb code symbol. */
+
+ int patchit = false;
+
+ if (h != NULL
+ && ( h->class == C_THUMBSTATFUNC
+ || h->class == C_THUMBEXTFUNC))
+ {
+ patchit = true;
+ }
+ else if (sym != NULL
+ && sym->n_scnum > N_UNDEF)
+ {
+ /* No hash entry - use the symbol instead. */
+
+ if ( sym->n_sclass == C_THUMBSTATFUNC
+ || sym->n_sclass == C_THUMBEXTFUNC)
+ patchit = true;
+ }
+
+ if (patchit)
+ {
+ bfd_byte * location = contents + rel->r_vaddr - input_section->vma;
+ bfd_vma x = bfd_get_32 (input_bfd, location);
+
+ bfd_put_32 (input_bfd, x | 1, location);
+ }
+ }
+#endif /* THUMBEXTENSION */
+
+ switch (rstat)
+ {
+ default:
+ abort ();
+ case bfd_reloc_ok:
+ break;
+ case bfd_reloc_outofrange:
+ (*_bfd_error_handler)
+ ("%s: bad reloc address 0x%lx in section `%s'",
+ bfd_get_filename (input_bfd),
+ (unsigned long) rel->r_vaddr,
+ bfd_get_section_name (input_bfd, input_section));
+ return false;
+ case bfd_reloc_overflow:
+ {
+ const char *name;
+ char buf[SYMNMLEN + 1];
+
+ if (symndx == -1)
+ name = "*ABS*";
+ else if (h != NULL)
+ name = h->root.root.string;
+ else
+ {
+ name = _bfd_coff_internal_syment_name (input_bfd, sym, buf);
+ if (name == NULL)
+ return false;
+ }
+
+ if (! ((*info->callbacks->reloc_overflow)
+ (info, name, howto->name, (bfd_vma) 0, input_bfd,
+ input_section, rel->r_vaddr - input_section->vma)))
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+boolean
+arm_allocate_interworking_sections (info)
+ struct bfd_link_info *info;
+{
+ asection *s;
+ bfd_byte *foo;
+ static char test_char = '1';
+
+ if ( global_arm_glue_size != 0 )
+ {
+ BFD_ASSERT (bfd_of_glue_owner != NULL);
+
+ s = bfd_get_section_by_name (bfd_of_glue_owner, ARM2THUMB_GLUE_SECTION_NAME);
+
+ BFD_ASSERT (s != NULL);
+
+ foo = (bfd_byte *) bfd_alloc(bfd_of_glue_owner, global_arm_glue_size);
+ memset(foo, test_char, global_arm_glue_size);
+
+ s->_raw_size = s->_cooked_size = global_arm_glue_size;
+ s->contents = foo;
+ }
+
+ if (global_thumb_glue_size != 0)
+ {
+ BFD_ASSERT (bfd_of_glue_owner != NULL);
+
+ s = bfd_get_section_by_name (bfd_of_glue_owner, THUMB2ARM_GLUE_SECTION_NAME);
+
+ BFD_ASSERT (s != NULL);
+
+ foo = (bfd_byte *) bfd_alloc(bfd_of_glue_owner, global_thumb_glue_size);
+ memset(foo, test_char, global_thumb_glue_size);
+
+ s->_raw_size = s->_cooked_size = global_thumb_glue_size;
+ s->contents = foo;
+ }
+
+ return true;
+}
+
+static void
+record_arm_to_thumb_glue (info, h)
+ struct bfd_link_info * info;
+ struct coff_link_hash_entry * h;
+{
+ const char * name = h->root.root.string;
+ register asection * s;
+ char * tmp_name;
+ struct coff_link_hash_entry * myh;
+
+
+ BFD_ASSERT (bfd_of_glue_owner != NULL);
+
+ s = bfd_get_section_by_name (bfd_of_glue_owner,
+ ARM2THUMB_GLUE_SECTION_NAME);
+
+ BFD_ASSERT (s != NULL);
+
+ tmp_name = ((char *)
+ bfd_malloc (strlen (name) + strlen (ARM2THUMB_GLUE_ENTRY_NAME)));
+
+ BFD_ASSERT (tmp_name);
+
+ sprintf (tmp_name, ARM2THUMB_GLUE_ENTRY_NAME, name);
+
+ myh = coff_link_hash_lookup (coff_hash_table (info),
+ tmp_name,
+ false, false, true);
+
+ if (myh != NULL)
+ {
+ free (tmp_name);
+ return; /* we've already seen this guy */
+ }
+
+
+ /* The only trick here is using global_arm_glue_size as the value. Even
+ though the section isn't allocated yet, this is where we will be putting
+ it. */
+
+ bfd_coff_link_add_one_symbol (info, bfd_of_glue_owner, tmp_name,
+ BSF_EXPORT | BSF_GLOBAL,
+ s, global_arm_glue_size + 1,
+ NULL, true, false,
+ (struct bfd_link_hash_entry **) & myh);
+
+ global_arm_glue_size += ARM2THUMB_GLUE_SIZE;
+
+ free (tmp_name);
+
+ return;
+}
+
+static void
+record_thumb_to_arm_glue (info, h)
+ struct bfd_link_info * info;
+ struct coff_link_hash_entry * h;
+{
+ const char * name = h->root.root.string;
+ register asection * s;
+ char * tmp_name;
+ struct coff_link_hash_entry * myh;
+
+
+ BFD_ASSERT (bfd_of_glue_owner != NULL);
+
+ s = bfd_get_section_by_name (bfd_of_glue_owner, THUMB2ARM_GLUE_SECTION_NAME);
+
+ BFD_ASSERT (s != NULL);
+
+ tmp_name = (char *) bfd_malloc (strlen (name) + strlen (THUMB2ARM_GLUE_ENTRY_NAME));
+
+ BFD_ASSERT (tmp_name);
+
+ sprintf (tmp_name, THUMB2ARM_GLUE_ENTRY_NAME, name);
+
+ myh = coff_link_hash_lookup (coff_hash_table (info),
+ tmp_name,
+ false, false, true);
+
+ if (myh != NULL)
+ {
+ free (tmp_name);
+ return; /* we've already seen this guy */
+ }
+
+ bfd_coff_link_add_one_symbol (info, bfd_of_glue_owner, tmp_name,
+ BSF_LOCAL, s, global_thumb_glue_size + 1,
+ NULL, true, false,
+ (struct bfd_link_hash_entry **) & myh);
+
+ /* if we mark it 'thumb', the disassembler will do a better job */
+ myh->class = C_THUMBEXTFUNC;
+
+ free (tmp_name);
+
+#define CHANGE_TO_ARM "__%s_change_to_arm"
+
+ tmp_name = ((char *)
+ bfd_malloc (strlen (name) + strlen (CHANGE_TO_ARM)));
+
+ BFD_ASSERT (tmp_name);
+
+ sprintf (tmp_name, CHANGE_TO_ARM, name);
+
+ myh = NULL;
+
+ /* now allocate another symbol to switch back to arm mode */
+ bfd_coff_link_add_one_symbol (info, bfd_of_glue_owner, tmp_name,
+ BSF_LOCAL, s, global_thumb_glue_size + 4,
+ NULL, true, false,
+ (struct bfd_link_hash_entry **) & myh);
+
+ free (tmp_name);
+
+ global_thumb_glue_size += THUMB2ARM_GLUE_SIZE;
+
+ return;
+}
+
+boolean
+arm_process_before_allocation (abfd, info)
+ bfd * abfd;
+ struct bfd_link_info * info;
+{
+ asection * sec;
+
+ /* If we are only performing a partial link do not bother
+ to construct any glue. */
+ if (info->relocateable)
+ return true;
+
+ /* 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. */
+
+ _bfd_coff_get_external_symbols (abfd);
+
+ /* Rummage around all the relocs and map the glue vectors. */
+ sec = abfd->sections;
+
+ if (sec == NULL)
+ return true;
+
+ for (; sec != NULL; sec = sec->next)
+ {
+ struct internal_reloc * i;
+ struct internal_reloc * rel;
+
+ if (sec->reloc_count == 0)
+ continue;
+
+ /* Load the relocs. */
+ /* FIXME: there may be a storage leak here. */
+
+ i = _bfd_coff_read_internal_relocs (abfd, sec, 1, 0, 0, 0);
+
+ BFD_ASSERT (i != 0);
+
+ for (rel = i; rel < i + sec->reloc_count; ++rel)
+ {
+ unsigned short r_type = rel->r_type;
+ long symndx;
+ struct coff_link_hash_entry * h;
+
+ symndx = rel->r_symndx;
+
+ /* If the relocation is not against a symbol it cannot concern us. */
+ if (symndx == -1)
+ continue;
+
+ h = obj_coff_sym_hashes (abfd)[symndx];
+
+ /* If the relocation is against a static symbol it must be within
+ the current section and so canot be a cross ARM/Thumb relocation. */
+ if (h == NULL)
+ continue;
+
+ switch (r_type)
+ {
+ case ARM_26:
+ /* 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 (h->class == C_THUMBEXTFUNC)
+ {
+ record_arm_to_thumb_glue (info, h);
+ }
+ break;
+
+ case ARM_THUMB23:
+ /* This one is a call from thumb code. We used to look
+ for ARM_THUMB9 and ARM_THUMB12 as well. We need to look
+ up the target of the call. If it is an arm target, we
+ insert glue. */
+
+ switch (h->class)
+ {
+ case C_EXT:
+ case C_STAT:
+ case C_LABEL:
+ record_thumb_to_arm_glue (info, h);
+ break;
+ default:
+ ;
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+
+ return true;
+}
+
+#define coff_relocate_section coff_arm_relocate_section
+
+/* When doing a relocateable link, we want to convert ARM26 relocs
+ into ARM26D relocs. */
+
+static boolean
+coff_arm_adjust_symndx (obfd, info, ibfd, sec, irel, adjustedp)
+ bfd *obfd;
+ struct bfd_link_info *info;
+ bfd *ibfd;
+ asection *sec;
+ struct internal_reloc *irel;
+ boolean *adjustedp;
+{
+ if (irel->r_type == 3)
+ {
+ struct coff_link_hash_entry *h;
+
+ h = obj_coff_sym_hashes (ibfd)[irel->r_symndx];
+ if (h != NULL
+ && (h->root.type == bfd_link_hash_defined
+ || h->root.type == bfd_link_hash_defweak)
+ && h->root.u.def.section->output_section == sec->output_section)
+ irel->r_type = 7;
+ }
+ *adjustedp = false;
+ return true;
+}
+
+
+/* Called when merging the private data areas of two BFDs.
+ This is important as it allows us to detect if we are
+ attempting to merge binaries compiled for different ARM
+ targets, eg different CPUs or differents APCS's. */
+
+static boolean
+coff_arm_bfd_merge_private_bfd_data (ibfd, obfd)
+ bfd * ibfd;
+ bfd * obfd;
+{
+ BFD_ASSERT (ibfd != NULL && obfd != NULL);
+
+ if (ibfd == obfd)
+ return true;
+
+ /* If the two formats are different we cannot merge anything. */
+ if (ibfd->xvec != obfd->xvec)
+ {
+ bfd_set_error (bfd_error_wrong_format);
+ return false;
+ }
+
+ /* Verify that the APCS is the same for the two BFDs */
+ if (APCS_SET (ibfd))
+ {
+ if (APCS_SET (obfd))
+ {
+ /* If the src and dest have different APCS flag bits set, fail. */
+ if (APCS_26_FLAG (obfd) != APCS_26_FLAG (ibfd))
+ {
+ _bfd_error_handler
+ ("%s: ERROR: compiled for APCS-%d whereas target %s uses APCS-%d",
+ bfd_get_filename (ibfd), APCS_26_FLAG (ibfd) ? 26 : 32,
+ bfd_get_filename (obfd), APCS_26_FLAG (obfd) ? 26 : 32
+ );
+
+ bfd_set_error (bfd_error_wrong_format);
+ return false;
+ }
+
+ if (APCS_FLOAT_FLAG (obfd) != APCS_FLOAT_FLAG (ibfd))
+ {
+ _bfd_error_handler
+ ("%s: ERROR: passes floats in %s registers whereas target %s uses %s registers",
+ bfd_get_filename (ibfd), APCS_FLOAT_FLAG (ibfd) ? "float" : "integer",
+ bfd_get_filename (obfd), APCS_FLOAT_FLAG (obfd) ? "float" : "integer"
+ );
+
+ bfd_set_error (bfd_error_wrong_format);
+ return false;
+ }
+
+ if (PIC_FLAG (obfd) != PIC_FLAG (ibfd))
+ {
+ _bfd_error_handler
+ ("%s: ERROR: compiled as %s code, whereas target %s is %s",
+ bfd_get_filename (ibfd), PIC_FLAG (ibfd) ? "position independent" : "absoluste position",
+ bfd_get_filename (obfd), PIC_FLAG (obfd) ? "position independent" : "absoluste position"
+ );
+
+ bfd_set_error (bfd_error_wrong_format);
+ return false;
+ }
+ }
+ else
+ {
+ SET_APCS_FLAGS (obfd, APCS_26_FLAG (ibfd) | APCS_FLOAT_FLAG (ibfd) | PIC_FLAG (ibfd));
+
+ /* Set up the arch and fields as well as these are probably wrong. */
+ bfd_set_arch_mach (obfd, bfd_get_arch (ibfd), bfd_get_mach (ibfd));
+ }
+ }
+
+ /* Check the interworking support. */
+ if (INTERWORK_SET (ibfd))
+ {
+ if (INTERWORK_SET (obfd))
+ {
+ /* If the src and dest differ in their interworking issue a warning. */
+ if (INTERWORK_FLAG (obfd) != INTERWORK_FLAG (ibfd))
+ {
+ _bfd_error_handler
+ ("Warning: input file %s %s interworking, whereas %s does%s",
+ bfd_get_filename (ibfd),
+ INTERWORK_FLAG (ibfd) ? "supports" : "does not support",
+ bfd_get_filename (obfd),
+ INTERWORK_FLAG (obfd) ? "." : " not."
+ );
+ }
+ }
+ else
+ {
+ SET_INTERWORK_FLAG (obfd, INTERWORK_FLAG (ibfd));
+ }
+ }
+
+ return true;
+}
+
+
+/* Display the flags field */
+
+static boolean
+coff_arm_bfd_print_private_bfd_data (abfd, ptr)
+ bfd * abfd;
+ PTR ptr;
+{
+ FILE * file = (FILE *) ptr;
+
+ BFD_ASSERT (abfd != NULL && ptr != NULL)
+
+ fprintf (file, "private flags = %x", coff_data( abfd )->flags);
+
+ if (APCS_SET (abfd))
+ fprintf (file, ": [APCS-%d] [floats passed in %s registers] [%s]",
+ APCS_26_FLAG (abfd) ? 26 : 32,
+ APCS_FLOAT_FLAG (abfd) ? "float" : "integer",
+ PIC_FLAG (abfd) ? "position independent" : "absolute position"
+ );
+
+ if (INTERWORK_SET (abfd))
+ fprintf (file, ": [interworking %ssupported]",
+ INTERWORK_FLAG (abfd) ? "" : "not " );
+
+ fputc ('\n', file);
+
+ return true;
+}
+
+
+/* Copies the given flags into the coff_tdata.flags field.
+ Typically these flags come from the f_flags[] field of
+ the COFF filehdr structure, which contains important,
+ target specific information. */
+
+static boolean
+coff_arm_bfd_set_private_flags (abfd, flags)
+ bfd * abfd;
+ flagword flags;
+{
+ int flag;
+
+ BFD_ASSERT (abfd != NULL);
+
+ flag = (flags & F_APCS26) ? F_APCS_26 : 0;
+
+ /* Make sure that the APCS field has not been initialised to the opposite value. */
+ if (APCS_SET (abfd)
+ && ( (APCS_26_FLAG (abfd) != flag)
+ || (APCS_FLOAT_FLAG (abfd) != (flags & F_APCS_FLOAT))
+ || (PIC_FLAG (abfd) != (flags & F_PIC))
+ ))
+ return false;
+
+ flag |= (flags & (F_APCS_FLOAT | F_PIC));
+
+ SET_APCS_FLAGS (abfd, flag);
+
+ flag = (flags & F_INTERWORK);
+
+ /* If either the flags or the BFD do support interworking then do not set the interworking flag. */
+ if (INTERWORK_SET (abfd) && (INTERWORK_FLAG (abfd) != flag))
+ flag = 0;
+
+ SET_INTERWORK_FLAG (abfd, flag);
+
+ return true;
+}
+
+
+/* Copy the important parts of the target specific data
+ from one instance of a BFD to another. */
+
+static boolean
+coff_arm_bfd_copy_private_bfd_data (src, dest)
+ bfd * src;
+ bfd * dest;
+{
+ BFD_ASSERT (src != NULL && dest != NULL);
+
+ if (src == dest)
+ return true;
+
+ /* If the destination is not in the same format as the source, do not do the copy. */
+ if (src->xvec != dest->xvec)
+ return true;
+
+ /* copy the flags field */
+ if (APCS_SET (src))
+ {
+ if (APCS_SET (dest))
+ {
+ /* If the src and dest have different APCS flag bits set, fail. */
+ if (APCS_26_FLAG (dest) != APCS_26_FLAG (src))
+ return false;
+
+ if (APCS_FLOAT_FLAG (dest) != APCS_FLOAT_FLAG (src))
+ return false;
+
+ if (PIC_FLAG (dest) != PIC_FLAG (src))
+ return false;
+ }
+ else
+ SET_APCS_FLAGS (dest, APCS_26_FLAG (src) | APCS_FLOAT_FLAG (src) | PIC_FLAG (src));
+ }
+
+ if (INTERWORK_SET (src))
+ {
+ if (INTERWORK_SET (dest))
+ {
+ /* If the src and dest have different interworking flags then turn off the interworking bit. */
+ if (INTERWORK_FLAG (dest) != INTERWORK_FLAG (src))
+ SET_INTERWORK_FLAG (dest, 0);
+ }
+ else
+ {
+ SET_INTERWORK_FLAG (dest, INTERWORK_FLAG (src));
+ }
+ }
+
+ return true;
+}
+
+/* Note: the definitions here of LOCAL_LABEL_PREFIX and USER_LABEL_PREIFX
+ *must* match the definitions on gcc/config/arm/semi.h. */
+#define LOCAL_LABEL_PREFIX "."
+#define USER_LABEL_PREFIX "_"
+
+static boolean
+coff_arm_is_local_label_name (abfd, name)
+ bfd * abfd;
+ const char * name;
+{
+#ifdef LOCAL_LABEL_PREFIX
+ /* If there is a prefix for local labels then look for this.
+ If the prefix exists, but it is empty, then ignore the test. */
+
+ if (LOCAL_LABEL_PREFIX[0] != 0)
+ {
+ if (strncmp (name, LOCAL_LABEL_PREFIX, strlen (LOCAL_LABEL_PREFIX)) == 0)
+ return true;
+ }
+#endif
+#ifdef USER_LABEL_PREFIX
+ if (USER_LABEL_PREFIX[0] != 0)
+ {
+ if (strncmp (name, USER_LABEL_PREFIX, strlen (USER_LABEL_PREFIX)) == 0)
+ return false;
+ }
+#endif
+
+ /* devo/gcc/config/dbxcoff.h defines ASM_OUTPUT_SOURCE_LINE to generate local line numbers as .LM<number>, so treat these as local. */
+
+ switch (name[0])
+ {
+ case 'L': return true;
+ case '.': return (name[1] == 'L' && name[2] == 'M') ? true : false;
+ default: return false; /* Cannot make our minds up - default to false so that it will not be stripped by accident. */
+ }
+}
+
+#define coff_bfd_is_local_label_name coff_arm_is_local_label_name
+#define coff_adjust_symndx coff_arm_adjust_symndx
+#define coff_bfd_final_link coff_arm_bfd_final_link