OSDN Git Service

* elf64-sparc.c (sparc64_elf_output_arch_syms): Add missing
[pf3gnuchains/pf3gnuchains3x.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   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 \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_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 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
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 \f
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 ATTRIBUTE_UNUSED;
811      asymbol *sym;
812 {
813   return bfd_asymbol_value (sym);
814 }
815 \f
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   bfd_size_type 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"