Back to index

cell-binutils  2.17cvs20070401
coff-maxq.c
Go to the documentation of this file.
00001 /* BFD back-end for MAXQ COFF binaries.
00002    Copyright 2004, 2007  Free Software Foundation, Inc.
00003 
00004    Contributed by Vineet Sharma (vineets@noida.hcltech.com) Inderpreet S.
00005    (inderpreetb@noida.hcltech.com)
00006 
00007    HCL Technologies Ltd.
00008 
00009    This file is part of BFD, the Binary File Descriptor library.
00010 
00011    This program is free software; you can redistribute it and/or modify it
00012    under the terms of the GNU General Public License as published by the Free 
00013    Software Foundation; either version 2 of the License, or (at your option)
00014    any later version.
00015 
00016    This program is distributed in the hope that it will be useful, but
00017    WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 
00018    or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
00019    for more details.
00020 
00021    You should have received a copy of the GNU General Public License along
00022    with this program; if not, write to the Free Software Foundation, Inc., 
00023    51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
00024 
00025 #include "bfd.h"
00026 #include "sysdep.h"
00027 #include "libbfd.h"
00028 #include "coff/maxq.h"
00029 #include "coff/internal.h"
00030 #include "libcoff.h"
00031 #include "libiberty.h"
00032 
00033 #ifndef MAXQ20
00034 #define MAXQ20 1
00035 #endif
00036 
00037 #define RTYPE2HOWTO(cache_ptr, dst)                                     \
00038   ((cache_ptr)->howto =                                                 \
00039    ((dst)->r_type < 48                                                \
00040     ? howto_table + (((dst)->r_type==47) ? 6: ((dst)->r_type))        \
00041     : NULL))
00042 
00043 #define COFF_DEFAULT_SECTION_ALIGNMENT_POWER (2)
00044 
00045 /* Code to swap in the reloc offset.  */
00046 #define SWAP_IN_RELOC_OFFSET    H_GET_16
00047 #define SWAP_OUT_RELOC_OFFSET   H_PUT_16
00048 
00049 #define SHORT_JUMP           BFD_RELOC_16_PCREL_S2
00050 #define LONG_JUMP            BFD_RELOC_14
00051 #define ABSOLUTE_ADDR_FOR_DATA  BFD_RELOC_24
00052 
00053 /* checks the range of short jump -127 to 128 */
00054 #define IS_SJUMP_RANGE(x) ((x > -128) && (x < 129))
00055 #define HIGH_WORD_MASK    0xff00
00056 #define LOW_WORD_MASK     0x00ff
00057 
00058 static long
00059 get_symbol_value (asymbol *symbol)
00060 {
00061   long relocation = 0;
00062 
00063   if (bfd_is_com_section (symbol->section))
00064     relocation = 0;
00065   else
00066     relocation = symbol->value +
00067       symbol->section->output_section->vma + symbol->section->output_offset;
00068 
00069   return relocation;
00070 }
00071 
00072 /* This function performs all the maxq relocations.
00073    FIXME:  The handling of the addend in the 'BFD_*'
00074    relocations types.  */
00075 
00076 static bfd_reloc_status_type
00077 coff_maxq20_reloc (bfd *      abfd,
00078                  arelent *  reloc_entry,
00079                  asymbol *  symbol_in,
00080                  void *     data,
00081                  asection * input_section ATTRIBUTE_UNUSED,
00082                  bfd *      output_bfd    ATTRIBUTE_UNUSED,
00083                  char **    error_message ATTRIBUTE_UNUSED)
00084 {
00085   unsigned char *addr = NULL;
00086   unsigned long x = 0;
00087   long call_addr = 0;
00088   short addend = 0;
00089   long diff = 0;
00090 
00091   /* If this is an undefined symbol, return error.  */
00092   if (symbol_in->section == &bfd_und_section
00093       && (symbol_in->flags & BSF_WEAK) == 0)
00094     return bfd_reloc_continue;
00095 
00096   if (data && reloc_entry)
00097     {
00098       addr = (unsigned char *) data + reloc_entry->address;
00099       call_addr = call_addr - call_addr;
00100       call_addr = get_symbol_value (symbol_in);
00101 
00102       /* Over here the value val stores the 8 bit/16 bit value. We will put a 
00103          check if we are moving a 16 bit immediate value into an 8 bit
00104          register. In that case we will generate a Upper bytes into PFX[0]
00105          and move the lower 8 bits as SRC.  */
00106 
00107       switch (reloc_entry->howto->type)
00108        {
00109          /* BFD_RELOC_16_PCREL_S2 47 Handles all the relative jumps and
00110             calls Note: Every relative jump or call is in words.  */
00111        case SHORT_JUMP:
00112          /* Handle any addend.  */
00113          addend = reloc_entry->addend;
00114 
00115          if (addend > call_addr || addend > 0)
00116            call_addr = symbol_in->section->output_section->vma + addend;
00117          else if (addend < call_addr && addend > 0)
00118            call_addr = call_addr + addend;
00119          else if (addend < 0)
00120            call_addr = call_addr + addend;
00121 
00122          diff = ((call_addr << 1) - (reloc_entry->address << 1));
00123 
00124          if (!IS_SJUMP_RANGE (diff))
00125            {
00126              bfd_perror (_("Can't Make it a Short Jump"));
00127              return bfd_reloc_outofrange;
00128            }
00129 
00130          x = bfd_get_16 (abfd, addr);
00131 
00132          x = x & LOW_WORD_MASK;
00133          x = x | (diff << 8);
00134          bfd_put_16 (abfd, (bfd_vma) x, addr);
00135 
00136          return bfd_reloc_ok;
00137 
00138        case ABSOLUTE_ADDR_FOR_DATA:
00139        case LONG_JUMP:
00140          /* BFD_RELOC_14 Handles intersegment or long jumps which might be
00141             from code to code or code to data segment jumps. Note: When this 
00142             fucntion is called by gas the section flags somehow do not
00143             contain the info about the section type(CODE or DATA). Thus the
00144             user needs to evoke the linker after assembling the files
00145             because the Code-Code relocs are word aligned but code-data are
00146             byte aligned.  */
00147          addend = (reloc_entry->addend - reloc_entry->addend);
00148 
00149          /* Handle any addend.  */
00150          addend = reloc_entry->addend;
00151 
00152          /* For relocation involving multiple file added becomes zero thus
00153             this fails - check for zero added. In another case when we try
00154             to add a stub to a file the addend shows the offset from the
00155             start od this file.  */
00156          addend = 0;
00157 
00158          if (!bfd_is_com_section (symbol_in->section) &&
00159              ((symbol_in->flags & BSF_OLD_COMMON) == 0))
00160            {
00161              if (reloc_entry->addend > symbol_in->value)
00162               addend = reloc_entry->addend - symbol_in->value;
00163 
00164              if ((reloc_entry->addend < symbol_in->value)
00165                 && (reloc_entry->addend != 0))
00166               addend = reloc_entry->addend - symbol_in->value;
00167 
00168              if (reloc_entry->addend == symbol_in->value)
00169               addend = 0;
00170            }
00171 
00172          if (bfd_is_com_section (symbol_in->section) ||
00173              ((symbol_in->flags & BSF_OLD_COMMON) != 0))
00174            addend = reloc_entry->addend;
00175 
00176          if (addend < 0
00177              &&  (call_addr < (long) (addend * (-1))))
00178            addend = 0;
00179 
00180          call_addr += addend;
00181 
00182          /* FIXME: This check does not work well with the assembler,
00183             linker needs to be run always.  */
00184          if ((symbol_in->section->flags & SEC_CODE) == SEC_CODE)
00185            {
00186              /* Convert it into words.  */
00187              call_addr = call_addr >> 1;
00188 
00189              if (call_addr > 0xFFFF)      /* Intersegment Jump.  */
00190               {
00191                 bfd_perror (_("Exceeds Long Jump Range"));
00192                 return bfd_reloc_outofrange;
00193               }
00194            }
00195          else
00196            {
00197              /* case ABSOLUTE_ADDR_FOR_DATA : Resolves any code-data
00198                segemnt relocs. These are NOT word aligned.  */
00199 
00200              if (call_addr > 0xFFFF)      /* Intersegment Jump.  */
00201               {
00202                 bfd_perror (_("Absolute address Exceeds 16 bit Range"));
00203                 return bfd_reloc_outofrange;
00204               }
00205            }
00206 
00207          x = bfd_get_32 (abfd, addr);
00208 
00209          x = (x & 0xFF00FF00);
00210          x = (x | ((call_addr & HIGH_WORD_MASK) >> 8));
00211          x = (x | (call_addr & LOW_WORD_MASK) << 16);
00212 
00213          bfd_put_32 (abfd, (bfd_vma) x, addr);
00214          return bfd_reloc_ok;
00215 
00216        case BFD_RELOC_8:
00217          addend = (reloc_entry->addend - reloc_entry->addend);
00218 
00219          if (!bfd_is_com_section (symbol_in->section) &&
00220              ((symbol_in->flags & BSF_OLD_COMMON) == 0))
00221            {
00222              if (reloc_entry->addend > symbol_in->value)
00223               addend = reloc_entry->addend - symbol_in->value;
00224              if (reloc_entry->addend < symbol_in->value)
00225               addend = reloc_entry->addend - symbol_in->value;
00226              if (reloc_entry->addend == symbol_in->value)
00227               addend = 0;
00228            }
00229 
00230          if (bfd_is_com_section (symbol_in->section) ||
00231              ((symbol_in->flags & BSF_OLD_COMMON) != 0))
00232            addend = reloc_entry->addend;
00233 
00234          if (addend < 0
00235              && (call_addr < (long) (addend * (-1))))
00236            addend = 0;
00237 
00238          if (call_addr + addend > 0xFF)
00239            {
00240              bfd_perror (_("Absolute address Exceeds 8 bit Range"));
00241              return bfd_reloc_outofrange;
00242            }
00243 
00244          x = bfd_get_8 (abfd, addr);
00245          x = x & 0x00;
00246          x = x | (call_addr + addend);
00247 
00248          bfd_put_8 (abfd, (bfd_vma) x, addr);
00249          return bfd_reloc_ok;
00250 
00251        case BFD_RELOC_16:
00252          addend = (reloc_entry->addend - reloc_entry->addend);
00253          if (!bfd_is_com_section (symbol_in->section) &&
00254              ((symbol_in->flags & BSF_OLD_COMMON) == 0))
00255            {
00256              if (reloc_entry->addend > symbol_in->value)
00257               addend = reloc_entry->addend - symbol_in->value;
00258 
00259              if (reloc_entry->addend < symbol_in->value)
00260               addend = reloc_entry->addend - symbol_in->value;
00261 
00262              if (reloc_entry->addend == symbol_in->value)
00263               addend = 0;
00264            }
00265 
00266          if (bfd_is_com_section (symbol_in->section) ||
00267              ((symbol_in->flags & BSF_OLD_COMMON) != 0))
00268            addend = reloc_entry->addend;
00269 
00270          if (addend < 0
00271              && (call_addr < (long) (addend * (-1))))
00272            addend = 0;
00273 
00274          if ((call_addr + addend) > 0xFFFF)
00275            {
00276              bfd_perror (_("Absolute address Exceeds 16 bit Range"));
00277              return bfd_reloc_outofrange;
00278            }
00279          else
00280            {
00281              unsigned short val = (call_addr + addend);
00282 
00283              x = bfd_get_16 (abfd, addr);
00284 
00285              /* LE */
00286              x = (x & 0x0000);     /* Flush garbage value.  */
00287              x = val;
00288              if ((symbol_in->section->flags & SEC_CODE) == SEC_CODE)
00289               x = x >> 1;   /* Convert it into words.  */
00290            }
00291 
00292          bfd_put_16 (abfd, (bfd_vma) x, addr);
00293          return bfd_reloc_ok;
00294 
00295        case BFD_RELOC_32:
00296          addend = (reloc_entry->addend - reloc_entry->addend);
00297 
00298          if (!bfd_is_com_section (symbol_in->section) &&
00299              ((symbol_in->flags & BSF_OLD_COMMON) == 0))
00300            {
00301              if (reloc_entry->addend > symbol_in->value)
00302               addend = reloc_entry->addend - symbol_in->value;
00303              if (reloc_entry->addend < symbol_in->value)
00304               addend = reloc_entry->addend - symbol_in->value;
00305              if (reloc_entry->addend == symbol_in->value)
00306               addend = 0;
00307            }
00308 
00309          if (bfd_is_com_section (symbol_in->section) ||
00310              ((symbol_in->flags & BSF_OLD_COMMON) != 0))
00311            addend = reloc_entry->addend;
00312 
00313          if (addend < 0
00314              && (call_addr < (long) (addend * (-1))))
00315            addend = 0;
00316 
00317          if ((call_addr + addend) < 0)
00318            {
00319              bfd_perror ("Absolute address Exceeds 32 bit Range");
00320              return bfd_reloc_outofrange;
00321            }
00322 
00323          x = bfd_get_32 (abfd, addr);
00324          x = (x & 0x0000);  /* Flush garbage value.  */
00325          x = call_addr + addend;
00326          if ((symbol_in->section->flags & SEC_CODE) == SEC_CODE)
00327            x = x >> 1;      /* Convert it into words.  */
00328 
00329          bfd_put_32 (abfd, (bfd_vma) x, addr);
00330          return bfd_reloc_ok;
00331 
00332        default:
00333          bfd_perror (_("Unrecognized Reloc Type"));
00334          return bfd_reloc_notsupported;
00335        }
00336     }
00337 
00338   return bfd_reloc_notsupported;
00339 }
00340 
00341 static reloc_howto_type howto_table[] =
00342 {
00343   EMPTY_HOWTO (0),
00344   EMPTY_HOWTO (1),
00345   {
00346    BFD_RELOC_32, 0, 1, 8, FALSE, 0, complain_overflow_bitfield,
00347    coff_maxq20_reloc, "32Bit", TRUE, 0x000000ff, 0x000000ff, TRUE
00348   },
00349   {
00350    SHORT_JUMP, 0, 1, 8, FALSE, 0, complain_overflow_bitfield,
00351    coff_maxq20_reloc, "SHORT_JMP", TRUE, 0x000000ff, 0x000000ff, TRUE
00352   },
00353   {
00354    ABSOLUTE_ADDR_FOR_DATA, 0, 2, 32, FALSE, 0, complain_overflow_bitfield,
00355    coff_maxq20_reloc, "INTERSEGMENT_RELOC", TRUE, 0x00000000, 0x00000000,
00356    FALSE
00357   },
00358   {
00359    BFD_RELOC_16, 0, 1, 8, FALSE, 0, complain_overflow_bitfield,
00360    coff_maxq20_reloc, "16Bit", TRUE, 0x000000ff, 0x000000ff, TRUE
00361   },
00362   {
00363    LONG_JUMP, 0, 2, 32, FALSE, 0, complain_overflow_bitfield,
00364    coff_maxq20_reloc, "LONG_JUMP", TRUE, 0x00000000, 0x00000000, FALSE
00365   },
00366   {
00367    BFD_RELOC_8, 0, 1, 8, FALSE, 0, complain_overflow_bitfield,
00368    coff_maxq20_reloc, "8bit", TRUE, 0x000000ff, 0x000000ff, TRUE
00369   },
00370   EMPTY_HOWTO (8),
00371   EMPTY_HOWTO (9),
00372   EMPTY_HOWTO (10),
00373 };
00374 
00375 static reloc_howto_type *
00376 maxq_reloc_type_lookup (bfd * abfd ATTRIBUTE_UNUSED,
00377                      bfd_reloc_code_real_type code)
00378 {
00379   switch (code)
00380     {
00381       /* SHORT JUMP */
00382     case BFD_RELOC_16_PCREL_S2:
00383       return howto_table + 3;
00384       
00385       /* INTERSEGMENT JUMP */
00386     case BFD_RELOC_24:
00387       return howto_table + 4;
00388       
00389       /* BYTE RELOC */
00390     case BFD_RELOC_8:
00391       return howto_table + 7;
00392       
00393       /* WORD RELOC */
00394     case BFD_RELOC_16:
00395       return howto_table + 5;
00396       
00397       /* LONG RELOC */
00398     case BFD_RELOC_32:
00399       return howto_table + 2;
00400       
00401       /* LONG JUMP */
00402     case BFD_RELOC_14:
00403       return howto_table + 6;
00404       
00405     default:
00406       return NULL;
00407     }
00408 }
00409 
00410 static reloc_howto_type *
00411 maxq_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, const char *r_name)
00412 {
00413   unsigned int i;
00414 
00415   for (i = 0; i < sizeof (howto_table) / sizeof (howto_table[0]); i++)
00416     if (howto_table[i].name != NULL
00417        && strcasecmp (howto_table[i].name, r_name) == 0)
00418       return &howto_table[i];
00419 
00420   return NULL;
00421 }
00422 
00423 #define coff_bfd_reloc_type_lookup maxq_reloc_type_lookup
00424 #define coff_bfd_reloc_name_lookup maxq_reloc_name_lookup
00425 
00426 /* Perform any necessary magic to the addend in a reloc entry.  */
00427 #define CALC_ADDEND(abfd, symbol, ext_reloc, cache_ptr) \
00428  cache_ptr->addend =  ext_reloc.r_offset;
00429 
00430 #include "coffcode.h"
00431 
00432 #ifndef TARGET_UNDERSCORE
00433 #define TARGET_UNDERSCORE 1
00434 #endif
00435 
00436 #ifndef EXTRA_S_FLAGS
00437 #define EXTRA_S_FLAGS 0
00438 #endif
00439 
00440 /* Forward declaration for use initialising alternative_target field.  */
00441 CREATE_LITTLE_COFF_TARGET_VEC (maxqcoff_vec, "coff-maxq", 0, EXTRA_S_FLAGS,
00442                             TARGET_UNDERSCORE, NULL, COFF_SWAP_TABLE);
00443