1 /* Support for 32-bit Alpha NLM (NetWare Loadable Module)
2    Copyright (C) 1993-2016 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 
42 static bfd_boolean
nlm_alpha_backend_object_p(bfd * abfd)43 nlm_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 
66 static bfd_boolean
nlm_alpha_write_prefix(bfd * abfd)67 nlm_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 
84 static 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 
372 static 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 
391 static bfd_boolean
nlm_alpha_read_reloc(bfd * abfd,nlmNAME (symbol_type)* sym,asection ** secp,arelent * rel)392 nlm_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 
586 static bfd_boolean
nlm_alpha_mangle_relocs(bfd * abfd ATTRIBUTE_UNUSED,asection * sec ATTRIBUTE_UNUSED,const void * data ATTRIBUTE_UNUSED,bfd_vma offset ATTRIBUTE_UNUSED,bfd_size_type count ATTRIBUTE_UNUSED)587 nlm_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 
598 static bfd_boolean
nlm_alpha_read_import(bfd * abfd,nlmNAME (symbol_type)* sym)599 nlm_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 
648 static bfd_boolean
nlm_alpha_write_import(bfd * abfd,asection * sec,arelent * rel)649 nlm_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 
756 static bfd_boolean
nlm_alpha_set_public_section(bfd * abfd,nlmNAME (symbol_type)* sym)757 nlm_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 
780 static bfd_vma
nlm_alpha_get_public_offset(bfd * abfd ATTRIBUTE_UNUSED,asymbol * sym)781 nlm_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 
788 static bfd_boolean
nlm_alpha_write_external(bfd * abfd,bfd_size_type count,asymbol * sym,struct reloc_and_sec * relocs)789 nlm_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 
833 static 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