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