diff options
author | Nick Clifton <nickc@redhat.com> | 2003-04-01 13:08:06 +0000 |
---|---|---|
committer | Nick Clifton <nickc@redhat.com> | 2003-04-01 13:08:06 +0000 |
commit | 031f3f89def963dd63262a8cc5a3e008ecd7b668 (patch) | |
tree | 6ab280db470aecc1d4905e95d4cb3e6b518fdb6e /bfd/cpu-arm.c | |
parent | 6c2ac673ce1e0640f4c2ddea2dd33e3ee0b1220c (diff) | |
download | gdb-031f3f89def963dd63262a8cc5a3e008ecd7b668.tar.gz |
Fixes for iWMMXt contribution.
Diffstat (limited to 'bfd/cpu-arm.c')
-rw-r--r-- | bfd/cpu-arm.c | 278 |
1 files changed, 277 insertions, 1 deletions
diff --git a/bfd/cpu-arm.c b/bfd/cpu-arm.c index eb3011d7d29..66c3a466523 100644 --- a/bfd/cpu-arm.c +++ b/bfd/cpu-arm.c @@ -1,5 +1,5 @@ /* BFD support for the ARM processor - Copyright 1994, 1997, 1999, 2000, 2002 Free Software Foundation, Inc. + Copyright 1994, 1997, 1999, 2000, 2002, 2003 Free Software Foundation, Inc. Contributed by Richard Earnshaw (rwe@pegasus.esprit.ec.org) This file is part of BFD, the Binary File Descriptor library. @@ -21,11 +21,14 @@ #include "bfd.h" #include "sysdep.h" #include "libbfd.h" +#include "libiberty.h" static const bfd_arch_info_type * compatible PARAMS ((const bfd_arch_info_type *, const bfd_arch_info_type *)); static bfd_boolean scan PARAMS ((const struct bfd_arch_info *, const char *)); +static bfd_boolean arm_check_note + PARAMS ((bfd *, char *, bfd_size_type, const char *, char **)); /* This routine is provided two arch_infos and works out which ARM machine which would be compatible with both and returns a pointer @@ -149,3 +152,276 @@ static const bfd_arch_info_type arch_info_struct[] = const bfd_arch_info_type bfd_arm_arch = N (0, "arm", TRUE, & arch_info_struct[0]); + +/* Support functions used by both the COFF and ELF versions of the ARM port. */ + +/* Handle the mergeing of the 'machine' settings of input file IBFD + and an output file OBFD. These values actually represent the + different possible ARM architecture variants. + Returns TRUE if they were merged successfully or FALSE otherwise. */ + +bfd_boolean +bfd_arm_merge_machines (ibfd, obfd) + bfd * ibfd; + bfd * obfd; +{ + unsigned int in = bfd_get_mach (ibfd); + unsigned int out = bfd_get_mach (obfd); + + /* If the output architecture is unknown, we now have a value to set. */ + if (out == bfd_mach_arm_unknown) + bfd_set_arch_mach (obfd, bfd_arch_arm, in); + + /* If the input architecure is unknown, + then so must be the output architecture. */ + else if (in == bfd_mach_arm_unknown) + /* FIXME: We ought to have some way to + override this on the command line. */ + bfd_set_arch_mach (obfd, bfd_arch_arm, bfd_mach_arm_unknown); + + /* If they are the same then nothing needs to be done. */ + else if (out == in) + ; + + /* Otherwise the general principle that a earlier architecture can be + linked with a later architecure to produce a binary that will execute + on the later architecture. + + We fail however if we attempt to link a Cirrus EP9312 binary with an + Intel XScale binary, since these architecture have co-processors which + will not both be present on the same physical hardware. */ + else if (in == bfd_mach_arm_ep9312 + && (out == bfd_mach_arm_XScale || out == bfd_mach_arm_iWMMXt)) + { + _bfd_error_handler (_("\ +ERROR: %s is compiled for the EP9312, whereas %s is compiled for XScale"), + bfd_archive_filename (ibfd), + bfd_get_filename (obfd)); + bfd_set_error (bfd_error_wrong_format); + return FALSE; + } + else if (out == bfd_mach_arm_ep9312 + && (in == bfd_mach_arm_XScale || in == bfd_mach_arm_iWMMXt)) + { + _bfd_error_handler (_("\ +ERROR: %s is compiled for the EP9312, whereas %s is compiled for XScale"), + bfd_archive_filename (obfd), + bfd_get_filename (ibfd)); + bfd_set_error (bfd_error_wrong_format); + return FALSE; + } + else if (in > out) + bfd_set_arch_mach (obfd, bfd_arch_arm, in); + /* else + Nothing to do. */ + + return TRUE; +} + +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; + +static bfd_boolean +arm_check_note (abfd, buffer, buffer_size, expected_name, description_return) + bfd * abfd; + char * buffer; + bfd_size_type buffer_size; + const char * expected_name; + char ** description_return; +{ + unsigned long namesz; + unsigned long descsz; + unsigned long type; + char * descr; + + if (buffer_size < offsetof (arm_Note, name)) + return FALSE; + + /* We have to extract the values this way to allow for a + host whose endian-ness is different from the target. */ + namesz = bfd_get_32 (abfd, buffer); + descsz = bfd_get_32 (abfd, buffer + offsetof (arm_Note, descsz)); + type = bfd_get_32 (abfd, buffer + offsetof (arm_Note, type)); + descr = buffer + offsetof (arm_Note, name); + + /* Check for buffer overflow. */ + if (namesz + descsz + offsetof (arm_Note, name) > buffer_size) + return FALSE; + + if (expected_name == NULL) + { + if (namesz != 0) + return FALSE; + } + else + { + if (namesz != (strlen (expected_name) + 1 + 3) & ~3) + return FALSE; + + if (strcmp (descr, expected_name) != 0) + return FALSE; + + descr += (namesz + 3) & ~3; + } + + /* FIXME: We should probably check the type as well. */ + + if (description_return != NULL) + * description_return = descr; + + return TRUE; +} + +#define NOTE_ARCH_STRING "arch: " + +bfd_boolean +bfd_arm_update_notes (abfd, note_section) + bfd * abfd; + const char * note_section; +{ + asection * arm_arch_section; + bfd_size_type buffer_size; + char * buffer; + char * arch_string; + char * expected; + + /* Look for a note section. If one is present check the architecture + string encoded in it, and set it to the current architecture if it is + different. */ + arm_arch_section = bfd_get_section_by_name (abfd, note_section); + + if (arm_arch_section == NULL) + return TRUE; + + buffer_size = arm_arch_section->_raw_size; + if (buffer_size == 0) + return FALSE; + + buffer = bfd_malloc (buffer_size); + if (buffer == NULL) + return FALSE; + + if (! bfd_get_section_contents (abfd, arm_arch_section, buffer, + (file_ptr) 0, buffer_size)) + goto FAIL; + + /* Parse the note. */ + if (! arm_check_note (abfd, buffer, buffer_size, NOTE_ARCH_STRING, & arch_string)) + goto FAIL; + + /* Check the architecture in the note against the architecture of the bfd. */ + switch (bfd_get_mach (abfd)) + { + default: + case bfd_mach_arm_unknown: expected = "unknown"; break; + case bfd_mach_arm_2: expected = "armv2"; break; + case bfd_mach_arm_2a: expected = "armv2a"; break; + case bfd_mach_arm_3: expected = "armv3"; break; + case bfd_mach_arm_3M: expected = "armv3M"; break; + case bfd_mach_arm_4: expected = "armv4"; break; + case bfd_mach_arm_4T: expected = "armv4t"; break; + case bfd_mach_arm_5: expected = "armv5"; break; + case bfd_mach_arm_5T: expected = "armv5t"; break; + case bfd_mach_arm_5TE: expected = "armv5te"; break; + case bfd_mach_arm_XScale: expected = "XScale"; break; + case bfd_mach_arm_ep9312: expected = "ep9312"; break; + case bfd_mach_arm_iWMMXt: expected = "iWMMXt"; break; + } + + if (strcmp (arch_string, expected) != 0) + { + strcpy (buffer + offsetof (arm_Note, name) + ((strlen (NOTE_ARCH_STRING) + 3) & ~3), expected); + + if (! bfd_set_section_contents (abfd, arm_arch_section, buffer, + (file_ptr) 0, buffer_size)) + { + (*_bfd_error_handler) + (_("warning: unable to update contents of %s section in %s"), + note_section, bfd_get_filename (abfd)); + goto FAIL; + } + } + + free (buffer); + return TRUE; + + FAIL: + free (buffer); + return FALSE; +} + + +static struct +{ + const char * string; + unsigned int mach; +} +architectures[] = +{ + { "armv2", bfd_mach_arm_2 }, + { "armv2a", bfd_mach_arm_2a }, + { "armv3", bfd_mach_arm_3 }, + { "armv3M", bfd_mach_arm_3M }, + { "armv4", bfd_mach_arm_4 }, + { "armv4t", bfd_mach_arm_4T }, + { "armv5", bfd_mach_arm_5 }, + { "armv5t", bfd_mach_arm_5T }, + { "armv5te", bfd_mach_arm_5TE }, + { "XScale", bfd_mach_arm_XScale }, + { "ep9312", bfd_mach_arm_ep9312 }, + { "iWMMXt", bfd_mach_arm_iWMMXt } +}; + +/* Extract the machine number stored in a note section. */ +unsigned int +bfd_arm_get_mach_from_notes (abfd, note_section) + bfd * abfd; + const char * note_section; +{ + asection * arm_arch_section; + bfd_size_type buffer_size; + char * buffer; + char * arch_string; + int i; + + /* Look for a note section. If one is present check the architecture + string encoded in it, and set it to the current architecture if it is + different. */ + arm_arch_section = bfd_get_section_by_name (abfd, note_section); + + if (arm_arch_section == NULL) + return bfd_mach_arm_unknown; + + buffer_size = arm_arch_section->_raw_size; + if (buffer_size == 0) + return bfd_mach_arm_unknown; + + buffer = bfd_malloc (buffer_size); + if (buffer == NULL) + return bfd_mach_arm_unknown; + + if (! bfd_get_section_contents (abfd, arm_arch_section, buffer, + (file_ptr) 0, buffer_size)) + goto FAIL; + + /* Parse the note. */ + if (! arm_check_note (abfd, buffer, buffer_size, NOTE_ARCH_STRING, & arch_string)) + goto FAIL; + + /* Interpret the architecture string. */ + for (i = ARRAY_SIZE (architectures); i--;) + if (strcmp (arch_string, architectures[i].string) == 0) + { + free (buffer); + return architectures[i].mach; + } + + FAIL: + free (buffer); + return bfd_mach_arm_unknown; +} |