Back to index

cell-binutils  2.17cvs20070401
pe-mips.c
Go to the documentation of this file.
00001 /* BFD back-end for MIPS PE COFF files.
00002    Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
00003    2000, 2001, 2002, 2003, 2004, 2005, 2007 Free Software Foundation, Inc.
00004    Modified from coff-i386.c by DJ Delorie, dj@cygnus.com
00005 
00006    This file is part of BFD, the Binary File Descriptor library.
00007 
00008    This program is free software; you can redistribute it and/or modify
00009    it under the terms of the GNU General Public License as published by
00010    the Free Software Foundation; either version 2 of the License, or
00011    (at your option) any later version.
00012 
00013    This program is distributed in the hope that it will be useful,
00014    but WITHOUT ANY WARRANTY; without even the implied warranty of
00015    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016    GNU General Public License for more details.
00017 
00018    You should have received a copy of the GNU General Public License
00019    along with this program; if not, write to the Free Software
00020    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
00021 
00022 #define COFF_WITH_PE
00023 #define COFF_LONG_SECTION_NAMES
00024 #define PCRELOFFSET TRUE
00025 
00026 #include "bfd.h"
00027 #include "sysdep.h"
00028 #include "libbfd.h"
00029 #include "coff/mipspe.h"
00030 #include "coff/internal.h"
00031 #include "coff/pe.h"
00032 #include "libcoff.h"
00033 
00034 #define COFF_DEFAULT_SECTION_ALIGNMENT_POWER 2
00035 /* The page size is a guess based on ELF.  */
00036 
00037 #define COFF_PAGE_SIZE 0x1000
00038 
00039 /* For some reason when using mips COFF the value stored in the .text
00040    section for a reference to a common symbol is the value itself plus
00041    any desired offset.  Ian Taylor, Cygnus Support.  */
00042 
00043 /* If we are producing relocatable output, we need to do some
00044    adjustments to the object file that are not done by the
00045    bfd_perform_relocation function.  This function is called by every
00046    reloc type to make any required adjustments.  */
00047 
00048 static bfd_reloc_status_type
00049 coff_mips_reloc (bfd *abfd,
00050                arelent *reloc_entry,
00051                asymbol *symbol,
00052                void * data,
00053                asection *input_section ATTRIBUTE_UNUSED,
00054                bfd *output_bfd,
00055                char **error_message ATTRIBUTE_UNUSED)
00056 {
00057   symvalue diff;
00058 
00059   if (output_bfd == NULL)
00060     return bfd_reloc_continue;
00061 
00062   if (bfd_is_com_section (symbol->section))
00063     {
00064 #ifndef COFF_WITH_PE
00065       /* We are relocating a common symbol.  The current value in the
00066         object file is ORIG + OFFSET, where ORIG is the value of the
00067         common symbol as seen by the object file when it was compiled
00068         (this may be zero if the symbol was undefined) and OFFSET is
00069         the offset into the common symbol (normally zero, but may be
00070         non-zero when referring to a field in a common structure).
00071         ORIG is the negative of reloc_entry->addend, which is set by
00072         the CALC_ADDEND macro below.  We want to replace the value in
00073         the object file with NEW + OFFSET, where NEW is the value of
00074         the common symbol which we are going to put in the final
00075         object file.  NEW is symbol->value.  */
00076       diff = symbol->value + reloc_entry->addend;
00077 #else
00078       /* In PE mode, we do not offset the common symbol.  */
00079       diff = reloc_entry->addend;
00080 #endif
00081     }
00082   else
00083     /* For some reason bfd_perform_relocation always effectively
00084        ignores the addend for a COFF target when producing
00085        relocatable output.  This seems to be always wrong for 386
00086        COFF, so we handle the addend here instead.  */
00087     diff = reloc_entry->addend;
00088 
00089 #define DOIT(x) \
00090   x = ((x & ~howto->dst_mask) | (((x & howto->src_mask) + (diff >> howto->rightshift)) & howto->dst_mask))
00091 
00092     if (diff != 0)
00093       {
00094        reloc_howto_type *howto = reloc_entry->howto;
00095        unsigned char *addr = (unsigned char *) data + reloc_entry->address;
00096 
00097        switch (howto->size)
00098          {
00099          case 0:
00100            {
00101              char x = bfd_get_8 (abfd, addr);
00102 
00103              DOIT (x);
00104              bfd_put_8 (abfd, x, addr);
00105            }
00106            break;
00107 
00108          case 1:
00109            {
00110              short x = bfd_get_16 (abfd, addr);
00111 
00112              DOIT (x);
00113              bfd_put_16 (abfd, (bfd_vma) x, addr);
00114            }
00115            break;
00116 
00117          case 2:
00118            {
00119              long x = bfd_get_32 (abfd, addr);
00120 
00121              DOIT (x);
00122              bfd_put_32 (abfd, (bfd_vma) x, addr);
00123            }
00124            break;
00125 
00126          default:
00127            abort ();
00128          }
00129       }
00130 
00131   /* Now let bfd_perform_relocation finish everything up.  */
00132   return bfd_reloc_continue;
00133 }
00134 
00135 #ifdef COFF_WITH_PE
00136 /* Return TRUE if this relocation should
00137    appear in the output .reloc section.  */
00138 
00139 static bfd_boolean
00140 in_reloc_p (bfd * abfd ATTRIBUTE_UNUSED, reloc_howto_type *howto)
00141 {
00142   return ! howto->pc_relative && howto->type != MIPS_R_RVA;
00143 }
00144 #endif
00145 
00146 #ifndef PCRELOFFSET
00147 #define PCRELOFFSET FALSE
00148 #endif
00149 
00150 static reloc_howto_type howto_table[] =
00151 {
00152   /* Reloc type 0 is ignored.  The reloc reading code ensures that
00153      this is a reference to the .abs section, which will cause
00154      bfd_perform_relocation to do nothing.  */
00155   HOWTO (MIPS_R_ABSOLUTE,   /* Type.  */
00156         0,                  /* Rightshift.  */
00157         0,                  /* Size (0 = byte, 1 = short, 2 = long).  */
00158         8,                  /* Bitsize.  */
00159         FALSE,                     /* PC_relative.  */
00160         0,                  /* Bitpos. */
00161         complain_overflow_dont, /* Complain_on_overflow. */
00162         0,                  /* Special_function. */
00163         "IGNORE",           /* Name. */
00164         FALSE,                     /* Partial_inplace. */
00165         0,                  /* Src_mask. */
00166         0,                  /* Dst_mask. */
00167         FALSE),             /* Pcrel_offset. */
00168 
00169   /* A 16 bit reference to a symbol, normally from a data section.  */
00170   HOWTO (MIPS_R_REFHALF,    /* Type.  */
00171         0,                  /* Rightshift.  */
00172         1,                  /* Size (0 = byte, 1 = short, 2 = long).  */
00173         16,                 /* Bitsize.  */
00174         FALSE,                     /* PC_relative.  */
00175         0,                  /* Bitpos. */
00176         complain_overflow_bitfield, /* Complain_on_overflow. */
00177         coff_mips_reloc,    /* Special_function. */
00178         "REFHALF",          /* Name. */
00179         TRUE,               /* Partial_inplace. */
00180         0xffff,             /* Src_mask. */
00181         0xffff,             /* Dst_mask. */
00182         FALSE),             /* Pcrel_offset. */
00183 
00184   /* A 32 bit reference to a symbol, normally from a data section.  */
00185   HOWTO (MIPS_R_REFWORD,    /* Type.  */
00186         0,                  /* Rightshift.  */
00187         2,                  /* Size (0 = byte, 1 = short, 2 = long).  */
00188         32,                 /* Bitsize.  */
00189         FALSE,                     /* PC_relative.  */
00190         0,                  /* Bitpos. */
00191         complain_overflow_bitfield, /* Complain_on_overflow. */
00192         coff_mips_reloc,    /* Special_function. */
00193         "REFWORD",          /* Name. */
00194         TRUE,               /* Partial_inplace. */
00195         0xffffffff,         /* Src_mask. */
00196         0xffffffff,         /* Dst_mask. */
00197         FALSE),             /* Pcrel_offset. */
00198 
00199   /* A 26 bit absolute jump address.  */
00200   HOWTO (MIPS_R_JMPADDR,    /* Type.  */
00201         2,                  /* Rightshift.  */
00202         2,                  /* Size (0 = byte, 1 = short, 2 = long).  */
00203         26,                 /* Bitsize.  */
00204         FALSE,                     /* PC_relative.  */
00205         0,                  /* Bitpos. */
00206         complain_overflow_dont, /* Complain_on_overflow. */
00207                             /* This needs complex overflow
00208                                detection, because the upper four
00209                                bits must match the PC.  */
00210         coff_mips_reloc,    /* Special_function. */
00211         "JMPADDR",          /* Name. */
00212         TRUE,               /* Partial_inplace. */
00213         0x3ffffff,          /* Src_mask. */
00214         0x3ffffff,          /* Dst_mask. */
00215         FALSE),             /* Pcrel_offset. */
00216 
00217   /* The high 16 bits of a symbol value.  Handled by the function
00218      mips_refhi_reloc.  */
00219   HOWTO (MIPS_R_REFHI,             /* Type.  */
00220         16,                 /* Rightshift.  */
00221         2,                  /* Size (0 = byte, 1 = short, 2 = long).  */
00222         16,                 /* Bitsize.  */
00223         FALSE,                     /* PC_relative.  */
00224         0,                  /* Bitpos. */
00225         complain_overflow_bitfield, /* Complain_on_overflow. */
00226         coff_mips_reloc,    /* Special_function. */
00227         "REFHI",            /* Name. */
00228         TRUE,               /* Partial_inplace. */
00229         0xffff,             /* Src_mask. */
00230         0xffff,             /* Dst_mask. */
00231         FALSE),             /* Pcrel_offset. */
00232 
00233   /* The low 16 bits of a symbol value.  */
00234   HOWTO (MIPS_R_REFLO,             /* Type.  */
00235         0,                  /* Rightshift.  */
00236         2,                  /* Size (0 = byte, 1 = short, 2 = long).  */
00237         16,                 /* Bitsize.  */
00238         FALSE,                     /* PC_relative.  */
00239         0,                  /* Bitpos. */
00240         complain_overflow_dont, /* Complain_on_overflow. */
00241         coff_mips_reloc,    /* Special_function. */
00242         "REFLO",            /* Name. */
00243         TRUE,               /* Partial_inplace. */
00244         0xffff,             /* Src_mask. */
00245         0xffff,             /* Dst_mask. */
00246         FALSE),             /* Pcrel_offset. */
00247 
00248   /* A reference to an offset from the gp register.  Handled by the
00249      function mips_gprel_reloc.  */
00250   HOWTO (MIPS_R_GPREL,             /* Type.  */
00251         0,                  /* Rightshift.  */
00252         2,                  /* Size (0 = byte, 1 = short, 2 = long).  */
00253         16,                 /* Bitsize.  */
00254         FALSE,                     /* PC_relative.  */
00255         0,                  /* Bitpos. */
00256         complain_overflow_signed, /* Complain_on_overflow. */
00257         coff_mips_reloc,    /* Special_function. */
00258         "GPREL",            /* Name. */
00259         TRUE,               /* Partial_inplace. */
00260         0xffff,             /* Src_mask. */
00261         0xffff,             /* Dst_mask. */
00262         FALSE),             /* Pcrel_offset. */
00263 
00264   /* A reference to a literal using an offset from the gp register.
00265      Handled by the function mips_gprel_reloc.  */
00266   HOWTO (MIPS_R_LITERAL,    /* Type.  */
00267         0,                  /* Rightshift.  */
00268         2,                  /* Size (0 = byte, 1 = short, 2 = long).  */
00269         16,                 /* Bitsize.  */
00270         FALSE,                     /* PC_relative.  */
00271         0,                  /* Bitpos. */
00272         complain_overflow_signed, /* Complain_on_overflow. */
00273         coff_mips_reloc,    /* Special_function. */
00274         "LITERAL",          /* Name. */
00275         TRUE,               /* Partial_inplace. */
00276         0xffff,             /* Src_mask. */
00277         0xffff,             /* Dst_mask. */
00278         FALSE),             /* Pcrel_offset. */
00279 
00280   EMPTY_HOWTO (8),
00281   EMPTY_HOWTO (9),
00282   EMPTY_HOWTO (10),
00283   EMPTY_HOWTO (11),
00284   EMPTY_HOWTO (12),
00285   EMPTY_HOWTO (13),
00286   EMPTY_HOWTO (14),
00287   EMPTY_HOWTO (15),
00288   EMPTY_HOWTO (16),
00289   EMPTY_HOWTO (17),
00290   EMPTY_HOWTO (18),
00291   EMPTY_HOWTO (19),
00292   EMPTY_HOWTO (20),
00293   EMPTY_HOWTO (21),
00294   EMPTY_HOWTO (22),
00295   EMPTY_HOWTO (23),
00296   EMPTY_HOWTO (24),
00297   EMPTY_HOWTO (25),
00298   EMPTY_HOWTO (26),
00299   EMPTY_HOWTO (27),
00300   EMPTY_HOWTO (28),
00301   EMPTY_HOWTO (29),
00302   EMPTY_HOWTO (30),
00303   EMPTY_HOWTO (31),
00304   EMPTY_HOWTO (32),
00305   EMPTY_HOWTO (33),
00306   HOWTO (MIPS_R_RVA,            /* Type.  */
00307         0,                    /* Rightshift.  */
00308         2,                    /* Size (0 = byte, 1 = short, 2 = long).  */
00309         32,                   /* Bitsize.  */
00310         FALSE,                       /* PC_relative.  */
00311         0,                    /* Bitpos. */
00312         complain_overflow_bitfield, /* Complain_on_overflow. */
00313         coff_mips_reloc,       /* Special_function. */
00314         "rva32",             /* Name. */
00315         TRUE,                 /* Partial_inplace. */
00316         0xffffffff,            /* Src_mask. */
00317         0xffffffff,            /* Dst_mask. */
00318         FALSE),                /* Pcrel_offset. */
00319   EMPTY_HOWTO (35),
00320   EMPTY_HOWTO (36),
00321   HOWTO (MIPS_R_PAIR,           /* Type.  */
00322         0,                    /* Rightshift.  */
00323         2,                    /* Size (0 = byte, 1 = short, 2 = long).  */
00324         32,                   /* Bitsize.  */
00325         FALSE,                       /* PC_relative.  */
00326         0,                    /* Bitpos. */
00327         complain_overflow_bitfield, /* Complain_on_overflow. */
00328         coff_mips_reloc,       /* Special_function. */
00329         "PAIR",              /* Name. */
00330         TRUE,                 /* Partial_inplace. */
00331         0xffffffff,            /* Src_mask. */
00332         0xffffffff,            /* Dst_mask. */
00333         FALSE),                /* Pcrel_offset. */
00334 };
00335 
00336 /* Turn a howto into a reloc nunmber.  */
00337 
00338 #define SELECT_RELOC(x, howto) { x.r_type = howto->type; }
00339 #define BADMAG(x)              MIPSBADMAG (x)
00340 
00341 /* Customize coffcode.h.  */
00342 #define MIPS 1
00343 
00344 #define RTYPE2HOWTO(cache_ptr, dst) \
00345            (cache_ptr)->howto = howto_table + (dst)->r_type;
00346 
00347 /* Compute the addend of a reloc.  If the reloc is to a common symbol,
00348    the object file contains the value of the common symbol.  By the
00349    time this is called, the linker may be using a different symbol
00350    from a different object file with a different value.  Therefore, we
00351    hack wildly to locate the original symbol from this file so that we
00352    can make the correct adjustment.  This macro sets coffsym to the
00353    symbol from the original file, and uses it to set the addend value
00354    correctly.  If this is not a common symbol, the usual addend
00355    calculation is done, except that an additional tweak is needed for
00356    PC relative relocs.
00357    FIXME: This macro refers to symbols and asect; these are from the
00358    calling function, not the macro arguments.  */
00359 
00360 #define CALC_ADDEND(abfd, ptr, reloc, cache_ptr)        \
00361   {                                                     \
00362     coff_symbol_type *coffsym = NULL;                          \
00363     if (ptr && bfd_asymbol_bfd (ptr) != abfd)                  \
00364       coffsym = (obj_symbols (abfd)                            \
00365                 + (cache_ptr->sym_ptr_ptr - symbols));         \
00366     else if (ptr)                                       \
00367       coffsym = coff_symbol_from (abfd, ptr);                  \
00368     if (coffsym != NULL                                        \
00369        && coffsym->native->u.syment.n_scnum == 0)              \
00370       cache_ptr->addend = - coffsym->native->u.syment.n_value; \
00371     else if (ptr && bfd_asymbol_bfd (ptr) == abfd              \
00372             && ptr->section != NULL)                           \
00373       cache_ptr->addend = - (ptr->section->vma + ptr->value);  \
00374     else                                                \
00375       cache_ptr->addend = 0;                                   \
00376     if (ptr && howto_table[reloc.r_type].pc_relative)          \
00377       cache_ptr->addend += asect->vma;                         \
00378   }
00379 
00380 /* Convert an rtype to howto for the COFF backend linker.  */
00381 
00382 static reloc_howto_type *
00383 coff_mips_rtype_to_howto (bfd *abfd ATTRIBUTE_UNUSED,
00384                        asection *sec,
00385                        struct internal_reloc *rel,
00386                        struct coff_link_hash_entry *h,
00387                        struct internal_syment *sym,
00388                        bfd_vma *addendp)
00389 {
00390 
00391   reloc_howto_type *howto;
00392 
00393   howto = howto_table + rel->r_type;
00394 
00395 #ifdef COFF_WITH_PE
00396   *addendp = 0;
00397 #endif
00398 
00399   if (howto->pc_relative)
00400     *addendp += sec->vma;
00401 
00402   if (sym != NULL && sym->n_scnum == 0 && sym->n_value != 0)
00403     {
00404       /* This is a common symbol.  The section contents include the
00405         size (sym->n_value) as an addend.  The relocate_section
00406         function will be adding in the final value of the symbol.  We
00407         need to subtract out the current size in order to get the
00408         correct result.  */
00409 
00410       BFD_ASSERT (h != NULL);
00411 
00412 #ifndef COFF_WITH_PE
00413       /* I think we *do* want to bypass this.  If we don't, I have
00414         seen some data parameters get the wrong relocation address.
00415         If I link two versions with and without this section bypassed
00416         and then do a binary comparison, the addresses which are
00417         different can be looked up in the map.  The case in which
00418         this section has been bypassed has addresses which correspond
00419         to values I can find in the map.  */
00420       *addendp -= sym->n_value;
00421 #endif
00422     }
00423 
00424 #ifndef COFF_WITH_PE
00425   /* If the output symbol is common (in which case this must be a
00426      relocatable link), we need to add in the final size of the
00427      common symbol.  */
00428   if (h != NULL && h->root.type == bfd_link_hash_common)
00429     *addendp += h->root.u.c.size;
00430 #endif
00431 
00432 #ifdef COFF_WITH_PE
00433   if (howto->pc_relative)
00434     {
00435       *addendp -= 4;
00436 
00437       /* If the symbol is defined, then the generic code is going to
00438          add back the symbol value in order to cancel out an
00439          adjustment it made to the addend.  However, we set the addend
00440          to 0 at the start of this function.  We need to adjust here,
00441          to avoid the adjustment the generic code will make.  FIXME:
00442          This is getting a bit hackish.  */
00443       if (sym != NULL && sym->n_scnum != 0)
00444        *addendp -= sym->n_value;
00445     }
00446 
00447   if (rel->r_type == MIPS_R_RVA)
00448     *addendp -= pe_data (sec->output_section->owner)->pe_opthdr.ImageBase;
00449 #endif
00450 
00451   return howto;
00452 }
00453 
00454 #define coff_rtype_to_howto         coff_mips_rtype_to_howto
00455 #define coff_bfd_reloc_type_lookup  coff_mips_reloc_type_lookup
00456 #define coff_bfd_reloc_name_lookup coff_mips_reloc_name_lookup
00457 
00458 /* Get the howto structure for a generic reloc type.  */
00459 
00460 static reloc_howto_type *
00461 coff_mips_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED,
00462                           bfd_reloc_code_real_type code)
00463 {
00464   int mips_type;
00465 
00466   switch (code)
00467     {
00468     case BFD_RELOC_16:
00469       mips_type = MIPS_R_REFHALF;
00470       break;
00471     case BFD_RELOC_32:
00472     case BFD_RELOC_CTOR:
00473       mips_type = MIPS_R_REFWORD;
00474       break;
00475     case BFD_RELOC_MIPS_JMP:
00476       mips_type = MIPS_R_JMPADDR;
00477       break;
00478     case BFD_RELOC_HI16_S:
00479       mips_type = MIPS_R_REFHI;
00480       break;
00481     case BFD_RELOC_LO16:
00482       mips_type = MIPS_R_REFLO;
00483       break;
00484     case BFD_RELOC_GPREL16:
00485       mips_type = MIPS_R_GPREL;
00486       break;
00487     case BFD_RELOC_MIPS_LITERAL:
00488       mips_type = MIPS_R_LITERAL;
00489       break;
00490     case BFD_RELOC_RVA:
00491       mips_type = MIPS_R_RVA;
00492       break;
00493     default:
00494       return NULL;
00495     }
00496 
00497   return & howto_table [mips_type];
00498 }
00499 
00500 static reloc_howto_type *
00501 coff_mips_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED,
00502                           const char *r_name)
00503 {
00504   unsigned int i;
00505 
00506   for (i = 0;
00507        i < sizeof (howto_table) / sizeof (howto_table[0]);
00508        i++)
00509     if (howto_table[i].name != NULL
00510        && strcasecmp (howto_table[i].name, r_name) == 0)
00511       return &howto_table[i];
00512 
00513   return NULL;
00514 }
00515 
00516 static void
00517 mips_swap_reloc_in (bfd * abfd, void * src, void * dst)
00518 {
00519   static struct internal_reloc pair_prev;
00520   RELOC *reloc_src = (RELOC *) src;
00521   struct internal_reloc *reloc_dst = (struct internal_reloc *) dst;
00522 
00523   reloc_dst->r_vaddr = H_GET_32 (abfd, reloc_src->r_vaddr);
00524   reloc_dst->r_symndx = H_GET_S32 (abfd, reloc_src->r_symndx);
00525   reloc_dst->r_type = H_GET_16 (abfd, reloc_src->r_type);
00526   reloc_dst->r_size = 0;
00527   reloc_dst->r_extern = 0;
00528   reloc_dst->r_offset = 0;
00529 
00530   switch (reloc_dst->r_type)
00531   {
00532   case MIPS_R_REFHI:
00533     pair_prev = *reloc_dst;
00534     break;
00535   case MIPS_R_PAIR:
00536     reloc_dst->r_offset = reloc_dst->r_symndx;
00537     if (reloc_dst->r_offset & 0x8000)
00538       reloc_dst->r_offset -= 0x10000;
00539     reloc_dst->r_symndx = pair_prev.r_symndx;
00540     break;
00541   }
00542 }
00543 
00544 static unsigned int
00545 mips_swap_reloc_out (bfd * abfd, void * src, void * dst)
00546 {
00547   static int prev_offset = 1;
00548   static bfd_vma prev_addr = 0;
00549   struct internal_reloc *reloc_src = (struct internal_reloc *)src;
00550   struct external_reloc *reloc_dst = (struct external_reloc *)dst;
00551 
00552   switch (reloc_src->r_type)
00553     {
00554     case MIPS_R_REFHI:
00555       prev_addr = reloc_src->r_vaddr;
00556       prev_offset = reloc_src->r_offset;
00557       break;
00558     case MIPS_R_REFLO:
00559       if (reloc_src->r_vaddr == prev_addr)
00560        {
00561          /* FIXME: only slightly hackish.  If we see a REFLO pointing to
00562             the same address as a REFHI, we assume this is the matching
00563             PAIR reloc and output it accordingly.  The symndx is really
00564             the low 16 bits of the addend */
00565          H_PUT_32 (abfd, reloc_src->r_vaddr, reloc_dst->r_vaddr);
00566          H_PUT_32 (abfd, reloc_src->r_symndx, reloc_dst->r_symndx);
00567          H_PUT_16 (abfd, MIPS_R_PAIR, reloc_dst->r_type);
00568          return RELSZ;
00569        }
00570       break;
00571     }
00572 
00573   H_PUT_32 (abfd, reloc_src->r_vaddr, reloc_dst->r_vaddr);
00574   H_PUT_32 (abfd, reloc_src->r_symndx, reloc_dst->r_symndx);
00575 
00576   H_PUT_16 (abfd, reloc_src->r_type, reloc_dst->r_type);
00577   return RELSZ;
00578 }
00579 
00580 #define coff_swap_reloc_in   mips_swap_reloc_in
00581 #define coff_swap_reloc_out  mips_swap_reloc_out
00582 #define NO_COFF_RELOCS
00583 
00584 static bfd_boolean
00585 coff_pe_mips_relocate_section (bfd *output_bfd,
00586                             struct bfd_link_info *info,
00587                             bfd *input_bfd,
00588                             asection *input_section,
00589                             bfd_byte *contents,
00590                             struct internal_reloc *relocs,
00591                             struct internal_syment *syms,
00592                             asection **sections)
00593 {
00594   bfd_vma gp;
00595   bfd_boolean gp_undefined;
00596   size_t adjust;
00597   struct internal_reloc *rel;
00598   struct internal_reloc *rel_end;
00599   unsigned int i;
00600   bfd_boolean got_lo;
00601 
00602   if (info->relocatable)
00603     {
00604       (*_bfd_error_handler)
00605        (_("%B: `ld -r' not supported with PE MIPS objects\n"), input_bfd);
00606       bfd_set_error (bfd_error_bad_value);
00607       return FALSE;
00608     }
00609 
00610   BFD_ASSERT (input_bfd->xvec->byteorder
00611              == output_bfd->xvec->byteorder);
00612 
00613   gp = _bfd_get_gp_value (output_bfd);
00614   gp_undefined = (gp == 0) ? TRUE : FALSE;
00615   got_lo = FALSE;
00616   adjust = 0;
00617   rel = relocs;
00618   rel_end = rel + input_section->reloc_count;
00619 
00620   for (i = 0; rel < rel_end; rel++, i++)
00621     {
00622       long symndx;
00623       struct coff_link_hash_entry *h;
00624       struct internal_syment *sym;
00625       bfd_vma addend = 0;
00626       bfd_vma val, tmp, targ, src, low;
00627       reloc_howto_type *howto;
00628       unsigned char *mem = contents + rel->r_vaddr;
00629 
00630       symndx = rel->r_symndx;
00631 
00632       if (symndx == -1)
00633        {
00634          h = NULL;
00635          sym = NULL;
00636        }
00637       else
00638        {
00639          h = obj_coff_sym_hashes (input_bfd)[symndx];
00640          sym = syms + symndx;
00641        }
00642 
00643       /* COFF treats common symbols in one of two ways.  Either the
00644          size of the symbol is included in the section contents, or it
00645          is not.  We assume that the size is not included, and force
00646          the rtype_to_howto function to adjust the addend as needed.  */
00647 
00648       if (sym != NULL && sym->n_scnum != 0)
00649        addend = - sym->n_value;
00650       else
00651        addend = 0;
00652 
00653       howto = bfd_coff_rtype_to_howto (input_bfd, input_section, rel, h,
00654                                    sym, &addend);
00655       if (howto == NULL)
00656        return FALSE;
00657 
00658       /* If we are doing a relocatable link, then we can just ignore
00659          a PC relative reloc that is pcrel_offset.  It will already
00660          have the correct value.  If this is not a relocatable link,
00661          then we should ignore the symbol value.  */
00662       if (howto->pc_relative && howto->pcrel_offset)
00663        {
00664          if (info->relocatable)
00665            continue;
00666          if (sym != NULL && sym->n_scnum != 0)
00667            addend += sym->n_value;
00668        }
00669 
00670       val = 0;
00671 
00672       if (h == NULL)
00673        {
00674          asection *sec;
00675 
00676          if (symndx == -1)
00677            {
00678              sec = bfd_abs_section_ptr;
00679              val = 0;
00680            }
00681          else
00682            {
00683              sec = sections[symndx];
00684               val = (sec->output_section->vma
00685                    + sec->output_offset
00686                    + sym->n_value);
00687              if (! obj_pe (input_bfd))
00688               val -= sec->vma;
00689            }
00690        }
00691       else
00692        {
00693          if (h->root.type == bfd_link_hash_defined
00694              || h->root.type == bfd_link_hash_defweak)
00695            {
00696              asection *sec;
00697 
00698              sec = h->root.u.def.section;
00699              val = (h->root.u.def.value
00700                    + sec->output_section->vma
00701                    + sec->output_offset);
00702              }
00703 
00704          else if (! info->relocatable)
00705            {
00706              if (! ((*info->callbacks->undefined_symbol)
00707                    (info, h->root.root.string, input_bfd, input_section,
00708                     rel->r_vaddr - input_section->vma, TRUE)))
00709               return FALSE;
00710            }
00711        }
00712 
00713       src = rel->r_vaddr + input_section->output_section->vma
00714        + input_section->output_offset;
00715 
00716       /* OK, at this point the following variables are set up:
00717           src = VMA of the memory we're fixing up
00718           mem = pointer to memory we're fixing up
00719           val = VMA of what we need to refer to.  */
00720 
00721 #define UI(x) (*_bfd_error_handler) (_("%B: unimplemented %s\n"), \
00722                                  input_bfd, x); \
00723              bfd_set_error (bfd_error_bad_value);
00724 
00725       switch (rel->r_type)
00726        {
00727        case MIPS_R_ABSOLUTE:
00728          /* Ignore these.  */
00729          break;
00730 
00731        case MIPS_R_REFHALF:
00732          UI ("refhalf");
00733          break;
00734 
00735        case MIPS_R_REFWORD:
00736          tmp = bfd_get_32 (input_bfd, mem);
00737          /* printf ("refword: src=%08x targ=%08x+%08x\n", src, tmp, val); */
00738          tmp += val;
00739          bfd_put_32 (input_bfd, tmp, mem);
00740          break;
00741 
00742        case MIPS_R_JMPADDR:
00743          tmp = bfd_get_32 (input_bfd, mem);
00744          targ = val + (tmp & 0x03ffffff) * 4;
00745          if ((src & 0xf0000000) != (targ & 0xf0000000))
00746            {
00747              (*_bfd_error_handler) (_("%B: jump too far away\n"), input_bfd);
00748              bfd_set_error (bfd_error_bad_value);
00749              return FALSE;
00750            }
00751          tmp &= 0xfc000000;
00752          tmp |= (targ / 4) & 0x3ffffff;
00753          bfd_put_32 (input_bfd, tmp, mem);
00754          break;
00755 
00756        case MIPS_R_REFHI:
00757          tmp = bfd_get_32 (input_bfd, mem);
00758          switch (rel[1].r_type)
00759            {
00760            case MIPS_R_PAIR:
00761              /* MS PE object */
00762              targ = val + rel[1].r_offset + ((tmp & 0xffff) << 16);
00763              break;
00764            case MIPS_R_REFLO:
00765              /* GNU COFF object */
00766              low = bfd_get_32 (input_bfd, contents + rel[1].r_vaddr);
00767              low &= 0xffff;
00768              if (low & 0x8000)
00769               low -= 0x10000;
00770              targ = val + low + ((tmp & 0xffff) << 16);
00771              break;
00772            default:
00773              (*_bfd_error_handler) (_("%B: bad pair/reflo after refhi\n"),
00774                                  input_bfd);
00775              bfd_set_error (bfd_error_bad_value);
00776              return FALSE;
00777            }
00778          tmp &= 0xffff0000;
00779          tmp |= (targ >> 16) & 0xffff;
00780          bfd_put_32 (input_bfd, tmp, mem);
00781          break;
00782 
00783        case MIPS_R_REFLO:
00784          tmp = bfd_get_32 (input_bfd, mem);
00785          targ = val + (tmp & 0xffff);
00786          /* printf ("refword: src=%08x targ=%08x\n", src, targ); */
00787          tmp &= 0xffff0000;
00788          tmp |= targ & 0xffff;
00789          bfd_put_32 (input_bfd, tmp, mem);
00790          break;
00791 
00792        case MIPS_R_GPREL:
00793        case MIPS_R_LITERAL:
00794          UI ("gprel");
00795          break;
00796 
00797        case MIPS_R_SECTION:
00798          UI ("section");
00799          break;
00800 
00801        case MIPS_R_SECREL:
00802          UI ("secrel");
00803          break;
00804 
00805        case MIPS_R_SECRELLO:
00806          UI ("secrello");
00807          break;
00808 
00809        case MIPS_R_SECRELHI:
00810          UI ("secrelhi");
00811          break;
00812 
00813        case MIPS_R_RVA:
00814          tmp = bfd_get_32 (input_bfd, mem);
00815          /* printf ("rva: src=%08x targ=%08x+%08x\n", src, tmp, val); */
00816          tmp += val
00817            - pe_data (input_section->output_section->owner)->pe_opthdr.ImageBase;
00818          bfd_put_32 (input_bfd, tmp, mem);
00819          break;
00820 
00821        case MIPS_R_PAIR:
00822          /* ignore these */
00823          break;
00824        }
00825     }
00826 
00827   return TRUE;
00828 }
00829 
00830 #define coff_relocate_section coff_pe_mips_relocate_section
00831 
00832 #ifdef TARGET_UNDERSCORE
00833 
00834 /* If mips gcc uses underscores for symbol names, then it does not use
00835    a leading dot for local labels, so if TARGET_UNDERSCORE is defined
00836    we treat all symbols starting with L as local.  */
00837 
00838 static bfd_boolean
00839 coff_mips_is_local_label_name (bfd *abfd, const char *name)
00840 {
00841   if (name[0] == 'L')
00842     return TRUE;
00843 
00844   return _bfd_coff_is_local_label_name (abfd, name);
00845 }
00846 
00847 #define coff_bfd_is_local_label_name coff_mips_is_local_label_name
00848 
00849 #endif /* TARGET_UNDERSCORE */
00850 
00851 #define COFF_NO_HACK_SCNHDR_SIZE
00852 
00853 #include "coffcode.h"
00854 
00855 const bfd_target
00856 #ifdef TARGET_SYM
00857   TARGET_SYM =
00858 #else
00859   mipslpe_vec =
00860 #endif
00861 {
00862 #ifdef TARGET_NAME
00863   TARGET_NAME,
00864 #else
00865   "pe-mips",                /* Name.  */
00866 #endif
00867   bfd_target_coff_flavour,
00868   BFD_ENDIAN_LITTLE,        /* Data byte order is little.  */
00869   BFD_ENDIAN_LITTLE,        /* Header byte order is little.  */
00870 
00871   (HAS_RELOC | EXEC_P |            /* Object flags.  */
00872    HAS_LINENO | HAS_DEBUG |
00873    HAS_SYMS | HAS_LOCALS | WP_TEXT | D_PAGED),
00874 
00875 #ifndef COFF_WITH_PE
00876   (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC /* Section flags.  */
00877    | SEC_CODE | SEC_DATA),
00878 #else
00879   (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC /* Section flags.  */
00880    | SEC_CODE | SEC_DATA
00881    | SEC_LINK_ONCE | SEC_LINK_DUPLICATES),
00882 #endif
00883 
00884 #ifdef TARGET_UNDERSCORE
00885   TARGET_UNDERSCORE,        /* Leading underscore.  */
00886 #else
00887   0,                        /* leading underscore */
00888 #endif
00889   '/',                      /* AR_pad_char.  */
00890   15,                       /* AR_max_namelen.  */
00891 
00892   bfd_getl64, bfd_getl_signed_64, bfd_putl64,
00893      bfd_getl32, bfd_getl_signed_32, bfd_putl32,
00894      bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* Data.  */
00895   bfd_getl64, bfd_getl_signed_64, bfd_putl64,
00896      bfd_getl32, bfd_getl_signed_32, bfd_putl32,
00897      bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* Headers.  */
00898 
00899   /* Note that we allow an object file to be treated as a core file as well.  */
00900   {_bfd_dummy_target, coff_object_p, /* bfd_check_format.  */
00901    bfd_generic_archive_p, coff_object_p},
00902   {bfd_false, coff_mkobject, _bfd_generic_mkarchive, /* bfd_set_format.  */
00903    bfd_false},
00904   {bfd_false, coff_write_object_contents, /* bfd_write_contents.  */
00905    _bfd_write_archive_contents, bfd_false},
00906 
00907   BFD_JUMP_TABLE_GENERIC (coff),
00908   BFD_JUMP_TABLE_COPY (coff),
00909   BFD_JUMP_TABLE_CORE (_bfd_nocore),
00910   BFD_JUMP_TABLE_ARCHIVE (_bfd_archive_coff),
00911   BFD_JUMP_TABLE_SYMBOLS (coff),
00912   BFD_JUMP_TABLE_RELOCS (coff),
00913   BFD_JUMP_TABLE_WRITE (coff),
00914   BFD_JUMP_TABLE_LINK (coff),
00915   BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic),
00916 
00917   NULL,
00918 
00919   COFF_SWAP_TABLE
00920 };