OSDN Git Service

Update the FSF address in the copyright/GPL notice
[pf3gnuchains/pf3gnuchains3x.git] / bfd / nlm32-alpha.c
1 /* Support for 32-bit Alpha NLM (NetWare Loadable Module)
2    Copyright 1993, 1994, 2000, 2001, 2002, 2003, 2004, 2005
3    Free Software Foundation, Inc.
4    Written by Ian Lance Taylor, Cygnus Support.
5
6    This file is part of BFD, the Binary File Descriptor library.
7
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 2 of the License, or
11    (at your option) any later version.
12
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02110-1301, USA.  */
21
22 /* This file describes the 32 bit Alpha NLM format.  You might think
23    that an Alpha chip would use a 64 bit format, but, for some reason,
24    it doesn't.  */
25
26 #include "bfd.h"
27 #include "sysdep.h"
28 #include "libbfd.h"
29
30 #define ARCH_SIZE 32
31
32 #include "nlm/alpha-ext.h"
33 #define Nlm_External_Fixed_Header       Nlm32_alpha_External_Fixed_Header
34
35 #include "libnlm.h"
36 \f
37 /* Alpha NLM's have a prefix header before the standard NLM.  This
38    function reads it in, verifies the version, and seeks the bfd to
39    the location before the regular NLM header.  */
40
41 static bfd_boolean
42 nlm_alpha_backend_object_p (bfd *abfd)
43 {
44   struct nlm32_alpha_external_prefix_header s;
45   file_ptr size;
46
47   if (bfd_bread (&s, (bfd_size_type) sizeof s, abfd) != sizeof s)
48     return FALSE;
49
50   if (H_GET_32 (abfd, s.magic) != NLM32_ALPHA_MAGIC)
51     return FALSE;
52
53   /* FIXME: Should we check the format number?  */
54
55   /* Skip to the end of the header.  */
56   size = H_GET_32 (abfd, s.size);
57   if (bfd_seek (abfd, size, SEEK_SET) != 0)
58     return FALSE;
59
60   return TRUE;
61 }
62
63 /* Write out the prefix.  */
64
65 static bfd_boolean
66 nlm_alpha_write_prefix (bfd *abfd)
67 {
68   struct nlm32_alpha_external_prefix_header s;
69
70   memset (&s, 0, sizeof s);
71   H_PUT_32 (abfd, NLM32_ALPHA_MAGIC, s.magic);
72   H_PUT_32 (abfd, 2, s.format);
73   H_PUT_32 (abfd, sizeof s, s.size);
74   if (bfd_bwrite (&s, (bfd_size_type) sizeof s, abfd) != sizeof s)
75     return FALSE;
76   return TRUE;
77 }
78 \f
79 #define ONES(n) (((bfd_vma) 1 << ((n) - 1) << 1) - 1)
80
81 /* How to process the various reloc types.  */
82
83 static reloc_howto_type nlm32_alpha_howto_table[] =
84 {
85   /* Reloc type 0 is ignored by itself.  However, it appears after a
86      GPDISP reloc to identify the location where the low order 16 bits
87      of the gp register are loaded.  */
88   HOWTO (ALPHA_R_IGNORE,        /* Type.  */
89          0,                     /* Rightshift.  */
90          0,                     /* Size (0 = byte, 1 = short, 2 = long).  */
91          8,                     /* Bitsize.  */
92          FALSE,                 /* PC_relative.  */
93          0,                     /* Bitpos.  */
94          complain_overflow_dont, /* Complain_on_overflow.  */
95          0,                     /* Special_function.  */
96          "IGNORE",              /* Name.  */
97          FALSE,                 /* Partial_inplace.  */
98          0,                     /* Source mask.  */
99          0,                     /* Dest mask.  */
100          FALSE),                /* PCrel_offset.  */
101
102   /* A 32 bit reference to a symbol.  */
103   HOWTO (ALPHA_R_REFLONG,       /* Type.  */
104          0,                     /* Rightshift.  */
105          2,                     /* Size (0 = byte, 1 = short, 2 = long).  */
106          32,                    /* Bitsize.  */
107          FALSE,                 /* PC_relative.  */
108          0,                     /* Bitpos.  */
109          complain_overflow_bitfield, /* Complain_on_overflow.  */
110          0,                     /* Special_function.  */
111          "REFLONG",             /* Name.  */
112          TRUE,                  /* Partial_inplace.  */
113          0xffffffff,            /* Source mask.  */
114          0xffffffff,            /* Dest mask.  */
115          FALSE),                /* PCrel_offset.  */
116
117   /* A 64 bit reference to a symbol.  */
118   HOWTO (ALPHA_R_REFQUAD,       /* Type.  */
119          0,                     /* Rightshift.  */
120          4,                     /* Size (0 = byte, 1 = short, 2 = long).  */
121          64,                    /* Bitsize.  */
122          FALSE,                 /* PC_relative.  */
123          0,                     /* Bitpos.  */
124          complain_overflow_bitfield, /* Complain_on_overflow.  */
125          0,                     /* Special_function.  */
126          "REFQUAD",             /* Name.  */
127          TRUE,                  /* Partial_inplace.  */
128          ONES (64),             /* Source mask.  */
129          ONES (64),             /* Dest mask.  */
130          FALSE),                /* PCrel_offset.  */
131
132   /* A 32 bit GP relative offset.  This is just like REFLONG except
133      that when the value is used the value of the gp register will be
134      added in.  */
135   HOWTO (ALPHA_R_GPREL32,       /* Type.  */
136          0,                     /* Rightshift.  */
137          2,                     /* Size (0 = byte, 1 = short, 2 = long).  */
138          32,                    /* Bitsize.  */
139          FALSE,                 /* PC_relative.  */
140          0,                     /* Bitpos.  */
141          complain_overflow_bitfield, /* Complain_on_overflow.  */
142          0,                     /* Special_function.  */
143          "GPREL32",             /* Name.  */
144          TRUE,                  /* Partial_inplace.  */
145          0xffffffff,            /* Source mask.  */
146          0xffffffff,            /* Dest mask.  */
147          FALSE),                /* PCrel_offset.  */
148
149   /* Used for an instruction that refers to memory off the GP
150      register.  The offset is 16 bits of the 32 bit instruction.  This
151      reloc always seems to be against the .lita section.  */
152   HOWTO (ALPHA_R_LITERAL,       /* Type.  */
153          0,                     /* Rightshift.  */
154          2,                     /* Size (0 = byte, 1 = short, 2 = long).  */
155          16,                    /* Bitsize.  */
156          FALSE,                 /* PC_relative.  */
157          0,                     /* Bitpos.  */
158          complain_overflow_signed, /* Complain_on_overflow.  */
159          0,                     /* Special_function.  */
160          "LITERAL",             /* Name.  */
161          TRUE,                  /* Partial_inplace.  */
162          0xffff,                /* Source mask.  */
163          0xffff,                /* Dest mask.  */
164          FALSE),                /* PCrel_offset.  */
165
166   /* This reloc only appears immediately following a LITERAL reloc.
167      It identifies a use of the literal.  It seems that the linker can
168      use this to eliminate a portion of the .lita section.  The symbol
169      index is special: 1 means the literal address is in the base
170      register of a memory format instruction; 2 means the literal
171      address is in the byte offset register of a byte-manipulation
172      instruction; 3 means the literal address is in the target
173      register of a jsr instruction.  This does not actually do any
174      relocation.  */
175   HOWTO (ALPHA_R_LITUSE,        /* Type.  */
176          0,                     /* Rightshift.  */
177          2,                     /* Size (0 = byte, 1 = short, 2 = long).  */
178          32,                    /* Bitsize.  */
179          FALSE,                 /* PC_relative.  */
180          0,                     /* Bitpos.  */
181          complain_overflow_dont, /* Complain_on_overflow.  */
182          0,                     /* Special_function.  */
183          "LITUSE",              /* Name.  */
184          FALSE,                 /* Partial_inplace.  */
185          0,                     /* Source mask.  */
186          0,                     /* Dest mask.  */
187          FALSE),                /* PCrel_offset.  */
188
189   /* Load the gp register.  This is always used for a ldah instruction
190      which loads the upper 16 bits of the gp register.  The next reloc
191      will be an IGNORE reloc which identifies the location of the lda
192      instruction which loads the lower 16 bits.  The symbol index of
193      the GPDISP instruction appears to actually be the number of bytes
194      between the ldah and lda instructions.  This gives two different
195      ways to determine where the lda instruction is; I don't know why
196      both are used.  The value to use for the relocation is the
197      difference between the GP value and the current location; the
198      load will always be done against a register holding the current
199      address.  */
200   HOWTO (ALPHA_R_GPDISP,        /* Type.  */
201          16,                    /* Rightshift.  */
202          2,                     /* Size (0 = byte, 1 = short, 2 = long).  */
203          16,                    /* Bitsize.  */
204          TRUE,                  /* PC_relative.  */
205          0,                     /* Bitpos.  */
206          complain_overflow_dont, /* Complain_on_overflow.  */
207          0,                     /* Special_function.  */
208          "GPDISP",              /* Name.  */
209          TRUE,                  /* Partial_inplace.  */
210          0xffff,                /* Source mask.  */
211          0xffff,                /* Dest mask.  */
212          TRUE),                 /* PCrel_offset.  */
213
214   /* A 21 bit branch.  The native assembler generates these for
215      branches within the text segment, and also fills in the PC
216      relative offset in the instruction.  It seems to me that this
217      reloc, unlike the others, is not partial_inplace.  */
218   HOWTO (ALPHA_R_BRADDR,        /* Type.  */
219          2,                     /* Rightshift.  */
220          2,                     /* Size (0 = byte, 1 = short, 2 = long).  */
221          21,                    /* Bitsize.  */
222          TRUE,                  /* PC_relative.  */
223          0,                     /* Bitpos.  */
224          complain_overflow_signed, /* Complain_on_overflow.  */
225          0,                     /* Special_function.  */
226          "BRADDR",              /* Name.  */
227          FALSE,                 /* Partial_inplace.  */
228          0,                     /* Source mask.  */
229          0x1fffff,              /* Dest mask.  */
230          FALSE),                /* PCrel_offset.  */
231
232   /* A hint for a jump to a register.  */
233   HOWTO (ALPHA_R_HINT,          /* Type.  */
234          2,                     /* Rightshift.  */
235          2,                     /* Size (0 = byte, 1 = short, 2 = long).  */
236          14,                    /* Bitsize.  */
237          FALSE,                 /* PC_relative.  */
238          0,                     /* Bitpos.  */
239          complain_overflow_dont, /* Complain_on_overflow.  */
240          0,                     /* Special_function.  */
241          "HINT",                /* Name.  */
242          TRUE,                  /* Partial_inplace.  */
243          0x3fff,                /* Source mask.  */
244          0x3fff,                /* Dest mask.  */
245          FALSE),                /* PCrel_offset.  */
246
247   /* 16 bit PC relative offset.  */
248   HOWTO (ALPHA_R_SREL16,        /* Type.  */
249          0,                     /* Rightshift.  */
250          1,                     /* Size (0 = byte, 1 = short, 2 = long).  */
251          16,                    /* Bitsize.  */
252          TRUE,                  /* PC_relative.  */
253          0,                     /* Bitpos.  */
254          complain_overflow_signed, /* Complain_on_overflow.  */
255          0,                     /* Special_function.  */
256          "SREL16",              /* Name.  */
257          TRUE,                  /* Partial_inplace.  */
258          0xffff,                /* Source mask.  */
259          0xffff,                /* Dest mask.  */
260          FALSE),                /* PCrel_offset.  */
261
262   /* 32 bit PC relative offset.  */
263   HOWTO (ALPHA_R_SREL32,        /* Type.  */
264          0,                     /* Rightshift.  */
265          2,                     /* Size (0 = byte, 1 = short, 2 = long).  */
266          32,                    /* Bitsize.  */
267          TRUE,                  /* PC_relative.  */
268          0,                     /* Bitpos.  */
269          complain_overflow_signed, /* Complain_on_overflow.  */
270          0,                     /* Special_function.  */
271          "SREL32",              /* Name.  */
272          TRUE,                  /* Partial_inplace.  */
273          0xffffffff,            /* Source mask.  */
274          0xffffffff,            /* Dest mask.  */
275          FALSE),                /* PCrel_offset.  */
276
277   /* A 64 bit PC relative offset.  */
278   HOWTO (ALPHA_R_SREL64,        /* Type.  */
279          0,                     /* Rightshift.  */
280          4,                     /* Size (0 = byte, 1 = short, 2 = long).  */
281          64,                    /* Bitsize.  */
282          TRUE,                  /* PC_relative.  */
283          0,                     /* Bitpos.  */
284          complain_overflow_signed, /* Complain_on_overflow.  */
285          0,                     /* Special_function.  */
286          "SREL64",              /* Name.  */
287          TRUE,                  /* Partial_inplace.  */
288          ONES (64),             /* Source mask.  */
289          ONES (64),             /* Dest mask.  */
290          FALSE),                /* PCrel_offset.  */
291
292   /* Push a value on the reloc evaluation stack.  */
293   HOWTO (ALPHA_R_OP_PUSH,       /* Type.  */
294          0,                     /* Rightshift.  */
295          0,                     /* Size (0 = byte, 1 = short, 2 = long).  */
296          0,                     /* Bitsize.  */
297          FALSE,                 /* PC_relative.  */
298          0,                     /* Bitpos.  */
299          complain_overflow_dont, /* Complain_on_overflow.  */
300          0,                     /* Special_function.  */
301          "OP_PUSH",             /* Name.  */
302          FALSE,                 /* Partial_inplace.  */
303          0,                     /* Source mask.  */
304          0,                     /* Dest mask.  */
305          FALSE),                /* PCrel_offset.  */
306
307   /* Store the value from the stack at the given address.  Store it in
308      a bitfield of size r_size starting at bit position r_offset.  */
309   HOWTO (ALPHA_R_OP_STORE,      /* Type.  */
310          0,                     /* Rightshift.  */
311          4,                     /* Size (0 = byte, 1 = short, 2 = long).  */
312          64,                    /* Bitsize.  */
313          FALSE,                 /* PC_relative.  */
314          0,                     /* Bitpos.  */
315          complain_overflow_dont, /* Complain_on_overflow.  */
316          0,                     /* Special_function.  */
317          "OP_STORE",            /* Name.  */
318          FALSE,                 /* Partial_inplace.  */
319          0,                     /* Source mask.  */
320          ONES (64),             /* Dest mask.  */
321          FALSE),                /* PCrel_offset.  */
322
323   /* Subtract the reloc address from the value on the top of the
324      relocation stack.  */
325   HOWTO (ALPHA_R_OP_PSUB,       /* Type.  */
326          0,                     /* Rightshift.  */
327          0,                     /* Size (0 = byte, 1 = short, 2 = long).  */
328          0,                     /* Bitsize.  */
329          FALSE,                 /* PC_relative.  */
330          0,                     /* Bitpos.  */
331          complain_overflow_dont, /* Complain_on_overflow.  */
332          0,                     /* Special_function.  */
333          "OP_PSUB",             /* Name.  */
334          FALSE,                 /* Partial_inplace.  */
335          0,                     /* Source mask.  */
336          0,                     /* Dest mask.  */
337          FALSE),                /* PCrel_offset.  */
338
339   /* Shift the value on the top of the relocation stack right by the
340      given value.  */
341   HOWTO (ALPHA_R_OP_PRSHIFT,    /* Type.  */
342          0,                     /* Rightshift.  */
343          0,                     /* Size (0 = byte, 1 = short, 2 = long).  */
344          0,                     /* Bitsize.  */
345          FALSE,                 /* PC_relative.  */
346          0,                     /* Bitpos.  */
347          complain_overflow_dont, /* Complain_on_overflow.  */
348          0,                      /* Special_function.  */
349          "OP_PRSHIFT",          /* Name.  */
350          FALSE,                 /* Partial_inplace.  */
351          0,                     /* Source mask.  */
352          0,                     /* Dest mask.  */
353          FALSE),                /* PCrel_offset.  */
354
355   /* Adjust the GP value for a new range in the object file.  */
356   HOWTO (ALPHA_R_GPVALUE,       /* Type.  */
357          0,                     /* Rightshift.  */
358          0,                     /* Size (0 = byte, 1 = short, 2 = long).  */
359          0,                     /* Bitsize.  */
360          FALSE,                 /* PC_relative.  */
361          0,                     /* Bitpos.  */
362          complain_overflow_dont, /* Complain_on_overflow.  */
363          0,                     /* Special_function.  */
364          "GPVALUE",             /* Name.  */
365          FALSE,                 /* Partial_inplace.  */
366          0,                     /* Source mask.  */
367          0,                     /* Dest mask.  */
368          FALSE)                 /* PCrel_offset.  */
369 };
370
371 static reloc_howto_type nlm32_alpha_nw_howto =
372   HOWTO (ALPHA_R_NW_RELOC,      /* Type.  */
373          0,                     /* Rightshift.  */
374          0,                     /* Size (0 = byte, 1 = short, 2 = long).  */
375          0,                     /* Bitsize.  */
376          FALSE,                 /* PC_relative.  */
377          0,                     /* Bitpos.  */
378          complain_overflow_dont, /* Complain_on_overflow.  */
379          0,                     /* Special_function.  */
380          "NW_RELOC",            /* Name.  */
381          FALSE,                 /* Partial_inplace.  */
382          0,                     /* Source mask.  */
383          0,                     /* Dest mask.  */
384          FALSE);                /* PCrel_offset.  */
385
386 /* Read an Alpha NLM reloc.  This routine keeps some static data which
387    it uses when handling local relocs.  This only works correctly
388    because all the local relocs are read at once.  */
389
390 static bfd_boolean
391 nlm_alpha_read_reloc (bfd *abfd,
392                       nlmNAME (symbol_type) *sym,
393                       asection **secp,
394                       arelent *rel)
395 {
396   static bfd_vma gp_value;
397   static bfd_vma lita_address;
398   struct nlm32_alpha_external_reloc ext;
399   bfd_vma r_vaddr;
400   long r_symndx;
401   int r_type, r_extern, r_offset, r_size;
402   asection *code_sec, *data_sec;
403
404   /* Read the reloc from the file.  */
405   if (bfd_bread (&ext, (bfd_size_type) sizeof ext, abfd) != sizeof ext)
406     return FALSE;
407
408   /* Swap in the reloc information.  */
409   r_vaddr = H_GET_64 (abfd, ext.r_vaddr);
410   r_symndx = H_GET_32 (abfd, ext.r_symndx);
411
412   BFD_ASSERT (bfd_little_endian (abfd));
413
414   r_type = ((ext.r_bits[0] & RELOC_BITS0_TYPE_LITTLE)
415             >> RELOC_BITS0_TYPE_SH_LITTLE);
416   r_extern = (ext.r_bits[1] & RELOC_BITS1_EXTERN_LITTLE) != 0;
417   r_offset = ((ext.r_bits[1] & RELOC_BITS1_OFFSET_LITTLE)
418               >> RELOC_BITS1_OFFSET_SH_LITTLE);
419   /* Ignore the reserved bits.  */
420   r_size = ((ext.r_bits[3] & RELOC_BITS3_SIZE_LITTLE)
421             >> RELOC_BITS3_SIZE_SH_LITTLE);
422
423   /* Fill in the BFD arelent structure.  */
424   code_sec = bfd_get_section_by_name (abfd, NLM_CODE_NAME);
425   data_sec = bfd_get_section_by_name (abfd, NLM_INITIALIZED_DATA_NAME);
426   if (r_extern)
427     {
428       /* External relocations are only used for imports.  */
429       BFD_ASSERT (sym != NULL);
430       /* We don't need to set sym_ptr_ptr for this case.  It is set in
431          nlm_canonicalize_reloc.  */
432       rel->sym_ptr_ptr = NULL;
433       rel->addend = 0;
434     }
435   else
436     {
437       /* Internal relocations are only used for local relocation
438          fixups.  If they are not NW_RELOC or GPDISP or IGNORE, they
439          must be against .text or .data.  */
440       BFD_ASSERT (r_type == ALPHA_R_NW_RELOC || sym == NULL);
441       if (r_type == ALPHA_R_NW_RELOC
442           || r_type == ALPHA_R_GPDISP
443           || r_type == ALPHA_R_IGNORE)
444         {
445           rel->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr;
446           rel->addend = 0;
447         }
448       else if (r_symndx == ALPHA_RELOC_SECTION_TEXT)
449         {
450           rel->sym_ptr_ptr = code_sec->symbol_ptr_ptr;
451           BFD_ASSERT (bfd_get_section_vma (abfd, code_sec) == 0);
452           rel->addend = 0;
453         }
454       else if (r_symndx == ALPHA_RELOC_SECTION_DATA)
455         {
456           rel->sym_ptr_ptr = data_sec->symbol_ptr_ptr;
457           rel->addend = - bfd_get_section_vma (abfd, data_sec);
458         }
459       else
460         {
461           BFD_ASSERT (0);
462           rel->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr;
463           rel->addend = 0;
464         }
465     }
466
467   /* We use the address to determine whether the reloc is in the .text
468      or .data section.  R_NW_RELOC relocs don't really have a section,
469      so we put them in .text.  */
470   if (r_type == ALPHA_R_NW_RELOC
471       || r_vaddr < code_sec->size)
472     {
473       *secp = code_sec;
474       rel->address = r_vaddr;
475     }
476   else
477     {
478       *secp = data_sec;
479       rel->address = r_vaddr - code_sec->size;
480     }
481
482   /* We must adjust the addend based on the type.  */
483   BFD_ASSERT ((r_type >= 0 && r_type <= ALPHA_R_GPVALUE)
484               || r_type == ALPHA_R_NW_RELOC);
485
486   switch (r_type)
487     {
488     case ALPHA_R_BRADDR:
489     case ALPHA_R_SREL16:
490     case ALPHA_R_SREL32:
491     case ALPHA_R_SREL64:
492       /* The PC relative relocs do not seem to use the section VMA as
493          a negative addend.  */
494       rel->addend = 0;
495       break;
496
497     case ALPHA_R_GPREL32:
498       /* Copy the gp value for this object file into the addend, to
499          ensure that we are not confused by the linker.  */
500       if (! r_extern)
501         rel->addend += gp_value;
502       break;
503
504     case ALPHA_R_LITERAL:
505       BFD_ASSERT (! r_extern);
506       rel->addend += lita_address;
507       break;
508
509     case ALPHA_R_LITUSE:
510     case ALPHA_R_GPDISP:
511       /* The LITUSE and GPDISP relocs do not use a symbol, or an
512          addend, but they do use a special code.  Put this code in the
513          addend field.  */
514       rel->addend = r_symndx;
515       rel->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr;
516       break;
517
518     case ALPHA_R_OP_STORE:
519       /* The STORE reloc needs the size and offset fields.  We store
520          them in the addend.  */
521       BFD_ASSERT (r_offset < 256 && r_size < 256);
522       rel->addend = (r_offset << 8) + r_size;
523       break;
524
525     case ALPHA_R_OP_PUSH:
526     case ALPHA_R_OP_PSUB:
527     case ALPHA_R_OP_PRSHIFT:
528       /* The PUSH, PSUB and PRSHIFT relocs do not actually use an
529          address.  I believe that the address supplied is really an
530          addend.  */
531       rel->addend = r_vaddr;
532       break;
533
534     case ALPHA_R_GPVALUE:
535       /* Record the new gp value.  */
536       gp_value += r_symndx;
537       rel->addend = gp_value;
538       break;
539
540     case ALPHA_R_IGNORE:
541       /* If the type is ALPHA_R_IGNORE, make sure this is a reference
542          to the absolute section so that the reloc is ignored.  For
543          some reason the address of this reloc type is not adjusted by
544          the section vma.  We record the gp value for this object file
545          here, for convenience when doing the GPDISP relocation.  */
546       rel->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr;
547       rel->address = r_vaddr;
548       rel->addend = gp_value;
549       break;
550
551     case ALPHA_R_NW_RELOC:
552       /* If this is SETGP, we set the addend to 0.  Otherwise we set
553          the addend to the size of the .lita section (this is
554          r_symndx) plus 1.  We have already set the address of the
555          reloc to r_vaddr.  */
556       if (r_size == ALPHA_R_NW_RELOC_SETGP)
557         {
558           gp_value = r_vaddr;
559           rel->addend = 0;
560         }
561       else if (r_size == ALPHA_R_NW_RELOC_LITA)
562         {
563           lita_address = r_vaddr;
564           rel->addend = r_symndx + 1;
565         }
566       else
567         BFD_ASSERT (0);
568       rel->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr;
569       break;
570
571     default:
572       break;
573     }
574
575   if (r_type == ALPHA_R_NW_RELOC)
576     rel->howto = &nlm32_alpha_nw_howto;
577   else
578     rel->howto = &nlm32_alpha_howto_table[r_type];
579
580   return TRUE;
581 }
582
583 /* Mangle Alpha NLM relocs for output.  */
584
585 static bfd_boolean
586 nlm_alpha_mangle_relocs (bfd *abfd ATTRIBUTE_UNUSED,
587                          asection *sec ATTRIBUTE_UNUSED,
588                          const void * data ATTRIBUTE_UNUSED,
589                          bfd_vma offset ATTRIBUTE_UNUSED,
590                          bfd_size_type count ATTRIBUTE_UNUSED)
591 {
592   return TRUE;
593 }
594
595 /* Read an ALPHA NLM import record.  */
596
597 static bfd_boolean
598 nlm_alpha_read_import (bfd *abfd, nlmNAME (symbol_type) * sym)
599 {
600   struct nlm_relent *nlm_relocs;        /* Relocation records for symbol.  */
601   bfd_size_type rcount;                 /* Number of relocs.  */
602   bfd_byte temp[NLM_TARGET_LONG_SIZE];  /* Temporary 32-bit value.  */
603   unsigned char symlength;              /* Length of symbol name.  */
604   char *name;
605   bfd_size_type amt;
606
607   if (bfd_bread (& symlength, (bfd_size_type) sizeof (symlength), abfd)
608       != sizeof (symlength))
609     return FALSE;
610   sym -> symbol.the_bfd = abfd;
611   name = bfd_alloc (abfd, (bfd_size_type) symlength + 1);
612   if (name == NULL)
613     return FALSE;
614   if (bfd_bread (name, (bfd_size_type) symlength, abfd) != symlength)
615     return FALSE;
616   name[symlength] = '\0';
617   sym -> symbol.name = name;
618   sym -> symbol.flags = 0;
619   sym -> symbol.value = 0;
620   sym -> symbol.section = bfd_und_section_ptr;
621   if (bfd_bread (temp, (bfd_size_type) sizeof (temp), abfd)
622       != sizeof (temp))
623     return FALSE;
624   rcount = H_GET_32 (abfd, temp);
625   amt = rcount * sizeof (struct nlm_relent);
626   nlm_relocs = bfd_alloc (abfd, amt);
627   if (!nlm_relocs)
628     return FALSE;
629   sym -> relocs = nlm_relocs;
630   sym -> rcnt = 0;
631   while (sym -> rcnt < rcount)
632     {
633       asection *section;
634
635       if (! nlm_alpha_read_reloc (abfd, sym, &section, &nlm_relocs -> reloc))
636         return FALSE;
637       nlm_relocs -> section = section;
638       nlm_relocs++;
639       sym -> rcnt++;
640     }
641
642   return TRUE;
643 }
644
645 /* Write an Alpha NLM reloc.  */
646
647 static bfd_boolean
648 nlm_alpha_write_import (bfd * abfd, asection * sec, arelent * rel)
649 {
650   asymbol *sym;
651   bfd_vma r_vaddr;
652   long r_symndx;
653   int r_type, r_extern, r_offset, r_size;
654   struct nlm32_alpha_external_reloc ext;
655
656   sym = *rel->sym_ptr_ptr;
657
658   /* Get values for the relocation fields.  */
659   r_type = rel->howto->type;
660   if (r_type != ALPHA_R_NW_RELOC)
661     {
662       r_vaddr = bfd_get_section_vma (abfd, sec) + rel->address;
663       if ((sec->flags & SEC_CODE) == 0)
664         r_vaddr += bfd_get_section_by_name (abfd, NLM_CODE_NAME) -> size;
665       if (bfd_is_und_section (bfd_get_section (sym)))
666         {
667           r_extern = 1;
668           r_symndx = 0;
669         }
670       else
671         {
672           r_extern = 0;
673           if (bfd_get_section_flags (abfd, bfd_get_section (sym)) & SEC_CODE)
674             r_symndx = ALPHA_RELOC_SECTION_TEXT;
675           else
676             r_symndx = ALPHA_RELOC_SECTION_DATA;
677         }
678       r_offset = 0;
679       r_size = 0;
680
681       switch (r_type)
682         {
683         case ALPHA_R_LITUSE:
684         case ALPHA_R_GPDISP:
685           r_symndx = rel->addend;
686           break;
687
688         case ALPHA_R_OP_STORE:
689           r_size = rel->addend & 0xff;
690           r_offset = (rel->addend >> 8) & 0xff;
691           break;
692
693         case ALPHA_R_OP_PUSH:
694         case ALPHA_R_OP_PSUB:
695         case ALPHA_R_OP_PRSHIFT:
696           r_vaddr = rel->addend;
697           break;
698
699         case ALPHA_R_IGNORE:
700           r_vaddr = rel->address;
701           break;
702
703         default:
704           break;
705         }
706     }
707   else
708     {
709       /* r_type == ALPHA_R_NW_RELOC.  */
710       r_vaddr = rel->address;
711       if (rel->addend == 0)
712         {
713           r_symndx = 0;
714           r_size = ALPHA_R_NW_RELOC_SETGP;
715         }
716       else
717         {
718           r_symndx = rel->addend - 1;
719           r_size = ALPHA_R_NW_RELOC_LITA;
720         }
721       r_extern = 0;
722       r_offset = 0;
723     }
724
725   /* Swap out the relocation fields.  */
726   H_PUT_64 (abfd, r_vaddr, ext.r_vaddr);
727   H_PUT_32 (abfd, r_symndx, ext.r_symndx);
728
729   BFD_ASSERT (bfd_little_endian (abfd));
730
731   ext.r_bits[0] = ((r_type << RELOC_BITS0_TYPE_SH_LITTLE)
732                    & RELOC_BITS0_TYPE_LITTLE);
733   ext.r_bits[1] = ((r_extern ? RELOC_BITS1_EXTERN_LITTLE : 0)
734                    | ((r_offset << RELOC_BITS1_OFFSET_SH_LITTLE)
735                       & RELOC_BITS1_OFFSET_LITTLE));
736   ext.r_bits[2] = 0;
737   ext.r_bits[3] = ((r_size << RELOC_BITS3_SIZE_SH_LITTLE)
738                    & RELOC_BITS3_SIZE_LITTLE);
739
740   /* Write out the relocation.  */
741   if (bfd_bwrite (&ext, (bfd_size_type) sizeof ext, abfd) != sizeof ext)
742     return FALSE;
743
744   return TRUE;
745 }
746 \f
747 /* Alpha NetWare does not use the high bit to determine whether a
748    public symbol is in the code segment or the data segment.  Instead,
749    it just uses the address.  The set_public_section and
750    get_public_offset routines override the default code which uses the
751    high bit.  */
752
753 /* Set the section for a public symbol.  */
754
755 static bfd_boolean
756 nlm_alpha_set_public_section (bfd * abfd, nlmNAME (symbol_type) * sym)
757 {
758   asection *code_sec, *data_sec;
759
760   code_sec = bfd_get_section_by_name (abfd, NLM_CODE_NAME);
761   data_sec = bfd_get_section_by_name (abfd, NLM_INITIALIZED_DATA_NAME);
762   if (sym->symbol.value < code_sec->size)
763     {
764       sym->symbol.section = code_sec;
765       sym->symbol.flags |= BSF_FUNCTION;
766     }
767   else
768     {
769       sym->symbol.section = data_sec;
770       sym->symbol.value -= code_sec->size;
771       /* The data segment had better be aligned.  */
772       BFD_ASSERT ((code_sec->size & 0xf) == 0);
773     }
774   return TRUE;
775 }
776
777 /* Get the offset to write out for a public symbol.  */
778
779 static bfd_vma
780 nlm_alpha_get_public_offset (bfd * abfd ATTRIBUTE_UNUSED, asymbol * sym)
781 {
782   return bfd_asymbol_value (sym);
783 }
784 \f
785 /* Write an Alpha NLM external symbol.  */
786
787 static bfd_boolean
788 nlm_alpha_write_external (bfd *abfd,
789                           bfd_size_type count,
790                           asymbol *sym,
791                           struct reloc_and_sec *relocs)
792 {
793   bfd_size_type i;
794   bfd_byte len;
795   unsigned char temp[NLM_TARGET_LONG_SIZE];
796   arelent r;
797
798   len = strlen (sym->name);
799   if ((bfd_bwrite (&len, (bfd_size_type) sizeof (bfd_byte), abfd)
800        != sizeof (bfd_byte))
801       || bfd_bwrite (sym->name, (bfd_size_type) len, abfd) != len)
802     return FALSE;
803
804   bfd_put_32 (abfd, count + 2, temp);
805   if (bfd_bwrite (temp, (bfd_size_type) sizeof (temp), abfd) != sizeof (temp))
806     return FALSE;
807
808   /* The first two relocs for each external symbol are the .lita
809      address and the GP value.  */
810   r.sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr;
811   r.howto = &nlm32_alpha_nw_howto;
812
813   r.address = nlm_alpha_backend_data (abfd)->lita_address;
814   r.addend = nlm_alpha_backend_data (abfd)->lita_size + 1;
815   if (! nlm_alpha_write_import (abfd, NULL, &r))
816     return FALSE;
817
818   r.address = nlm_alpha_backend_data (abfd)->gp;
819   r.addend = 0;
820   if (! nlm_alpha_write_import (abfd, NULL, &r))
821     return FALSE;
822
823   for (i = 0; i < count; i++)
824     if (! nlm_alpha_write_import (abfd, relocs[i].sec, relocs[i].rel))
825       return FALSE;
826
827   return TRUE;
828 }
829
830 #include "nlmswap.h"
831
832 static const struct nlm_backend_data nlm32_alpha_backend =
833 {
834   "NetWare Alpha Module   \032",
835   sizeof (Nlm32_alpha_External_Fixed_Header),
836   sizeof (struct nlm32_alpha_external_prefix_header),
837   bfd_arch_alpha,
838   0,
839   TRUE, /* No uninitialized data permitted by Alpha NetWare.  */
840   nlm_alpha_backend_object_p,
841   nlm_alpha_write_prefix,
842   nlm_alpha_read_reloc,
843   nlm_alpha_mangle_relocs,
844   nlm_alpha_read_import,
845   nlm_alpha_write_import,
846   nlm_alpha_set_public_section,
847   nlm_alpha_get_public_offset,
848   nlm_swap_fixed_header_in,
849   nlm_swap_fixed_header_out,
850   nlm_alpha_write_external,
851   0,    /* Write_export.  */
852 };
853
854 #define TARGET_LITTLE_NAME              "nlm32-alpha"
855 #define TARGET_LITTLE_SYM               nlmNAME (alpha_vec)
856 #define TARGET_BACKEND_DATA             & nlm32_alpha_backend
857
858 #include "nlm-target.h"