Back to index

cell-binutils  2.17cvs20070401
nlm32-alpha.c
Go to the documentation of this file.
00001 /* Support for 32-bit Alpha NLM (NetWare Loadable Module)
00002    Copyright 1993, 1994, 2000, 2001, 2002, 2003, 2004, 2005
00003    Free Software Foundation, Inc.
00004    Written by Ian Lance Taylor, Cygnus Support.
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 /* This file describes the 32 bit Alpha NLM format.  You might think
00023    that an Alpha chip would use a 64 bit format, but, for some reason,
00024    it doesn't.  */
00025 
00026 #include "bfd.h"
00027 #include "sysdep.h"
00028 #include "libbfd.h"
00029 
00030 #define ARCH_SIZE 32
00031 
00032 #include "nlm/alpha-ext.h"
00033 #define Nlm_External_Fixed_Header  Nlm32_alpha_External_Fixed_Header
00034 
00035 #include "libnlm.h"
00036 
00037 /* Alpha NLM's have a prefix header before the standard NLM.  This
00038    function reads it in, verifies the version, and seeks the bfd to
00039    the location before the regular NLM header.  */
00040 
00041 static bfd_boolean
00042 nlm_alpha_backend_object_p (bfd *abfd)
00043 {
00044   struct nlm32_alpha_external_prefix_header s;
00045   file_ptr size;
00046 
00047   if (bfd_bread (&s, (bfd_size_type) sizeof s, abfd) != sizeof s)
00048     return FALSE;
00049 
00050   if (H_GET_32 (abfd, s.magic) != NLM32_ALPHA_MAGIC)
00051     return FALSE;
00052 
00053   /* FIXME: Should we check the format number?  */
00054 
00055   /* Skip to the end of the header.  */
00056   size = H_GET_32 (abfd, s.size);
00057   if (bfd_seek (abfd, size, SEEK_SET) != 0)
00058     return FALSE;
00059 
00060   return TRUE;
00061 }
00062 
00063 /* Write out the prefix.  */
00064 
00065 static bfd_boolean
00066 nlm_alpha_write_prefix (bfd *abfd)
00067 {
00068   struct nlm32_alpha_external_prefix_header s;
00069 
00070   memset (&s, 0, sizeof s);
00071   H_PUT_32 (abfd, NLM32_ALPHA_MAGIC, s.magic);
00072   H_PUT_32 (abfd, 2, s.format);
00073   H_PUT_32 (abfd, sizeof s, s.size);
00074   if (bfd_bwrite (&s, (bfd_size_type) sizeof s, abfd) != sizeof s)
00075     return FALSE;
00076   return TRUE;
00077 }
00078 
00079 #define ONES(n) (((bfd_vma) 1 << ((n) - 1) << 1) - 1)
00080 
00081 /* How to process the various reloc types.  */
00082 
00083 static reloc_howto_type nlm32_alpha_howto_table[] =
00084 {
00085   /* Reloc type 0 is ignored by itself.  However, it appears after a
00086      GPDISP reloc to identify the location where the low order 16 bits
00087      of the gp register are loaded.  */
00088   HOWTO (ALPHA_R_IGNORE,    /* Type.  */
00089         0,                  /* Rightshift.  */
00090         0,                  /* Size (0 = byte, 1 = short, 2 = long).  */
00091         8,                  /* Bitsize.  */
00092         FALSE,                     /* PC_relative.  */
00093         0,                  /* Bitpos.  */
00094         complain_overflow_dont, /* Complain_on_overflow.  */
00095         0,                  /* Special_function.  */
00096         "IGNORE",           /* Name.  */
00097         FALSE,                     /* Partial_inplace.  */
00098         0,                  /* Source mask.  */
00099         0,                  /* Dest mask.  */
00100         FALSE),             /* PCrel_offset.  */
00101 
00102   /* A 32 bit reference to a symbol.  */
00103   HOWTO (ALPHA_R_REFLONG,   /* Type.  */
00104         0,                  /* Rightshift.  */
00105         2,                  /* Size (0 = byte, 1 = short, 2 = long).  */
00106         32,                 /* Bitsize.  */
00107         FALSE,                     /* PC_relative.  */
00108         0,                  /* Bitpos.  */
00109         complain_overflow_bitfield, /* Complain_on_overflow.  */
00110         0,                  /* Special_function.  */
00111         "REFLONG",          /* Name.  */
00112         TRUE,               /* Partial_inplace.  */
00113         0xffffffff,         /* Source mask.  */
00114         0xffffffff,         /* Dest mask.  */
00115         FALSE),             /* PCrel_offset.  */
00116 
00117   /* A 64 bit reference to a symbol.  */
00118   HOWTO (ALPHA_R_REFQUAD,   /* Type.  */
00119         0,                  /* Rightshift.  */
00120         4,                  /* Size (0 = byte, 1 = short, 2 = long).  */
00121         64,                 /* Bitsize.  */
00122         FALSE,                     /* PC_relative.  */
00123         0,                  /* Bitpos.  */
00124         complain_overflow_bitfield, /* Complain_on_overflow.  */
00125         0,                  /* Special_function.  */
00126         "REFQUAD",          /* Name.  */
00127         TRUE,               /* Partial_inplace.  */
00128         ONES (64),          /* Source mask.  */
00129         ONES (64),          /* Dest mask.  */
00130         FALSE),             /* PCrel_offset.  */
00131 
00132   /* A 32 bit GP relative offset.  This is just like REFLONG except
00133      that when the value is used the value of the gp register will be
00134      added in.  */
00135   HOWTO (ALPHA_R_GPREL32,   /* Type.  */
00136         0,                  /* Rightshift.  */
00137         2,                  /* Size (0 = byte, 1 = short, 2 = long).  */
00138         32,                 /* Bitsize.  */
00139         FALSE,                     /* PC_relative.  */
00140         0,                  /* Bitpos.  */
00141         complain_overflow_bitfield, /* Complain_on_overflow.  */
00142         0,                  /* Special_function.  */
00143         "GPREL32",          /* Name.  */
00144         TRUE,               /* Partial_inplace.  */
00145         0xffffffff,         /* Source mask.  */
00146         0xffffffff,         /* Dest mask.  */
00147         FALSE),             /* PCrel_offset.  */
00148 
00149   /* Used for an instruction that refers to memory off the GP
00150      register.  The offset is 16 bits of the 32 bit instruction.  This
00151      reloc always seems to be against the .lita section.  */
00152   HOWTO (ALPHA_R_LITERAL,   /* Type.  */
00153         0,                  /* Rightshift.  */
00154         2,                  /* Size (0 = byte, 1 = short, 2 = long).  */
00155         16,                 /* Bitsize.  */
00156         FALSE,                     /* PC_relative.  */
00157         0,                  /* Bitpos.  */
00158         complain_overflow_signed, /* Complain_on_overflow.  */
00159         0,                  /* Special_function.  */
00160         "LITERAL",          /* Name.  */
00161         TRUE,               /* Partial_inplace.  */
00162         0xffff,             /* Source mask.  */
00163         0xffff,             /* Dest mask.  */
00164         FALSE),             /* PCrel_offset.  */
00165 
00166   /* This reloc only appears immediately following a LITERAL reloc.
00167      It identifies a use of the literal.  It seems that the linker can
00168      use this to eliminate a portion of the .lita section.  The symbol
00169      index is special: 1 means the literal address is in the base
00170      register of a memory format instruction; 2 means the literal
00171      address is in the byte offset register of a byte-manipulation
00172      instruction; 3 means the literal address is in the target
00173      register of a jsr instruction.  This does not actually do any
00174      relocation.  */
00175   HOWTO (ALPHA_R_LITUSE,    /* Type.  */
00176         0,                  /* Rightshift.  */
00177         2,                  /* Size (0 = byte, 1 = short, 2 = long).  */
00178         32,                 /* Bitsize.  */
00179         FALSE,                     /* PC_relative.  */
00180         0,                  /* Bitpos.  */
00181         complain_overflow_dont, /* Complain_on_overflow.  */
00182         0,                  /* Special_function.  */
00183         "LITUSE",           /* Name.  */
00184         FALSE,                     /* Partial_inplace.  */
00185         0,                  /* Source mask.  */
00186         0,                  /* Dest mask.  */
00187         FALSE),             /* PCrel_offset.  */
00188 
00189   /* Load the gp register.  This is always used for a ldah instruction
00190      which loads the upper 16 bits of the gp register.  The next reloc
00191      will be an IGNORE reloc which identifies the location of the lda
00192      instruction which loads the lower 16 bits.  The symbol index of
00193      the GPDISP instruction appears to actually be the number of bytes
00194      between the ldah and lda instructions.  This gives two different
00195      ways to determine where the lda instruction is; I don't know why
00196      both are used.  The value to use for the relocation is the
00197      difference between the GP value and the current location; the
00198      load will always be done against a register holding the current
00199      address.  */
00200   HOWTO (ALPHA_R_GPDISP,    /* Type.  */
00201         16,                 /* Rightshift.  */
00202         2,                  /* Size (0 = byte, 1 = short, 2 = long).  */
00203         16,                 /* Bitsize.  */
00204         TRUE,               /* PC_relative.  */
00205         0,                  /* Bitpos.  */
00206         complain_overflow_dont, /* Complain_on_overflow.  */
00207         0,                  /* Special_function.  */
00208         "GPDISP",           /* Name.  */
00209         TRUE,               /* Partial_inplace.  */
00210         0xffff,             /* Source mask.  */
00211         0xffff,             /* Dest mask.  */
00212         TRUE),                     /* PCrel_offset.  */
00213 
00214   /* A 21 bit branch.  The native assembler generates these for
00215      branches within the text segment, and also fills in the PC
00216      relative offset in the instruction.  It seems to me that this
00217      reloc, unlike the others, is not partial_inplace.  */
00218   HOWTO (ALPHA_R_BRADDR,    /* Type.  */
00219         2,                  /* Rightshift.  */
00220         2,                  /* Size (0 = byte, 1 = short, 2 = long).  */
00221         21,                 /* Bitsize.  */
00222         TRUE,               /* PC_relative.  */
00223         0,                  /* Bitpos.  */
00224         complain_overflow_signed, /* Complain_on_overflow.  */
00225         0,                  /* Special_function.  */
00226         "BRADDR",           /* Name.  */
00227         FALSE,                     /* Partial_inplace.  */
00228         0,                  /* Source mask.  */
00229         0x1fffff,           /* Dest mask.  */
00230         FALSE),             /* PCrel_offset.  */
00231 
00232   /* A hint for a jump to a register.  */
00233   HOWTO (ALPHA_R_HINT,             /* Type.  */
00234         2,                  /* Rightshift.  */
00235         2,                  /* Size (0 = byte, 1 = short, 2 = long).  */
00236         14,                 /* Bitsize.  */
00237         FALSE,                     /* PC_relative.  */
00238         0,                  /* Bitpos.  */
00239         complain_overflow_dont, /* Complain_on_overflow.  */
00240         0,                  /* Special_function.  */
00241         "HINT",             /* Name.  */
00242         TRUE,               /* Partial_inplace.  */
00243         0x3fff,             /* Source mask.  */
00244         0x3fff,             /* Dest mask.  */
00245         FALSE),             /* PCrel_offset.  */
00246 
00247   /* 16 bit PC relative offset.  */
00248   HOWTO (ALPHA_R_SREL16,    /* Type.  */
00249         0,                  /* Rightshift.  */
00250         1,                  /* Size (0 = byte, 1 = short, 2 = long).  */
00251         16,                 /* Bitsize.  */
00252         TRUE,               /* PC_relative.  */
00253         0,                  /* Bitpos.  */
00254         complain_overflow_signed, /* Complain_on_overflow.  */
00255         0,                  /* Special_function.  */
00256         "SREL16",           /* Name.  */
00257         TRUE,               /* Partial_inplace.  */
00258         0xffff,             /* Source mask.  */
00259         0xffff,             /* Dest mask.  */
00260         FALSE),             /* PCrel_offset.  */
00261 
00262   /* 32 bit PC relative offset.  */
00263   HOWTO (ALPHA_R_SREL32,    /* Type.  */
00264         0,                  /* Rightshift.  */
00265         2,                  /* Size (0 = byte, 1 = short, 2 = long).  */
00266         32,                 /* Bitsize.  */
00267         TRUE,               /* PC_relative.  */
00268         0,                  /* Bitpos.  */
00269         complain_overflow_signed, /* Complain_on_overflow.  */
00270         0,                  /* Special_function.  */
00271         "SREL32",           /* Name.  */
00272         TRUE,               /* Partial_inplace.  */
00273         0xffffffff,         /* Source mask.  */
00274         0xffffffff,         /* Dest mask.  */
00275         FALSE),             /* PCrel_offset.  */
00276 
00277   /* A 64 bit PC relative offset.  */
00278   HOWTO (ALPHA_R_SREL64,    /* Type.  */
00279         0,                  /* Rightshift.  */
00280         4,                  /* Size (0 = byte, 1 = short, 2 = long).  */
00281         64,                 /* Bitsize.  */
00282         TRUE,               /* PC_relative.  */
00283         0,                  /* Bitpos.  */
00284         complain_overflow_signed, /* Complain_on_overflow.  */
00285         0,                  /* Special_function.  */
00286         "SREL64",           /* Name.  */
00287         TRUE,               /* Partial_inplace.  */
00288         ONES (64),          /* Source mask.  */
00289         ONES (64),          /* Dest mask.  */
00290         FALSE),             /* PCrel_offset.  */
00291 
00292   /* Push a value on the reloc evaluation stack.  */
00293   HOWTO (ALPHA_R_OP_PUSH,   /* Type.  */
00294         0,                  /* Rightshift.  */
00295         0,                  /* Size (0 = byte, 1 = short, 2 = long).  */
00296         0,                  /* Bitsize.  */
00297         FALSE,                     /* PC_relative.  */
00298         0,                  /* Bitpos.  */
00299         complain_overflow_dont, /* Complain_on_overflow.  */
00300         0,                  /* Special_function.  */
00301         "OP_PUSH",          /* Name.  */
00302         FALSE,                     /* Partial_inplace.  */
00303         0,                  /* Source mask.  */
00304         0,                  /* Dest mask.  */
00305         FALSE),             /* PCrel_offset.  */
00306 
00307   /* Store the value from the stack at the given address.  Store it in
00308      a bitfield of size r_size starting at bit position r_offset.  */
00309   HOWTO (ALPHA_R_OP_STORE,  /* Type.  */
00310         0,                  /* Rightshift.  */
00311         4,                  /* Size (0 = byte, 1 = short, 2 = long).  */
00312         64,                 /* Bitsize.  */
00313         FALSE,                     /* PC_relative.  */
00314         0,                  /* Bitpos.  */
00315         complain_overflow_dont, /* Complain_on_overflow.  */
00316         0,                  /* Special_function.  */
00317         "OP_STORE",         /* Name.  */
00318         FALSE,                     /* Partial_inplace.  */
00319         0,                  /* Source mask.  */
00320         ONES (64),          /* Dest mask.  */
00321         FALSE),             /* PCrel_offset.  */
00322 
00323   /* Subtract the reloc address from the value on the top of the
00324      relocation stack.  */
00325   HOWTO (ALPHA_R_OP_PSUB,   /* Type.  */
00326         0,                  /* Rightshift.  */
00327         0,                  /* Size (0 = byte, 1 = short, 2 = long).  */
00328         0,                  /* Bitsize.  */
00329         FALSE,                     /* PC_relative.  */
00330         0,                  /* Bitpos.  */
00331         complain_overflow_dont, /* Complain_on_overflow.  */
00332         0,                  /* Special_function.  */
00333         "OP_PSUB",          /* Name.  */
00334         FALSE,                     /* Partial_inplace.  */
00335         0,                  /* Source mask.  */
00336         0,                  /* Dest mask.  */
00337         FALSE),             /* PCrel_offset.  */
00338 
00339   /* Shift the value on the top of the relocation stack right by the
00340      given value.  */
00341   HOWTO (ALPHA_R_OP_PRSHIFT,       /* Type.  */
00342         0,                  /* Rightshift.  */
00343         0,                  /* Size (0 = byte, 1 = short, 2 = long).  */
00344         0,                  /* Bitsize.  */
00345         FALSE,                     /* PC_relative.  */
00346         0,                  /* Bitpos.  */
00347         complain_overflow_dont, /* Complain_on_overflow.  */
00348         0,                   /* Special_function.  */
00349         "OP_PRSHIFT",              /* Name.  */
00350         FALSE,                     /* Partial_inplace.  */
00351         0,                  /* Source mask.  */
00352         0,                  /* Dest mask.  */
00353         FALSE),             /* PCrel_offset.  */
00354 
00355   /* Adjust the GP value for a new range in the object file.  */
00356   HOWTO (ALPHA_R_GPVALUE,   /* Type.  */
00357         0,                  /* Rightshift.  */
00358         0,                  /* Size (0 = byte, 1 = short, 2 = long).  */
00359         0,                  /* Bitsize.  */
00360         FALSE,                     /* PC_relative.  */
00361         0,                  /* Bitpos.  */
00362         complain_overflow_dont, /* Complain_on_overflow.  */
00363         0,                  /* Special_function.  */
00364         "GPVALUE",          /* Name.  */
00365         FALSE,                     /* Partial_inplace.  */
00366         0,                  /* Source mask.  */
00367         0,                  /* Dest mask.  */
00368         FALSE)                     /* PCrel_offset.  */
00369 };
00370 
00371 static reloc_howto_type nlm32_alpha_nw_howto =
00372   HOWTO (ALPHA_R_NW_RELOC,  /* Type.  */
00373         0,                  /* Rightshift.  */
00374         0,                  /* Size (0 = byte, 1 = short, 2 = long).  */
00375         0,                  /* Bitsize.  */
00376         FALSE,                     /* PC_relative.  */
00377         0,                  /* Bitpos.  */
00378         complain_overflow_dont, /* Complain_on_overflow.  */
00379         0,                  /* Special_function.  */
00380         "NW_RELOC",         /* Name.  */
00381         FALSE,                     /* Partial_inplace.  */
00382         0,                  /* Source mask.  */
00383         0,                  /* Dest mask.  */
00384         FALSE);             /* PCrel_offset.  */
00385 
00386 /* Read an Alpha NLM reloc.  This routine keeps some static data which
00387    it uses when handling local relocs.  This only works correctly
00388    because all the local relocs are read at once.  */
00389 
00390 static bfd_boolean
00391 nlm_alpha_read_reloc (bfd *abfd,
00392                     nlmNAME (symbol_type) *sym,
00393                     asection **secp,
00394                     arelent *rel)
00395 {
00396   static bfd_vma gp_value;
00397   static bfd_vma lita_address;
00398   struct nlm32_alpha_external_reloc ext;
00399   bfd_vma r_vaddr;
00400   long r_symndx;
00401   int r_type, r_extern, r_offset, r_size;
00402   asection *code_sec, *data_sec;
00403 
00404   /* Read the reloc from the file.  */
00405   if (bfd_bread (&ext, (bfd_size_type) sizeof ext, abfd) != sizeof ext)
00406     return FALSE;
00407 
00408   /* Swap in the reloc information.  */
00409   r_vaddr = H_GET_64 (abfd, ext.r_vaddr);
00410   r_symndx = H_GET_32 (abfd, ext.r_symndx);
00411 
00412   BFD_ASSERT (bfd_little_endian (abfd));
00413 
00414   r_type = ((ext.r_bits[0] & RELOC_BITS0_TYPE_LITTLE)
00415            >> RELOC_BITS0_TYPE_SH_LITTLE);
00416   r_extern = (ext.r_bits[1] & RELOC_BITS1_EXTERN_LITTLE) != 0;
00417   r_offset = ((ext.r_bits[1] & RELOC_BITS1_OFFSET_LITTLE)
00418              >> RELOC_BITS1_OFFSET_SH_LITTLE);
00419   /* Ignore the reserved bits.  */
00420   r_size = ((ext.r_bits[3] & RELOC_BITS3_SIZE_LITTLE)
00421            >> RELOC_BITS3_SIZE_SH_LITTLE);
00422 
00423   /* Fill in the BFD arelent structure.  */
00424   code_sec = bfd_get_section_by_name (abfd, NLM_CODE_NAME);
00425   data_sec = bfd_get_section_by_name (abfd, NLM_INITIALIZED_DATA_NAME);
00426   if (r_extern)
00427     {
00428       /* External relocations are only used for imports.  */
00429       BFD_ASSERT (sym != NULL);
00430       /* We don't need to set sym_ptr_ptr for this case.  It is set in
00431         nlm_canonicalize_reloc.  */
00432       rel->sym_ptr_ptr = NULL;
00433       rel->addend = 0;
00434     }
00435   else
00436     {
00437       /* Internal relocations are only used for local relocation
00438         fixups.  If they are not NW_RELOC or GPDISP or IGNORE, they
00439         must be against .text or .data.  */
00440       BFD_ASSERT (r_type == ALPHA_R_NW_RELOC || sym == NULL);
00441       if (r_type == ALPHA_R_NW_RELOC
00442          || r_type == ALPHA_R_GPDISP
00443          || r_type == ALPHA_R_IGNORE)
00444        {
00445          rel->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr;
00446          rel->addend = 0;
00447        }
00448       else if (r_symndx == ALPHA_RELOC_SECTION_TEXT)
00449        {
00450          rel->sym_ptr_ptr = code_sec->symbol_ptr_ptr;
00451          BFD_ASSERT (bfd_get_section_vma (abfd, code_sec) == 0);
00452          rel->addend = 0;
00453        }
00454       else if (r_symndx == ALPHA_RELOC_SECTION_DATA)
00455        {
00456          rel->sym_ptr_ptr = data_sec->symbol_ptr_ptr;
00457          rel->addend = - bfd_get_section_vma (abfd, data_sec);
00458        }
00459       else
00460        {
00461          BFD_ASSERT (0);
00462          rel->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr;
00463          rel->addend = 0;
00464        }
00465     }
00466 
00467   /* We use the address to determine whether the reloc is in the .text
00468      or .data section.  R_NW_RELOC relocs don't really have a section,
00469      so we put them in .text.  */
00470   if (r_type == ALPHA_R_NW_RELOC
00471       || r_vaddr < code_sec->size)
00472     {
00473       *secp = code_sec;
00474       rel->address = r_vaddr;
00475     }
00476   else
00477     {
00478       *secp = data_sec;
00479       rel->address = r_vaddr - code_sec->size;
00480     }
00481 
00482   /* We must adjust the addend based on the type.  */
00483   BFD_ASSERT ((r_type >= 0 && r_type <= ALPHA_R_GPVALUE)
00484              || r_type == ALPHA_R_NW_RELOC);
00485 
00486   switch (r_type)
00487     {
00488     case ALPHA_R_BRADDR:
00489     case ALPHA_R_SREL16:
00490     case ALPHA_R_SREL32:
00491     case ALPHA_R_SREL64:
00492       /* The PC relative relocs do not seem to use the section VMA as
00493         a negative addend.  */
00494       rel->addend = 0;
00495       break;
00496 
00497     case ALPHA_R_GPREL32:
00498       /* Copy the gp value for this object file into the addend, to
00499         ensure that we are not confused by the linker.  */
00500       if (! r_extern)
00501        rel->addend += gp_value;
00502       break;
00503 
00504     case ALPHA_R_LITERAL:
00505       BFD_ASSERT (! r_extern);
00506       rel->addend += lita_address;
00507       break;
00508 
00509     case ALPHA_R_LITUSE:
00510     case ALPHA_R_GPDISP:
00511       /* The LITUSE and GPDISP relocs do not use a symbol, or an
00512         addend, but they do use a special code.  Put this code in the
00513         addend field.  */
00514       rel->addend = r_symndx;
00515       rel->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr;
00516       break;
00517 
00518     case ALPHA_R_OP_STORE:
00519       /* The STORE reloc needs the size and offset fields.  We store
00520         them in the addend.  */
00521       BFD_ASSERT (r_offset < 256 && r_size < 256);
00522       rel->addend = (r_offset << 8) + r_size;
00523       break;
00524 
00525     case ALPHA_R_OP_PUSH:
00526     case ALPHA_R_OP_PSUB:
00527     case ALPHA_R_OP_PRSHIFT:
00528       /* The PUSH, PSUB and PRSHIFT relocs do not actually use an
00529         address.  I believe that the address supplied is really an
00530         addend.  */
00531       rel->addend = r_vaddr;
00532       break;
00533 
00534     case ALPHA_R_GPVALUE:
00535       /* Record the new gp value.  */
00536       gp_value += r_symndx;
00537       rel->addend = gp_value;
00538       break;
00539 
00540     case ALPHA_R_IGNORE:
00541       /* If the type is ALPHA_R_IGNORE, make sure this is a reference
00542         to the absolute section so that the reloc is ignored.  For
00543         some reason the address of this reloc type is not adjusted by
00544         the section vma.  We record the gp value for this object file
00545         here, for convenience when doing the GPDISP relocation.  */
00546       rel->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr;
00547       rel->address = r_vaddr;
00548       rel->addend = gp_value;
00549       break;
00550 
00551     case ALPHA_R_NW_RELOC:
00552       /* If this is SETGP, we set the addend to 0.  Otherwise we set
00553         the addend to the size of the .lita section (this is
00554         r_symndx) plus 1.  We have already set the address of the
00555         reloc to r_vaddr.  */
00556       if (r_size == ALPHA_R_NW_RELOC_SETGP)
00557        {
00558          gp_value = r_vaddr;
00559          rel->addend = 0;
00560        }
00561       else if (r_size == ALPHA_R_NW_RELOC_LITA)
00562        {
00563          lita_address = r_vaddr;
00564          rel->addend = r_symndx + 1;
00565        }
00566       else
00567        BFD_ASSERT (0);
00568       rel->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr;
00569       break;
00570 
00571     default:
00572       break;
00573     }
00574 
00575   if (r_type == ALPHA_R_NW_RELOC)
00576     rel->howto = &nlm32_alpha_nw_howto;
00577   else
00578     rel->howto = &nlm32_alpha_howto_table[r_type];
00579 
00580   return TRUE;
00581 }
00582 
00583 /* Mangle Alpha NLM relocs for output.  */
00584 
00585 static bfd_boolean
00586 nlm_alpha_mangle_relocs (bfd *abfd ATTRIBUTE_UNUSED,
00587                       asection *sec ATTRIBUTE_UNUSED,
00588                       const void * data ATTRIBUTE_UNUSED,
00589                       bfd_vma offset ATTRIBUTE_UNUSED,
00590                       bfd_size_type count ATTRIBUTE_UNUSED)
00591 {
00592   return TRUE;
00593 }
00594 
00595 /* Read an ALPHA NLM import record.  */
00596 
00597 static bfd_boolean
00598 nlm_alpha_read_import (bfd *abfd, nlmNAME (symbol_type) * sym)
00599 {
00600   struct nlm_relent *nlm_relocs;   /* Relocation records for symbol.  */
00601   bfd_size_type rcount;                   /* Number of relocs.  */
00602   bfd_byte temp[NLM_TARGET_LONG_SIZE];    /* Temporary 32-bit value.  */
00603   unsigned char symlength;         /* Length of symbol name.  */
00604   char *name;
00605   bfd_size_type amt;
00606 
00607   if (bfd_bread (& symlength, (bfd_size_type) sizeof (symlength), abfd)
00608       != sizeof (symlength))
00609     return FALSE;
00610   sym -> symbol.the_bfd = abfd;
00611   name = bfd_alloc (abfd, (bfd_size_type) symlength + 1);
00612   if (name == NULL)
00613     return FALSE;
00614   if (bfd_bread (name, (bfd_size_type) symlength, abfd) != symlength)
00615     return FALSE;
00616   name[symlength] = '\0';
00617   sym -> symbol.name = name;
00618   sym -> symbol.flags = 0;
00619   sym -> symbol.value = 0;
00620   sym -> symbol.section = bfd_und_section_ptr;
00621   if (bfd_bread (temp, (bfd_size_type) sizeof (temp), abfd)
00622       != sizeof (temp))
00623     return FALSE;
00624   rcount = H_GET_32 (abfd, temp);
00625   amt = rcount * sizeof (struct nlm_relent);
00626   nlm_relocs = bfd_alloc (abfd, amt);
00627   if (!nlm_relocs)
00628     return FALSE;
00629   sym -> relocs = nlm_relocs;
00630   sym -> rcnt = 0;
00631   while (sym -> rcnt < rcount)
00632     {
00633       asection *section;
00634 
00635       if (! nlm_alpha_read_reloc (abfd, sym, &section, &nlm_relocs -> reloc))
00636        return FALSE;
00637       nlm_relocs -> section = section;
00638       nlm_relocs++;
00639       sym -> rcnt++;
00640     }
00641 
00642   return TRUE;
00643 }
00644 
00645 /* Write an Alpha NLM reloc.  */
00646 
00647 static bfd_boolean
00648 nlm_alpha_write_import (bfd * abfd, asection * sec, arelent * rel)
00649 {
00650   asymbol *sym;
00651   bfd_vma r_vaddr;
00652   long r_symndx;
00653   int r_type, r_extern, r_offset, r_size;
00654   struct nlm32_alpha_external_reloc ext;
00655 
00656   sym = *rel->sym_ptr_ptr;
00657 
00658   /* Get values for the relocation fields.  */
00659   r_type = rel->howto->type;
00660   if (r_type != ALPHA_R_NW_RELOC)
00661     {
00662       r_vaddr = bfd_get_section_vma (abfd, sec) + rel->address;
00663       if ((sec->flags & SEC_CODE) == 0)
00664        r_vaddr += bfd_get_section_by_name (abfd, NLM_CODE_NAME) -> size;
00665       if (bfd_is_und_section (bfd_get_section (sym)))
00666        {
00667          r_extern = 1;
00668          r_symndx = 0;
00669        }
00670       else
00671        {
00672          r_extern = 0;
00673          if (bfd_get_section_flags (abfd, bfd_get_section (sym)) & SEC_CODE)
00674            r_symndx = ALPHA_RELOC_SECTION_TEXT;
00675          else
00676            r_symndx = ALPHA_RELOC_SECTION_DATA;
00677        }
00678       r_offset = 0;
00679       r_size = 0;
00680 
00681       switch (r_type)
00682        {
00683        case ALPHA_R_LITUSE:
00684        case ALPHA_R_GPDISP:
00685          r_symndx = rel->addend;
00686          break;
00687 
00688        case ALPHA_R_OP_STORE:
00689          r_size = rel->addend & 0xff;
00690          r_offset = (rel->addend >> 8) & 0xff;
00691          break;
00692 
00693        case ALPHA_R_OP_PUSH:
00694        case ALPHA_R_OP_PSUB:
00695        case ALPHA_R_OP_PRSHIFT:
00696          r_vaddr = rel->addend;
00697          break;
00698 
00699        case ALPHA_R_IGNORE:
00700          r_vaddr = rel->address;
00701          break;
00702 
00703        default:
00704          break;
00705        }
00706     }
00707   else
00708     {
00709       /* r_type == ALPHA_R_NW_RELOC.  */
00710       r_vaddr = rel->address;
00711       if (rel->addend == 0)
00712        {
00713          r_symndx = 0;
00714          r_size = ALPHA_R_NW_RELOC_SETGP;
00715        }
00716       else
00717        {
00718          r_symndx = rel->addend - 1;
00719          r_size = ALPHA_R_NW_RELOC_LITA;
00720        }
00721       r_extern = 0;
00722       r_offset = 0;
00723     }
00724 
00725   /* Swap out the relocation fields.  */
00726   H_PUT_64 (abfd, r_vaddr, ext.r_vaddr);
00727   H_PUT_32 (abfd, r_symndx, ext.r_symndx);
00728 
00729   BFD_ASSERT (bfd_little_endian (abfd));
00730 
00731   ext.r_bits[0] = ((r_type << RELOC_BITS0_TYPE_SH_LITTLE)
00732                  & RELOC_BITS0_TYPE_LITTLE);
00733   ext.r_bits[1] = ((r_extern ? RELOC_BITS1_EXTERN_LITTLE : 0)
00734                  | ((r_offset << RELOC_BITS1_OFFSET_SH_LITTLE)
00735                     & RELOC_BITS1_OFFSET_LITTLE));
00736   ext.r_bits[2] = 0;
00737   ext.r_bits[3] = ((r_size << RELOC_BITS3_SIZE_SH_LITTLE)
00738                  & RELOC_BITS3_SIZE_LITTLE);
00739 
00740   /* Write out the relocation.  */
00741   if (bfd_bwrite (&ext, (bfd_size_type) sizeof ext, abfd) != sizeof ext)
00742     return FALSE;
00743 
00744   return TRUE;
00745 }
00746 
00747 /* Alpha NetWare does not use the high bit to determine whether a
00748    public symbol is in the code segment or the data segment.  Instead,
00749    it just uses the address.  The set_public_section and
00750    get_public_offset routines override the default code which uses the
00751    high bit.  */
00752 
00753 /* Set the section for a public symbol.  */
00754 
00755 static bfd_boolean
00756 nlm_alpha_set_public_section (bfd * abfd, nlmNAME (symbol_type) * sym)
00757 {
00758   asection *code_sec, *data_sec;
00759 
00760   code_sec = bfd_get_section_by_name (abfd, NLM_CODE_NAME);
00761   data_sec = bfd_get_section_by_name (abfd, NLM_INITIALIZED_DATA_NAME);
00762   if (sym->symbol.value < code_sec->size)
00763     {
00764       sym->symbol.section = code_sec;
00765       sym->symbol.flags |= BSF_FUNCTION;
00766     }
00767   else
00768     {
00769       sym->symbol.section = data_sec;
00770       sym->symbol.value -= code_sec->size;
00771       /* The data segment had better be aligned.  */
00772       BFD_ASSERT ((code_sec->size & 0xf) == 0);
00773     }
00774   return TRUE;
00775 }
00776 
00777 /* Get the offset to write out for a public symbol.  */
00778 
00779 static bfd_vma
00780 nlm_alpha_get_public_offset (bfd * abfd ATTRIBUTE_UNUSED, asymbol * sym)
00781 {
00782   return bfd_asymbol_value (sym);
00783 }
00784 
00785 /* Write an Alpha NLM external symbol.  */
00786 
00787 static bfd_boolean
00788 nlm_alpha_write_external (bfd *abfd,
00789                        bfd_size_type count,
00790                        asymbol *sym,
00791                        struct reloc_and_sec *relocs)
00792 {
00793   bfd_size_type i;
00794   bfd_byte len;
00795   unsigned char temp[NLM_TARGET_LONG_SIZE];
00796   arelent r;
00797 
00798   len = strlen (sym->name);
00799   if ((bfd_bwrite (&len, (bfd_size_type) sizeof (bfd_byte), abfd)
00800        != sizeof (bfd_byte))
00801       || bfd_bwrite (sym->name, (bfd_size_type) len, abfd) != len)
00802     return FALSE;
00803 
00804   bfd_put_32 (abfd, count + 2, temp);
00805   if (bfd_bwrite (temp, (bfd_size_type) sizeof (temp), abfd) != sizeof (temp))
00806     return FALSE;
00807 
00808   /* The first two relocs for each external symbol are the .lita
00809      address and the GP value.  */
00810   r.sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr;
00811   r.howto = &nlm32_alpha_nw_howto;
00812 
00813   r.address = nlm_alpha_backend_data (abfd)->lita_address;
00814   r.addend = nlm_alpha_backend_data (abfd)->lita_size + 1;
00815   if (! nlm_alpha_write_import (abfd, NULL, &r))
00816     return FALSE;
00817 
00818   r.address = nlm_alpha_backend_data (abfd)->gp;
00819   r.addend = 0;
00820   if (! nlm_alpha_write_import (abfd, NULL, &r))
00821     return FALSE;
00822 
00823   for (i = 0; i < count; i++)
00824     if (! nlm_alpha_write_import (abfd, relocs[i].sec, relocs[i].rel))
00825       return FALSE;
00826 
00827   return TRUE;
00828 }
00829 
00830 #include "nlmswap.h"
00831 
00832 static const struct nlm_backend_data nlm32_alpha_backend =
00833 {
00834   "NetWare Alpha Module   \032",
00835   sizeof (Nlm32_alpha_External_Fixed_Header),
00836   sizeof (struct nlm32_alpha_external_prefix_header),
00837   bfd_arch_alpha,
00838   0,
00839   TRUE, /* No uninitialized data permitted by Alpha NetWare.  */
00840   nlm_alpha_backend_object_p,
00841   nlm_alpha_write_prefix,
00842   nlm_alpha_read_reloc,
00843   nlm_alpha_mangle_relocs,
00844   nlm_alpha_read_import,
00845   nlm_alpha_write_import,
00846   nlm_alpha_set_public_section,
00847   nlm_alpha_get_public_offset,
00848   nlm_swap_fixed_header_in,
00849   nlm_swap_fixed_header_out,
00850   nlm_alpha_write_external,
00851   0,   /* Write_export.  */
00852 };
00853 
00854 #define TARGET_LITTLE_NAME         "nlm32-alpha"
00855 #define TARGET_LITTLE_SYM          nlmNAME (alpha_vec)
00856 #define TARGET_BACKEND_DATA        & nlm32_alpha_backend
00857 
00858 #include "nlm-target.h"