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