Back to index

cell-binutils  2.17cvs20070401
nlm32-ppc.c
Go to the documentation of this file.
00001 /* Support for 32-bit PowerPC NLM (NetWare Loadable Module)
00002    Copyright 1994, 1995, 1999, 2000, 2001, 2002, 2003, 2004,
00003    2005 Free Software Foundation, Inc.
00004 
00005    This file is part of BFD, the Binary File Descriptor library.
00006 
00007    This program is free software; you can redistribute it and/or modify
00008    it under the terms of the GNU General Public License as published by
00009    the Free Software Foundation; either version 2 of the License, or
00010    (at your option) any later version.
00011 
00012    This program is distributed in the hope that it will be useful,
00013    but WITHOUT ANY WARRANTY; without even the implied warranty of
00014    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015    GNU General Public License for more details.
00016 
00017    You should have received a copy of the GNU General Public License
00018    along with this program; if not, write to the Free Software
00019    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
00020 
00021 #include "bfd.h"
00022 #include "sysdep.h"
00023 #include "libbfd.h"
00024 
00025 /* The format of a PowerPC NLM changed.  Define OLDFORMAT to get the
00026    old format.  */
00027 
00028 #define ARCH_SIZE 32
00029 
00030 #include "nlm/ppc-ext.h"
00031 #define Nlm_External_Fixed_Header  Nlm32_powerpc_External_Fixed_Header
00032 
00033 #include "libnlm.h"
00034 
00035 #ifdef OLDFORMAT
00036 
00037 /* The prefix header is only used in the old format.  */
00038 
00039 /* PowerPC NLM's have a prefix header before the standard NLM.  This
00040    function reads it in, verifies the version, and seeks the bfd to
00041    the location before the regular NLM header.  */
00042 
00043 static bfd_boolean
00044 nlm_powerpc_backend_object_p (bfd *abfd)
00045 {
00046   struct nlm32_powerpc_external_prefix_header s;
00047 
00048   if (bfd_bread (& s, (bfd_size_type) sizeof s, abfd) != sizeof s)
00049     return FALSE;
00050 
00051   if (memcmp (s.signature, NLM32_POWERPC_SIGNATURE, sizeof s.signature) != 0
00052       || H_GET_32 (abfd, s.headerVersion) != NLM32_POWERPC_HEADER_VERSION)
00053     return FALSE;
00054 
00055   return TRUE;
00056 }
00057 
00058 /* Write out the prefix.  */
00059 
00060 static bfd_boolean
00061 nlm_powerpc_write_prefix (bfd *abfd)
00062 {
00063   struct nlm32_powerpc_external_prefix_header s;
00064 
00065   memset (&s, 0, sizeof s);
00066   memcpy (s.signature, NLM32_POWERPC_SIGNATURE, sizeof s.signature);
00067   H_PUT_32 (abfd, NLM32_POWERPC_HEADER_VERSION, s.headerVersion);
00068   H_PUT_32 (abfd, 0, s.origins);
00069 
00070   /* FIXME: What should we do about the date?  */
00071 
00072   if (bfd_bwrite (& s, (bfd_size_type) sizeof s, abfd) != sizeof s)
00073     return FALSE;
00074 
00075   return TRUE;
00076 }
00077 
00078 /* This reloc handling is only applicable to the old format.  */
00079 
00080 /* How to process the various reloc types.  PowerPC NLMs use XCOFF
00081    reloc types, and I have just copied the XCOFF reloc table here.  */
00082 
00083 static reloc_howto_type nlm_powerpc_howto_table[] =
00084 {
00085   /* Standard 32 bit relocation.  */
00086   HOWTO (0,                   /* Type.  */
00087         0,                    /* Rightshift.  */
00088         2,                    /* Size (0 = byte, 1 = short, 2 = long).  */
00089         32,                   /* Bitsize.  */
00090         FALSE,                       /* PC relative.  */
00091         0,                    /* Bitpos.  */
00092         complain_overflow_bitfield, /* Complain_on_overflow.  */
00093         0,                   /* Special_function.  */
00094         "R_POS",               /* Name.  */
00095         TRUE,                 /* Partial_inplace.  */
00096         0xffffffff,            /* Source mask.  */
00097         0xffffffff,            /* Dest mask.  */
00098         FALSE),                /* PC rel offset.  */
00099 
00100   /* 32 bit relocation, but store negative value.  */
00101   HOWTO (1,                   /* Type.  */
00102         0,                    /* Rightshift.  */
00103         -2,                   /* Size (0 = byte, 1 = short, 2 = long).  */
00104         32,                   /* Bitsize.  */
00105         FALSE,                       /* PC relative.  */
00106         0,                    /* Bitpos.  */
00107         complain_overflow_bitfield, /* Complain_on_overflow.  */
00108         0,                   /* Special_function.  */
00109         "R_NEG",               /* Name.  */
00110         TRUE,                 /* Partial_inplace.  */
00111         0xffffffff,            /* Source mask.  */
00112         0xffffffff,            /* Dest mask.  */
00113         FALSE),                /* PC rel offset.  */
00114 
00115   /* 32 bit PC relative relocation.  */
00116   HOWTO (2,                   /* Type.  */
00117         0,                    /* Rightshift.  */
00118         2,                    /* Size (0 = byte, 1 = short, 2 = long).  */
00119         32,                   /* Bitsize.  */
00120         TRUE,                 /* PC relative.  */
00121         0,                    /* Bitpos.  */
00122         complain_overflow_signed, /* Complain_on_overflow.  */
00123         0,                   /* Special_function.  */
00124         "R_REL",               /* Name.  */
00125         TRUE,                 /* Partial_inplace.  */
00126         0xffffffff,            /* Source mask.  */
00127         0xffffffff,            /* Dest mask.  */
00128         FALSE),                /* PC rel offset.  */
00129 
00130   /* 16 bit TOC relative relocation.  */
00131   HOWTO (3,                   /* Type.  */
00132         0,                    /* Rightshift.  */
00133         1,                    /* Size (0 = byte, 1 = short, 2 = long).  */
00134         16,                   /* Bitsize.  */
00135         FALSE,                       /* PC relative.  */
00136         0,                    /* Bitpos.  */
00137         complain_overflow_signed, /* Complain_on_overflow.  */
00138         0,                   /* Special_function.  */
00139         "R_TOC",               /* Name.  */
00140         TRUE,                 /* Partial_inplace.  */
00141         0xffff,              /* Source mask.  */
00142         0xffff,             /* Dest mask.  */
00143         FALSE),                /* PC rel offset.  */
00144 
00145   /* I don't really know what this is.  */
00146   HOWTO (4,                   /* Type.  */
00147         1,                    /* Rightshift.  */
00148         2,                    /* Size (0 = byte, 1 = short, 2 = long).  */
00149         32,                   /* Bitsize.  */
00150         FALSE,                       /* PC relative.  */
00151         0,                    /* Bitpos.  */
00152         complain_overflow_bitfield, /* Complain_on_overflow.  */
00153         0,                   /* Special_function.  */
00154         "R_RTB",               /* Name.  */
00155         TRUE,                 /* Partial_inplace.  */
00156         0xffffffff,          /* Source mask.  */
00157         0xffffffff,         /* Dest mask.  */
00158         FALSE),                /* PC rel offset.  */
00159 
00160   /* External TOC relative symbol.  */
00161   HOWTO (5,                   /* Type.  */
00162         0,                    /* Rightshift.  */
00163         2,                    /* Size (0 = byte, 1 = short, 2 = long).  */
00164         16,                   /* Bitsize.  */
00165         FALSE,                       /* PC relative.  */
00166         0,                    /* Bitpos.  */
00167         complain_overflow_bitfield, /* Complain_on_overflow.  */
00168         0,                   /* Special_function.  */
00169         "R_GL",                /* Name.  */
00170         TRUE,                 /* Partial_inplace.  */
00171         0xffff,              /* Source mask.  */
00172         0xffff,             /* Dest mask.  */
00173         FALSE),                /* PC rel offset.  */
00174 
00175   /* Local TOC relative symbol.  */
00176   HOWTO (6,                   /* Type.  */
00177         0,                    /* Rightshift.  */
00178         2,                    /* Size (0 = byte, 1 = short, 2 = long).  */
00179         16,                   /* Bitsize.  */
00180         FALSE,                       /* PC relative.  */
00181         0,                    /* Bitpos.  */
00182         complain_overflow_bitfield, /* Complain_on_overflow.  */
00183         0,                   /* Special_function.  */
00184         "R_TCL",               /* Name.  */
00185         TRUE,                 /* Partial_inplace.  */
00186         0xffff,              /* Source mask.  */
00187         0xffff,             /* Dest mask.  */
00188         FALSE),                /* PC rel offset.  */
00189 
00190   { 7 },
00191 
00192   /* Non modifiable absolute branch.  */
00193   HOWTO (8,                   /* Type.  */
00194         0,                    /* Rightshift.  */
00195         2,                    /* Size (0 = byte, 1 = short, 2 = long).  */
00196         26,                   /* Bitsize.  */
00197         FALSE,                       /* PC relative.  */
00198         0,                    /* Bitpos.  */
00199         complain_overflow_bitfield, /* Complain_on_overflow.  */
00200         0,                   /* Special_function.  */
00201         "R_BA",                /* Name.  */
00202         TRUE,                 /* Partial_inplace.  */
00203         0x3fffffc,           /* Source mask.  */
00204         0x3fffffc,          /* Dest mask.  */
00205         FALSE),                /* PC rel offset.  */
00206 
00207   { 9 },
00208 
00209   /* Non modifiable relative branch.  */
00210   HOWTO (0xa,                 /* Type.  */
00211         0,                    /* Rightshift.  */
00212         2,                    /* Size (0 = byte, 1 = short, 2 = long).  */
00213         26,                   /* Bitsize.  */
00214         TRUE,                 /* PC relative.  */
00215         0,                    /* Bitpos.  */
00216         complain_overflow_signed, /* Complain_on_overflow.  */
00217         0,                   /* Special_function.  */
00218         "R_BR",                /* Name.  */
00219         TRUE,                 /* Partial_inplace.  */
00220         0x3fffffc,           /* Source mask.  */
00221         0x3fffffc,          /* Dest mask.  */
00222         FALSE),                /* PC rel offset.  */
00223 
00224   { 0xb },
00225 
00226   /* Indirect load.  */
00227   HOWTO (0xc,                 /* Type.  */
00228         0,                    /* Rightshift.  */
00229         2,                    /* Size (0 = byte, 1 = short, 2 = long).  */
00230         16,                   /* Bitsize.  */
00231         FALSE,                       /* PC relative.  */
00232         0,                    /* Bitpos.  */
00233         complain_overflow_bitfield, /* Complain_on_overflow.  */
00234         0,                   /* Special_function.  */
00235         "R_RL",                /* Name.  */
00236         TRUE,                 /* Partial_inplace.  */
00237         0xffff,              /* Source mask.  */
00238         0xffff,             /* Dest mask.  */
00239         FALSE),                /* PC rel offset.  */
00240 
00241   /* Load address.  */
00242   HOWTO (0xd,                 /* Type.  */
00243         0,                    /* Rightshift.  */
00244         2,                    /* Size (0 = byte, 1 = short, 2 = long).  */
00245         16,                   /* Bitsize.  */
00246         FALSE,                       /* PC relative.  */
00247         0,                    /* Bitpos.  */
00248         complain_overflow_bitfield, /* Complain_on_overflow.  */
00249         0,                   /* Special_function.  */
00250         "R_RLA",               /* Name.  */
00251         TRUE,                 /* Partial_inplace.  */
00252         0xffff,              /* Source mask.  */
00253         0xffff,             /* Dest mask.  */
00254         FALSE),                /* PC rel offset.  */
00255 
00256   { 0xe },
00257 
00258   /* Non-relocating reference.  */
00259   HOWTO (0xf,                 /* Type.  */
00260         0,                    /* Rightshift.  */
00261         2,                    /* Size (0 = byte, 1 = short, 2 = long).  */
00262         32,                   /* Bitsize.  */
00263         FALSE,                       /* PC relative.  */
00264         0,                    /* Bitpos.  */
00265         complain_overflow_bitfield, /* Complain_on_overflow.  */
00266         0,                   /* Special_function.  */
00267         "R_REF",               /* Name.  */
00268         FALSE,                       /* Partial_inplace.  */
00269         0,                   /* Source mask.  */
00270         0,                  /* Dest mask.  */
00271         FALSE),                /* PC rel offset.  */
00272 
00273   { 0x10 },
00274   { 0x11 },
00275 
00276   /* TOC relative indirect load.  */
00277   HOWTO (0x12,                       /* Type.  */
00278         0,                    /* Rightshift.  */
00279         2,                    /* Size (0 = byte, 1 = short, 2 = long).  */
00280         16,                   /* Bitsize.  */
00281         FALSE,                       /* PC relative.  */
00282         0,                    /* Bitpos.  */
00283         complain_overflow_bitfield, /* Complain_on_overflow.  */
00284         0,                   /* Special_function.  */
00285         "R_TRL",               /* Name.  */
00286         TRUE,                 /* Partial_inplace.  */
00287         0xffff,              /* Source mask.  */
00288         0xffff,             /* Dest mask.  */
00289         FALSE),                /* PC rel offset.  */
00290 
00291   /* TOC relative load address.  */
00292   HOWTO (0x13,                       /* Type.  */
00293         0,                    /* Rightshift.  */
00294         2,                    /* Size (0 = byte, 1 = short, 2 = long).  */
00295         16,                   /* Bitsize.  */
00296         FALSE,                       /* PC relative.  */
00297         0,                    /* Bitpos.  */
00298         complain_overflow_bitfield, /* Complain_on_overflow.  */
00299         0,                   /* Special_function.  */
00300         "R_TRLA",              /* Name.  */
00301         TRUE,                 /* Partial_inplace.  */
00302         0xffff,              /* Source mask.  */
00303         0xffff,             /* Dest mask.  */
00304         FALSE),                /* PC rel offset.  */
00305 
00306   /* Modifiable relative branch.  */
00307   HOWTO (0x14,                       /* Type.  */
00308         1,                    /* Rightshift.  */
00309         2,                    /* Size (0 = byte, 1 = short, 2 = long).  */
00310         32,                   /* Bitsize.  */
00311         FALSE,                       /* PC relative.  */
00312         0,                    /* Bitpos.  */
00313         complain_overflow_bitfield, /* Complain_on_overflow.  */
00314         0,                   /* Special_function.  */
00315         "R_RRTBI",             /* Name.  */
00316         TRUE,                 /* Partial_inplace.  */
00317         0xffffffff,          /* Source mask.  */
00318         0xffffffff,         /* Dest mask.  */
00319         FALSE),                /* PC rel offset.  */
00320 
00321   /* Modifiable absolute branch.  */
00322   HOWTO (0x15,                       /* Type.  */
00323         1,                    /* Rightshift.  */
00324         2,                    /* Size (0 = byte, 1 = short, 2 = long).  */
00325         32,                   /* Bitsize.  */
00326         FALSE,                       /* PC relative.  */
00327         0,                    /* Bitpos.  */
00328         complain_overflow_bitfield, /* Complain_on_overflow.  */
00329         0,                   /* Special_function.  */
00330         "R_RRTBA",             /* Name.  */
00331         TRUE,                 /* Partial_inplace.  */
00332         0xffffffff,          /* Source mask.  */
00333         0xffffffff,         /* Dest mask.  */
00334         FALSE),                /* PC rel offset.  */
00335 
00336   /* Modifiable call absolute indirect.  */
00337   HOWTO (0x16,                       /* Type.  */
00338         0,                    /* Rightshift.  */
00339         2,                    /* Size (0 = byte, 1 = short, 2 = long).  */
00340         16,                   /* Bitsize.  */
00341         FALSE,                       /* PC relative.  */
00342         0,                    /* Bitpos.  */
00343         complain_overflow_bitfield, /* Complain_on_overflow.  */
00344         0,                   /* Special_function.  */
00345         "R_CAI",               /* Name.  */
00346         TRUE,                 /* Partial_inplace.  */
00347         0xffff,              /* Source mask.  */
00348         0xffff,             /* Dest mask.  */
00349         FALSE),                /* PC rel offset.  */
00350 
00351   /* Modifiable call relative.  */
00352   HOWTO (0x17,                       /* Type.  */
00353         0,                    /* Rightshift.  */
00354         2,                    /* Size (0 = byte, 1 = short, 2 = long).  */
00355         16,                   /* Bitsize.  */
00356         FALSE,                       /* PC relative.  */
00357         0,                    /* Bitpos.  */
00358         complain_overflow_bitfield, /* Complain_on_overflow.  */
00359         0,                   /* Special_function.  */
00360         "R_REL",               /* Name.  */
00361         TRUE,                 /* Partial_inplace.  */
00362         0xffff,              /* Source mask.  */
00363         0xffff,             /* Dest mask.  */
00364         FALSE),                /* PC rel offset.  */
00365 
00366   /* Modifiable branch absolute.  */
00367   HOWTO (0x18,                       /* Type.  */
00368         0,                    /* Rightshift.  */
00369         2,                    /* Size (0 = byte, 1 = short, 2 = long).  */
00370         16,                   /* Bitsize.  */
00371         FALSE,                       /* PC relative.  */
00372         0,                    /* Bitpos.  */
00373         complain_overflow_bitfield, /* Complain_on_overflow.  */
00374         0,                   /* Special_function.  */
00375         "R_RBA",               /* Name.  */
00376         TRUE,                 /* Partial_inplace.  */
00377         0xffff,              /* Source mask.  */
00378         0xffff,             /* Dest mask.  */
00379         FALSE),                /* PC rel offset.  */
00380 
00381   /* Modifiable branch absolute.  */
00382   HOWTO (0x19,                       /* Type.  */
00383         0,                    /* Rightshift.  */
00384         2,                    /* Size (0 = byte, 1 = short, 2 = long).  */
00385         16,                   /* Bitsize.  */
00386         FALSE,                       /* PC relative.  */
00387         0,                    /* Bitpos.  */
00388         complain_overflow_bitfield, /* Complain_on_overflow.  */
00389         0,                   /* Special_function.  */
00390         "R_RBAC",              /* Name.  */
00391         TRUE,                 /* Partial_inplace.  */
00392         0xffff,              /* Source mask.  */
00393         0xffff,             /* Dest mask.  */
00394         FALSE),                /* PC rel offset.  */
00395 
00396   /* Modifiable branch relative.  */
00397   HOWTO (0x1a,                       /* Type.  */
00398         0,                    /* Rightshift.  */
00399         2,                    /* Size (0 = byte, 1 = short, 2 = long).  */
00400         26,                   /* Bitsize.  */
00401         FALSE,                       /* PC relative.  */
00402         0,                    /* Bitpos.  */
00403         complain_overflow_signed, /* Complain_on_overflow.  */
00404         0,                   /* Special_function.  */
00405         "R_REL",               /* Name.  */
00406         TRUE,                 /* Partial_inplace.  */
00407         0xffff,              /* Source mask.  */
00408         0xffff,             /* Dest mask.  */
00409         FALSE),                /* PC rel offset.  */
00410 
00411   /* Modifiable branch absolute.  */
00412   HOWTO (0x1b,                       /* Type.  */
00413         0,                    /* Rightshift.  */
00414         2,                    /* Size (0 = byte, 1 = short, 2 = long).  */
00415         16,                   /* Bitsize.  */
00416         FALSE,                       /* PC relative.  */
00417         0,                    /* Bitpos.  */
00418         complain_overflow_bitfield, /* Complain_on_overflow.  */
00419         0,                   /* Special_function.  */
00420         "R_REL",               /* Name.  */
00421         TRUE,                 /* Partial_inplace.  */
00422         0xffff,              /* Source mask.  */
00423         0xffff,             /* Dest mask.  */
00424         FALSE)                 /* PC rel offset.  */
00425 };
00426 
00427 #define HOWTO_COUNT (sizeof nlm_powerpc_howto_table            \
00428                    / sizeof nlm_powerpc_howto_table[0])
00429 
00430 /* Read a PowerPC NLM reloc.  */
00431 
00432 static bfd_boolean
00433 nlm_powerpc_read_reloc (bfd *abfd,
00434                      nlmNAME (symbol_type) *sym,
00435                      asection **secp,
00436                      arelent *rel)
00437 {
00438   struct nlm32_powerpc_external_reloc ext;
00439   bfd_vma l_vaddr;
00440   unsigned long l_symndx;
00441   int l_rtype;
00442   int l_rsecnm;
00443   asection *code_sec, *data_sec, *bss_sec;
00444 
00445   /* Read the reloc from the file.  */
00446   if (bfd_bread (&ext, (bfd_size_type) sizeof ext, abfd) != sizeof ext)
00447     return FALSE;
00448 
00449   /* Swap in the fields.  */
00450   l_vaddr = H_GET_32 (abfd, ext.l_vaddr);
00451   l_symndx = H_GET_32 (abfd, ext.l_symndx);
00452   l_rtype = H_GET_16 (abfd, ext.l_rtype);
00453   l_rsecnm = H_GET_16 (abfd, ext.l_rsecnm);
00454 
00455   /* Get the sections now, for convenience.  */
00456   code_sec = bfd_get_section_by_name (abfd, NLM_CODE_NAME);
00457   data_sec = bfd_get_section_by_name (abfd, NLM_INITIALIZED_DATA_NAME);
00458   bss_sec = bfd_get_section_by_name (abfd, NLM_UNINITIALIZED_DATA_NAME);
00459 
00460   /* Work out the arelent fields.  */
00461   if (sym != NULL)
00462     /* This is an import.  sym_ptr_ptr is filled in by
00463        nlm_canonicalize_reloc.  */
00464     rel->sym_ptr_ptr = NULL;
00465   else
00466     {
00467       asection *sec;
00468 
00469       if (l_symndx == 0)
00470        sec = code_sec;
00471       else if (l_symndx == 1)
00472        sec = data_sec;
00473       else if (l_symndx == 2)
00474        sec = bss_sec;
00475       else
00476        {
00477          bfd_set_error (bfd_error_bad_value);
00478          return FALSE;
00479        }
00480 
00481       rel->sym_ptr_ptr = sec->symbol_ptr_ptr;
00482     }
00483 
00484   rel->addend = 0;
00485 
00486   BFD_ASSERT ((l_rtype & 0xff) < HOWTO_COUNT);
00487 
00488   rel->howto = nlm_powerpc_howto_table + (l_rtype & 0xff);
00489 
00490   BFD_ASSERT (rel->howto->name != NULL
00491              && ((l_rtype & 0x8000) != 0
00492                 ? (rel->howto->complain_on_overflow
00493                    == complain_overflow_signed)
00494                 : (rel->howto->complain_on_overflow
00495                    == complain_overflow_bitfield))
00496              && ((l_rtype >> 8) & 0x1f) == rel->howto->bitsize - 1);
00497 
00498   if (l_rsecnm == 0)
00499     *secp = code_sec;
00500   else if (l_rsecnm == 1)
00501     {
00502       *secp = data_sec;
00503       l_vaddr -= code_sec->size;
00504     }
00505   else
00506     {
00507       bfd_set_error (bfd_error_bad_value);
00508       return FALSE;
00509     }
00510 
00511   rel->address = l_vaddr;
00512 
00513   return TRUE;
00514 }
00515 
00516 #else /* not OLDFORMAT */
00517 
00518 /* There is only one type of reloc in a PowerPC NLM.  */
00519 
00520 static reloc_howto_type nlm_powerpc_howto =
00521   HOWTO (0,                 /* Type.  */
00522         0,                  /* Rightshift.  */
00523         2,                  /* Size (0 = byte, 1 = short, 2 = long).  */
00524         32,                 /* Bitsize.  */
00525         FALSE,                     /* PC relative.  */
00526         0,                  /* Bitpos.  */
00527         complain_overflow_bitfield, /* Complain_on_overflow.  */
00528         0,                  /* Special_function.  */
00529         "32",               /* Name.  */
00530         TRUE,               /* Partial_inplace.  */
00531         0xffffffff,         /* Source mask.  */
00532         0xffffffff,         /* Dest mask.  */
00533         FALSE);             /* PC rel_offset.  */
00534 
00535 /* Read a PowerPC NLM reloc.  */
00536 
00537 static bfd_boolean
00538 nlm_powerpc_read_reloc (bfd *abfd,
00539                      nlmNAME (symbol_type) *sym,
00540                      asection **secp,
00541                      arelent *rel)
00542 {
00543   bfd_byte temp[4];
00544   bfd_vma val;
00545   const char *name;
00546 
00547   if (bfd_bread (temp, (bfd_size_type) sizeof (temp), abfd) != sizeof (temp))
00548     return FALSE;
00549 
00550   val = bfd_get_32 (abfd, temp);
00551 
00552   /* The value is a word offset into either the code or data segment.
00553      This is the location which needs to be adjusted.
00554 
00555      The high bit is 0 if the value is an offset into the data
00556      segment, or 1 if the value is an offset into the text segment.
00557 
00558      If this is a relocation fixup rather than an imported symbol (the
00559      sym argument is NULL), then the second most significant bit is 0
00560      if the address of the data segment should be added to the
00561      location addressed by the value, or 1 if the address of the text
00562      segment should be added.
00563 
00564      If this is an imported symbol, the second most significant bit is
00565      not used and must be 0.  */
00566 
00567   if ((val & NLM_HIBIT) == 0)
00568     name = NLM_INITIALIZED_DATA_NAME;
00569   else
00570     {
00571       name = NLM_CODE_NAME;
00572       val &=~ NLM_HIBIT;
00573     }
00574   *secp = bfd_get_section_by_name (abfd, name);
00575 
00576   if (sym == NULL)
00577     {
00578       if ((val & (NLM_HIBIT >> 1)) == 0)
00579        name = NLM_INITIALIZED_DATA_NAME;
00580       else
00581        {
00582          name = NLM_CODE_NAME;
00583          val &=~ (NLM_HIBIT >> 1);
00584        }
00585       rel->sym_ptr_ptr = bfd_get_section_by_name (abfd, name)->symbol_ptr_ptr;
00586     }
00587 
00588   rel->howto   = & nlm_powerpc_howto;
00589   rel->address = val << 2;
00590   rel->addend  = 0;
00591 
00592   return TRUE;
00593 }
00594 
00595 #endif /* not OLDFORMAT */
00596 
00597 /* Mangle PowerPC NLM relocs for output.  */
00598 
00599 static bfd_boolean
00600 nlm_powerpc_mangle_relocs (bfd *abfd ATTRIBUTE_UNUSED,
00601                         asection *sec ATTRIBUTE_UNUSED,
00602                         const void * data ATTRIBUTE_UNUSED,
00603                         bfd_vma offset ATTRIBUTE_UNUSED,
00604                         bfd_size_type count ATTRIBUTE_UNUSED)
00605 {
00606   return TRUE;
00607 }
00608 
00609 /* Read a PowerPC NLM import record */
00610 
00611 static bfd_boolean
00612 nlm_powerpc_read_import (bfd * abfd, nlmNAME (symbol_type) * sym)
00613 {
00614   struct nlm_relent *nlm_relocs;   /* Relocation records for symbol.  */
00615   bfd_size_type rcount;                   /* Number of relocs.  */
00616   bfd_byte temp[NLM_TARGET_LONG_SIZE];    /* Temporary 32-bit value.  */
00617   unsigned char symlength;         /* Length of symbol name.  */
00618   char *name;
00619 
00620   if (bfd_bread (& symlength, (bfd_size_type) sizeof (symlength), abfd)
00621       != sizeof (symlength))
00622     return FALSE;
00623   sym -> symbol.the_bfd = abfd;
00624   name = bfd_alloc (abfd, (bfd_size_type) symlength + 1);
00625   if (name == NULL)
00626     return FALSE;
00627   if (bfd_bread (name, (bfd_size_type) symlength, abfd) != symlength)
00628     return FALSE;
00629   name[symlength] = '\0';
00630   sym -> symbol.name = name;
00631   sym -> symbol.flags = 0;
00632   sym -> symbol.value = 0;
00633   sym -> symbol.section = bfd_und_section_ptr;
00634   if (bfd_bread (temp, (bfd_size_type) sizeof (temp), abfd)
00635       != sizeof (temp))
00636     return FALSE;
00637   rcount = H_GET_32 (abfd, temp);
00638   nlm_relocs = bfd_alloc (abfd, rcount * sizeof (struct nlm_relent));
00639   if (nlm_relocs == NULL)
00640     return FALSE;
00641   sym -> relocs = nlm_relocs;
00642   sym -> rcnt = 0;
00643   while (sym -> rcnt < rcount)
00644     {
00645       asection *section;
00646 
00647       if (! nlm_powerpc_read_reloc (abfd, sym, &section, &nlm_relocs -> reloc))
00648        return FALSE;
00649       nlm_relocs -> section = section;
00650       nlm_relocs++;
00651       sym -> rcnt++;
00652     }
00653   return TRUE;
00654 }
00655 
00656 #ifndef OLDFORMAT
00657 
00658 /* Write a PowerPC NLM reloc.  */
00659 
00660 static bfd_boolean
00661 nlm_powerpc_write_import (bfd * abfd, asection * sec, arelent * rel)
00662 {
00663   asymbol *sym;
00664   bfd_vma val;
00665   bfd_byte temp[4];
00666 
00667   /* PowerPC NetWare only supports one kind of reloc.  */
00668   if (rel->addend != 0
00669       || rel->howto == NULL
00670       || rel->howto->rightshift != 0
00671       || rel->howto->size != 2
00672       || rel->howto->bitsize != 32
00673       || rel->howto->bitpos != 0
00674       || rel->howto->pc_relative
00675       || (rel->howto->src_mask != 0xffffffff && rel->addend != 0)
00676       || rel->howto->dst_mask != 0xffffffff)
00677     {
00678       bfd_set_error (bfd_error_invalid_operation);
00679       return FALSE;
00680     }
00681 
00682   sym = *rel->sym_ptr_ptr;
00683 
00684   /* The value we write out is the offset into the appropriate
00685      segment, rightshifted by two.  This offset is the section vma,
00686      adjusted by the vma of the lowest section in that segment, plus
00687      the address of the relocation.  */
00688   val = bfd_get_section_vma (abfd, sec) + rel->address;
00689   if ((val & 3) != 0)
00690     {
00691       bfd_set_error (bfd_error_bad_value);
00692       return FALSE;
00693     }
00694   val >>= 2;
00695 
00696   /* The high bit is 0 if the reloc is in the data section, or 1 if
00697      the reloc is in the code section.  */
00698   if (bfd_get_section_flags (abfd, sec) & SEC_DATA)
00699     val -= nlm_get_data_low (abfd);
00700   else
00701     {
00702       val -= nlm_get_text_low (abfd);
00703       val |= NLM_HIBIT;
00704     }
00705 
00706   if (! bfd_is_und_section (bfd_get_section (sym)))
00707     {
00708       /* This is an internal relocation fixup.  The second most
00709         significant bit is 0 if this is a reloc against the data
00710         segment, or 1 if it is a reloc against the text segment.  */
00711       if (bfd_get_section_flags (abfd, bfd_get_section (sym)) & SEC_CODE)
00712        val |= NLM_HIBIT >> 1;
00713     }
00714 
00715   bfd_put_32 (abfd, val, temp);
00716   if (bfd_bwrite (temp, (bfd_size_type) sizeof (temp), abfd) != sizeof (temp))
00717     return FALSE;
00718 
00719   return TRUE;
00720 }
00721 
00722 #else /* OLDFORMAT */
00723 
00724 /* This is used for the reloc handling in the old format.  */
00725 
00726 /* Write a PowerPC NLM reloc.  */
00727 
00728 static bfd_boolean
00729 nlm_powerpc_write_reloc (bfd *abfd,
00730                       asection *sec,
00731                       arelent *rel,
00732                       int indx)
00733 {
00734   struct nlm32_powerpc_external_reloc ext;
00735   asection *code_sec, *data_sec, *bss_sec;
00736   asymbol *sym;
00737   asection *symsec;
00738   unsigned long l_symndx;
00739   int l_rtype;
00740   int l_rsecnm;
00741   reloc_howto_type *howto;
00742   bfd_size_type address;
00743 
00744   /* Get the sections now, for convenience.  */
00745   code_sec = bfd_get_section_by_name (abfd, NLM_CODE_NAME);
00746   data_sec = bfd_get_section_by_name (abfd, NLM_INITIALIZED_DATA_NAME);
00747   bss_sec = bfd_get_section_by_name (abfd, NLM_UNINITIALIZED_DATA_NAME);
00748 
00749   sym = *rel->sym_ptr_ptr;
00750   symsec = bfd_get_section (sym);
00751   if (indx != -1)
00752     {
00753       BFD_ASSERT (bfd_is_und_section (symsec));
00754       l_symndx = indx + 3;
00755     }
00756   else
00757     {
00758       if (symsec == code_sec)
00759        l_symndx = 0;
00760       else if (symsec == data_sec)
00761        l_symndx = 1;
00762       else if (symsec == bss_sec)
00763        l_symndx = 2;
00764       else
00765        {
00766          bfd_set_error (bfd_error_bad_value);
00767          return FALSE;
00768        }
00769     }
00770 
00771   H_PUT_32 (abfd, l_symndx, ext.l_symndx);
00772 
00773   for (howto = nlm_powerpc_howto_table;
00774        howto < nlm_powerpc_howto_table + HOWTO_COUNT;
00775        howto++)
00776     {
00777       if (howto->rightshift == rel->howto->rightshift
00778          && howto->size == rel->howto->size
00779          && howto->bitsize == rel->howto->bitsize
00780          && howto->pc_relative == rel->howto->pc_relative
00781          && howto->bitpos == rel->howto->bitpos
00782          && (howto->partial_inplace == rel->howto->partial_inplace
00783              || (! rel->howto->partial_inplace
00784                 && rel->addend == 0))
00785          && (howto->src_mask == rel->howto->src_mask
00786              || (rel->howto->src_mask == 0
00787                 && rel->addend == 0))
00788          && howto->dst_mask == rel->howto->dst_mask
00789          && howto->pcrel_offset == rel->howto->pcrel_offset)
00790        break;
00791     }
00792   if (howto >= nlm_powerpc_howto_table + HOWTO_COUNT)
00793     {
00794       bfd_set_error (bfd_error_bad_value);
00795       return FALSE;
00796     }
00797 
00798   l_rtype = howto->type;
00799   if (howto->complain_on_overflow == complain_overflow_signed)
00800     l_rtype |= 0x8000;
00801   l_rtype |= (howto->bitsize - 1) << 8;
00802   H_PUT_16 (abfd, l_rtype, ext.l_rtype);
00803 
00804   address = rel->address;
00805 
00806   if (sec == code_sec)
00807     l_rsecnm = 0;
00808   else if (sec == data_sec)
00809     {
00810       l_rsecnm = 1;
00811       address += code_sec->size;
00812     }
00813   else
00814     {
00815       bfd_set_error (bfd_error_bad_value);
00816       return FALSE;
00817     }
00818 
00819   H_PUT_16 (abfd, l_rsecnm, ext.l_rsecnm);
00820   H_PUT_32 (abfd, address, ext.l_vaddr);
00821 
00822   if (bfd_bwrite (&ext, (bfd_size_type) sizeof ext, abfd) != sizeof ext)
00823     return FALSE;
00824 
00825   return TRUE;
00826 }
00827 
00828 /* Write a PowerPC NLM import.  */
00829 
00830 static bfd_boolean
00831 nlm_powerpc_write_import (bfd * abfd, asection * sec, arelent * rel)
00832 {
00833   return nlm_powerpc_write_reloc (abfd, sec, rel, -1);
00834 }
00835 
00836 #endif /* OLDFORMAT */
00837 
00838 /* Write a PowerPC NLM external symbol.  This routine keeps a static
00839    count of the symbol index.  FIXME: I don't know if this is
00840    necessary, and the index never gets reset.  */
00841 
00842 static bfd_boolean
00843 nlm_powerpc_write_external (bfd *abfd,
00844                          bfd_size_type count,
00845                          asymbol *sym,
00846                          struct reloc_and_sec *relocs)
00847 {
00848   unsigned int i;
00849   bfd_byte len;
00850   unsigned char temp[NLM_TARGET_LONG_SIZE];
00851 #ifdef OLDFORMAT
00852   static int indx;
00853 #endif
00854 
00855   len = strlen (sym->name);
00856   if ((bfd_bwrite (&len, (bfd_size_type) sizeof (bfd_byte), abfd)
00857        != sizeof (bfd_byte))
00858       || bfd_bwrite (sym->name, (bfd_size_type) len, abfd) != len)
00859     return FALSE;
00860 
00861   bfd_put_32 (abfd, count, temp);
00862   if (bfd_bwrite (temp, (bfd_size_type) sizeof (temp), abfd) != sizeof (temp))
00863     return FALSE;
00864 
00865   for (i = 0; i < count; i++)
00866     {
00867 #ifndef OLDFORMAT
00868       if (! nlm_powerpc_write_import (abfd, relocs[i].sec, relocs[i].rel))
00869        return FALSE;
00870 #else
00871       if (! nlm_powerpc_write_reloc (abfd, relocs[i].sec,
00872                                  relocs[i].rel, indx))
00873        return FALSE;
00874 #endif
00875     }
00876 
00877 #ifdef OLDFORMAT
00878   ++indx;
00879 #endif
00880 
00881   return TRUE;
00882 }
00883 
00884 #ifndef OLDFORMAT
00885 
00886 /* PowerPC Netware uses a word offset, not a byte offset, for public
00887    symbols.  */
00888 
00889 /* Set the section for a public symbol.  */
00890 
00891 static bfd_boolean
00892 nlm_powerpc_set_public_section (bfd *abfd, nlmNAME (symbol_type) *sym)
00893 {
00894   if (sym->symbol.value & NLM_HIBIT)
00895     {
00896       sym->symbol.value &= ~NLM_HIBIT;
00897       sym->symbol.flags |= BSF_FUNCTION;
00898       sym->symbol.section =
00899        bfd_get_section_by_name (abfd, NLM_CODE_NAME);
00900     }
00901   else
00902     sym->symbol.section =
00903       bfd_get_section_by_name (abfd, NLM_INITIALIZED_DATA_NAME);
00904 
00905   sym->symbol.value <<= 2;
00906 
00907   return TRUE;
00908 }
00909 
00910 /* Get the offset to write out for a public symbol.  */
00911 
00912 static bfd_vma
00913 nlm_powerpc_get_public_offset (bfd *abfd, asymbol *sym)
00914 {
00915   bfd_vma offset;
00916   asection *sec;
00917 
00918   offset = bfd_asymbol_value (sym);
00919   sec = bfd_get_section (sym);
00920   if (sec->flags & SEC_CODE)
00921     {
00922       offset -= nlm_get_text_low (abfd);
00923       offset |= NLM_HIBIT;
00924     }
00925   else if (sec->flags & (SEC_DATA | SEC_ALLOC))
00926     {
00927       /* SEC_ALLOC is for the .bss section.  */
00928       offset -= nlm_get_data_low (abfd);
00929     }
00930   else
00931     {
00932       /* We can't handle an exported symbol that is not in the code or
00933         data segment.  */
00934       bfd_set_error (bfd_error_invalid_operation);
00935       /* FIXME: No way to return error.  */
00936       abort ();
00937     }
00938 
00939   return offset;
00940 }
00941 
00942 #endif /* ! defined (OLDFORMAT) */
00943 
00944 #include "nlmswap.h"
00945 
00946 static const struct nlm_backend_data nlm32_powerpc_backend =
00947 {
00948   "NetWare PowerPC Module \032",
00949   sizeof (Nlm32_powerpc_External_Fixed_Header),
00950 #ifndef OLDFORMAT
00951   0,   /* Optional_prefix_size.  */
00952 #else
00953   sizeof (struct nlm32_powerpc_external_prefix_header),
00954 #endif
00955   bfd_arch_powerpc,
00956   0,
00957   FALSE,
00958 #ifndef OLDFORMAT
00959   0,   /* Backend_object_p.  */
00960   0,   /* Write_prefix.  */
00961 #else
00962   nlm_powerpc_backend_object_p,
00963   nlm_powerpc_write_prefix,
00964 #endif
00965   nlm_powerpc_read_reloc,
00966   nlm_powerpc_mangle_relocs,
00967   nlm_powerpc_read_import,
00968   nlm_powerpc_write_import,
00969 #ifndef OLDFORMAT
00970   nlm_powerpc_set_public_section,
00971   nlm_powerpc_get_public_offset,
00972 #else
00973   0,   /* Set_public_section.  */
00974   0,   /* Get_public_offset.  */
00975 #endif
00976   nlm_swap_fixed_header_in,
00977   nlm_swap_fixed_header_out,
00978   nlm_powerpc_write_external,
00979   0,   /* Write_export.  */
00980 };
00981 
00982 #define TARGET_BIG_NAME                   "nlm32-powerpc"
00983 #define TARGET_BIG_SYM                    nlmNAME (powerpc_vec)
00984 #define TARGET_BACKEND_DATA        & nlm32_powerpc_backend
00985 
00986 #include "nlm-target.h"