/[gcl]/gcl/binutils/bfd/coff-mips.c
ViewVC logotype

Diff of /gcl/binutils/bfd/coff-mips.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 1.1.1.1 by camm, Fri Aug 9 05:34:51 2002 UTC revision 1.1.1.1.20.1 by camm, Fri Sep 30 02:08:54 2005 UTC
# Line 1  Line 1 
1  /* BFD back-end for MIPS Extended-Coff files.  /* BFD back-end for MIPS Extended-Coff files.
2     Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,     Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
3     2000, 2001, 2002     2000, 2001, 2002, 2003, 2004
4     Free Software Foundation, Inc.     Free Software Foundation, Inc.
5     Original version by Per Bothner.     Original version by Per Bothner.
6     Full support added by Ian Lance Taylor, ian@cygnus.com.     Full support added by Ian Lance Taylor, ian@cygnus.com.
# Line 35  Foundation, Inc., 59 Temple Place - Suit Line 35  Foundation, Inc., 59 Temple Place - Suit
35    
36  /* Prototypes for static functions.  */  /* Prototypes for static functions.  */
37    
38  static boolean mips_ecoff_bad_format_hook PARAMS ((bfd *abfd, PTR filehdr));  static bfd_boolean mips_ecoff_bad_format_hook
39  static void mips_ecoff_swap_reloc_in PARAMS ((bfd *, PTR,    PARAMS ((bfd *abfd, PTR filehdr));
40                                                struct internal_reloc *));  static void mips_ecoff_swap_reloc_in
41  static void mips_ecoff_swap_reloc_out PARAMS ((bfd *,    PARAMS ((bfd *, PTR, struct internal_reloc *));
42                                                 const struct internal_reloc *,  static void mips_ecoff_swap_reloc_out
43                                                 PTR));    PARAMS ((bfd *, const struct internal_reloc *, PTR));
44  static void mips_adjust_reloc_in PARAMS ((bfd *,  static void mips_adjust_reloc_in
45                                            const struct internal_reloc *,    PARAMS ((bfd *, const struct internal_reloc *, arelent *));
46                                            arelent *));  static void mips_adjust_reloc_out
47  static void mips_adjust_reloc_out PARAMS ((bfd *, const arelent *,    PARAMS ((bfd *, const arelent *, struct internal_reloc *));
48                                             struct internal_reloc *));  static bfd_reloc_status_type mips_generic_reloc
49  static bfd_reloc_status_type mips_generic_reloc PARAMS ((bfd *abfd,    PARAMS ((bfd *abfd, arelent *reloc, asymbol *symbol, PTR data,
50                                                           arelent *reloc,             asection *section, bfd *output_bfd, char **error));
51                                                           asymbol *symbol,  static bfd_reloc_status_type mips_refhi_reloc
52                                                           PTR data,    PARAMS ((bfd *abfd, arelent *reloc, asymbol *symbol, PTR data,
53                                                           asection *section,             asection *section, bfd *output_bfd, char **error));
54                                                           bfd *output_bfd,  static bfd_reloc_status_type mips_reflo_reloc
55                                                           char **error));    PARAMS ((bfd *abfd, arelent *reloc, asymbol *symbol, PTR data,
56  static bfd_reloc_status_type mips_refhi_reloc PARAMS ((bfd *abfd,             asection *section, bfd *output_bfd, char **error));
57                                                         arelent *reloc,  static bfd_reloc_status_type mips_gprel_reloc
58                                                         asymbol *symbol,    PARAMS ((bfd *abfd, arelent *reloc, asymbol *symbol, PTR data,
59                                                         PTR data,             asection *section, bfd *output_bfd, char **error));
60                                                         asection *section,  static void mips_relocate_hi
61                                                         bfd *output_bfd,    PARAMS ((struct internal_reloc *refhi, struct internal_reloc *reflo,
62                                                         char **error));             bfd *input_bfd, asection *input_section, bfd_byte *contents,
63  static bfd_reloc_status_type mips_reflo_reloc PARAMS ((bfd *abfd,             bfd_vma relocation));
64                                                         arelent *reloc,  static bfd_boolean mips_relocate_section
65                                                         asymbol *symbol,    PARAMS ((bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *, PTR));
                                                        PTR data,  
                                                        asection *section,  
                                                        bfd *output_bfd,  
                                                        char **error));  
 static bfd_reloc_status_type mips_gprel_reloc PARAMS ((bfd *abfd,  
                                                        arelent *reloc,  
                                                        asymbol *symbol,  
                                                        PTR data,  
                                                        asection *section,  
                                                        bfd *output_bfd,  
                                                        char **error));  
 static bfd_reloc_status_type mips_relhi_reloc PARAMS ((bfd *abfd,  
                                                        arelent *reloc,  
                                                        asymbol *symbol,  
                                                        PTR data,  
                                                        asection *section,  
                                                        bfd *output_bfd,  
                                                        char **error));  
 static bfd_reloc_status_type mips_rello_reloc PARAMS ((bfd *abfd,  
                                                        arelent *reloc,  
                                                        asymbol *symbol,  
                                                        PTR data,  
                                                        asection *section,  
                                                        bfd *output_bfd,  
                                                        char **error));  
 static bfd_reloc_status_type mips_switch_reloc PARAMS ((bfd *abfd,  
                                                         arelent *reloc,  
                                                         asymbol *symbol,  
                                                         PTR data,  
                                                         asection *section,  
                                                         bfd *output_bfd,  
                                                         char **error));  
 static void mips_relocate_hi PARAMS ((struct internal_reloc *refhi,  
                                       struct internal_reloc *reflo,  
                                       bfd *input_bfd,  
                                       asection *input_section,  
                                       bfd_byte *contents,  
                                       size_t adjust,  
                                       bfd_vma relocation,  
                                       boolean pcrel));  
 static boolean mips_relocate_section PARAMS ((bfd *, struct bfd_link_info *,  
                                               bfd *, asection *,  
                                               bfd_byte *, PTR));  
 static boolean mips_read_relocs PARAMS ((bfd *, asection *));  
 static boolean mips_relax_section PARAMS ((bfd *, asection *,  
                                            struct bfd_link_info *,  
                                            boolean *));  
 static boolean mips_relax_pcrel16 PARAMS ((struct bfd_link_info *, bfd *,  
                                            asection *,  
                                            struct ecoff_link_hash_entry *,  
                                            bfd_byte *, bfd_vma));  
66  static reloc_howto_type *mips_bfd_reloc_type_lookup  static reloc_howto_type *mips_bfd_reloc_type_lookup
67    PARAMS ((bfd *, bfd_reloc_code_real_type));    PARAMS ((bfd *, bfd_reloc_code_real_type));
68    
# Line 152  static reloc_howto_type mips_howto_table Line 101  static reloc_howto_type mips_howto_table
101           0,                     /* rightshift */           0,                     /* rightshift */
102           0,                     /* size (0 = byte, 1 = short, 2 = long) */           0,                     /* size (0 = byte, 1 = short, 2 = long) */
103           8,                     /* bitsize */           8,                     /* bitsize */
104           false,                 /* pc_relative */           FALSE,                 /* pc_relative */
105           0,                     /* bitpos */           0,                     /* bitpos */
106           complain_overflow_dont, /* complain_on_overflow */           complain_overflow_dont, /* complain_on_overflow */
107           0,                     /* special_function */           0,                     /* special_function */
108           "IGNORE",              /* name */           "IGNORE",              /* name */
109           false,                 /* partial_inplace */           FALSE,                 /* partial_inplace */
110           0,                     /* src_mask */           0,                     /* src_mask */
111           0,                     /* dst_mask */           0,                     /* dst_mask */
112           false),                /* pcrel_offset */           FALSE),                /* pcrel_offset */
113    
114    /* A 16 bit reference to a symbol, normally from a data section.  */    /* A 16 bit reference to a symbol, normally from a data section.  */
115    HOWTO (MIPS_R_REFHALF,        /* type */    HOWTO (MIPS_R_REFHALF,        /* type */
116           0,                     /* rightshift */           0,                     /* rightshift */
117           1,                     /* size (0 = byte, 1 = short, 2 = long) */           1,                     /* size (0 = byte, 1 = short, 2 = long) */
118           16,                    /* bitsize */           16,                    /* bitsize */
119           false,                 /* pc_relative */           FALSE,                 /* pc_relative */
120           0,                     /* bitpos */           0,                     /* bitpos */
121           complain_overflow_bitfield, /* complain_on_overflow */           complain_overflow_bitfield, /* complain_on_overflow */
122           mips_generic_reloc,    /* special_function */           mips_generic_reloc,    /* special_function */
123           "REFHALF",             /* name */           "REFHALF",             /* name */
124           true,                  /* partial_inplace */           TRUE,                  /* partial_inplace */
125           0xffff,                /* src_mask */           0xffff,                /* src_mask */
126           0xffff,                /* dst_mask */           0xffff,                /* dst_mask */
127           false),                /* pcrel_offset */           FALSE),                /* pcrel_offset */
128    
129    /* A 32 bit reference to a symbol, normally from a data section.  */    /* A 32 bit reference to a symbol, normally from a data section.  */
130    HOWTO (MIPS_R_REFWORD,        /* type */    HOWTO (MIPS_R_REFWORD,        /* type */
131           0,                     /* rightshift */           0,                     /* rightshift */
132           2,                     /* size (0 = byte, 1 = short, 2 = long) */           2,                     /* size (0 = byte, 1 = short, 2 = long) */
133           32,                    /* bitsize */           32,                    /* bitsize */
134           false,                 /* pc_relative */           FALSE,                 /* pc_relative */
135           0,                     /* bitpos */           0,                     /* bitpos */
136           complain_overflow_bitfield, /* complain_on_overflow */           complain_overflow_bitfield, /* complain_on_overflow */
137           mips_generic_reloc,    /* special_function */           mips_generic_reloc,    /* special_function */
138           "REFWORD",             /* name */           "REFWORD",             /* name */
139           true,                  /* partial_inplace */           TRUE,                  /* partial_inplace */
140           0xffffffff,            /* src_mask */           0xffffffff,            /* src_mask */
141           0xffffffff,            /* dst_mask */           0xffffffff,            /* dst_mask */
142           false),                /* pcrel_offset */           FALSE),                /* pcrel_offset */
143    
144    /* A 26 bit absolute jump address.  */    /* A 26 bit absolute jump address.  */
145    HOWTO (MIPS_R_JMPADDR,        /* type */    HOWTO (MIPS_R_JMPADDR,        /* type */
146           2,                     /* rightshift */           2,                     /* rightshift */
147           2,                     /* size (0 = byte, 1 = short, 2 = long) */           2,                     /* size (0 = byte, 1 = short, 2 = long) */
148           26,                    /* bitsize */           26,                    /* bitsize */
149           false,                 /* pc_relative */           FALSE,                 /* pc_relative */
150           0,                     /* bitpos */           0,                     /* bitpos */
151           complain_overflow_dont, /* complain_on_overflow */           complain_overflow_dont, /* complain_on_overflow */
152                                  /* This needs complex overflow                                  /* This needs complex overflow
# Line 205  static reloc_howto_type mips_howto_table Line 154  static reloc_howto_type mips_howto_table
154                                     bits must match the PC.  */                                     bits must match the PC.  */
155           mips_generic_reloc,    /* special_function */           mips_generic_reloc,    /* special_function */
156           "JMPADDR",             /* name */           "JMPADDR",             /* name */
157           true,                  /* partial_inplace */           TRUE,                  /* partial_inplace */
158           0x3ffffff,             /* src_mask */           0x3ffffff,             /* src_mask */
159           0x3ffffff,             /* dst_mask */           0x3ffffff,             /* dst_mask */
160           false),                /* pcrel_offset */           FALSE),                /* pcrel_offset */
161    
162    /* The high 16 bits of a symbol value.  Handled by the function    /* The high 16 bits of a symbol value.  Handled by the function
163       mips_refhi_reloc.  */       mips_refhi_reloc.  */
# Line 216  static reloc_howto_type mips_howto_table Line 165  static reloc_howto_type mips_howto_table
165           16,                    /* rightshift */           16,                    /* rightshift */
166           2,                     /* size (0 = byte, 1 = short, 2 = long) */           2,                     /* size (0 = byte, 1 = short, 2 = long) */
167           16,                    /* bitsize */           16,                    /* bitsize */
168           false,                 /* pc_relative */           FALSE,                 /* pc_relative */
169           0,                     /* bitpos */           0,                     /* bitpos */
170           complain_overflow_bitfield, /* complain_on_overflow */           complain_overflow_bitfield, /* complain_on_overflow */
171           mips_refhi_reloc,      /* special_function */           mips_refhi_reloc,      /* special_function */
172           "REFHI",               /* name */           "REFHI",               /* name */
173           true,                  /* partial_inplace */           TRUE,                  /* partial_inplace */
174           0xffff,                /* src_mask */           0xffff,                /* src_mask */
175           0xffff,                /* dst_mask */           0xffff,                /* dst_mask */
176           false),                /* pcrel_offset */           FALSE),                /* pcrel_offset */
177    
178    /* The low 16 bits of a symbol value.  */    /* The low 16 bits of a symbol value.  */
179    HOWTO (MIPS_R_REFLO,          /* type */    HOWTO (MIPS_R_REFLO,          /* type */
180           0,                     /* rightshift */           0,                     /* rightshift */
181           2,                     /* size (0 = byte, 1 = short, 2 = long) */           2,                     /* size (0 = byte, 1 = short, 2 = long) */
182           16,                    /* bitsize */           16,                    /* bitsize */
183           false,                 /* pc_relative */           FALSE,                 /* pc_relative */
184           0,                     /* bitpos */           0,                     /* bitpos */
185           complain_overflow_dont, /* complain_on_overflow */           complain_overflow_dont, /* complain_on_overflow */
186           mips_reflo_reloc,      /* special_function */           mips_reflo_reloc,      /* special_function */
187           "REFLO",               /* name */           "REFLO",               /* name */
188           true,                  /* partial_inplace */           TRUE,                  /* partial_inplace */
189           0xffff,                /* src_mask */           0xffff,                /* src_mask */
190           0xffff,                /* dst_mask */           0xffff,                /* dst_mask */
191           false),                /* pcrel_offset */           FALSE),                /* pcrel_offset */
192    
193    /* A reference to an offset from the gp register.  Handled by the    /* A reference to an offset from the gp register.  Handled by the
194       function mips_gprel_reloc.  */       function mips_gprel_reloc.  */
# Line 247  static reloc_howto_type mips_howto_table Line 196  static reloc_howto_type mips_howto_table
196           0,                     /* rightshift */           0,                     /* rightshift */
197           2,                     /* size (0 = byte, 1 = short, 2 = long) */           2,                     /* size (0 = byte, 1 = short, 2 = long) */
198           16,                    /* bitsize */           16,                    /* bitsize */
199           false,                 /* pc_relative */           FALSE,                 /* pc_relative */
200           0,                     /* bitpos */           0,                     /* bitpos */
201           complain_overflow_signed, /* complain_on_overflow */           complain_overflow_signed, /* complain_on_overflow */
202           mips_gprel_reloc,      /* special_function */           mips_gprel_reloc,      /* special_function */
203           "GPREL",               /* name */           "GPREL",               /* name */
204           true,                  /* partial_inplace */           TRUE,                  /* partial_inplace */
205           0xffff,                /* src_mask */           0xffff,                /* src_mask */
206           0xffff,                /* dst_mask */           0xffff,                /* dst_mask */
207           false),                /* pcrel_offset */           FALSE),                /* pcrel_offset */
208    
209    /* A reference to a literal using an offset from the gp register.    /* A reference to a literal using an offset from the gp register.
210       Handled by the function mips_gprel_reloc.  */       Handled by the function mips_gprel_reloc.  */
# Line 263  static reloc_howto_type mips_howto_table Line 212  static reloc_howto_type mips_howto_table
212           0,                     /* rightshift */           0,                     /* rightshift */
213           2,                     /* size (0 = byte, 1 = short, 2 = long) */           2,                     /* size (0 = byte, 1 = short, 2 = long) */
214           16,                    /* bitsize */           16,                    /* bitsize */
215           false,                 /* pc_relative */           FALSE,                 /* pc_relative */
216           0,                     /* bitpos */           0,                     /* bitpos */
217           complain_overflow_signed, /* complain_on_overflow */           complain_overflow_signed, /* complain_on_overflow */
218           mips_gprel_reloc,      /* special_function */           mips_gprel_reloc,      /* special_function */
219           "LITERAL",             /* name */           "LITERAL",             /* name */
220           true,                  /* partial_inplace */           TRUE,                  /* partial_inplace */
221           0xffff,                /* src_mask */           0xffff,                /* src_mask */
222           0xffff,                /* dst_mask */           0xffff,                /* dst_mask */
223           false),                /* pcrel_offset */           FALSE),                /* pcrel_offset */
224    
225    EMPTY_HOWTO (8),    EMPTY_HOWTO (8),
226    EMPTY_HOWTO (9),    EMPTY_HOWTO (9),
227    EMPTY_HOWTO (10),    EMPTY_HOWTO (10),
228    EMPTY_HOWTO (11),    EMPTY_HOWTO (11),
229    
230    /* This reloc is a Cygnus extension used when generating position    /* FIXME: This relocation is used (internally only) to represent branches
231       independent code for embedded systems.  It represents a 16 bit PC       when assembling.  It should never appear in output files, and
232       relative reloc rightshifted twice as used in the MIPS branch       be removed.  (It used to be used for embedded-PIC support.)  */
      instructions.  */  
233    HOWTO (MIPS_R_PCREL16,        /* type */    HOWTO (MIPS_R_PCREL16,        /* type */
234           2,                     /* rightshift */           2,                     /* rightshift */
235           2,                     /* size (0 = byte, 1 = short, 2 = long) */           2,                     /* size (0 = byte, 1 = short, 2 = long) */
236           16,                    /* bitsize */           16,                    /* bitsize */
237           true,                  /* pc_relative */           TRUE,                  /* pc_relative */
238           0,                     /* bitpos */           0,                     /* bitpos */
239           complain_overflow_signed, /* complain_on_overflow */           complain_overflow_signed, /* complain_on_overflow */
240           mips_generic_reloc,    /* special_function */           mips_generic_reloc,    /* special_function */
241           "PCREL16",             /* name */           "PCREL16",             /* name */
242           true,                  /* partial_inplace */           TRUE,                  /* partial_inplace */
243           0xffff,                /* src_mask */           0xffff,                /* src_mask */
244           0xffff,                /* dst_mask */           0xffff,                /* dst_mask */
245           true),                 /* pcrel_offset */           TRUE),                 /* pcrel_offset */
   
   /* This reloc is a Cygnus extension used when generating position  
      independent code for embedded systems.  It represents the high 16  
      bits of a PC relative reloc.  The next reloc must be  
      MIPS_R_RELLO, and the addend is formed from the addends of the  
      two instructions, just as in MIPS_R_REFHI and MIPS_R_REFLO.  The  
      final value is actually PC relative to the location of the  
      MIPS_R_RELLO reloc, not the MIPS_R_RELHI reloc.  */  
   HOWTO (MIPS_R_RELHI,          /* type */  
          16,                    /* rightshift */  
          2,                     /* size (0 = byte, 1 = short, 2 = long) */  
          16,                    /* bitsize */  
          true,                  /* pc_relative */  
          0,                     /* bitpos */  
          complain_overflow_bitfield, /* complain_on_overflow */  
          mips_relhi_reloc,      /* special_function */  
          "RELHI",               /* name */  
          true,                  /* partial_inplace */  
          0xffff,                /* src_mask */  
          0xffff,                /* dst_mask */  
          true),                 /* pcrel_offset */  
   
   /* This reloc is a Cygnus extension used when generating position  
      independent code for embedded systems.  It represents the low 16  
      bits of a PC relative reloc.  */  
   HOWTO (MIPS_R_RELLO,          /* type */  
          0,                     /* rightshift */  
          2,                     /* size (0 = byte, 1 = short, 2 = long) */  
          16,                    /* bitsize */  
          true,                  /* pc_relative */  
          0,                     /* bitpos */  
          complain_overflow_dont, /* complain_on_overflow */  
          mips_rello_reloc,      /* special_function */  
          "RELLO",               /* name */  
          true,                  /* partial_inplace */  
          0xffff,                /* src_mask */  
          0xffff,                /* dst_mask */  
          true),                 /* pcrel_offset */  
   
   EMPTY_HOWTO (15),  
   EMPTY_HOWTO (16),  
   EMPTY_HOWTO (17),  
   EMPTY_HOWTO (18),  
   EMPTY_HOWTO (19),  
   EMPTY_HOWTO (20),  
   EMPTY_HOWTO (21),  
   
   /* This reloc is a Cygnus extension used when generating position  
      independent code for embedded systems.  It represents an entry in  
      a switch table, which is the difference between two symbols in  
      the .text section.  The symndx is actually the offset from the  
      reloc address to the subtrahend.  See include/coff/mips.h for  
      more details.  */  
   HOWTO (MIPS_R_SWITCH,         /* type */  
          0,                     /* rightshift */  
          2,                     /* size (0 = byte, 1 = short, 2 = long) */  
          32,                    /* bitsize */  
          true,                  /* pc_relative */  
          0,                     /* bitpos */  
          complain_overflow_dont, /* complain_on_overflow */  
          mips_switch_reloc,     /* special_function */  
          "SWITCH",              /* name */  
          true,                  /* partial_inplace */  
          0xffffffff,            /* src_mask */  
          0xffffffff,            /* dst_mask */  
          true)                  /* pcrel_offset */  
246  };  };
247    
248  #define MIPS_HOWTO_COUNT \  #define MIPS_HOWTO_COUNT \
249    (sizeof mips_howto_table / sizeof mips_howto_table[0])    (sizeof mips_howto_table / sizeof mips_howto_table[0])
   
 /* When the linker is doing relaxing, it may change an external PCREL16  
    reloc.  This typically represents an instruction like  
        bal foo  
    We change it to  
        .set  noreorder  
        bal   $L1  
        lui   $at,%hi(foo - $L1)  
      $L1:  
        addiu $at,%lo(foo - $L1)  
        addu  $at,$at,$31  
        jalr  $at  
    PCREL16_EXPANSION_ADJUSTMENT is the number of bytes this changes the  
    instruction by.  */  
   
 #define PCREL16_EXPANSION_ADJUSTMENT (4 * 4)  
250    
251  /* See whether the magic number matches.  */  /* See whether the magic number matches.  */
252    
253  static boolean  static bfd_boolean
254  mips_ecoff_bad_format_hook (abfd, filehdr)  mips_ecoff_bad_format_hook (abfd, filehdr)
255       bfd *abfd;       bfd *abfd;
256       PTR filehdr;       PTR filehdr;
# Line 395  mips_ecoff_bad_format_hook (abfd, filehd Line 261  mips_ecoff_bad_format_hook (abfd, filehd
261      {      {
262      case MIPS_MAGIC_1:      case MIPS_MAGIC_1:
263        /* I don't know what endianness this implies.  */        /* I don't know what endianness this implies.  */
264        return true;        return TRUE;
265    
266      case MIPS_MAGIC_BIG:      case MIPS_MAGIC_BIG:
267      case MIPS_MAGIC_BIG2:      case MIPS_MAGIC_BIG2:
# Line 408  mips_ecoff_bad_format_hook (abfd, filehd Line 274  mips_ecoff_bad_format_hook (abfd, filehd
274        return bfd_little_endian (abfd);        return bfd_little_endian (abfd);
275    
276      default:      default:
277        return false;        return FALSE;
278      }      }
279  }  }
280    
# Line 453  mips_ecoff_swap_reloc_in (abfd, ext_ptr, Line 319  mips_ecoff_swap_reloc_in (abfd, ext_ptr,
319                             << RELOC_BITS3_TYPEHI_SH_LITTLE));                             << RELOC_BITS3_TYPEHI_SH_LITTLE));
320        intern->r_extern = (ext->r_bits[3] & RELOC_BITS3_EXTERN_LITTLE) != 0;        intern->r_extern = (ext->r_bits[3] & RELOC_BITS3_EXTERN_LITTLE) != 0;
321      }      }
   
   /* If this is a MIPS_R_SWITCH reloc, or an internal MIPS_R_RELHI or  
      MIPS_R_RELLO reloc, r_symndx is actually the offset from the  
      reloc address to the base of the difference (see  
      include/coff/mips.h for more details).  We copy symndx into the  
      r_offset field so as not to confuse ecoff_slurp_reloc_table in  
      ecoff.c.  In adjust_reloc_in we then copy r_offset into the reloc  
      addend.  */  
   if (intern->r_type == MIPS_R_SWITCH  
       || (! intern->r_extern  
           && (intern->r_type == MIPS_R_RELLO  
               || intern->r_type == MIPS_R_RELHI)))  
     {  
       BFD_ASSERT (! intern->r_extern);  
       intern->r_offset = intern->r_symndx;  
       if (intern->r_offset & 0x800000)  
         intern->r_offset -= 0x1000000;  
       intern->r_symndx = RELOC_SECTION_TEXT;  
     }  
322  }  }
323    
324  /* Swap a reloc out.  */  /* Swap a reloc out.  */
# Line 488  mips_ecoff_swap_reloc_out (abfd, intern, Line 335  mips_ecoff_swap_reloc_out (abfd, intern,
335    BFD_ASSERT (intern->r_extern    BFD_ASSERT (intern->r_extern
336                || (intern->r_symndx >= 0 && intern->r_symndx <= 12));                || (intern->r_symndx >= 0 && intern->r_symndx <= 12));
337    
338    /* If this is a MIPS_R_SWITCH reloc, or an internal MIPS_R_RELLO or    r_symndx = intern->r_symndx;
      MIPS_R_RELHI reloc, we actually want to write the contents of  
      r_offset out as the symbol index.  This undoes the change made by  
      mips_ecoff_swap_reloc_in.  */  
   if (intern->r_type != MIPS_R_SWITCH  
       && (intern->r_extern  
           || (intern->r_type != MIPS_R_RELHI  
               && intern->r_type != MIPS_R_RELLO)))  
     r_symndx = intern->r_symndx;  
   else  
     {  
       BFD_ASSERT (intern->r_symndx == RELOC_SECTION_TEXT);  
       r_symndx = intern->r_offset & 0xffffff;  
     }  
339    
340    H_PUT_32 (abfd, intern->r_vaddr, ext->r_vaddr);    H_PUT_32 (abfd, intern->r_vaddr, ext->r_vaddr);
341    if (bfd_header_big_endian (abfd))    if (bfd_header_big_endian (abfd))
# Line 536  mips_adjust_reloc_in (abfd, intern, rptr Line 370  mips_adjust_reloc_in (abfd, intern, rptr
370       const struct internal_reloc *intern;       const struct internal_reloc *intern;
371       arelent *rptr;       arelent *rptr;
372  {  {
373    if (intern->r_type > MIPS_R_SWITCH)    if (intern->r_type > MIPS_R_PCREL16)
374      abort ();      abort ();
375    
376    if (! intern->r_extern    if (! intern->r_extern
# Line 549  mips_adjust_reloc_in (abfd, intern, rptr Line 383  mips_adjust_reloc_in (abfd, intern, rptr
383    if (intern->r_type == MIPS_R_IGNORE)    if (intern->r_type == MIPS_R_IGNORE)
384      rptr->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr;      rptr->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr;
385    
   /* If this is a MIPS_R_SWITCH reloc, or an internal MIPS_R_RELHI or  
      MIPS_R_RELLO reloc, we want the addend field of the BFD relocto  
      hold the value which was originally in the symndx field of the  
      internal MIPS ECOFF reloc.  This value was copied into  
      intern->r_offset by mips_swap_reloc_in, and here we copy it into  
      the addend field.  */  
   if (intern->r_type == MIPS_R_SWITCH  
       || (! intern->r_extern  
           && (intern->r_type == MIPS_R_RELHI  
               || intern->r_type == MIPS_R_RELLO)))  
     rptr->addend = intern->r_offset;  
   
386    rptr->howto = &mips_howto_table[intern->r_type];    rptr->howto = &mips_howto_table[intern->r_type];
387  }  }
388    
# Line 570  mips_adjust_reloc_in (abfd, intern, rptr Line 392  mips_adjust_reloc_in (abfd, intern, rptr
392  static void  static void
393  mips_adjust_reloc_out (abfd, rel, intern)  mips_adjust_reloc_out (abfd, rel, intern)
394       bfd *abfd ATTRIBUTE_UNUSED;       bfd *abfd ATTRIBUTE_UNUSED;
395       const arelent *rel;       const arelent *rel ATTRIBUTE_UNUSED;
396       struct internal_reloc *intern;       struct internal_reloc *intern ATTRIBUTE_UNUSED;
397  {  {
   /* For a MIPS_R_SWITCH reloc, or an internal MIPS_R_RELHI or  
      MIPS_R_RELLO reloc, we must copy rel->addend into  
      intern->r_offset.  This will then be written out as the symbol  
      index by mips_ecoff_swap_reloc_out.  This operation parallels the  
      action of mips_adjust_reloc_in.  */  
   if (intern->r_type == MIPS_R_SWITCH  
       || (! intern->r_extern  
           && (intern->r_type == MIPS_R_RELHI  
               || intern->r_type == MIPS_R_RELLO)))  
     intern->r_offset = rel->addend;  
398  }  }
399    
400  /* ECOFF relocs are either against external symbols, or against  /* ECOFF relocs are either against external symbols, or against
401     sections.  If we are producing relocateable output, and the reloc     sections.  If we are producing relocatable output, and the reloc
402     is against an external symbol, and nothing has given us any     is against an external symbol, and nothing has given us any
403     additional addend, the resulting reloc will also be against the     additional addend, the resulting reloc will also be against the
404     same symbol.  In such a case, we don't want to change anything     same symbol.  In such a case, we don't want to change anything
# Line 594  mips_adjust_reloc_out (abfd, rel, intern Line 406  mips_adjust_reloc_out (abfd, rel, intern
406     final link time.  Rather than put special case code into     final link time.  Rather than put special case code into
407     bfd_perform_relocation, all the reloc types use this howto     bfd_perform_relocation, all the reloc types use this howto
408     function.  It just short circuits the reloc if producing     function.  It just short circuits the reloc if producing
409     relocateable output against an external symbol.  */     relocatable output against an external symbol.  */
410    
411  static bfd_reloc_status_type  static bfd_reloc_status_type
412  mips_generic_reloc (abfd,  mips_generic_reloc (abfd,
# Line 687  mips_refhi_reloc (abfd, Line 499  mips_refhi_reloc (abfd,
499    relocation += symbol->section->output_offset;    relocation += symbol->section->output_offset;
500    relocation += reloc_entry->addend;    relocation += reloc_entry->addend;
501    
502    if (reloc_entry->address > input_section->_cooked_size)    if (reloc_entry->address > bfd_get_section_limit (abfd, input_section))
503      return bfd_reloc_outofrange;      return bfd_reloc_outofrange;
504    
505    /* Save the information, and let REFLO do the actual relocation.  */    /* Save the information, and let REFLO do the actual relocation.  */
# Line 793  mips_gprel_reloc (abfd, Line 605  mips_gprel_reloc (abfd,
605       bfd *output_bfd;       bfd *output_bfd;
606       char **error_message;       char **error_message;
607  {  {
608    boolean relocateable;    bfd_boolean relocatable;
609    bfd_vma gp;    bfd_vma gp;
610    bfd_vma relocation;    bfd_vma relocation;
611    unsigned long val;    unsigned long val;
# Line 812  mips_gprel_reloc (abfd, Line 624  mips_gprel_reloc (abfd,
624      }      }
625    
626    if (output_bfd != (bfd *) NULL)    if (output_bfd != (bfd *) NULL)
627      relocateable = true;      relocatable = TRUE;
628    else    else
629      {      {
630        relocateable = false;        relocatable = FALSE;
631        output_bfd = symbol->section->output_section->owner;        output_bfd = symbol->section->output_section->owner;
632      }      }
633    
634    if (bfd_is_und_section (symbol->section) && ! relocateable)    if (bfd_is_und_section (symbol->section) && ! relocatable)
635      return bfd_reloc_undefined;      return bfd_reloc_undefined;
636    
637    /* We have to figure out the gp value, so that we can adjust the    /* We have to figure out the gp value, so that we can adjust the
638       symbol value correctly.  We look up the symbol _gp in the output       symbol value correctly.  We look up the symbol _gp in the output
639       BFD.  If we can't find it, we're stuck.  We cache it in the ECOFF       BFD.  If we can't find it, we're stuck.  We cache it in the ECOFF
640       target data.  We don't need to adjust the symbol value for an       target data.  We don't need to adjust the symbol value for an
641       external symbol if we are producing relocateable output.  */       external symbol if we are producing relocatable output.  */
642    gp = _bfd_get_gp_value (output_bfd);    gp = _bfd_get_gp_value (output_bfd);
643    if (gp == 0    if (gp == 0
644        && (! relocateable        && (! relocatable
645            || (symbol->flags & BSF_SECTION_SYM) != 0))            || (symbol->flags & BSF_SECTION_SYM) != 0))
646      {      {
647        if (relocateable)        if (relocatable)
648          {          {
649            /* Make up a value.  */            /* Make up a value.  */
650            gp = symbol->section->output_section->vma + 0x4000;            gp = symbol->section->output_section->vma + 0x4000;
# Line 885  mips_gprel_reloc (abfd, Line 697  mips_gprel_reloc (abfd,
697    relocation += symbol->section->output_section->vma;    relocation += symbol->section->output_section->vma;
698    relocation += symbol->section->output_offset;    relocation += symbol->section->output_offset;
699    
700    if (reloc_entry->address > input_section->_cooked_size)    if (reloc_entry->address > bfd_get_section_limit (abfd, input_section))
701      return bfd_reloc_outofrange;      return bfd_reloc_outofrange;
702    
703    insn = bfd_get_32 (abfd, (bfd_byte *) data + reloc_entry->address);    insn = bfd_get_32 (abfd, (bfd_byte *) data + reloc_entry->address);
# Line 896  mips_gprel_reloc (abfd, Line 708  mips_gprel_reloc (abfd,
708      val -= 0x10000;      val -= 0x10000;
709    
710    /* Adjust val for the final section location and GP value.  If we    /* Adjust val for the final section location and GP value.  If we
711       are producing relocateable output, we don't want to do this for       are producing relocatable output, we don't want to do this for
712       an external symbol.  */       an external symbol.  */
713    if (! relocateable    if (! relocatable
714        || (symbol->flags & BSF_SECTION_SYM) != 0)        || (symbol->flags & BSF_SECTION_SYM) != 0)
715      val += relocation - gp;      val += relocation - gp;
716    
717    insn = (insn &~ (unsigned) 0xffff) | (val & 0xffff);    insn = (insn &~ (unsigned) 0xffff) | (val & 0xffff);
718    bfd_put_32 (abfd, (bfd_vma) insn, (bfd_byte *) data + reloc_entry->address);    bfd_put_32 (abfd, (bfd_vma) insn, (bfd_byte *) data + reloc_entry->address);
719    
720    if (relocateable)    if (relocatable)
721      reloc_entry->address += input_section->output_offset;      reloc_entry->address += input_section->output_offset;
722    
723    /* Make sure it fit in 16 bits.  */    /* Make sure it fit in 16 bits.  */
# Line 915  mips_gprel_reloc (abfd, Line 727  mips_gprel_reloc (abfd,
727    return bfd_reloc_ok;    return bfd_reloc_ok;
728  }  }
729    
 /* Do a RELHI relocation.  We do this in conjunction with a RELLO  
    reloc, just as REFHI and REFLO are done together.  RELHI and RELLO  
    are Cygnus extensions used when generating position independent  
    code for embedded systems.  */  
   
 /* FIXME: This should not be a static variable.  */  
   
 static struct mips_hi *mips_relhi_list;  
   
 static bfd_reloc_status_type  
 mips_relhi_reloc (abfd,  
                   reloc_entry,  
                   symbol,  
                   data,  
                   input_section,  
                   output_bfd,  
                   error_message)  
      bfd *abfd ATTRIBUTE_UNUSED;  
      arelent *reloc_entry;  
      asymbol *symbol;  
      PTR data;  
      asection *input_section;  
      bfd *output_bfd;  
      char **error_message ATTRIBUTE_UNUSED;  
 {  
   bfd_reloc_status_type ret;  
   bfd_vma relocation;  
   struct mips_hi *n;  
   
   /* If this is a reloc against a section symbol, then it is correct  
      in the object file.  The only time we want to change this case is  
      when we are relaxing, and that is handled entirely by  
      mips_relocate_section and never calls this function.  */  
   if ((symbol->flags & BSF_SECTION_SYM) != 0)  
     {  
       if (output_bfd != (bfd *) NULL)  
         reloc_entry->address += input_section->output_offset;  
       return bfd_reloc_ok;  
     }  
   
   /* This is an external symbol.  If we're relocating, we don't want  
      to change anything.  */  
   if (output_bfd != (bfd *) NULL)  
     {  
       reloc_entry->address += input_section->output_offset;  
       return bfd_reloc_ok;  
     }  
   
   ret = bfd_reloc_ok;  
   if (bfd_is_und_section (symbol->section)  
       && output_bfd == (bfd *) NULL)  
     ret = bfd_reloc_undefined;  
   
   if (bfd_is_com_section (symbol->section))  
     relocation = 0;  
   else  
     relocation = symbol->value;  
   
   relocation += symbol->section->output_section->vma;  
   relocation += symbol->section->output_offset;  
   relocation += reloc_entry->addend;  
   
   if (reloc_entry->address > input_section->_cooked_size)  
     return bfd_reloc_outofrange;  
   
   /* Save the information, and let RELLO do the actual relocation.  */  
   n = (struct mips_hi *) bfd_malloc ((bfd_size_type) sizeof *n);  
   if (n == NULL)  
     return bfd_reloc_outofrange;  
   n->addr = (bfd_byte *) data + reloc_entry->address;  
   n->addend = relocation;  
   n->next = mips_relhi_list;  
   mips_relhi_list = n;  
   
   if (output_bfd != (bfd *) NULL)  
     reloc_entry->address += input_section->output_offset;  
   
   return ret;  
 }  
   
 /* Do a RELLO relocation.  This is a straightforward 16 bit PC  
    relative relocation; this function exists in order to do the RELHI  
    relocation described above.  */  
   
 static bfd_reloc_status_type  
 mips_rello_reloc (abfd,  
                   reloc_entry,  
                   symbol,  
                   data,  
                   input_section,  
                   output_bfd,  
                   error_message)  
      bfd *abfd;  
      arelent *reloc_entry;  
      asymbol *symbol;  
      PTR data;  
      asection *input_section;  
      bfd *output_bfd;  
      char **error_message;  
 {  
   if (mips_relhi_list != NULL)  
     {  
       struct mips_hi *l;  
   
       l = mips_relhi_list;  
       while (l != NULL)  
         {  
           unsigned long insn;  
           unsigned long val;  
           unsigned long vallo;  
           struct mips_hi *next;  
   
           /* Do the RELHI relocation.  Note that we actually don't  
              need to know anything about the RELLO itself, except  
              where to find the low 16 bits of the addend needed by the  
              RELHI.  */  
           insn = bfd_get_32 (abfd, l->addr);  
           vallo = (bfd_get_32 (abfd, (bfd_byte *) data + reloc_entry->address)  
                    & 0xffff);  
           val = ((insn & 0xffff) << 16) + vallo;  
           val += l->addend;  
   
           /* If the symbol is defined, make val PC relative.  If the  
              symbol is not defined we don't want to do this, because  
              we don't want the value in the object file to incorporate  
              the address of the reloc.  */  
           if (! bfd_is_und_section (bfd_get_section (symbol))  
               && ! bfd_is_com_section (bfd_get_section (symbol)))  
             val -= (input_section->output_section->vma  
                     + input_section->output_offset  
                     + reloc_entry->address);  
   
           /* The low order 16 bits are always treated as a signed  
              value.  Therefore, a negative value in the low order bits  
              requires an adjustment in the high order bits.  We need  
              to make this adjustment in two ways: once for the bits we  
              took from the data, and once for the bits we are putting  
              back in to the data.  */  
           if ((vallo & 0x8000) != 0)  
             val -= 0x10000;  
           if ((val & 0x8000) != 0)  
             val += 0x10000;  
   
           insn = (insn &~ (unsigned) 0xffff) | ((val >> 16) & 0xffff);  
           bfd_put_32 (abfd, (bfd_vma) insn, l->addr);  
   
           next = l->next;  
           free (l);  
           l = next;  
         }  
   
       mips_relhi_list = NULL;  
     }  
   
   /* If this is a reloc against a section symbol, then it is correct  
      in the object file.  The only time we want to change this case is  
      when we are relaxing, and that is handled entirely by  
      mips_relocate_section and never calls this function.  */  
   if ((symbol->flags & BSF_SECTION_SYM) != 0)  
     {  
       if (output_bfd != (bfd *) NULL)  
         reloc_entry->address += input_section->output_offset;  
       return bfd_reloc_ok;  
     }  
   
   /* bfd_perform_relocation does not handle pcrel_offset relocations  
      correctly when generating a relocateable file, so handle them  
      directly here.  */  
   if (output_bfd != (bfd *) NULL)  
     {  
       reloc_entry->address += input_section->output_offset;  
       return bfd_reloc_ok;  
     }  
   
   /* Now do the RELLO reloc in the usual way.  */  
   return mips_generic_reloc (abfd, reloc_entry, symbol, data,  
                               input_section, output_bfd, error_message);  
 }  
   
 /* This is the special function for the MIPS_R_SWITCH reloc.  This  
    special reloc is normally correct in the object file, and only  
    requires special handling when relaxing.  We don't want  
    bfd_perform_relocation to tamper with it at all.  */  
   
 static bfd_reloc_status_type  
 mips_switch_reloc (abfd,  
                    reloc_entry,  
                    symbol,  
                    data,  
                    input_section,  
                    output_bfd,  
                    error_message)  
      bfd *abfd ATTRIBUTE_UNUSED;  
      arelent *reloc_entry ATTRIBUTE_UNUSED;  
      asymbol *symbol ATTRIBUTE_UNUSED;  
      PTR data ATTRIBUTE_UNUSED;  
      asection *input_section ATTRIBUTE_UNUSED;  
      bfd *output_bfd ATTRIBUTE_UNUSED;  
      char **error_message ATTRIBUTE_UNUSED;  
 {  
   return bfd_reloc_ok;  
 }  
   
730  /* Get the howto structure for a generic reloc type.  */  /* Get the howto structure for a generic reloc type.  */
731    
732  static reloc_howto_type *  static reloc_howto_type *
# Line 1154  mips_bfd_reloc_type_lookup (abfd, code) Line 763  mips_bfd_reloc_type_lookup (abfd, code)
763      case BFD_RELOC_16_PCREL_S2:      case BFD_RELOC_16_PCREL_S2:
764        mips_type = MIPS_R_PCREL16;        mips_type = MIPS_R_PCREL16;
765        break;        break;
     case BFD_RELOC_PCREL_HI16_S:  
       mips_type = MIPS_R_RELHI;  
       break;  
     case BFD_RELOC_PCREL_LO16:  
       mips_type = MIPS_R_RELLO;  
       break;  
     case BFD_RELOC_GPREL32:  
       mips_type = MIPS_R_SWITCH;  
       break;  
766      default:      default:
767        return (reloc_howto_type *) NULL;        return (reloc_howto_type *) NULL;
768      }      }
# Line 1171  mips_bfd_reloc_type_lookup (abfd, code) Line 771  mips_bfd_reloc_type_lookup (abfd, code)
771  }  }
772    
773  /* A helper routine for mips_relocate_section which handles the REFHI  /* A helper routine for mips_relocate_section which handles the REFHI
774     and RELHI relocations.  The REFHI relocation must be followed by a     relocations.  The REFHI relocation must be followed by a REFLO
775     REFLO relocation (and RELHI by a RELLO), and the addend used is     relocation, and the addend used is formed from the addends of both
776     formed from the addends of both instructions.  */     instructions.  */
777    
778  static void  static void
779  mips_relocate_hi (refhi, reflo, input_bfd, input_section, contents, adjust,  mips_relocate_hi (refhi, reflo, input_bfd, input_section, contents,
780                    relocation, pcrel)                    relocation)
781       struct internal_reloc *refhi;       struct internal_reloc *refhi;
782       struct internal_reloc *reflo;       struct internal_reloc *reflo;
783       bfd *input_bfd;       bfd *input_bfd;
784       asection *input_section;       asection *input_section;
785       bfd_byte *contents;       bfd_byte *contents;
      size_t adjust;  
786       bfd_vma relocation;       bfd_vma relocation;
      boolean pcrel;  
787  {  {
788    unsigned long insn;    unsigned long insn;
789    unsigned long val;    unsigned long val;
# Line 1195  mips_relocate_hi (refhi, reflo, input_bf Line 793  mips_relocate_hi (refhi, reflo, input_bf
793      return;      return;
794    
795    insn = bfd_get_32 (input_bfd,    insn = bfd_get_32 (input_bfd,
796                       contents + adjust + refhi->r_vaddr - input_section->vma);                       contents + refhi->r_vaddr - input_section->vma);
797    if (reflo == NULL)    if (reflo == NULL)
798      vallo = 0;      vallo = 0;
799    else    else
800      vallo = (bfd_get_32 (input_bfd,      vallo = (bfd_get_32 (input_bfd,
801                           contents + adjust + reflo->r_vaddr - input_section->vma)                           contents + reflo->r_vaddr - input_section->vma)
802               & 0xffff);               & 0xffff);
803    
804    val = ((insn & 0xffff) << 16) + vallo;    val = ((insn & 0xffff) << 16) + vallo;
# Line 1214  mips_relocate_hi (refhi, reflo, input_bf Line 812  mips_relocate_hi (refhi, reflo, input_bf
812    if ((vallo & 0x8000) != 0)    if ((vallo & 0x8000) != 0)
813      val -= 0x10000;      val -= 0x10000;
814    
   if (pcrel)  
     val -= (input_section->output_section->vma  
             + input_section->output_offset  
             + (reflo->r_vaddr - input_section->vma + adjust));  
   
815    if ((val & 0x8000) != 0)    if ((val & 0x8000) != 0)
816      val += 0x10000;      val += 0x10000;
817    
818    insn = (insn &~ (unsigned) 0xffff) | ((val >> 16) & 0xffff);    insn = (insn &~ (unsigned) 0xffff) | ((val >> 16) & 0xffff);
819    bfd_put_32 (input_bfd, (bfd_vma) insn,    bfd_put_32 (input_bfd, (bfd_vma) insn,
820                contents + adjust + refhi->r_vaddr - input_section->vma);                contents + refhi->r_vaddr - input_section->vma);
821  }  }
822    
823  /* Relocate a section while linking a MIPS ECOFF file.  */  /* Relocate a section while linking a MIPS ECOFF file.  */
824    
825  static boolean  static bfd_boolean
826  mips_relocate_section (output_bfd, info, input_bfd, input_section,  mips_relocate_section (output_bfd, info, input_bfd, input_section,
827                         contents, external_relocs)                         contents, external_relocs)
828       bfd *output_bfd;       bfd *output_bfd;
# Line 1242  mips_relocate_section (output_bfd, info, Line 835  mips_relocate_section (output_bfd, info,
835    asection **symndx_to_section;    asection **symndx_to_section;
836    struct ecoff_link_hash_entry **sym_hashes;    struct ecoff_link_hash_entry **sym_hashes;
837    bfd_vma gp;    bfd_vma gp;
838    boolean gp_undefined;    bfd_boolean gp_undefined;
   size_t adjust;  
   long *offsets;  
839    struct external_reloc *ext_rel;    struct external_reloc *ext_rel;
840    struct external_reloc *ext_rel_end;    struct external_reloc *ext_rel_end;
841    unsigned int i;    unsigned int i;
842    boolean got_lo;    bfd_boolean got_lo;
843    struct internal_reloc lo_int_rel;    struct internal_reloc lo_int_rel;
844    bfd_size_type amt;    bfd_size_type amt;
845    
# Line 1264  mips_relocate_section (output_bfd, info, Line 855  mips_relocate_section (output_bfd, info,
855        amt = NUM_RELOC_SECTIONS * sizeof (asection *);        amt = NUM_RELOC_SECTIONS * sizeof (asection *);
856        symndx_to_section = (asection **) bfd_alloc (input_bfd, amt);        symndx_to_section = (asection **) bfd_alloc (input_bfd, amt);
857        if (!symndx_to_section)        if (!symndx_to_section)
858          return false;          return FALSE;
859    
860        symndx_to_section[RELOC_SECTION_NONE] = NULL;        symndx_to_section[RELOC_SECTION_NONE] = NULL;
861        symndx_to_section[RELOC_SECTION_TEXT] =        symndx_to_section[RELOC_SECTION_TEXT] =
# Line 1299  mips_relocate_section (output_bfd, info, Line 890  mips_relocate_section (output_bfd, info,
890    
891    gp = _bfd_get_gp_value (output_bfd);    gp = _bfd_get_gp_value (output_bfd);
892    if (gp == 0)    if (gp == 0)
893      gp_undefined = true;      gp_undefined = TRUE;
894    else    else
895      gp_undefined = false;      gp_undefined = FALSE;
   
   got_lo = false;  
896    
897    adjust = 0;    got_lo = FALSE;
   
   if (ecoff_section_data (input_bfd, input_section) == NULL)  
     offsets = NULL;  
   else  
     offsets = ecoff_section_data (input_bfd, input_section)->offsets;  
898    
899    ext_rel = (struct external_reloc *) external_relocs;    ext_rel = (struct external_reloc *) external_relocs;
900    ext_rel_end = ext_rel + input_section->reloc_count;    ext_rel_end = ext_rel + input_section->reloc_count;
901    for (i = 0; ext_rel < ext_rel_end; ext_rel++, i++)    for (i = 0; ext_rel < ext_rel_end; ext_rel++, i++)
902      {      {
903        struct internal_reloc int_rel;        struct internal_reloc int_rel;
904        boolean use_lo = false;        bfd_boolean use_lo = FALSE;
905        bfd_vma addend;        bfd_vma addend;
906        reloc_howto_type *howto;        reloc_howto_type *howto;
907        struct ecoff_link_hash_entry *h = NULL;        struct ecoff_link_hash_entry *h = NULL;
# Line 1330  mips_relocate_section (output_bfd, info, Line 914  mips_relocate_section (output_bfd, info,
914        else        else
915          {          {
916            int_rel = lo_int_rel;            int_rel = lo_int_rel;
917            got_lo = false;            got_lo = FALSE;
918          }          }
919    
920        BFD_ASSERT (int_rel.r_type        BFD_ASSERT (int_rel.r_type
921                    < sizeof mips_howto_table / sizeof mips_howto_table[0]);                    < sizeof mips_howto_table / sizeof mips_howto_table[0]);
922    
923        /* The REFHI and RELHI relocs requires special handling.  they        /* The REFHI reloc requires special handling.  It must be followed
924           must be followed by a REFLO or RELLO reloc, respectively, and           by a REFLO reloc, and the addend is formed from both relocs.  */
925           the addend is formed from both relocs.  */        if (int_rel.r_type == MIPS_R_REFHI)
       if (int_rel.r_type == MIPS_R_REFHI  
           || int_rel.r_type == MIPS_R_RELHI)  
926          {          {
927            struct external_reloc *lo_ext_rel;            struct external_reloc *lo_ext_rel;
928    
929            /* As a GNU extension, permit an arbitrary number of REFHI            /* As a GNU extension, permit an arbitrary number of REFHI
930               or RELHI relocs before the REFLO or RELLO reloc.  This               relocs before the REFLO reloc.  This permits gcc to emit
931               permits gcc to emit the HI and LO relocs itself.  */               the HI and LO relocs itself.  */
932            for (lo_ext_rel = ext_rel + 1;            for (lo_ext_rel = ext_rel + 1;
933                 lo_ext_rel < ext_rel_end;                 lo_ext_rel < ext_rel_end;
934                 lo_ext_rel++)                 lo_ext_rel++)
# Line 1358  mips_relocate_section (output_bfd, info, Line 940  mips_relocate_section (output_bfd, info,
940              }              }
941    
942            if (lo_ext_rel < ext_rel_end            if (lo_ext_rel < ext_rel_end
943                && (lo_int_rel.r_type                && lo_int_rel.r_type == MIPS_R_REFLO
                   == (int_rel.r_type == MIPS_R_REFHI  
                       ? MIPS_R_REFLO  
                       : MIPS_R_RELLO))  
944                && int_rel.r_extern == lo_int_rel.r_extern                && int_rel.r_extern == lo_int_rel.r_extern
945                && int_rel.r_symndx == lo_int_rel.r_symndx)                && int_rel.r_symndx == lo_int_rel.r_symndx)
946              {              {
947                use_lo = true;                use_lo = TRUE;
948                if (lo_ext_rel == ext_rel + 1)                if (lo_ext_rel == ext_rel + 1)
949                  got_lo = true;                  got_lo = TRUE;
950              }              }
951          }          }
952    
953        howto = &mips_howto_table[int_rel.r_type];        howto = &mips_howto_table[int_rel.r_type];
954    
       /* The SWITCH reloc must be handled specially.  This reloc is  
          marks the location of a difference between two portions of an  
          object file.  The symbol index does not reference a symbol,  
          but is actually the offset from the reloc to the subtrahend  
          of the difference.  This reloc is correct in the object file,  
          and needs no further adjustment, unless we are relaxing.  If  
          we are relaxing, we may have to add in an offset.  Since no  
          symbols are involved in this reloc, we handle it completely  
          here.  */  
       if (int_rel.r_type == MIPS_R_SWITCH)  
         {  
           if (offsets != NULL  
               && offsets[i] != 0)  
             {  
               r = _bfd_relocate_contents (howto, input_bfd,  
                                           (bfd_vma) offsets[i],  
                                           (contents  
                                            + adjust  
                                            + int_rel.r_vaddr  
                                            - input_section->vma));  
               BFD_ASSERT (r == bfd_reloc_ok);  
             }  
   
           continue;  
         }  
   
955        if (int_rel.r_extern)        if (int_rel.r_extern)
956          {          {
957            h = sym_hashes[int_rel.r_symndx];            h = sym_hashes[int_rel.r_symndx];
# Line 1432  mips_relocate_section (output_bfd, info, Line 985  mips_relocate_section (output_bfd, info,
985                       (info, _("GP relative relocation used when GP not defined"),                       (info, _("GP relative relocation used when GP not defined"),
986                        input_bfd, input_section,                        input_bfd, input_section,
987                        int_rel.r_vaddr - input_section->vma)))                        int_rel.r_vaddr - input_section->vma)))
988                  return false;                  return FALSE;
989                /* Only give the error once per link.  */                /* Only give the error once per link.  */
990                gp = 4;                gp = 4;
991                _bfd_set_gp_value (output_bfd, gp);                _bfd_set_gp_value (output_bfd, gp);
992                gp_undefined = false;                gp_undefined = FALSE;
993              }              }
994            if (! int_rel.r_extern)            if (! int_rel.r_extern)
995              {              {
# Line 1448  mips_relocate_section (output_bfd, info, Line 1001  mips_relocate_section (output_bfd, info,
1001                   and the GP value of OUTPUT_BFD (which is in GP).  */                   and the GP value of OUTPUT_BFD (which is in GP).  */
1002                addend = ecoff_data (input_bfd)->gp - gp;                addend = ecoff_data (input_bfd)->gp - gp;
1003              }              }
1004            else if (! info->relocateable            else if (! info->relocatable
1005                     || h->root.type == bfd_link_hash_defined                     || h->root.type == bfd_link_hash_defined
1006                     || h->root.type == bfd_link_hash_defweak)                     || h->root.type == bfd_link_hash_defweak)
1007              {              {
# Line 1467  mips_relocate_section (output_bfd, info, Line 1020  mips_relocate_section (output_bfd, info,
1020                /* This is a relocation against an undefined or common                /* This is a relocation against an undefined or common
1021                   symbol.  The current addend in the instruction is                   symbol.  The current addend in the instruction is
1022                   simply the desired offset into the symbol (normally                   simply the desired offset into the symbol (normally
1023                   zero).  We are generating relocateable output, and we                   zero).  We are generating relocatable output, and we
1024                   aren't going to define this symbol, so we just leave                   aren't going to define this symbol, so we just leave
1025                   the instruction alone.  */                   the instruction alone.  */
1026                addend = 0;                addend = 0;
1027              }              }
1028          }          }
1029    
1030        /* If we are relaxing, mips_relax_section may have set        if (info->relocatable)
          offsets[i] to some value.  A value of 1 means we must expand  
          a PC relative branch into a multi-instruction of sequence,  
          and any other value is an addend.  */  
       if (offsets != NULL  
           && offsets[i] != 0)  
1031          {          {
1032            BFD_ASSERT (! info->relocateable);            /* We are generating relocatable output, and must convert
           BFD_ASSERT (int_rel.r_type == MIPS_R_PCREL16  
                       || int_rel.r_type == MIPS_R_RELHI  
                       || int_rel.r_type == MIPS_R_RELLO);  
           if (offsets[i] != 1)  
             addend += offsets[i];  
           else  
             {  
               bfd_byte *here;  
   
               BFD_ASSERT (int_rel.r_extern  
                           && int_rel.r_type == MIPS_R_PCREL16);  
   
               /* Move the rest of the instructions up.  */  
               here = (contents  
                       + adjust  
                       + int_rel.r_vaddr  
                       - input_section->vma);  
               memmove (here + PCREL16_EXPANSION_ADJUSTMENT, here,  
                        (size_t) (input_section->_raw_size  
                                  - (int_rel.r_vaddr - input_section->vma)));  
   
               /* Generate the new instructions.  */  
               if (! mips_relax_pcrel16 (info, input_bfd, input_section,  
                                         h, here,  
                                         (input_section->output_section->vma  
                                          + input_section->output_offset  
                                          + (int_rel.r_vaddr  
                                             - input_section->vma)  
                                          + adjust)))  
                 return false;  
   
               /* We must adjust everything else up a notch.  */  
               adjust += PCREL16_EXPANSION_ADJUSTMENT;  
   
               /* mips_relax_pcrel16 handles all the details of this  
                  relocation.  */  
               continue;  
             }  
         }  
   
       /* If we are relaxing, and this is a reloc against the .text  
          segment, we may need to adjust it if some branches have been  
          expanded.  The reloc types which are likely to occur in the  
          .text section are handled efficiently by mips_relax_section,  
          and thus do not need to be handled here.  */  
       if (ecoff_data (input_bfd)->debug_info.adjust != NULL  
           && ! int_rel.r_extern  
           && int_rel.r_symndx == RELOC_SECTION_TEXT  
           && (strcmp (bfd_get_section_name (input_bfd, input_section),  
                       ".text") != 0  
               || (int_rel.r_type != MIPS_R_PCREL16  
                   && int_rel.r_type != MIPS_R_SWITCH  
                   && int_rel.r_type != MIPS_R_RELHI  
                   && int_rel.r_type != MIPS_R_RELLO)))  
         {  
           bfd_vma adr;  
           struct ecoff_value_adjust *a;  
   
           /* We need to get the addend so that we know whether we need  
              to adjust the address.  */  
           BFD_ASSERT (int_rel.r_type == MIPS_R_REFWORD);  
   
           adr = bfd_get_32 (input_bfd,  
                             (contents  
                              + adjust  
                              + int_rel.r_vaddr  
                              - input_section->vma));  
   
           for (a = ecoff_data (input_bfd)->debug_info.adjust;  
                a != (struct ecoff_value_adjust *) NULL;  
                a = a->next)  
             {  
               if (adr >= a->start && adr < a->end)  
                 addend += a->adjust;  
             }  
         }  
   
       if (info->relocateable)  
         {  
           /* We are generating relocateable output, and must convert  
1033               the existing reloc.  */               the existing reloc.  */
1034            if (int_rel.r_extern)            if (int_rel.r_extern)
1035              {              {
# Line 1636  mips_relocate_section (output_bfd, info, Line 1104  mips_relocate_section (output_bfd, info,
1104                       currently holds just the addend.  We must adjust                       currently holds just the addend.  We must adjust
1105                       by the address to get the right value.  */                       by the address to get the right value.  */
1106                    if (howto->pc_relative)                    if (howto->pc_relative)
1107                      {                      relocation -= int_rel.r_vaddr - input_section->vma;
                       relocation -= int_rel.r_vaddr - input_section->vma;  
   
                       /* If we are converting a RELHI or RELLO reloc  
                          from being against an external symbol to  
                          being against a section, we must put a  
                          special value into the r_offset field.  This  
                          value is the old addend.  The r_offset for  
                          both the RELHI and RELLO relocs are the same,  
                          and we set both when we see RELHI.  */  
                       if (int_rel.r_type == MIPS_R_RELHI)  
                         {  
                           long addhi, addlo;  
   
                           addhi = bfd_get_32 (input_bfd,  
                                               (contents  
                                                + adjust  
                                                + int_rel.r_vaddr  
                                                - input_section->vma));  
                           addhi &= 0xffff;  
                           if (addhi & 0x8000)  
                             addhi -= 0x10000;  
                           addhi <<= 16;  
   
                           if (! use_lo)  
                             addlo = 0;  
                           else  
                             {  
                               addlo = bfd_get_32 (input_bfd,  
                                                   (contents  
                                                    + adjust  
                                                    + lo_int_rel.r_vaddr  
                                                    - input_section->vma));  
                               addlo &= 0xffff;  
                               if (addlo & 0x8000)  
                                 addlo -= 0x10000;  
   
                               lo_int_rel.r_offset = addhi + addlo;  
                             }  
   
                           int_rel.r_offset = addhi + addlo;  
                         }  
                     }  
1108    
1109                    h = NULL;                    h = NULL;
1110                  }                  }
# Line 1694  mips_relocate_section (output_bfd, info, Line 1120  mips_relocate_section (output_bfd, info,
1120                               (info, h->root.root.string, input_bfd,                               (info, h->root.root.string, input_bfd,
1121                                input_section,                                input_section,
1122                                int_rel.r_vaddr - input_section->vma)))                                int_rel.r_vaddr - input_section->vma)))
1123                          return false;                          return FALSE;
1124                        int_rel.r_symndx = 0;                        int_rel.r_symndx = 0;
1125                      }                      }
1126                    relocation = 0;                    relocation = 0;
# Line 1714  mips_relocate_section (output_bfd, info, Line 1140  mips_relocate_section (output_bfd, info,
1140    
1141            /* Adjust a PC relative relocation by removing the reference            /* Adjust a PC relative relocation by removing the reference
1142               to the original address in the section and including the               to the original address in the section and including the
1143               reference to the new address.  However, external RELHI               reference to the new address.  */
1144               and RELLO relocs are PC relative, but don't include any            if (howto->pc_relative)
              reference to the address.  The addend is merely an  
              addend.  */  
           if (howto->pc_relative  
               && (! int_rel.r_extern  
                   || (int_rel.r_type != MIPS_R_RELHI  
                       && int_rel.r_type != MIPS_R_RELLO)))  
1145              relocation -= (input_section->output_section->vma              relocation -= (input_section->output_section->vma
1146                             + input_section->output_offset                             + input_section->output_offset
1147                             - input_section->vma);                             - input_section->vma);
# Line 1731  mips_relocate_section (output_bfd, info, Line 1151  mips_relocate_section (output_bfd, info,
1151              r = bfd_reloc_ok;              r = bfd_reloc_ok;
1152            else            else
1153              {              {
1154                if (int_rel.r_type != MIPS_R_REFHI                if (int_rel.r_type != MIPS_R_REFHI)
                   && int_rel.r_type != MIPS_R_RELHI)  
1155                  r = _bfd_relocate_contents (howto, input_bfd, relocation,                  r = _bfd_relocate_contents (howto, input_bfd, relocation,
1156                                              (contents                                              (contents
                                              + adjust  
1157                                               + int_rel.r_vaddr                                               + int_rel.r_vaddr
1158                                               - input_section->vma));                                               - input_section->vma));
1159                else                else
# Line 1743  mips_relocate_section (output_bfd, info, Line 1161  mips_relocate_section (output_bfd, info,
1161                    mips_relocate_hi (&int_rel,                    mips_relocate_hi (&int_rel,
1162                                      use_lo ? &lo_int_rel : NULL,                                      use_lo ? &lo_int_rel : NULL,
1163                                      input_bfd, input_section, contents,                                      input_bfd, input_section, contents,
1164                                      adjust, relocation,                                      relocation);
                                     int_rel.r_type == MIPS_R_RELHI);  
1165                    r = bfd_reloc_ok;                    r = bfd_reloc_ok;
1166                  }                  }
1167              }              }
# Line 1778  mips_relocate_section (output_bfd, info, Line 1195  mips_relocate_section (output_bfd, info,
1195                    if (! ((*info->callbacks->undefined_symbol)                    if (! ((*info->callbacks->undefined_symbol)
1196                           (info, h->root.root.string, input_bfd,                           (info, h->root.root.string, input_bfd,
1197                            input_section,                            input_section,
1198                            int_rel.r_vaddr - input_section->vma, true)))                            int_rel.r_vaddr - input_section->vma, TRUE)))
1199                      return false;                      return FALSE;
1200                    relocation = 0;                    relocation = 0;
1201                  }                  }
1202              }              }
# Line 1794  mips_relocate_section (output_bfd, info, Line 1211  mips_relocate_section (output_bfd, info,
1211                   file.  Make it look like a pcrel_offset relocation by                   file.  Make it look like a pcrel_offset relocation by
1212                   adding in the start address.  */                   adding in the start address.  */
1213                if (howto->pc_relative)                if (howto->pc_relative)
1214                  {                  relocation += int_rel.r_vaddr;
                   if (int_rel.r_type != MIPS_R_RELHI || ! use_lo)  
                     relocation += int_rel.r_vaddr + adjust;  
                   else  
                     relocation += lo_int_rel.r_vaddr + adjust;  
                 }  
1215              }              }
1216    
1217            if (int_rel.r_type != MIPS_R_REFHI            if (int_rel.r_type != MIPS_R_REFHI)
               && int_rel.r_type != MIPS_R_RELHI)  
1218              r = _bfd_final_link_relocate (howto,              r = _bfd_final_link_relocate (howto,
1219                                            input_bfd,                                            input_bfd,
1220                                            input_section,                                            input_section,
1221                                            contents,                                            contents,
1222                                            (int_rel.r_vaddr                                            (int_rel.r_vaddr
1223                                             - input_section->vma                                             - input_section->vma),
                                            + adjust),  
1224                                            relocation,                                            relocation,
1225                                            addend);                                            addend);
1226            else            else
1227              {              {
1228                mips_relocate_hi (&int_rel,                mips_relocate_hi (&int_rel,
1229                                  use_lo ? &lo_int_rel : NULL,                                  use_lo ? &lo_int_rel : NULL,
1230                                  input_bfd, input_section, contents, adjust,                                  input_bfd, input_section, contents,
1231                                  relocation,                                  relocation);
                                 int_rel.r_type == MIPS_R_RELHI);  
1232                r = bfd_reloc_ok;                r = bfd_reloc_ok;
1233              }              }
1234          }          }
# Line 1836  mips_relocate_section (output_bfd, info, Line 1245  mips_relocate_section (output_bfd, info,
1245                 & 0xf0000000)                 & 0xf0000000)
1246                != ((input_section->output_section->vma                != ((input_section->output_section->vma
1247                     + input_section->output_offset                     + input_section->output_offset
1248                     + (int_rel.r_vaddr - input_section->vma)                     + (int_rel.r_vaddr - input_section->vma))
                    + adjust)  
1249                    & 0xf0000000)))                    & 0xf0000000)))
1250          r = bfd_reloc_overflow;          r = bfd_reloc_overflow;
1251    
# Line 1853  mips_relocate_section (output_bfd, info, Line 1261  mips_relocate_section (output_bfd, info,
1261                  const char *name;                  const char *name;
1262    
1263                  if (int_rel.r_extern)                  if (int_rel.r_extern)
1264                    name = h->root.root.string;                    name = NULL;
1265                  else                  else
1266                    name = bfd_section_name (input_bfd, s);                    name = bfd_section_name (input_bfd, s);
1267                  if (! ((*info->callbacks->reloc_overflow)                  if (! ((*info->callbacks->reloc_overflow)
1268                         (info, name, howto->name, (bfd_vma) 0,                         (info, (h ? &h->root : NULL), name, howto->name,
1269                          input_bfd, input_section,                          (bfd_vma) 0, input_bfd, input_section,
1270                          int_rel.r_vaddr - input_section->vma)))                          int_rel.r_vaddr - input_section->vma)))
1271                    return false;                    return FALSE;
1272                }                }
1273                break;                break;
1274              }              }
1275          }          }
1276      }      }
1277    
1278    return true;    return TRUE;
 }  
   
 /* Read in the relocs for a section.  */  
   
 static boolean  
 mips_read_relocs (abfd, sec)  
      bfd *abfd;  
      asection *sec;  
 {  
   struct ecoff_section_tdata *section_tdata;  
   bfd_size_type amt;  
   
   section_tdata = ecoff_section_data (abfd, sec);  
   if (section_tdata == (struct ecoff_section_tdata *) NULL)  
     {  
       amt = sizeof (struct ecoff_section_tdata);  
       sec->used_by_bfd = (PTR) bfd_alloc (abfd, amt);  
       if (sec->used_by_bfd == NULL)  
         return false;  
   
       section_tdata = ecoff_section_data (abfd, sec);  
       section_tdata->external_relocs = NULL;  
       section_tdata->contents = NULL;  
       section_tdata->offsets = NULL;  
     }  
   
   if (section_tdata->external_relocs == NULL)  
     {  
       amt = ecoff_backend (abfd)->external_reloc_size;  
       amt *= sec->reloc_count;  
       section_tdata->external_relocs = (PTR) bfd_alloc (abfd, amt);  
       if (section_tdata->external_relocs == NULL && amt != 0)  
         return false;  
   
       if (bfd_seek (abfd, sec->rel_filepos, SEEK_SET) != 0  
           || bfd_bread (section_tdata->external_relocs, amt, abfd) != amt)  
         return false;  
     }  
   
   return true;  
 }  
   
 /* Relax a section when linking a MIPS ECOFF file.  This is used for  
    embedded PIC code, which always uses PC relative branches which  
    only have an 18 bit range on MIPS.  If a branch is not in range, we  
    generate a long instruction sequence to compensate.  Each time we  
    find a branch to expand, we have to check all the others again to  
    make sure they are still in range.  This is slow, but it only has  
    to be done when -relax is passed to the linker.  
   
    This routine figures out which branches need to expand; the actual  
    expansion is done in mips_relocate_section when the section  
    contents are relocated.  The information is stored in the offsets  
    field of the ecoff_section_tdata structure.  An offset of 1 means  
    that the branch must be expanded into a multi-instruction PC  
    relative branch (such an offset will only occur for a PC relative  
    branch to an external symbol).  Any other offset must be a multiple  
    of four, and is the amount to change the branch by (such an offset  
    will only occur for a PC relative branch within the same section).  
   
    We do not modify the section relocs or contents themselves so that  
    if memory usage becomes an issue we can discard them and read them  
    again.  The only information we must save in memory between this  
    routine and the mips_relocate_section routine is the table of  
    offsets.  */  
   
 static boolean  
 mips_relax_section (abfd, sec, info, again)  
      bfd *abfd;  
      asection *sec;  
      struct bfd_link_info *info;  
      boolean *again;  
 {  
   struct ecoff_section_tdata *section_tdata;  
   bfd_byte *contents = NULL;  
   long *offsets;  
   struct external_reloc *ext_rel;  
   struct external_reloc *ext_rel_end;  
   unsigned int i;  
   
   /* Assume we are not going to need another pass.  */  
   *again = false;  
   
   /* If we are not generating an ECOFF file, this is much too  
      confusing to deal with.  */  
   if (info->hash->creator->flavour != bfd_get_flavour (abfd))  
     return true;  
   
   /* If there are no relocs, there is nothing to do.  */  
   if (sec->reloc_count == 0)  
     return true;  
   
   /* We are only interested in PC relative relocs, and why would there  
      ever be one from anything but the .text section?  */  
   if (strcmp (bfd_get_section_name (abfd, sec), ".text") != 0)  
     return true;  
   
   /* Read in the relocs, if we haven't already got them.  */  
   section_tdata = ecoff_section_data (abfd, sec);  
   if (section_tdata == (struct ecoff_section_tdata *) NULL  
       || section_tdata->external_relocs == NULL)  
     {  
       if (! mips_read_relocs (abfd, sec))  
         goto error_return;  
       section_tdata = ecoff_section_data (abfd, sec);  
     }  
   
   if (sec->_cooked_size == 0)  
     {  
       /* We must initialize _cooked_size only the first time we are  
          called.  */  
       sec->_cooked_size = sec->_raw_size;  
     }  
   
   contents = section_tdata->contents;  
   offsets = section_tdata->offsets;  
   
   /* Look for any external PC relative relocs.  Internal PC relative  
      relocs are already correct in the object file, so they certainly  
      can not overflow.  */  
   ext_rel = (struct external_reloc *) section_tdata->external_relocs;  
   ext_rel_end = ext_rel + sec->reloc_count;  
   for (i = 0; ext_rel < ext_rel_end; ext_rel++, i++)  
     {  
       struct internal_reloc int_rel;  
       struct ecoff_link_hash_entry *h;  
       asection *hsec;  
       bfd_signed_vma relocation;  
       struct external_reloc *adj_ext_rel;  
       unsigned int adj_i;  
       unsigned long ext_count;  
       struct ecoff_link_hash_entry **adj_h_ptr;  
       struct ecoff_link_hash_entry **adj_h_ptr_end;  
       struct ecoff_value_adjust *adjust;  
       bfd_size_type amt;  
   
       /* If we have already expanded this reloc, we certainly don't  
          need to do it again.  */  
       if (offsets != (long *) NULL && offsets[i] == 1)  
         continue;  
   
       /* Quickly check that this reloc is external PCREL16.  */  
       if (bfd_header_big_endian (abfd))  
         {  
           if ((ext_rel->r_bits[3] & RELOC_BITS3_EXTERN_BIG) == 0  
               || (((ext_rel->r_bits[3] & RELOC_BITS3_TYPE_BIG)  
                    >> RELOC_BITS3_TYPE_SH_BIG)  
                   != MIPS_R_PCREL16))  
             continue;  
         }  
       else  
         {  
           if ((ext_rel->r_bits[3] & RELOC_BITS3_EXTERN_LITTLE) == 0  
               || (((ext_rel->r_bits[3] & RELOC_BITS3_TYPE_LITTLE)  
                    >> RELOC_BITS3_TYPE_SH_LITTLE)  
                   != MIPS_R_PCREL16))  
             continue;  
         }  
   
       mips_ecoff_swap_reloc_in (abfd, (PTR) ext_rel, &int_rel);  
   
       h = ecoff_data (abfd)->sym_hashes[int_rel.r_symndx];  
       if (h == (struct ecoff_link_hash_entry *) NULL)  
         abort ();  
   
       if (h->root.type != bfd_link_hash_defined  
           && h->root.type != bfd_link_hash_defweak)  
         {  
           /* Just ignore undefined symbols.  These will presumably  
              generate an error later in the link.  */  
           continue;  
         }  
   
       /* Get the value of the symbol.  */  
       hsec = h->root.u.def.section;  
       relocation = (h->root.u.def.value  
                     + hsec->output_section->vma  
                     + hsec->output_offset);  
   
       /* Subtract out the current address.  */  
       relocation -= (sec->output_section->vma  
                      + sec->output_offset  
                      + (int_rel.r_vaddr - sec->vma));  
   
       /* The addend is stored in the object file.  In the normal case  
          of ``bal symbol'', the addend will be -4.  It will only be  
          different in the case of ``bal symbol+constant''.  To avoid  
          always reading in the section contents, we don't check the  
          addend in the object file (we could easily check the contents  
          if we happen to have already read them in, but I fear that  
          this could be confusing).  This means we will screw up if  
          there is a branch to a symbol that is in range, but added to  
          a constant which puts it out of range; in such a case the  
          link will fail with a reloc overflow error.  Since the  
          compiler will never generate such code, it should be easy  
          enough to work around it by changing the assembly code in the  
          source file.  */  
       relocation -= 4;  
   
       /* Now RELOCATION is the number we want to put in the object  
          file.  See whether it fits.  */  
       if (relocation >= -0x20000 && relocation < 0x20000)  
         continue;  
   
       /* Now that we know this reloc needs work, which will rarely  
          happen, go ahead and grab the section contents.  */  
       if (contents == (bfd_byte *) NULL)  
         {  
           if (info->keep_memory)  
             contents = (bfd_byte *) bfd_alloc (abfd, sec->_raw_size);  
           else  
             contents = (bfd_byte *) bfd_malloc (sec->_raw_size);  
           if (contents == (bfd_byte *) NULL)  
             goto error_return;  
           if (! bfd_get_section_contents (abfd, sec, (PTR) contents,  
                                           (file_ptr) 0, sec->_raw_size))  
             goto error_return;  
           if (info->keep_memory)  
             section_tdata->contents = contents;  
         }  
   
       /* We only support changing the bal instruction.  It would be  
          possible to handle other PC relative branches, but some of  
          them (the conditional branches) would require a different  
          length instruction sequence which would complicate both this  
          routine and mips_relax_pcrel16.  It could be written if  
          somebody felt it were important.  Ignoring this reloc will  
          presumably cause a reloc overflow error later on.  */  
       if (bfd_get_32 (abfd, contents + int_rel.r_vaddr - sec->vma)  
           != 0x0411ffff) /* bgezal $0,. == bal .  */  
         continue;  
   
       /* Bother.  We need to expand this reloc, and we will need to  
          make another relaxation pass since this change may put other  
          relocs out of range.  We need to examine the local branches  
          and we need to allocate memory to hold the offsets we must  
          add to them.  We also need to adjust the values of all  
          symbols in the object file following this location.  */  
   
       sec->_cooked_size += PCREL16_EXPANSION_ADJUSTMENT;  
       *again = true;  
   
       if (offsets == (long *) NULL)  
         {  
           bfd_size_type size;  
   
           size = (bfd_size_type) sec->reloc_count * sizeof (long);  
           offsets = (long *) bfd_zalloc (abfd, size);  
           if (offsets == (long *) NULL)  
             goto error_return;  
           section_tdata->offsets = offsets;  
         }  
   
       offsets[i] = 1;  
   
       /* Now look for all PC relative references that cross this reloc  
          and adjust their offsets.  */  
       adj_ext_rel = (struct external_reloc *) section_tdata->external_relocs;  
       for (adj_i = 0; adj_ext_rel < ext_rel_end; adj_ext_rel++, adj_i++)  
         {  
           struct internal_reloc adj_int_rel;  
           bfd_vma start, stop;  
           int change;  
   
           mips_ecoff_swap_reloc_in (abfd, (PTR) adj_ext_rel, &adj_int_rel);  
   
           if (adj_int_rel.r_type == MIPS_R_PCREL16)  
             {  
               unsigned long insn;  
   
               /* We only care about local references.  External ones  
                  will be relocated correctly anyhow.  */  
               if (adj_int_rel.r_extern)  
                 continue;  
   
               /* We are only interested in a PC relative reloc within  
                  this section.  FIXME: Cross section PC relative  
                  relocs may not be handled correctly; does anybody  
                  care?  */  
               if (adj_int_rel.r_symndx != RELOC_SECTION_TEXT)  
                 continue;  
   
               start = adj_int_rel.r_vaddr;  
   
               insn = bfd_get_32 (abfd,  
                                  contents + adj_int_rel.r_vaddr - sec->vma);  
   
               stop = (insn & 0xffff) << 2;  
               if ((stop & 0x20000) != 0)  
                 stop -= 0x40000;  
               stop += adj_int_rel.r_vaddr + 4;  
             }  
           else if (adj_int_rel.r_type == MIPS_R_RELHI)  
             {  
               struct internal_reloc rello;  
               long addhi, addlo;  
   
               /* The next reloc must be MIPS_R_RELLO, and we handle  
                  them together.  */  
               BFD_ASSERT (adj_ext_rel + 1 < ext_rel_end);  
   
               mips_ecoff_swap_reloc_in (abfd, (PTR) (adj_ext_rel + 1), &rello);  
   
               BFD_ASSERT (rello.r_type == MIPS_R_RELLO);  
   
               addhi = bfd_get_32 (abfd,  
                                    contents + adj_int_rel.r_vaddr - sec->vma);  
               addhi &= 0xffff;  
               if (addhi & 0x8000)  
                 addhi -= 0x10000;  
               addhi <<= 16;  
   
               addlo = bfd_get_32 (abfd, contents + rello.r_vaddr - sec->vma);  
               addlo &= 0xffff;  
               if (addlo & 0x8000)  
                 addlo -= 0x10000;  
   
               if (adj_int_rel.r_extern)  
                 {  
                   /* The value we want here is  
                        sym - RELLOaddr + addend  
                      which we can express as  
                        sym - (RELLOaddr - addend)  
                      Therefore if we are expanding the area between  
                      RELLOaddr and RELLOaddr - addend we must adjust  
                      the addend.  This is admittedly ambiguous, since  
                      we might mean (sym + addend) - RELLOaddr, but in  
                      practice we don't, and there is no way to handle  
                      that case correctly since at this point we have  
                      no idea whether any reloc is being expanded  
                      between sym and sym + addend.  */  
                   start = rello.r_vaddr - (addhi + addlo);  
                   stop = rello.r_vaddr;  
                 }  
               else  
                 {  
                   /* An internal RELHI/RELLO pair represents the  
                      difference between two addresses, $LC0 - foo.  
                      The symndx value is actually the difference  
                      between the reloc address and $LC0.  This lets us  
                      compute $LC0, and, by considering the addend,  
                      foo.  If the reloc we are expanding falls between  
                      those two relocs, we must adjust the addend.  At  
                      this point, the symndx value is actually in the  
                      r_offset field, where it was put by  
                      mips_ecoff_swap_reloc_in.  */  
                   start = rello.r_vaddr - adj_int_rel.r_offset;  
                   stop = start + addhi + addlo;  
                 }  
             }  
           else if (adj_int_rel.r_type == MIPS_R_SWITCH)  
             {  
               /* A MIPS_R_SWITCH reloc represents a word of the form  
                    .word $L3-$LS12  
                  The value in the object file is correct, assuming the  
                  original value of $L3.  The symndx value is actually  
                  the difference between the reloc address and $LS12.  
                  This lets us compute the original value of $LS12 as  
                    vaddr - symndx  
                  and the original value of $L3 as  
                    vaddr - symndx + addend  
                  where addend is the value from the object file.  At  
                  this point, the symndx value is actually found in the  
                  r_offset field, since it was moved by  
                  mips_ecoff_swap_reloc_in.  */  
               start = adj_int_rel.r_vaddr - adj_int_rel.r_offset;  
               stop = start + bfd_get_32 (abfd,  
                                          (contents  
                                           + adj_int_rel.r_vaddr  
                                           - sec->vma));  
             }  
           else  
             continue;  
   
           /* If the range expressed by this reloc, which is the  
              distance between START and STOP crosses the reloc we are  
              expanding, we must adjust the offset.  The sign of the  
              adjustment depends upon the direction in which the range  
              crosses the reloc being expanded.  */  
           if (start <= int_rel.r_vaddr && stop > int_rel.r_vaddr)  
             change = PCREL16_EXPANSION_ADJUSTMENT;  
           else if (start > int_rel.r_vaddr && stop <= int_rel.r_vaddr)  
             change = - PCREL16_EXPANSION_ADJUSTMENT;  
           else  
             change = 0;  
   
           offsets[adj_i] += change;  
   
           if (adj_int_rel.r_type == MIPS_R_RELHI)  
             {  
               adj_ext_rel++;  
               adj_i++;  
               offsets[adj_i] += change;  
             }  
         }  
   
       /* Find all symbols in this section defined by this object file  
          and adjust their values.  Note that we decide whether to  
          adjust the value based on the value stored in the ECOFF EXTR  
          structure, because the value stored in the hash table may  
          have been changed by an earlier expanded reloc and thus may  
          no longer correctly indicate whether the symbol is before or  
          after the expanded reloc.  */  
       ext_count = ecoff_data (abfd)->debug_info.symbolic_header.iextMax;  
       adj_h_ptr = ecoff_data (abfd)->sym_hashes;  
       adj_h_ptr_end = adj_h_ptr + ext_count;  
       for (; adj_h_ptr < adj_h_ptr_end; adj_h_ptr++)  
         {  
           struct ecoff_link_hash_entry *adj_h;  
   
           adj_h = *adj_h_ptr;  
           if (adj_h != (struct ecoff_link_hash_entry *) NULL  
               && (adj_h->root.type == bfd_link_hash_defined  
                   || adj_h->root.type == bfd_link_hash_defweak)  
               && adj_h->root.u.def.section == sec  
               && adj_h->esym.asym.value > int_rel.r_vaddr)  
             adj_h->root.u.def.value += PCREL16_EXPANSION_ADJUSTMENT;  
         }  
   
       /* Add an entry to the symbol value adjust list.  This is used  
          by bfd_ecoff_debug_accumulate to adjust the values of  
          internal symbols and FDR's.  */  
       amt = sizeof (struct ecoff_value_adjust);  
       adjust = (struct ecoff_value_adjust *) bfd_alloc (abfd, amt);  
       if (adjust == (struct ecoff_value_adjust *) NULL)  
         goto error_return;  
   
       adjust->start = int_rel.r_vaddr;  
       adjust->end = sec->vma + sec->_raw_size;  
       adjust->adjust = PCREL16_EXPANSION_ADJUSTMENT;  
   
       adjust->next = ecoff_data (abfd)->debug_info.adjust;  
       ecoff_data (abfd)->debug_info.adjust = adjust;  
     }  
   
   if (contents != (bfd_byte *) NULL && ! info->keep_memory)  
     free (contents);  
   
   return true;  
   
  error_return:  
   if (contents != (bfd_byte *) NULL && ! info->keep_memory)  
     free (contents);  
   return false;  
 }  
   
 /* This routine is called from mips_relocate_section when a PC  
    relative reloc must be expanded into the five instruction sequence.  
    It handles all the details of the expansion, including resolving  
    the reloc.  */  
   
 static boolean  
 mips_relax_pcrel16 (info, input_bfd, input_section, h, location, address)  
      struct bfd_link_info *info ATTRIBUTE_UNUSED;  
      bfd *input_bfd;  
      asection *input_section ATTRIBUTE_UNUSED;  
      struct ecoff_link_hash_entry *h;  
      bfd_byte *location;  
      bfd_vma address;  
 {  
   bfd_vma relocation;  
   
   /* 0x0411ffff is bgezal $0,. == bal .  */  
   BFD_ASSERT (bfd_get_32 (input_bfd, location) == 0x0411ffff);  
   
   /* We need to compute the distance between the symbol and the  
      current address plus eight.  */  
   relocation = (h->root.u.def.value  
                 + h->root.u.def.section->output_section->vma  
                 + h->root.u.def.section->output_offset);  
   relocation -= address + 8;  
   
   /* If the lower half is negative, increment the upper 16 half.  */  
   if ((relocation & 0x8000) != 0)  
     relocation += 0x10000;  
   
   bfd_put_32 (input_bfd, (bfd_vma) 0x04110001, location); /* bal .+8 */  
   bfd_put_32 (input_bfd,  
               0x3c010000 | ((relocation >> 16) & 0xffff), /* lui $at,XX */  
               location + 4);  
   bfd_put_32 (input_bfd,  
               0x24210000 | (relocation & 0xffff), /* addiu $at,$at,XX */  
               location + 8);  
   bfd_put_32 (input_bfd,  
               (bfd_vma) 0x003f0821, location + 12); /* addu $at,$at,$ra */  
   bfd_put_32 (input_bfd,  
               (bfd_vma) 0x0020f809, location + 16); /* jalr $at */  
   
   return true;  
 }  
   
 /* Given a .sdata section and a .rel.sdata in-memory section, store  
    relocation information into the .rel.sdata section which can be  
    used at runtime to relocate the section.  This is called by the  
    linker when the --embedded-relocs switch is used.  This is called  
    after the add_symbols entry point has been called for all the  
    objects, and before the final_link entry point is called.  This  
    function presumes that the object was compiled using  
    -membedded-pic.  */  
   
 boolean  
 bfd_mips_ecoff_create_embedded_relocs (abfd, info, datasec, relsec, errmsg)  
      bfd *abfd;  
      struct bfd_link_info *info;  
      asection *datasec;  
      asection *relsec;  
      char **errmsg;  
 {  
   struct ecoff_link_hash_entry **sym_hashes;  
   struct ecoff_section_tdata *section_tdata;  
   struct external_reloc *ext_rel;  
   struct external_reloc *ext_rel_end;  
   bfd_byte *p;  
   bfd_size_type amt;  
   
   BFD_ASSERT (! info->relocateable);  
   
   *errmsg = NULL;  
   
   if (datasec->reloc_count == 0)  
     return true;  
   
   sym_hashes = ecoff_data (abfd)->sym_hashes;  
   
   if (! mips_read_relocs (abfd, datasec))  
     return false;  
   
   amt = (bfd_size_type) datasec->reloc_count * 4;  
   relsec->contents = (bfd_byte *) bfd_alloc (abfd, amt);  
   if (relsec->contents == NULL)  
     return false;  
   
   p = relsec->contents;  
   
   section_tdata = ecoff_section_data (abfd, datasec);  
   ext_rel = (struct external_reloc *) section_tdata->external_relocs;  
   ext_rel_end = ext_rel + datasec->reloc_count;  
   for (; ext_rel < ext_rel_end; ext_rel++, p += 4)  
     {  
       struct internal_reloc int_rel;  
       boolean text_relative;  
   
       mips_ecoff_swap_reloc_in (abfd, (PTR) ext_rel, &int_rel);  
   
       /* We are going to write a four byte word into the runtime reloc  
          section.  The word will be the address in the data section  
          which must be relocated.  This must be on a word boundary,  
          which means the lower two bits must be zero.  We use the  
          least significant bit to indicate how the value in the data  
          section must be relocated.  A 0 means that the value is  
          relative to the text section, while a 1 indicates that the  
          value is relative to the data section.  Given that we are  
          assuming the code was compiled using -membedded-pic, there  
          should not be any other possibilities.  */  
   
       /* We can only relocate REFWORD relocs at run time.  */  
       if (int_rel.r_type != MIPS_R_REFWORD)  
         {  
           *errmsg = _("unsupported reloc type");  
           bfd_set_error (bfd_error_bad_value);  
           return false;  
         }  
   
       if (int_rel.r_extern)  
         {  
           struct ecoff_link_hash_entry *h;  
   
           h = sym_hashes[int_rel.r_symndx];  
           /* If h is NULL, that means that there is a reloc against an  
              external symbol which we thought was just a debugging  
              symbol.  This should not happen.  */  
           if (h == (struct ecoff_link_hash_entry *) NULL)  
             abort ();  
           if ((h->root.type == bfd_link_hash_defined  
                || h->root.type == bfd_link_hash_defweak)  
               && (h->root.u.def.section->flags & SEC_CODE) != 0)  
             text_relative = true;  
           else  
             text_relative = false;  
         }  
       else  
         {  
           switch (int_rel.r_symndx)  
             {  
             case RELOC_SECTION_TEXT:  
               text_relative = true;  
               break;  
             case RELOC_SECTION_SDATA:  
             case RELOC_SECTION_SBSS:  
             case RELOC_SECTION_LIT8:  
               text_relative = false;  
               break;  
             default:  
               /* No other sections should appear in -membedded-pic  
                  code.  */  
               *errmsg = _("reloc against unsupported section");  
               bfd_set_error (bfd_error_bad_value);  
               return false;  
             }  
         }  
   
       if ((int_rel.r_offset & 3) != 0)  
         {  
           *errmsg = _("reloc not properly aligned");  
           bfd_set_error (bfd_error_bad_value);  
           return false;  
         }  
   
       bfd_put_32 (abfd,  
                   (int_rel.r_vaddr - datasec->vma + datasec->output_offset  
                    + (text_relative ? 0 : 1)),  
                   p);  
     }  
   
   return true;  
1279  }  }
1280    
1281  /* This is the ECOFF backend structure.  The backend field of the  /* This is the ECOFF backend structure.  The backend field of the
# Line 2501  static const struct ecoff_backend_data m Line 1294  static const struct ecoff_backend_data m
1294      (unsigned (*) PARAMS ((bfd *,PTR,PTR))) bfd_void, /* reloc_out */      (unsigned (*) PARAMS ((bfd *,PTR,PTR))) bfd_void, /* reloc_out */
1295      mips_ecoff_swap_filehdr_out, mips_ecoff_swap_aouthdr_out,      mips_ecoff_swap_filehdr_out, mips_ecoff_swap_aouthdr_out,
1296      mips_ecoff_swap_scnhdr_out,      mips_ecoff_swap_scnhdr_out,
1297      FILHSZ, AOUTSZ, SCNHSZ, 0, 0, 0, 0, FILNMLEN, true, false, 4, false, 2,      FILHSZ, AOUTSZ, SCNHSZ, 0, 0, 0, 0, FILNMLEN, TRUE, FALSE, 4, FALSE, 2,
1298      mips_ecoff_swap_filehdr_in, mips_ecoff_swap_aouthdr_in,      mips_ecoff_swap_filehdr_in, mips_ecoff_swap_aouthdr_in,
1299      mips_ecoff_swap_scnhdr_in, NULL,      mips_ecoff_swap_scnhdr_in, NULL,
1300      mips_ecoff_bad_format_hook, _bfd_ecoff_set_arch_mach_hook,      mips_ecoff_bad_format_hook, _bfd_ecoff_set_arch_mach_hook,
# Line 2517  static const struct ecoff_backend_data m Line 1310  static const struct ecoff_backend_data m
1310    /* The page boundary used to align sections in a demand-paged    /* The page boundary used to align sections in a demand-paged
1311       executable file.  E.g., 0x1000.  */       executable file.  E.g., 0x1000.  */
1312    0x1000,    0x1000,
1313    /* True if the .rdata section is part of the text segment, as on the    /* TRUE if the .rdata section is part of the text segment, as on the
1314       Alpha.  False if .rdata is part of the data segment, as on the       Alpha.  FALSE if .rdata is part of the data segment, as on the
1315       MIPS.  */       MIPS.  */
1316    false,    FALSE,
1317    /* Bitsize of constructor entries.  */    /* Bitsize of constructor entries.  */
1318    32,    32,
1319    /* Reloc to use for constructor entries.  */    /* Reloc to use for constructor entries.  */
# Line 2592  static const struct ecoff_backend_data m Line 1385  static const struct ecoff_backend_data m
1385    _bfd_generic_get_section_contents_in_window    _bfd_generic_get_section_contents_in_window
1386    
1387  /* Relaxing sections is MIPS specific.  */  /* Relaxing sections is MIPS specific.  */
1388  #define _bfd_ecoff_bfd_relax_section mips_relax_section  #define _bfd_ecoff_bfd_relax_section bfd_generic_relax_section
1389    
1390  /* GC of sections is not done.  */  /* GC of sections is not done.  */
1391  #define _bfd_ecoff_bfd_gc_sections bfd_generic_gc_sections  #define _bfd_ecoff_bfd_gc_sections bfd_generic_gc_sections
# Line 2600  static const struct ecoff_backend_data m Line 1393  static const struct ecoff_backend_data m
1393  /* Merging of sections is not done.  */  /* Merging of sections is not done.  */
1394  #define _bfd_ecoff_bfd_merge_sections bfd_generic_merge_sections  #define _bfd_ecoff_bfd_merge_sections bfd_generic_merge_sections
1395    
1396    #define _bfd_ecoff_bfd_is_group_section bfd_generic_is_group_section
1397  #define _bfd_ecoff_bfd_discard_group bfd_generic_discard_group  #define _bfd_ecoff_bfd_discard_group bfd_generic_discard_group
1398    #define _bfd_ecoff_section_already_linked \
1399      _bfd_generic_section_already_linked
1400    
1401  extern const bfd_target ecoff_big_vec;  extern const bfd_target ecoff_big_vec;
1402    

Legend:
Removed from v.1.1.1.1  
changed lines
  Added in v.1.1.1.1.20.1

savannah-hackers-public@gnu.org
ViewVC Help
Powered by ViewVC 1.1.26