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