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