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