/* tc-arm.c -- Assemble for the ARM
- Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004
+ Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003,
+ 2004, 2005
Free Software Foundation, Inc.
Contributed by Richard Earnshaw (rwe@pegasus.esprit.ec.org)
Modified by David Taylor (dtaylor@armltd.co.uk)
#endif
#endif
-#ifdef TE_LINUX
-#define FPU_DEFAULT FPU_ARCH_FPA
-#endif
-
-#ifdef TE_NetBSD
-#ifdef OBJ_ELF
-#define FPU_DEFAULT FPU_ARCH_VFP /* Soft-float, but VFP order. */
-#else
-/* Legacy a.out format. */
-#define FPU_DEFAULT FPU_ARCH_FPA /* Soft-float, but FPA order. */
-#endif
-#endif
-
-/* For backwards compatibility we default to the FPA. */
#ifndef FPU_DEFAULT
-#define FPU_DEFAULT FPU_ARCH_FPA
-#endif
+# ifdef TE_LINUX
+# define FPU_DEFAULT FPU_ARCH_FPA
+# elif defined (TE_NetBSD)
+# ifdef OBJ_ELF
+# define FPU_DEFAULT FPU_ARCH_VFP /* Soft-float, but VFP order. */
+# else
+ /* Legacy a.out format. */
+# define FPU_DEFAULT FPU_ARCH_FPA /* Soft-float, but FPA order. */
+# endif
+# elif defined (TE_VXWORKS)
+# define FPU_DEFAULT FPU_ARCH_VFP /* Soft-float, VFP order. */
+# else
+ /* For backwards compatibility, default to FPA. */
+# define FPU_DEFAULT FPU_ARCH_FPA
+# endif
+#endif /* ifndef FPU_DEFAULT */
#define streq(a, b) (strcmp (a, b) == 0)
#define skip_whitespace(str) while (*(str) == ' ') ++(str)
static unsigned long cpu_variant;
-static int target_oabi = 0;
/* Flags stored in private area of BFD structure. */
static int uses_apcs_26 = FALSE;
return;
}
-#if 0 /* The first edition of the ARM architecture manual stated that
- writing anything other than the flags with an immediate operation
- had UNPREDICTABLE effects. This constraint was removed in the
- second edition of the specification. */
- if ((cpu_variant & ARM_EXT_V5) != ARM_EXT_V5
- && inst.instruction & ((PSR_c | PSR_x | PSR_s) << PSR_SHIFT))
- {
- inst.error = _("immediate value cannot be used to set this field");
- return;
- }
-#endif
-
inst.instruction |= INST_IMMEDIATE;
if (inst.reloc.exp.X_add_symbol)
end_of_line (str);
}
+#ifdef OBJ_ELF
static bfd_reloc_code_real_type
arm_parse_reloc (void)
{
return reloc_map[i].reloc;
}
+#endif
/* ARM V5 branch-link-exchange (argument parse) for BLX(1) only.
Expects inst.instruction is set for BLX(1).
return;
}
- if (inst.reloc.type != BFD_RELOC_NONE)
+ if (inst.reloc.type != BFD_RELOC_UNUSED)
{
/* This really doesn't seem worth it. */
- inst.reloc.type = BFD_RELOC_NONE;
+ inst.reloc.type = BFD_RELOC_UNUSED;
inst.error = _("expression too complex");
return;
}
return;
}
- if (inst.reloc.type != BFD_RELOC_NONE)
+ if (inst.reloc.type != BFD_RELOC_UNUSED)
{
/* This really doesn't seem worth it. */
- inst.reloc.type = BFD_RELOC_NONE;
+ inst.reloc.type = BFD_RELOC_UNUSED;
inst.error = _("expression too complex");
return;
}
}
}
-#if 0 /* Suppressed - for now. */
-#if defined OBJ_ELF || defined OBJ_COFF
-
-#ifdef OBJ_ELF
-#define arm_Note Elf_External_Note
-#else
-typedef struct
-{
- unsigned char namesz[4]; /* Size of entry's owner string. */
- unsigned char descsz[4]; /* Size of the note descriptor. */
- unsigned char type[4]; /* Interpretation of the descriptor. */
- char name[1]; /* Start of the name+desc data. */
-} arm_Note;
-#endif
-
-/* The description is kept to a fix sized in order to make updating
- it and merging it easier. */
-#define ARM_NOTE_DESCRIPTION_LENGTH 8
-
-static void
-arm_add_note (const char * name,
- const char * description,
- unsigned int type)
-{
- arm_Note note ATTRIBUTE_UNUSED;
- char * p;
- unsigned int name_len;
-
- name_len = (strlen (name) + 1 + 3) & ~3;
-
- p = frag_more (sizeof (note.namesz));
- md_number_to_chars (p, (valueT) name_len, sizeof (note.namesz));
-
- p = frag_more (sizeof (note.descsz));
- md_number_to_chars (p, (valueT) ARM_NOTE_DESCRIPTION_LENGTH, sizeof (note.descsz));
-
- p = frag_more (sizeof (note.type));
- md_number_to_chars (p, (valueT) type, sizeof (note.type));
-
- p = frag_more (name_len);
- strcpy (p, name);
-
- p = frag_more (ARM_NOTE_DESCRIPTION_LENGTH);
- strncpy (p, description, ARM_NOTE_DESCRIPTION_LENGTH);
- frag_align (2, 0, 0);
-}
-#endif
-#endif
-
\f
static const struct thumb_opcode tinsns[] =
{
}
else if (mfpu_opt == -1)
{
-#if !(defined (TE_LINUX) || defined (TE_NetBSD))
+#if !(defined (TE_LINUX) || defined (TE_NetBSD) || defined (TE_VXWORKS))
/* Some environments specify a default FPU. If they don't, infer it
from the processor. */
if (mcpu_fpu_opt != -1)
cpu_variant = mcpu_cpu_opt | mfpu_opt;
+#if defined OBJ_COFF || defined OBJ_ELF
{
unsigned int flags = 0;
{
case EF_ARM_EABI_UNKNOWN:
#endif
-#if defined OBJ_COFF || defined OBJ_ELF
/* Set the flags in the private structure. */
if (uses_apcs_26) flags |= F_APCS26;
if (support_interwork) flags |= F_INTERWORK;
/* Using VFP conventions (even if soft-float). */
if (cpu_variant & FPU_VFP_EXT_NONE)
flags |= F_VFP_FLOAT;
-#endif
+
#if defined OBJ_ELF
if (cpu_variant & FPU_ARCH_MAVERICK)
flags |= EF_ARM_MAVERICK_FLOAT;
abort ();
}
#endif
-#if defined OBJ_COFF || defined OBJ_ELF
bfd_set_private_flags (stdoutput, flags);
/* We have run out flags in the COFF header to encode the
bfd_set_section_contents (stdoutput, sec, NULL, 0, 0);
}
}
-#endif
}
+#endif
/* Record the CPU type as well. */
switch (cpu_variant & ARM_CPU_MASK)
else if (cpu_variant & ARM_EXT_V3M)
mach = bfd_mach_arm_3M;
-#if 0 /* Suppressed - for now. */
-#if defined (OBJ_ELF) || defined (OBJ_COFF)
-
- /* Create a .note section to fully identify this arm binary. */
-
-#define NOTE_ARCH_STRING "arch: "
-
-#if defined OBJ_COFF && ! defined NT_VERSION
-#define NT_VERSION 1
-#define NT_ARCH 2
-#endif
-
- {
- segT current_seg = now_seg;
- subsegT current_subseg = now_subseg;
- asection * arm_arch;
- const char * arch_string;
-
- arm_arch = bfd_make_section_old_way (stdoutput, ARM_NOTE_SECTION);
-
-#ifdef OBJ_COFF
- bfd_set_section_flags (stdoutput, arm_arch,
- SEC_DATA | SEC_ALLOC | SEC_LOAD | SEC_LINK_ONCE \
- | SEC_HAS_CONTENTS);
-#else
- bfd_set_section_flags (stdoutput, arm_arch,
- SEC_READONLY | SEC_HAS_CONTENTS);
-#endif
- arm_arch->output_section = arm_arch;
- subseg_set (arm_arch, 0);
-
- switch (mach)
- {
- default:
- case bfd_mach_arm_unknown: arch_string = "unknown"; break;
- case bfd_mach_arm_2: arch_string = "armv2"; break;
- case bfd_mach_arm_2a: arch_string = "armv2a"; break;
- case bfd_mach_arm_3: arch_string = "armv3"; break;
- case bfd_mach_arm_3M: arch_string = "armv3M"; break;
- case bfd_mach_arm_4: arch_string = "armv4"; break;
- case bfd_mach_arm_4T: arch_string = "armv4t"; break;
- case bfd_mach_arm_5: arch_string = "armv5"; break;
- case bfd_mach_arm_5T: arch_string = "armv5t"; break;
- case bfd_mach_arm_5TE: arch_string = "armv5te"; break;
- case bfd_mach_arm_XScale: arch_string = "XScale"; break;
- case bfd_mach_arm_ep9312: arch_string = "ep9312"; break;
- case bfd_mach_arm_iWMMXt: arch_string = "iWMMXt"; break;
- }
-
- arm_add_note (NOTE_ARCH_STRING, arch_string, NT_ARCH);
-
- subseg_set (current_seg, current_subseg);
- }
-#endif
-#endif /* Suppressed code. */
-
bfd_set_arch_mach (stdoutput, TARGET_ARCH, mach);
}
char * buf = fixP->fx_where + fixP->fx_frag->fr_literal;
arm_fix_data * arm_data = (arm_fix_data *) fixP->tc_fix_data;
- assert (fixP->fx_r_type < BFD_RELOC_UNUSED);
+ assert (fixP->fx_r_type <= BFD_RELOC_UNUSED);
/* Note whether this will delete the relocation. */
-#if 0
- /* Patch from REarnshaw to JDavis (disabled for the moment, since it
- doesn't work fully.) */
- if ((fixP->fx_addsy == 0 || symbol_constant_p (fixP->fx_addsy))
- && !fixP->fx_pcrel)
-#else
if (fixP->fx_addsy == 0 && !fixP->fx_pcrel)
-#endif
fixP->fx_done = 1;
/* If this symbol is in a different section then we need to leave it for
if (fixP->fx_addsy != NULL
&& S_IS_DEFINED (fixP->fx_addsy)
&& S_GET_SEGMENT (fixP->fx_addsy) != seg)
- {
- if (target_oabi
- && (fixP->fx_r_type == BFD_RELOC_ARM_PCREL_BRANCH
- || fixP->fx_r_type == BFD_RELOC_ARM_PCREL_BLX
- ))
- value = 0;
- else
- value += md_pcrel_from (fixP);
- }
+ value += md_pcrel_from (fixP);
}
/* Remember value for emit_reloc. */
switch (fixP->fx_r_type)
{
+ case BFD_RELOC_NONE:
+ /* This will need to go in the object file. */
+ fixP->fx_done = 0;
+ break;
+
case BFD_RELOC_ARM_IMMEDIATE:
/* We claim that this fixup has been processed here,
even if in fact we generate an error because we do
#define SEXT24(x) ((((x) & 0xffffff) ^ (~ 0x7fffff)) + 0x800000)
#ifdef OBJ_ELF
- if (! target_oabi)
- value = fixP->fx_offset;
+ value = fixP->fx_offset;
#endif
/* We are going to store value (shifted right by two) in the
branch instruction itself, then we can compute the relocation for
ourselves and not have to bother the linker with it.
- FIXME: The tests for OBJ_ELF and ! target_oabi are only here
- because I have not worked out how to do this for OBJ_COFF or
- target_oabi. */
- if (! target_oabi
- && fixP->fx_addsy != NULL
+ FIXME: The test for OBJ_ELF is only here because I have not
+ worked out how to do this for OBJ_COFF. */
+ if (fixP->fx_addsy != NULL
&& S_IS_DEFINED (fixP->fx_addsy)
&& S_GET_SEGMENT (fixP->fx_addsy) == seg)
{
as_bad_where (fixP->fx_file, fixP->fx_line,
_("out of range branch"));
- newval = (value & 0x00ffffff) | (newval & 0xff000000);
+ if (seg->use_rela_p && !fixP->fx_done)
+ {
+ /* Must unshift the value before storing it in the addend. */
+ value <<= 2;
+#ifdef OBJ_ELF
+ fixP->fx_offset = value;
+#endif
+ fixP->fx_addnumber = value;
+ newval = newval & 0xff000000;
+ }
+ else
+ newval = (value & 0x00ffffff) | (newval & 0xff000000);
md_number_to_chars (buf, newval, INSN_SIZE);
break;
newval = md_chars_to_number (buf, INSN_SIZE);
#ifdef OBJ_ELF
- if (! target_oabi)
- value = fixP->fx_offset;
+ value = fixP->fx_offset;
#endif
hbit = (value >> 1) & 1;
value = (value >> 2) & 0x00ffffff;
value = (value + (newval & 0x00ffffff)) & 0x00ffffff;
- newval = value | (newval & 0xfe000000) | (hbit << 24);
+
+ if (seg->use_rela_p && !fixP->fx_done)
+ {
+ /* Must sign-extend and unshift the value before storing
+ it in the addend. */
+ value = SEXT24 (value);
+ value = (value << 2) | hbit;
+#ifdef OBJ_ELF
+ fixP->fx_offset = value;
+#endif
+ fixP->fx_addnumber = value;
+ newval = newval & 0xfe000000;
+ }
+ else
+ newval = value | (newval & 0xfe000000) | (hbit << 24);
md_number_to_chars (buf, newval, INSN_SIZE);
}
break;
if ((value & ~0xff) && ((value & ~0xff) != ~0xff))
as_bad_where (fixP->fx_file, fixP->fx_line,
_("branch out of range"));
- newval = (newval & 0xff00) | ((value & 0x1ff) >> 1);
+ if (seg->use_rela_p && !fixP->fx_done)
+ {
+#ifdef OBJ_ELF
+ fixP->fx_offset = value;
+#endif
+ fixP->fx_addnumber = value;
+ newval = newval & 0xff00;
+ }
+ else
+ newval = (newval & 0xff00) | ((value & 0x1ff) >> 1);
}
md_number_to_chars (buf, newval, THUMB_SIZE);
break;
if ((value & ~0x7ff) && ((value & ~0x7ff) != ~0x7ff))
as_bad_where (fixP->fx_file, fixP->fx_line,
_("branch out of range"));
- newval = (newval & 0xf800) | ((value & 0xfff) >> 1);
+ if (seg->use_rela_p && !fixP->fx_done)
+ {
+#ifdef OBJ_ELF
+ fixP->fx_offset = value;
+#endif
+ fixP->fx_addnumber = value;
+ newval = newval & 0xf800;
+ }
+ else
+ newval = (newval & 0xf800) | ((value & 0xfff) >> 1);
}
md_number_to_chars (buf, newval, THUMB_SIZE);
break;
as_bad_where (fixP->fx_file, fixP->fx_line,
_("branch with link out of range"));
- newval = (newval & 0xf800) | ((value & 0x7fffff) >> 12);
- newval2 = (newval2 & 0xf800) | ((value & 0xfff) >> 1);
if (fixP->fx_r_type == BFD_RELOC_THUMB_PCREL_BLX)
/* For a BLX instruction, make sure that the relocation is rounded up
to a word boundary. This follows the semantics of the instruction
which specifies that bit 1 of the target address will come from bit
1 of the base address. */
- newval2 = (newval2 + 1) & ~ 1;
+ value = (value + 1) & ~ 1;
+
+ if (seg->use_rela_p && !fixP->fx_done)
+ {
+#ifdef OBJ_ELF
+ fixP->fx_offset = value;
+#endif
+ fixP->fx_addnumber = value;
+ newval = newval & 0xf800;
+ newval2 = newval2 & 0xf800;
+ }
+ else
+ {
+ newval = (newval & 0xf800) | ((value & 0x7fffff) >> 12);
+ newval2 = (newval2 & 0xf800) | ((value & 0xfff) >> 1);
+ }
md_number_to_chars (buf, newval, THUMB_SIZE);
md_number_to_chars (buf + THUMB_SIZE, newval2, THUMB_SIZE);
}
break;
case BFD_RELOC_8:
+ if (seg->use_rela_p && !fixP->fx_done)
+ break;
if (fixP->fx_done || fixP->fx_pcrel)
md_number_to_chars (buf, value, 1);
#ifdef OBJ_ELF
- else if (!target_oabi)
+ else
{
value = fixP->fx_offset;
md_number_to_chars (buf, value, 1);
break;
case BFD_RELOC_16:
+ if (seg->use_rela_p && !fixP->fx_done)
+ break;
if (fixP->fx_done || fixP->fx_pcrel)
md_number_to_chars (buf, value, 2);
#ifdef OBJ_ELF
- else if (!target_oabi)
+ else
{
value = fixP->fx_offset;
md_number_to_chars (buf, value, 2);
case BFD_RELOC_ARM_GOT32:
case BFD_RELOC_ARM_GOTOFF:
case BFD_RELOC_ARM_TARGET2:
+ if (seg->use_rela_p && !fixP->fx_done)
+ break;
md_number_to_chars (buf, 0, 4);
break;
#endif
case BFD_RELOC_ARM_ROSEGREL32:
case BFD_RELOC_ARM_SBREL32:
case BFD_RELOC_32_PCREL:
+ if (seg->use_rela_p && !fixP->fx_done)
+ break;
if (fixP->fx_done || fixP->fx_pcrel)
md_number_to_chars (buf, value, 4);
#ifdef OBJ_ELF
- else if (!target_oabi)
+ else
{
value = fixP->fx_offset;
md_number_to_chars (buf, value, 4);
fixP->fx_done = 0;
return;
- case BFD_RELOC_NONE:
+ case BFD_RELOC_UNUSED:
default:
as_bad_where (fixP->fx_file, fixP->fx_line,
_("bad relocation fixup type (%d)"), fixP->fx_r_type);
break;
}
+ case BFD_RELOC_NONE:
case BFD_RELOC_ARM_PCREL_BRANCH:
case BFD_RELOC_ARM_PCREL_BLX:
case BFD_RELOC_RVA:
switch (fixp->fx_r_type)
{
+ case BFD_RELOC_NONE: type = "NONE"; break;
case BFD_RELOC_ARM_OFFSET_IMM8: type = "OFFSET_IMM8"; break;
case BFD_RELOC_ARM_SHIFT_IMM: type = "SHIFT_IMM"; break;
case BFD_RELOC_ARM_SMI: type = "SMI"; break;
else
md_number_to_chars (to, inst.instruction, inst.size);
- if (inst.reloc.type != BFD_RELOC_NONE)
+ if (inst.reloc.type != BFD_RELOC_UNUSED)
fix_new_arm (frag_now, to - frag_now->fr_literal,
inst.size, & inst.reloc.exp, inst.reloc.pc_rel,
inst.reloc.type);
char *p;
char *start;
- /* Align the instruction.
- This may not be the right thing to do but ... */
-#if 0
- arm_align (2, 0);
-#endif
-
/* Align the previous label if needed. */
if (last_label_seen != NULL)
{
}
memset (&inst, '\0', sizeof (inst));
- inst.reloc.type = BFD_RELOC_NONE;
+ inst.reloc.type = BFD_RELOC_UNUSED;
skip_whitespace (str);
{"mthumb", N_("assemble Thumb code"), &thumb_mode, 1, NULL},
{"mthumb-interwork", N_("support ARM/Thumb interworking"),
&support_interwork, 1, NULL},
- {"moabi", N_("use old ABI (ELF only)"), &target_oabi, 1, NULL},
{"mapcs-32", N_("code uses 32-bit program counter"), &uses_apcs_26, 0, NULL},
{"mapcs-26", N_("code uses 26-bit program counter"), &uses_apcs_26, 1, NULL},
{"mapcs-float", N_("floating point args are in fp regs"), &uses_apcs_float,
{"arm1020", ARM_ARCH_V5TE, FPU_ARCH_VFP_V2},
{"arm1020t", ARM_ARCH_V5T, FPU_ARCH_VFP_V1},
{"arm1020e", ARM_ARCH_V5TE, FPU_ARCH_VFP_V2},
- {"arm1026ejs", ARM_ARCH_V5TE, FPU_ARCH_VFP_V2},
- {"arm1026ej-s", ARM_ARCH_V5TE, FPU_ARCH_VFP_V2},
+ {"arm1026ejs", ARM_ARCH_V5TEJ, FPU_ARCH_VFP_V2},
+ {"arm1026ej-s", ARM_ARCH_V5TEJ, FPU_ARCH_VFP_V2},
{"arm1136js", ARM_ARCH_V6, FPU_NONE},
{"arm1136j-s", ARM_ARCH_V6, FPU_NONE},
{"arm1136jfs", ARM_ARCH_V6, FPU_ARCH_VFP_V2},
return (target_big_endian
? "elf32-bigarm-symbian"
: "elf32-littlearm-symbian");
+#elif defined (TE_VXWORKS)
+ return (target_big_endian
+ ? "elf32-bigarm-vxworks"
+ : "elf32-littlearm-vxworks");
#else
if (target_big_endian)
- {
- if (target_oabi)
- return "elf32-bigarm-oabi";
- else
- return "elf32-bigarm";
- }
+ return "elf32-bigarm";
else
- {
- if (target_oabi)
- return "elf32-littlearm-oabi";
- else
- return "elf32-littlearm";
- }
+ return "elf32-littlearm";
#endif
}
/* Custom personality routine. */
fix_new (frag_now, where, 4, unwind.personality_routine, 0, 1,
BFD_RELOC_ARM_PREL31);
+
+ /* Indicate dependency to linker. */
+ {
+ char *name = "__aeabi_unwind_cpp_pr0";
+ symbolS *pr = symbol_find_or_make (name);
+ fix_new (frag_now, where, 4, pr, 0, 1, BFD_RELOC_NONE);
+ }
+
where += 4;
ptr += 4;
break;
/* ABI defined personality routines. */
- /* TODO: Emit R_ARM_NONE to the personality routine. */
case 0:
/* Three opcodes bytes are packed into the first word. */
data = 0x80;
n = 3;
- break;
+ goto emit_reloc;
case 1:
case 2:
/* The size and first two opcode bytes go in the first word. */
data = ((0x80 + unwind.personality_index) << 8) | size;
n = 2;
+ goto emit_reloc;
+
+ emit_reloc:
+ {
+ /* Indicate dependency to linker. */
+ char *name[] = { "__aeabi_unwind_cpp_pr0",
+ "__aeabi_unwind_cpp_pr1",
+ "__aeabi_unwind_cpp_pr2" };
+ symbolS *pr = symbol_find_or_make (name[unwind.personality_index]);
+ fix_new (frag_now, where, 4, pr, 0, 1, BFD_RELOC_NONE);
+ }
break;
default:
/* Self relative offset of the function start. */
fix_new (frag_now, where, 4, unwind.proc_start, 0, 1,
- BFD_RELOC_32);
+ BFD_RELOC_ARM_PREL31);
if (val)
/* Inline exception table entry. */