From 64543e1acf3388a4318688720d3e242e93fcb00b Mon Sep 17 00:00:00 2001 From: Richard Sandiford Date: Thu, 2 Jan 2003 21:31:32 +0000 Subject: [PATCH] bfd/ * elfxx-mips.c: Include libiberty.h. (elf_mips_isa, _bfd_mips_elf_mach_extends_p): Remove. (mips_set_isa_flags): New function, split out from... (_bfd_mips_elf_final_write_processing): ...here. Only call mips_set_isa_flags if the EF_MIPS_MACH bits are clear. (mips_mach_extensions): New array. (mips_32bit_flags_p): New function. (_bfd_mips_elf_merge_private_bfd_data): Rework architecture checks. Use mips_32bit_flags_p to check if one binary is 32-bit and the other is 64-bit. When adopting IBFD's architecture, adopt the bfd_mach as well as the flags. ld/testsuite/ * ld-mips-elf/jr.s: New file. * ld-mips-elf/mips-elf-flags.exp: New test. --- bfd/ChangeLog | 14 ++ bfd/elfxx-mips.c | 261 ++++++++++++-------- ld/testsuite/ChangeLog | 5 + ld/testsuite/ld-mips-elf/jr.s | 1 + ld/testsuite/ld-mips-elf/mips-elf-flags.exp | 146 +++++++++++ 5 files changed, 318 insertions(+), 109 deletions(-) create mode 100644 ld/testsuite/ld-mips-elf/jr.s create mode 100644 ld/testsuite/ld-mips-elf/mips-elf-flags.exp diff --git a/bfd/ChangeLog b/bfd/ChangeLog index a8503c1884..9c6674430a 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,17 @@ +2003-01-02 Richard Sandiford + + * elfxx-mips.c: Include libiberty.h. + (elf_mips_isa, _bfd_mips_elf_mach_extends_p): Remove. + (mips_set_isa_flags): New function, split out from... + (_bfd_mips_elf_final_write_processing): ...here. Only call + mips_set_isa_flags if the EF_MIPS_MACH bits are clear. + (mips_mach_extensions): New array. + (mips_32bit_flags_p): New function. + (_bfd_mips_elf_merge_private_bfd_data): Rework architecture checks. + Use mips_32bit_flags_p to check if one binary is 32-bit and the + other is 64-bit. When adopting IBFD's architecture, adopt the + bfd_mach as well as the flags. + 2003-01-02 Nick Kelsey * elf32-ip2k.c: Re-work of linker relaxation code for the ip2k to diff --git a/bfd/elfxx-mips.c b/bfd/elfxx-mips.c index ca79c64b98..3164a2ec17 100644 --- a/bfd/elfxx-mips.c +++ b/bfd/elfxx-mips.c @@ -1,6 +1,6 @@ /* MIPS-specific support for ELF - Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002 - Free Software Foundation, Inc. + Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, + 2003 Free Software Foundation, Inc. Most of the information added by Ian Lance Taylor, Cygnus Support, . @@ -30,6 +30,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "bfd.h" #include "sysdep.h" #include "libbfd.h" +#include "libiberty.h" #include "elf-bfd.h" #include "elfxx-mips.h" #include "elf/mips.h" @@ -382,11 +383,12 @@ static bfd_boolean mips_elf_create_dynamic_relocation PARAMS ((bfd *, struct bfd_link_info *, const Elf_Internal_Rela *, struct mips_elf_link_hash_entry *, asection *, bfd_vma, bfd_vma *, asection *)); -static INLINE int elf_mips_isa PARAMS ((flagword)); +static void mips_set_isa_flags PARAMS ((bfd *)); static INLINE char* elf_mips_abi_name PARAMS ((bfd *)); static void mips_elf_irix6_finish_dynamic_symbol PARAMS ((bfd *, const char *, Elf_Internal_Sym *)); -static bfd_boolean _bfd_mips_elf_mach_extends_p PARAMS ((flagword, flagword)); +static bfd_boolean mips_mach_extends_p PARAMS ((unsigned long, unsigned long)); +static bfd_boolean mips_32bit_flags_p PARAMS ((flagword)); static hashval_t mips_elf_got_entry_hash PARAMS ((const PTR)); static int mips_elf_got_entry_eq PARAMS ((const PTR, const PTR)); @@ -3080,34 +3082,6 @@ mips_elf_create_dynamic_relocation (output_bfd, info, rel, h, sec, return TRUE; } -/* Return the ISA for a MIPS e_flags value. */ - -static INLINE int -elf_mips_isa (flags) - flagword flags; -{ - switch (flags & EF_MIPS_ARCH) - { - case E_MIPS_ARCH_1: - return 1; - case E_MIPS_ARCH_2: - return 2; - case E_MIPS_ARCH_3: - return 3; - case E_MIPS_ARCH_4: - return 4; - case E_MIPS_ARCH_5: - return 5; - case E_MIPS_ARCH_32: - return 32; - case E_MIPS_ARCH_64: - return 64; - case E_MIPS_ARCH_32R2: - return 33; - } - return 4; -} - /* Return the MACH for a MIPS e_flags value. */ unsigned long @@ -5967,20 +5941,14 @@ _bfd_mips_elf_finish_dynamic_sections (output_bfd, info) return TRUE; } -/* The final processing done just before writing out a MIPS ELF object - file. This gets the MIPS architecture right based on the machine - number. This is used by both the 32-bit and the 64-bit ABI. */ -void -_bfd_mips_elf_final_write_processing (abfd, linker) +/* Set ABFD's EF_MIPS_ARCH and EF_MIPS_MACH flags. */ + +static void +mips_set_isa_flags (abfd) bfd *abfd; - bfd_boolean linker ATTRIBUTE_UNUSED; { - unsigned long val; - unsigned int i; - Elf_Internal_Shdr **hdrpp; - const char *name; - asection *sec; + flagword val; switch (bfd_get_mach (abfd)) { @@ -6059,10 +6027,32 @@ _bfd_mips_elf_final_write_processing (abfd, linker) val = E_MIPS_ARCH_32R2; break; } - elf_elfheader (abfd)->e_flags &= ~(EF_MIPS_ARCH | EF_MIPS_MACH); elf_elfheader (abfd)->e_flags |= val; +} + + +/* The final processing done just before writing out a MIPS ELF object + file. This gets the MIPS architecture right based on the machine + number. This is used by both the 32-bit and the 64-bit ABI. */ + +void +_bfd_mips_elf_final_write_processing (abfd, linker) + bfd *abfd; + bfd_boolean linker ATTRIBUTE_UNUSED; +{ + unsigned int i; + Elf_Internal_Shdr **hdrpp; + const char *name; + asection *sec; + + /* Keep the existing EF_MIPS_MACH and EF_MIPS_ARCH flags if the former + is nonzero. This is for compatibility with old objects, which used + a combination of a 32-bit EF_MIPS_ARCH and a 64-bit EF_MIPS_MACH. */ + if ((elf_elfheader (abfd)->e_flags & EF_MIPS_MACH) == 0) + mips_set_isa_flags (abfd); + /* Set the sh_info field for .gptab sections and other appropriate info for each special section. */ for (i = 1, hdrpp = elf_elfsections (abfd) + 1; @@ -7731,26 +7721,97 @@ _bfd_mips_elf_final_link (abfd, info) return TRUE; } -/* Return TRUE if machine EXTENSION is an extension of machine BASE, - meaning that it should be safe to link code for the two machines - and set the output machine to EXTENSION. EXTENSION and BASE are - both submasks of EF_MIPS_MACH. */ +/* Structure for saying that BFD machine EXTENSION extends BASE. */ + +struct mips_mach_extension { + unsigned long extension, base; +}; + + +/* An array describing how BFD machines relate to one another. The entries + are ordered topologically with MIPS I extensions listed last. */ + +static const struct mips_mach_extension mips_mach_extensions[] = { + /* MIPS64 extensions. */ + { bfd_mach_mips_sb1, bfd_mach_mipsisa64 }, + + /* MIPS V extensions. */ + { bfd_mach_mipsisa64, bfd_mach_mips5 }, + + /* R10000 extensions. */ + { bfd_mach_mips12000, bfd_mach_mips10000 }, + + /* R5000 extensions. Note: the vr5500 ISA is an extension of the core + vr5400 ISA, but doesn't include the multimedia stuff. It seems + better to allow vr5400 and vr5500 code to be merged anyway, since + many libraries will just use the core ISA. Perhaps we could add + some sort of ASE flag if this ever proves a problem. */ + { bfd_mach_mips5500, bfd_mach_mips5400 }, + { bfd_mach_mips5400, bfd_mach_mips5000 }, + + /* MIPS IV extensions. */ + { bfd_mach_mips5, bfd_mach_mips8000 }, + { bfd_mach_mips10000, bfd_mach_mips8000 }, + { bfd_mach_mips5000, bfd_mach_mips8000 }, + + /* VR4100 extensions. */ + { bfd_mach_mips4120, bfd_mach_mips4100 }, + { bfd_mach_mips4111, bfd_mach_mips4100 }, + + /* MIPS III extensions. */ + { bfd_mach_mips8000, bfd_mach_mips4000 }, + { bfd_mach_mips4650, bfd_mach_mips4000 }, + { bfd_mach_mips4600, bfd_mach_mips4000 }, + { bfd_mach_mips4400, bfd_mach_mips4000 }, + { bfd_mach_mips4300, bfd_mach_mips4000 }, + { bfd_mach_mips4100, bfd_mach_mips4000 }, + { bfd_mach_mips4010, bfd_mach_mips4000 }, + + /* MIPS32 extensions. */ + { bfd_mach_mipsisa32r2, bfd_mach_mipsisa32 }, + + /* MIPS II extensions. */ + { bfd_mach_mips4000, bfd_mach_mips6000 }, + { bfd_mach_mipsisa32, bfd_mach_mips6000 }, + + /* MIPS I extensions. */ + { bfd_mach_mips6000, bfd_mach_mips3000 }, + { bfd_mach_mips3900, bfd_mach_mips3000 } +}; + + +/* Return true if bfd machine EXTENSION is an extension of machine BASE. */ static bfd_boolean -_bfd_mips_elf_mach_extends_p (base, extension) - flagword base, extension; +mips_mach_extends_p (base, extension) + unsigned long base, extension; { - /* The vr5500 ISA is an extension of the core vr5400 ISA, but doesn't - include the multimedia stuff. It seems better to allow vr5400 - and vr5500 code to be merged anyway, since many libraries will - just use the core ISA. Perhaps we could add some sort of ASE - flag if this ever proves a problem. */ - return (base == 0 - || (base == E_MIPS_MACH_5400 && extension == E_MIPS_MACH_5500) - || (base == E_MIPS_MACH_4100 && extension == E_MIPS_MACH_4111) - || (base == E_MIPS_MACH_4100 && extension == E_MIPS_MACH_4120)); + size_t i; + + for (i = 0; extension != base && i < ARRAY_SIZE (mips_mach_extensions); i++) + if (extension == mips_mach_extensions[i].extension) + extension = mips_mach_extensions[i].base; + + return extension == base; } + +/* Return true if the given ELF header flags describe a 32-bit binary. */ + +static bfd_boolean +mips_32bit_flags_p (flags) + flagword flags; +{ + return ((flags & EF_MIPS_32BITMODE) != 0 + || (flags & EF_MIPS_ABI) == E_MIPS_ABI_O32 + || (flags & EF_MIPS_ABI) == E_MIPS_ABI_EABI32 + || (flags & EF_MIPS_ARCH) == E_MIPS_ARCH_1 + || (flags & EF_MIPS_ARCH) == E_MIPS_ARCH_2 + || (flags & EF_MIPS_ARCH) == E_MIPS_ARCH_32 + || (flags & EF_MIPS_ARCH) == E_MIPS_ARCH_32R2); +} + + /* Merge backend specific data from an object file to the output object file when linking. */ @@ -7846,68 +7907,50 @@ _bfd_mips_elf_merge_private_bfd_data (ibfd, obfd) ok = FALSE; } - /* Compare the ISA's. */ - if ((new_flags & (EF_MIPS_ARCH | EF_MIPS_MACH)) - != (old_flags & (EF_MIPS_ARCH | EF_MIPS_MACH))) + /* Compare the ISAs. */ + if (mips_32bit_flags_p (old_flags) != mips_32bit_flags_p (new_flags)) { - int new_mach = new_flags & EF_MIPS_MACH; - int old_mach = old_flags & EF_MIPS_MACH; - int new_isa = elf_mips_isa (new_flags); - int old_isa = elf_mips_isa (old_flags); - - /* If either has no machine specified, just compare the general isa's. - Some combinations of machines are ok, if the isa's match. */ - if (new_mach == old_mach - || _bfd_mips_elf_mach_extends_p (new_mach, old_mach) - || _bfd_mips_elf_mach_extends_p (old_mach, new_mach)) + (*_bfd_error_handler) + (_("%s: linking 32-bit code with 64-bit code"), + bfd_archive_filename (ibfd)); + ok = FALSE; + } + else if (!mips_mach_extends_p (bfd_get_mach (ibfd), bfd_get_mach (obfd))) + { + /* OBFD's ISA isn't the same as, or an extension of, IBFD's. */ + if (mips_mach_extends_p (bfd_get_mach (obfd), bfd_get_mach (ibfd))) { - /* Don't warn about mixing code using 32-bit ISAs, or mixing code - using 64-bit ISAs. They will normally use the same data sizes - and calling conventions. */ + /* Copy the architecture info from IBFD to OBFD. Also copy + the 32-bit flag (if set) so that we continue to recognise + OBFD as a 32-bit binary. */ + bfd_set_arch_info (obfd, bfd_get_arch_info (ibfd)); + elf_elfheader (obfd)->e_flags &= ~(EF_MIPS_ARCH | EF_MIPS_MACH); + elf_elfheader (obfd)->e_flags + |= new_flags & (EF_MIPS_ARCH | EF_MIPS_MACH | EF_MIPS_32BITMODE); - if (( (new_isa == 1 || new_isa == 2 || new_isa == 32 - || new_isa == 33) - ^ (old_isa == 1 || old_isa == 2 || old_isa == 32 - || old_isa == 33)) != 0) - { - (*_bfd_error_handler) - (_("%s: ISA mismatch (-mips%d) with previous modules (-mips%d)"), - bfd_archive_filename (ibfd), new_isa, old_isa); - ok = FALSE; - } - else - { - /* Do we need to update the mach field? */ - if (_bfd_mips_elf_mach_extends_p (old_mach, new_mach)) - { - elf_elfheader (obfd)->e_flags &= ~EF_MIPS_MACH; - elf_elfheader (obfd)->e_flags |= new_mach; - } - - /* Do we need to update the ISA field? */ - if (new_isa > old_isa) - { - elf_elfheader (obfd)->e_flags &= ~EF_MIPS_ARCH; - elf_elfheader (obfd)->e_flags - |= new_flags & EF_MIPS_ARCH; - } - } + /* Copy across the ABI flags if OBFD doesn't use them + and if that was what caused us to treat IBFD as 32-bit. */ + if ((old_flags & EF_MIPS_ABI) == 0 + && mips_32bit_flags_p (new_flags) + && !mips_32bit_flags_p (new_flags & ~EF_MIPS_ABI)) + elf_elfheader (obfd)->e_flags |= new_flags & EF_MIPS_ABI; } else { + /* The ISAs aren't compatible. */ (*_bfd_error_handler) - (_("%s: ISA mismatch (%d) with previous modules (%d)"), + (_("%s: linking %s module with previous %s modules"), bfd_archive_filename (ibfd), - _bfd_elf_mips_mach (new_flags), - _bfd_elf_mips_mach (old_flags)); + bfd_printable_name (ibfd), + bfd_printable_name (obfd)); ok = FALSE; } - - new_flags &= ~(EF_MIPS_ARCH | EF_MIPS_MACH); - old_flags &= ~(EF_MIPS_ARCH | EF_MIPS_MACH); } - /* Compare ABI's. The 64-bit ABI does not use EF_MIPS_ABI. But, it + new_flags &= ~(EF_MIPS_ARCH | EF_MIPS_MACH | EF_MIPS_32BITMODE); + old_flags &= ~(EF_MIPS_ARCH | EF_MIPS_MACH | EF_MIPS_32BITMODE); + + /* Compare ABIs. The 64-bit ABI does not use EF_MIPS_ABI. But, it does set EI_CLASS differently from any 32-bit ABI. */ if ((new_flags & EF_MIPS_ABI) != (old_flags & EF_MIPS_ABI) || (elf_elfheader (ibfd)->e_ident[EI_CLASS] diff --git a/ld/testsuite/ChangeLog b/ld/testsuite/ChangeLog index a09864f378..7bdb16be8f 100644 --- a/ld/testsuite/ChangeLog +++ b/ld/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2003-01-02 Richard Sandiford + + * ld-mips-elf/jr.s: New file. + * ld-mips-elf/mips-elf-flags.exp: New test. + 2002-12-18 Ralf Habacker * ld-auto-import: New directory. diff --git a/ld/testsuite/ld-mips-elf/jr.s b/ld/testsuite/ld-mips-elf/jr.s new file mode 100644 index 0000000000..df487d8755 --- /dev/null +++ b/ld/testsuite/ld-mips-elf/jr.s @@ -0,0 +1 @@ + jr $31 diff --git a/ld/testsuite/ld-mips-elf/mips-elf-flags.exp b/ld/testsuite/ld-mips-elf/mips-elf-flags.exp new file mode 100644 index 0000000000..30f1b497d4 --- /dev/null +++ b/ld/testsuite/ld-mips-elf/mips-elf-flags.exp @@ -0,0 +1,146 @@ +# Copyright 2003 Free Software Foundation, Inc. +# +# This file is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +if {![istarget mips*-*-*] || ![is_elf_format]} { + return +} + +# Assemble jr.s using each of the argument lists in ARGLIST. Return the +# list of object files on success and an empty list on failure. +proc assemble_for_flags {arglist} { + global as srcdir subdir + + set objs {} + set index 1 + + foreach args $arglist { + set obj "tmpdir/mips-flags-${index}.o" + if {![ld_assemble $as "$args $srcdir/$subdir/jr.s" $obj]} { + return "" + } + lappend objs $obj + incr index + } + return $objs +} + +# Assemble a file using each set of arguments in ARGLIST. Check that +# the objects can be linked together and that the readelf output +# includes each flag named in FLAGS. +proc good_combination {arglist flags} { + global ld READELF + + set finalobj "tmpdir/mips-flags.o" + set testname "MIPS compatible objects: $arglist" + set objs [assemble_for_flags $arglist] + + if {$objs == ""} { + unresolved $testname + } elseif {![ld_simple_link $ld $finalobj "-r $objs"]} { + fail $testname + } else { + catch "exec $READELF --headers $finalobj" output + if {![regexp "Flags: *(\[^\n\]*)" $output full gotflags]} { + unresolved $testname + } else { + set failed 0 + + # GOTFLAGS is a list of flags separated by ", ". + # Convert it to a tcl list. + regsub -all ", " $gotflags "," gotflags + set gotflags [split $gotflags ","] + + foreach flag $flags { + if {[lsearch -exact $gotflags $flag] < 0} { + set failed 1 + } + } + if {$failed} { + fail $testname + } else { + pass $testname + } + } + } +} + +# Like good_combination, but check that the objects can't be linked +# together successfully and that the output includes MESSAGE. +proc bad_combination {arglist message} { + global link_output ld + + set finalobj "tmpdir/mips-flags.o" + set testname "MIPS incompatible objects: $arglist" + set objs [assemble_for_flags $arglist] + + if {$objs == ""} { + unresolved $testname + } elseif {[ld_simple_link $ld $finalobj "-r $objs"] + || [string first $message $link_output] < 0} { + fail $testname + } else { + pass $testname + } +} + +# Routines to check for various kinds of incompatibility. + +proc abi_conflict {arglist firstabi secondabi} { + bad_combination $arglist \ + "linking $secondabi module with previous $firstabi modules" +} + +proc isa_conflict {arglist firstisa secondisa} { + bad_combination $arglist \ + "linking mips:$secondisa module with previous mips:$firstisa modules" +} + +proc regsize_conflict {arglist} { + bad_combination $arglist \ + "linking 32-bit code with 64-bit code" +} + +abi_conflict { "-mabi=eabi -mgp32" "-mips4 -mabi=32" } EABI32 O32 +abi_conflict { "-mips4 -mabi=o64" "-mips3 -mabi=eabi" } O64 EABI64 + +isa_conflict { "-march=vr5500" "-march=sb1" } 5500 sb1 +isa_conflict { "-march=vr5400" "-march=4120" } 5400 4120 +isa_conflict { "-march=r3900" "-march=r6000" } 3900 6000 +isa_conflict { "-march=r4010" "-march=r4650" } 4010 4650 +isa_conflict { "-mips3 -mgp32" "-mips32" } 4000 isa32 +isa_conflict { "-march=sb1 -mgp32" "-mips32r2" } sb1 isa32r2 + +regsize_conflict { "-mips4 -mgp64" "-mips2" } +regsize_conflict { "-mips4 -mabi=o64" "-mips4 -mabi=32" } +regsize_conflict { "-mabi=eabi -mgp32" "-mabi=eabi -mgp64" } +regsize_conflict { "-march=vr5000 -mgp64" "-march=vr5000 -mgp32" } +regsize_conflict { "-mips32" "-mips64" } +regsize_conflict { "-mips32r2" "-mips64" } + +good_combination { "-mips4 -mgp32" "-mips2" } { mips4 32bitmode } +good_combination { "-mips4 -mabi=32" "-mips2" } { mips4 o32 } +good_combination { "-mips2" "-mips4 -mabi=32" } { mips4 o32 } +good_combination { "-mips2" "-mips4 -mabi=eabi -mgp32" } { mips4 eabi32 } +good_combination { "-mips2" "-mips32" "-mips32r2" } { mips32r2 } +good_combination { "-mips1" "-mips32r2" "-mips32" } { mips32r2 } + +good_combination { "-march=vr4100" "-march=vr4120" } { 4120 } +good_combination { "-march=vr5400" "-march=vr5500" "-mips4" } { 5500 } +good_combination { "-mips3" "-mips4" "-march=sb1" "-mips5" } { sb1 } +good_combination { "-mips1" "-march=3900" } { 3900 } + +good_combination { "-march=vr4120 -mabi=32" "-mips3 -mabi=32" } { 4120 o32 } +good_combination { "-march=sb1 -mgp32" "-march=4000 -mgp32" } { sb1 32bitmode }