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