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