Touches most files in bfd/, so likely will be blamed for everything..
[platform/upstream/binutils.git] / bfd / nlm32-alpha.c
1 /* Support for 32-bit Alpha NLM (NetWare Loadable Module)
2    Copyright 1993, 1994, 2000, 2001 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 \f
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   file_ptr size;
65
66   if (bfd_bread ((PTR) &s, (bfd_size_type) sizeof s, abfd) != sizeof s)
67     return false;
68
69   if (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 = 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   H_PUT_32 (abfd, NLM32_ALPHA_MAGIC, s.magic);
92   H_PUT_32 (abfd, 2, s.format);
93   H_PUT_32 (abfd, sizeof s, s.size);
94   if (bfd_bwrite ((PTR) &s, (bfd_size_type) sizeof s, abfd) != sizeof s)
95     return false;
96   return true;
97 }
98 \f
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_bread (&ext, (bfd_size_type) sizeof ext, abfd) != sizeof ext)
425     return false;
426
427   /* Swap in the reloc information.  */
428   r_vaddr = H_GET_64 (abfd, ext.r_vaddr);
429   r_symndx = H_GET_32 (abfd, 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 ATTRIBUTE_UNUSED;
607      asection *sec ATTRIBUTE_UNUSED;
608      PTR data ATTRIBUTE_UNUSED;
609      bfd_vma offset ATTRIBUTE_UNUSED;
610      bfd_size_type count ATTRIBUTE_UNUSED;
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   bfd_size_type amt;
628
629   if (bfd_bread ((PTR) &symlength, (bfd_size_type) sizeof (symlength), abfd)
630       != sizeof (symlength))
631     return false;
632   sym -> symbol.the_bfd = abfd;
633   name = bfd_alloc (abfd, (bfd_size_type) symlength + 1);
634   if (name == NULL)
635     return false;
636   if (bfd_bread (name, (bfd_size_type) symlength, abfd) != symlength)
637     return false;
638   name[symlength] = '\0';
639   sym -> symbol.name = name;
640   sym -> symbol.flags = 0;
641   sym -> symbol.value = 0;
642   sym -> symbol.section = bfd_und_section_ptr;
643   if (bfd_bread ((PTR) temp, (bfd_size_type) sizeof (temp), abfd)
644       != sizeof (temp))
645     return false;
646   rcount = H_GET_32 (abfd, temp);
647   amt = rcount * sizeof (struct nlm_relent);
648   nlm_relocs = (struct nlm_relent *) bfd_alloc (abfd, amt);
649   if (!nlm_relocs)
650     return false;
651   sym -> relocs = nlm_relocs;
652   sym -> rcnt = 0;
653   while (sym -> rcnt < rcount)
654     {
655       asection *section;
656
657       if (nlm_alpha_read_reloc (abfd, sym, &section,
658                                 &nlm_relocs -> reloc)
659           == false)
660         return false;
661       nlm_relocs -> section = section;
662       nlm_relocs++;
663       sym -> rcnt++;
664     }
665
666   return true;
667 }
668
669 /* Write an Alpha NLM reloc.  */
670
671 static boolean
672 nlm_alpha_write_import (abfd, sec, rel)
673      bfd *abfd;
674      asection *sec;
675      arelent *rel;
676 {
677   asymbol *sym;
678   bfd_vma r_vaddr;
679   long r_symndx;
680   int r_type, r_extern, r_offset, r_size;
681   struct nlm32_alpha_external_reloc ext;
682
683   sym = *rel->sym_ptr_ptr;
684
685   /* Get values for the relocation fields.  */
686   r_type = rel->howto->type;
687   if (r_type != ALPHA_R_NW_RELOC)
688     {
689       r_vaddr = bfd_get_section_vma (abfd, sec) + rel->address;
690       if ((sec->flags & SEC_CODE) == 0)
691         r_vaddr += bfd_section_size (abfd,
692                                      bfd_get_section_by_name (abfd,
693                                                               NLM_CODE_NAME));
694       if (bfd_is_und_section (bfd_get_section (sym)))
695         {
696           r_extern = 1;
697           r_symndx = 0;
698         }
699       else
700         {
701           r_extern = 0;
702           if (bfd_get_section_flags (abfd, bfd_get_section (sym)) & SEC_CODE)
703             r_symndx = ALPHA_RELOC_SECTION_TEXT;
704           else
705             r_symndx = ALPHA_RELOC_SECTION_DATA;
706         }
707       r_offset = 0;
708       r_size = 0;
709
710       switch (r_type)
711         {
712         case ALPHA_R_LITUSE:
713         case ALPHA_R_GPDISP:
714           r_symndx = rel->addend;
715           break;
716
717         case ALPHA_R_OP_STORE:
718           r_size = rel->addend & 0xff;
719           r_offset = (rel->addend >> 8) & 0xff;
720           break;
721
722         case ALPHA_R_OP_PUSH:
723         case ALPHA_R_OP_PSUB:
724         case ALPHA_R_OP_PRSHIFT:
725           r_vaddr = rel->addend;
726           break;
727
728         case ALPHA_R_IGNORE:
729           r_vaddr = rel->address;
730           break;
731
732         default:
733           break;
734         }
735     }
736   else
737     {
738       /* r_type == ALPHA_R_NW_RELOC */
739       r_vaddr = rel->address;
740       if (rel->addend == 0)
741         {
742           r_symndx = 0;
743           r_size = ALPHA_R_NW_RELOC_SETGP;
744         }
745       else
746         {
747           r_symndx = rel->addend - 1;
748           r_size = ALPHA_R_NW_RELOC_LITA;
749         }
750       r_extern = 0;
751       r_offset = 0;
752     }
753
754   /* Swap out the relocation fields.  */
755   H_PUT_64 (abfd, r_vaddr, ext.r_vaddr);
756   H_PUT_32 (abfd, r_symndx, ext.r_symndx);
757
758   BFD_ASSERT (bfd_little_endian (abfd));
759
760   ext.r_bits[0] = ((r_type << RELOC_BITS0_TYPE_SH_LITTLE)
761                    & RELOC_BITS0_TYPE_LITTLE);
762   ext.r_bits[1] = ((r_extern ? RELOC_BITS1_EXTERN_LITTLE : 0)
763                    | ((r_offset << RELOC_BITS1_OFFSET_SH_LITTLE)
764                       & RELOC_BITS1_OFFSET_LITTLE));
765   ext.r_bits[2] = 0;
766   ext.r_bits[3] = ((r_size << RELOC_BITS3_SIZE_SH_LITTLE)
767                    & RELOC_BITS3_SIZE_LITTLE);
768
769   /* Write out the relocation.  */
770   if (bfd_bwrite (&ext, (bfd_size_type) sizeof ext, abfd) != sizeof ext)
771     return false;
772
773   return true;
774 }
775 \f
776 /* Alpha NetWare does not use the high bit to determine whether a
777    public symbol is in the code segment or the data segment.  Instead,
778    it just uses the address.  The set_public_section and
779    get_public_offset routines override the default code which uses the
780    high bit.  */
781
782 /* Set the section for a public symbol.  */
783
784 static boolean
785 nlm_alpha_set_public_section (abfd, sym)
786      bfd *abfd;
787      nlmNAME(symbol_type) *sym;
788 {
789   asection *code_sec, *data_sec;
790
791   code_sec = bfd_get_section_by_name (abfd, NLM_CODE_NAME);
792   data_sec = bfd_get_section_by_name (abfd, NLM_INITIALIZED_DATA_NAME);
793   if (sym->symbol.value < bfd_section_size (abfd, code_sec))
794     {
795       sym->symbol.section = code_sec;
796       sym->symbol.flags |= BSF_FUNCTION;
797     }
798   else
799     {
800       sym->symbol.section = data_sec;
801       sym->symbol.value -= bfd_section_size (abfd, code_sec);
802       /* The data segment had better be aligned.  */
803       BFD_ASSERT ((bfd_section_size (abfd, code_sec) & 0xf) == 0);
804     }
805   return true;
806 }
807
808 /* Get the offset to write out for a public symbol.  */
809
810 static bfd_vma
811 nlm_alpha_get_public_offset (abfd, sym)
812      bfd *abfd ATTRIBUTE_UNUSED;
813      asymbol *sym;
814 {
815   return bfd_asymbol_value (sym);
816 }
817 \f
818 /* Write an Alpha NLM external symbol.  */
819
820 static boolean
821 nlm_alpha_write_external (abfd, count, sym, relocs)
822      bfd *abfd;
823      bfd_size_type count;
824      asymbol *sym;
825      struct reloc_and_sec *relocs;
826 {
827   bfd_size_type i;
828   bfd_byte len;
829   unsigned char temp[NLM_TARGET_LONG_SIZE];
830   arelent r;
831
832   len = strlen (sym->name);
833   if ((bfd_bwrite (&len, (bfd_size_type) sizeof (bfd_byte), abfd)
834        != sizeof (bfd_byte))
835       || bfd_bwrite (sym->name, (bfd_size_type) len, abfd) != len)
836     return false;
837
838   bfd_put_32 (abfd, count + 2, temp);
839   if (bfd_bwrite (temp, (bfd_size_type) sizeof (temp), abfd) != sizeof (temp))
840     return false;
841
842   /* The first two relocs for each external symbol are the .lita
843      address and the GP value.  */
844   r.sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr;
845   r.howto = &nlm32_alpha_nw_howto;
846
847   r.address = nlm_alpha_backend_data (abfd)->lita_address;
848   r.addend = nlm_alpha_backend_data (abfd)->lita_size + 1;
849   if (nlm_alpha_write_import (abfd, (asection *) NULL, &r) == false)
850     return false;
851
852   r.address = nlm_alpha_backend_data (abfd)->gp;
853   r.addend = 0;
854   if (nlm_alpha_write_import (abfd, (asection *) NULL, &r) == false)
855     return false;
856
857   for (i = 0; i < count; i++)
858     {
859       if (nlm_alpha_write_import (abfd, relocs[i].sec,
860                                   relocs[i].rel) == false)
861         return false;
862     }
863
864   return true;
865 }
866
867 #include "nlmswap.h"
868
869 static const struct nlm_backend_data nlm32_alpha_backend =
870 {
871   "NetWare Alpha Module   \032",
872   sizeof (Nlm32_alpha_External_Fixed_Header),
873   sizeof (struct nlm32_alpha_external_prefix_header),
874   bfd_arch_alpha,
875   0,
876   true, /* no uninitialized data permitted by Alpha NetWare.  */
877   nlm_alpha_backend_object_p,
878   nlm_alpha_write_prefix,
879   nlm_alpha_read_reloc,
880   nlm_alpha_mangle_relocs,
881   nlm_alpha_read_import,
882   nlm_alpha_write_import,
883   nlm_alpha_set_public_section,
884   nlm_alpha_get_public_offset,
885   nlm_swap_fixed_header_in,
886   nlm_swap_fixed_header_out,
887   nlm_alpha_write_external,
888   0,    /* write_export */
889 };
890
891 #define TARGET_LITTLE_NAME              "nlm32-alpha"
892 #define TARGET_LITTLE_SYM               nlmNAME(alpha_vec)
893 #define TARGET_BACKEND_DATA             &nlm32_alpha_backend
894
895 #include "nlm-target.h"