This is the mail archive of the
binutils@sources.redhat.com
mailing list for the binutils project.
Patch to EF_MIPS_ARCH and EF_MIPS_MACH handling
- From: Richard Sandiford <rsandifo at redhat dot com>
- To: binutils at sources dot redhat dot com
- Date: 07 Dec 2002 11:55:51 +0000
- Subject: Patch to EF_MIPS_ARCH and EF_MIPS_MACH handling
This patch is basically the same as:
http://sources.redhat.com/ml/binutils/2002-12/msg00078.html
but with one of the error messages changed slightly to be more
consistent with the rest. The patch includes a test case for
various good and bad combinations.
To recap, the idea is to merge bfds based on their bfd_mach
and update the check for 32-bit/64-bit collisions. The patch
allows o32 code for 64-bit targets to be linked with o32
code for 32-bit targets. Start of original thread:
http://sources.redhat.com/ml/binutils/2002-11/msg00073.html
Tested on mips64-elf, mips-elf and mipsel-linux-gnu, no regressions.
OK to install?
Richard
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.
Index: bfd/elfxx-mips.c
===================================================================
RCS file: /cvs/src/src/bfd/elfxx-mips.c,v
retrieving revision 1.33
diff -c -d -p -F^\([(a-zA-Z0-9_]\|#define\) -r1.33 elfxx-mips.c
*** bfd/elfxx-mips.c 30 Nov 2002 08:39:39 -0000 1.33
--- bfd/elfxx-mips.c 7 Dec 2002 11:08:19 -0000
*************** Foundation, Inc., 59 Temple Place - Suit
*** 30,35 ****
--- 30,36 ----
#include "bfd.h"
#include "sysdep.h"
#include "libbfd.h"
+ #include "libiberty.h"
#include "elf-bfd.h"
#include "elfxx-mips.h"
#include "elf/mips.h"
*************** static bfd_boolean mips_elf_create_dynam
*** 360,370 ****
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 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));
/* This will be used when we sort the dynamic relocation records. */
static bfd *reldyn_sorting_bfd;
--- 361,372 ----
PARAMS ((bfd *, struct bfd_link_info *, const Elf_Internal_Rela *,
struct mips_elf_link_hash_entry *, asection *,
bfd_vma, bfd_vma *, asection *));
! 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 mips_mach_extends_p PARAMS ((int, int));
! static bfd_boolean mips_32bit_flags_p PARAMS ((flagword));
/* This will be used when we sort the dynamic relocation records. */
static bfd *reldyn_sorting_bfd;
*************** mips_elf_create_dynamic_relocation (outp
*** 3050,3081 ****
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;
- }
- return 4;
- }
-
/* Return the MACH for a MIPS e_flags value. */
unsigned long
--- 3052,3057 ----
*************** _bfd_mips_elf_finish_dynamic_sections (o
*** 5921,5940 ****
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)
bfd *abfd;
- bfd_boolean linker ATTRIBUTE_UNUSED;
{
! unsigned long val;
! unsigned int i;
! Elf_Internal_Shdr **hdrpp;
! const char *name;
! asection *sec;
switch (bfd_get_mach (abfd))
{
--- 5897,5910 ----
return TRUE;
}
! /* Set ABFD's EF_MIPS_ARCH and EF_MIPS_MACH flags. */
!
! static void
! mips_set_isa_flags (abfd)
bfd *abfd;
{
! flagword val;
switch (bfd_get_mach (abfd))
{
*************** _bfd_mips_elf_final_write_processing (ab
*** 6007,6016 ****
case bfd_mach_mipsisa64:
val = E_MIPS_ARCH_64;
}
-
elf_elfheader (abfd)->e_flags &= ~(EF_MIPS_ARCH | EF_MIPS_MACH);
elf_elfheader (abfd)->e_flags |= val;
/* Set the sh_info field for .gptab sections and other appropriate
info for each special section. */
--- 5977,6008 ----
case bfd_mach_mipsisa64:
val = E_MIPS_ARCH_64;
+ 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. */
*************** _bfd_mips_elf_final_link (abfd, info)
*** 7680,7705 ****
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. */
static bfd_boolean
! _bfd_mips_elf_mach_extends_p (base, extension)
! flagword 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));
}
/* Merge backend specific data from an object file to the output
object file when linking. */
--- 7672,7758 ----
return TRUE;
}
! /* An array describing how bfd_machs relate to one another. It contains
! (X, Y) if X is an extension of Y. The entries are ordered topologically,
! with MIPS I coming last. */
!
! static const int mips_mach_extensions[][2] = {
! /* 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 },
!
! /* 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_mach EXTENSION is an extennsion of bfd_mach BASE. */
static bfd_boolean
! mips_mach_extends_p (base, extension)
! int base, extension;
{
! size_t i;
!
! for (i = 0; extension != base && i < ARRAY_SIZE (mips_mach_extensions); i++)
! if (extension == mips_mach_extensions[i][0])
! extension = mips_mach_extensions[i][1];
!
! 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);
}
+
/* Merge backend specific data from an object file to the output
object file when linking. */
*************** _bfd_mips_elf_merge_private_bfd_data (ib
*** 7795,7858 ****
ok = FALSE;
}
! /* Compare the ISA's. */
! if ((new_flags & (EF_MIPS_ARCH | EF_MIPS_MACH))
! != (old_flags & (EF_MIPS_ARCH | EF_MIPS_MACH)))
{
! 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))
{
! /* 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. */
!
! if (( (new_isa == 1 || new_isa == 2 || new_isa == 32)
! ^ (old_isa == 1 || old_isa == 2 || old_isa == 32)) != 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;
! }
! }
}
else
{
(*_bfd_error_handler)
! (_("%s: ISA mismatch (%d) with previous modules (%d)"),
bfd_archive_filename (ibfd),
! _bfd_elf_mips_mach (new_flags),
! _bfd_elf_mips_mach (old_flags));
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
does set EI_CLASS differently from any 32-bit ABI. */
--- 7848,7894 ----
ok = FALSE;
}
! if (mips_32bit_flags_p (old_flags) != mips_32bit_flags_p (new_flags))
{
! (*_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)))
{
! /* 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);
! /* 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: linking %s module with previous %s modules"),
bfd_archive_filename (ibfd),
! bfd_printable_name (ibfd),
! bfd_printable_name (obfd));
ok = FALSE;
}
}
+
+ new_flags &= ~(EF_MIPS_ARCH | EF_MIPS_MACH | EF_MIPS_32BITMODE);
+ old_flags &= ~(EF_MIPS_ARCH | EF_MIPS_MACH | EF_MIPS_32BITMODE);
/* Compare ABI's. The 64-bit ABI does not use EF_MIPS_ABI. But, it
does set EI_CLASS differently from any 32-bit ABI. */
*** /dev/null Thu Apr 11 15:25:15 2002
--- ld/testsuite/ld-mips-elf/jr.s Sat Dec 7 11:17:17 2002
***************
*** 0 ****
--- 1 ----
+ jr $31
*** /dev/null Thu Apr 11 15:25:15 2002
--- ld/testsuite/ld-mips-elf/mips-elf-flags.exp Sat Dec 7 11:14:45 2002
***************
*** 0 ****
--- 1,142 ----
+ # Copyright 2002 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
+
+ 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" }
+
+ 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 { "-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 }