* config/i386/xm-go32.h: Include xm-i386.h.
[external/binutils.git] / bfd / nlm32-ppc.c
1 /* Support for 32-bit PowerPC NLM (NetWare Loadable Module)
2    Copyright 1994, 1995, 2000 Free Software Foundation, Inc.
3
4 This file is part of BFD, the Binary File Descriptor library.
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
19
20 #include "bfd.h"
21 #include "sysdep.h"
22 #include "libbfd.h"
23
24 /* The format of a PowerPC NLM changed.  Define OLDFORMAT to get the
25    old format.  */
26
27 #define ARCH_SIZE 32
28
29 #include "nlm/ppc-ext.h"
30 #define Nlm_External_Fixed_Header       Nlm32_powerpc_External_Fixed_Header
31
32 #include "libnlm.h"
33
34 #ifdef OLDFORMAT
35 static boolean nlm_powerpc_backend_object_p
36   PARAMS ((bfd *));
37 static boolean nlm_powerpc_write_prefix
38   PARAMS ((bfd *));
39 #endif
40
41 static boolean nlm_powerpc_read_reloc
42   PARAMS ((bfd *, nlmNAME(symbol_type) *, asection **, arelent *));
43 static boolean nlm_powerpc_mangle_relocs
44   PARAMS ((bfd *, asection *, PTR, bfd_vma, bfd_size_type));
45 static boolean nlm_powerpc_read_import
46   PARAMS ((bfd *, nlmNAME(symbol_type) *));
47
48 #ifdef OLDFORMAT
49 static boolean nlm_powerpc_write_reloc
50   PARAMS ((bfd *, asection *, arelent *, int));
51 #endif
52
53 static boolean nlm_powerpc_write_import
54   PARAMS ((bfd *, asection *, arelent *));
55 static boolean nlm_powerpc_write_external
56   PARAMS ((bfd *, bfd_size_type, asymbol *, struct reloc_and_sec *));
57
58 #ifndef OLDFORMAT
59 static boolean nlm_powerpc_set_public_section
60   PARAMS ((bfd *, nlmNAME(symbol_type) *));
61 static bfd_vma nlm_powerpc_get_public_offset
62   PARAMS ((bfd *, asymbol *));
63 #endif
64 \f
65 #ifdef OLDFORMAT
66
67 /* The prefix header is only used in the old format.  */
68
69 /* PowerPC NLM's have a prefix header before the standard NLM.  This
70    function reads it in, verifies the version, and seeks the bfd to
71    the location before the regular NLM header.  */
72
73 static boolean
74 nlm_powerpc_backend_object_p (abfd)
75      bfd *abfd;
76 {
77   struct nlm32_powerpc_external_prefix_header s;
78
79   if (bfd_read ((PTR) &s, sizeof s, 1, abfd) != sizeof s)
80     return false;
81
82   if (memcmp (s.signature, NLM32_POWERPC_SIGNATURE, sizeof s.signature) != 0
83       || bfd_h_get_32 (abfd, s.headerVersion) != NLM32_POWERPC_HEADER_VERSION)
84     return false;
85
86   return true;
87 }
88
89 /* Write out the prefix.  */
90
91 static boolean
92 nlm_powerpc_write_prefix (abfd)
93      bfd *abfd;
94 {
95   struct nlm32_powerpc_external_prefix_header s;
96
97   memset (&s, 0, sizeof s);
98   memcpy (s.signature, NLM32_POWERPC_SIGNATURE, sizeof s.signature);
99   bfd_h_put_32 (abfd, (bfd_vma) NLM32_POWERPC_HEADER_VERSION, s.headerVersion);
100   bfd_h_put_32 (abfd, (bfd_vma) 0, s.origins);
101
102   /* FIXME: What should we do about the date?  */
103
104   if (bfd_write ((PTR) &s, sizeof s, 1, abfd) != sizeof s)
105     return false;
106
107   return true;
108 }
109
110 #endif /* OLDFORMAT */
111 \f
112 #ifndef OLDFORMAT
113
114 /* There is only one type of reloc in a PowerPC NLM.  */
115
116 static reloc_howto_type nlm_powerpc_howto =
117   HOWTO (0,                     /* type */
118          0,                     /* rightshift */
119          2,                     /* size (0 = byte, 1 = short, 2 = long) */
120          32,                    /* bitsize */
121          false,                 /* pc_relative */
122          0,                     /* bitpos */
123          complain_overflow_bitfield, /* complain_on_overflow */
124          0,                     /* special_function */
125          "32",                  /* name */
126          true,                  /* partial_inplace */
127          0xffffffff,            /* src_mask */
128          0xffffffff,            /* dst_mask */
129          false);                /* pcrel_offset */
130
131 /* Read a PowerPC NLM reloc.  */
132
133 static boolean
134 nlm_powerpc_read_reloc (abfd, sym, secp, rel)
135      bfd *abfd;
136      nlmNAME(symbol_type) *sym;
137      asection **secp;
138      arelent *rel;
139 {
140   bfd_byte temp[4];
141   bfd_vma val;
142   const char *name;
143
144   if (bfd_read (temp, sizeof (temp), 1, abfd) != sizeof (temp))
145     return false;
146
147   val = bfd_get_32 (abfd, temp);
148
149   /* The value is a word offset into either the code or data segment.
150      This is the location which needs to be adjusted.
151
152      The high bit is 0 if the value is an offset into the data
153      segment, or 1 if the value is an offset into the text segment.
154
155      If this is a relocation fixup rather than an imported symbol (the
156      sym argument is NULL), then the second most significant bit is 0
157      if the address of the data segment should be added to the
158      location addressed by the value, or 1 if the address of the text
159      segment should be added.
160
161      If this is an imported symbol, the second most significant bit is
162      not used and must be 0.  */
163
164   if ((val & NLM_HIBIT) == 0)
165     name = NLM_INITIALIZED_DATA_NAME;
166   else
167     {
168       name = NLM_CODE_NAME;
169       val &=~ NLM_HIBIT;
170     }
171   *secp = bfd_get_section_by_name (abfd, name);
172
173   if (sym == NULL)
174     {
175       if ((val & (NLM_HIBIT >> 1)) == 0)
176         name = NLM_INITIALIZED_DATA_NAME;
177       else
178         {
179           name = NLM_CODE_NAME;
180           val &=~ (NLM_HIBIT >> 1);
181         }
182       rel->sym_ptr_ptr = bfd_get_section_by_name (abfd, name)->symbol_ptr_ptr;
183     }
184
185   rel->howto = &nlm_powerpc_howto;
186
187   rel->address = val << 2;
188   rel->addend = 0;
189
190   return true;
191 }
192
193 #else /* OLDFORMAT */
194
195 /* This reloc handling is only applicable to the old format.  */
196
197 /* How to process the various reloc types.  PowerPC NLMs use XCOFF
198    reloc types, and I have just copied the XCOFF reloc table here.  */
199
200 static reloc_howto_type nlm_powerpc_howto_table[] =
201 {
202   /* Standard 32 bit relocation.  */
203   HOWTO (0,                     /* type */
204          0,                     /* rightshift */
205          2,                     /* size (0 = byte, 1 = short, 2 = long) */
206          32,                    /* bitsize */
207          false,                 /* pc_relative */
208          0,                     /* bitpos */
209          complain_overflow_bitfield, /* complain_on_overflow */
210          0,                     /* special_function */
211          "R_POS",               /* name */
212          true,                  /* partial_inplace */
213          0xffffffff,            /* src_mask */
214          0xffffffff,            /* dst_mask */
215          false),                /* pcrel_offset */
216
217   /* 32 bit relocation, but store negative value.  */
218   HOWTO (1,                     /* type */
219          0,                     /* rightshift */
220          -2,                    /* size (0 = byte, 1 = short, 2 = long) */
221          32,                    /* bitsize */
222          false,                 /* pc_relative */
223          0,                     /* bitpos */
224          complain_overflow_bitfield, /* complain_on_overflow */
225          0,                     /* special_function */
226          "R_NEG",               /* name */
227          true,                  /* partial_inplace */
228          0xffffffff,            /* src_mask */
229          0xffffffff,            /* dst_mask */
230          false),                /* pcrel_offset */
231
232   /* 32 bit PC relative relocation.  */
233   HOWTO (2,                     /* type */
234          0,                     /* rightshift */
235          2,                     /* size (0 = byte, 1 = short, 2 = long) */
236          32,                    /* bitsize */
237          true,                  /* pc_relative */
238          0,                     /* bitpos */
239          complain_overflow_signed, /* complain_on_overflow */
240          0,                     /* special_function */
241          "R_REL",               /* name */
242          true,                  /* partial_inplace */
243          0xffffffff,            /* src_mask */
244          0xffffffff,            /* dst_mask */
245          false),                /* pcrel_offset */
246
247   /* 16 bit TOC relative relocation.  */
248   HOWTO (3,                     /* type */
249          0,                     /* rightshift */
250          1,                     /* size (0 = byte, 1 = short, 2 = long) */
251          16,                    /* bitsize */
252          false,                 /* pc_relative */
253          0,                     /* bitpos */
254          complain_overflow_signed, /* complain_on_overflow */
255          0,                     /* special_function */
256          "R_TOC",               /* name */
257          true,                  /* partial_inplace */
258          0xffff,                /* src_mask */
259          0xffff,                /* dst_mask */
260          false),                /* pcrel_offset */
261
262   /* I don't really know what this is.  */
263   HOWTO (4,                     /* type */
264          1,                     /* rightshift */
265          2,                     /* size (0 = byte, 1 = short, 2 = long) */
266          32,                    /* bitsize */
267          false,                 /* pc_relative */
268          0,                     /* bitpos */
269          complain_overflow_bitfield, /* complain_on_overflow */
270          0,                     /* special_function */
271          "R_RTB",               /* name */
272          true,                  /* partial_inplace */
273          0xffffffff,            /* src_mask */
274          0xffffffff,            /* dst_mask */
275          false),                /* pcrel_offset */
276
277   /* External TOC relative symbol.  */
278   HOWTO (5,                     /* type */
279          0,                     /* rightshift */
280          2,                     /* size (0 = byte, 1 = short, 2 = long) */
281          16,                    /* bitsize */
282          false,                 /* pc_relative */
283          0,                     /* bitpos */
284          complain_overflow_bitfield, /* complain_on_overflow */
285          0,                     /* special_function */
286          "R_GL",                /* name */
287          true,                  /* partial_inplace */
288          0xffff,                /* src_mask */
289          0xffff,                /* dst_mask */
290          false),                /* pcrel_offset */
291
292   /* Local TOC relative symbol.  */
293   HOWTO (6,                     /* type */
294          0,                     /* rightshift */
295          2,                     /* size (0 = byte, 1 = short, 2 = long) */
296          16,                    /* bitsize */
297          false,                 /* pc_relative */
298          0,                     /* bitpos */
299          complain_overflow_bitfield, /* complain_on_overflow */
300          0,                     /* special_function */
301          "R_TCL",               /* name */
302          true,                  /* partial_inplace */
303          0xffff,                /* src_mask */
304          0xffff,                /* dst_mask */
305          false),                /* pcrel_offset */
306
307   { 7 },
308
309   /* Non modifiable absolute branch.  */
310   HOWTO (8,                     /* type */
311          0,                     /* rightshift */
312          2,                     /* size (0 = byte, 1 = short, 2 = long) */
313          26,                    /* bitsize */
314          false,                 /* pc_relative */
315          0,                     /* bitpos */
316          complain_overflow_bitfield, /* complain_on_overflow */
317          0,                     /* special_function */
318          "R_BA",                /* name */
319          true,                  /* partial_inplace */
320          0x3fffffc,             /* src_mask */
321          0x3fffffc,             /* dst_mask */
322          false),                /* pcrel_offset */
323
324   { 9 },
325
326   /* Non modifiable relative branch.  */
327   HOWTO (0xa,                   /* type */
328          0,                     /* rightshift */
329          2,                     /* size (0 = byte, 1 = short, 2 = long) */
330          26,                    /* bitsize */
331          true,                  /* pc_relative */
332          0,                     /* bitpos */
333          complain_overflow_signed, /* complain_on_overflow */
334          0,                     /* special_function */
335          "R_BR",                /* name */
336          true,                  /* partial_inplace */
337          0x3fffffc,             /* src_mask */
338          0x3fffffc,             /* dst_mask */
339          false),                /* pcrel_offset */
340
341   { 0xb },
342
343   /* Indirect load.  */
344   HOWTO (0xc,                   /* type */
345          0,                     /* rightshift */
346          2,                     /* size (0 = byte, 1 = short, 2 = long) */
347          16,                    /* bitsize */
348          false,                 /* pc_relative */
349          0,                     /* bitpos */
350          complain_overflow_bitfield, /* complain_on_overflow */
351          0,                     /* special_function */
352          "R_RL",                /* name */
353          true,                  /* partial_inplace */
354          0xffff,                /* src_mask */
355          0xffff,                /* dst_mask */
356          false),                /* pcrel_offset */
357
358   /* Load address.  */
359   HOWTO (0xd,                   /* type */
360          0,                     /* rightshift */
361          2,                     /* size (0 = byte, 1 = short, 2 = long) */
362          16,                    /* bitsize */
363          false,                 /* pc_relative */
364          0,                     /* bitpos */
365          complain_overflow_bitfield, /* complain_on_overflow */
366          0,                     /* special_function */
367          "R_RLA",               /* name */
368          true,                  /* partial_inplace */
369          0xffff,                /* src_mask */
370          0xffff,                /* dst_mask */
371          false),                /* pcrel_offset */
372
373   { 0xe },
374
375   /* Non-relocating reference.  */
376   HOWTO (0xf,                   /* type */
377          0,                     /* rightshift */
378          2,                     /* size (0 = byte, 1 = short, 2 = long) */
379          32,                    /* bitsize */
380          false,                 /* pc_relative */
381          0,                     /* bitpos */
382          complain_overflow_bitfield, /* complain_on_overflow */
383          0,                     /* special_function */
384          "R_REF",               /* name */
385          false,                 /* partial_inplace */
386          0,                     /* src_mask */
387          0,                     /* dst_mask */
388          false),                /* pcrel_offset */
389
390   { 0x10 },
391   { 0x11 },
392
393   /* TOC relative indirect load.  */
394   HOWTO (0x12,                  /* type */
395          0,                     /* rightshift */
396          2,                     /* size (0 = byte, 1 = short, 2 = long) */
397          16,                    /* bitsize */
398          false,                 /* pc_relative */
399          0,                     /* bitpos */
400          complain_overflow_bitfield, /* complain_on_overflow */
401          0,                     /* special_function */
402          "R_TRL",               /* name */
403          true,                  /* partial_inplace */
404          0xffff,                /* src_mask */
405          0xffff,                /* dst_mask */
406          false),                /* pcrel_offset */
407
408   /* TOC relative load address.  */
409   HOWTO (0x13,                  /* type */
410          0,                     /* rightshift */
411          2,                     /* size (0 = byte, 1 = short, 2 = long) */
412          16,                    /* bitsize */
413          false,                 /* pc_relative */
414          0,                     /* bitpos */
415          complain_overflow_bitfield, /* complain_on_overflow */
416          0,                     /* special_function */
417          "R_TRLA",              /* name */
418          true,                  /* partial_inplace */
419          0xffff,                /* src_mask */
420          0xffff,                /* dst_mask */
421          false),                /* pcrel_offset */
422
423   /* Modifiable relative branch.  */
424   HOWTO (0x14,                  /* type */
425          1,                     /* rightshift */
426          2,                     /* size (0 = byte, 1 = short, 2 = long) */
427          32,                    /* bitsize */
428          false,                 /* pc_relative */
429          0,                     /* bitpos */
430          complain_overflow_bitfield, /* complain_on_overflow */
431          0,                     /* special_function */
432          "R_RRTBI",             /* name */
433          true,                  /* partial_inplace */
434          0xffffffff,            /* src_mask */
435          0xffffffff,            /* dst_mask */
436          false),                /* pcrel_offset */
437
438   /* Modifiable absolute branch.  */
439   HOWTO (0x15,                  /* type */
440          1,                     /* rightshift */
441          2,                     /* size (0 = byte, 1 = short, 2 = long) */
442          32,                    /* bitsize */
443          false,                 /* pc_relative */
444          0,                     /* bitpos */
445          complain_overflow_bitfield, /* complain_on_overflow */
446          0,                     /* special_function */
447          "R_RRTBA",             /* name */
448          true,                  /* partial_inplace */
449          0xffffffff,            /* src_mask */
450          0xffffffff,            /* dst_mask */
451          false),                /* pcrel_offset */
452
453   /* Modifiable call absolute indirect.  */
454   HOWTO (0x16,                  /* type */
455          0,                     /* rightshift */
456          2,                     /* size (0 = byte, 1 = short, 2 = long) */
457          16,                    /* bitsize */
458          false,                 /* pc_relative */
459          0,                     /* bitpos */
460          complain_overflow_bitfield, /* complain_on_overflow */
461          0,                     /* special_function */
462          "R_CAI",               /* name */
463          true,                  /* partial_inplace */
464          0xffff,                /* src_mask */
465          0xffff,                /* dst_mask */
466          false),                /* pcrel_offset */
467
468   /* Modifiable call relative.  */
469   HOWTO (0x17,                  /* type */
470          0,                     /* rightshift */
471          2,                     /* size (0 = byte, 1 = short, 2 = long) */
472          16,                    /* bitsize */
473          false,                 /* pc_relative */
474          0,                     /* bitpos */
475          complain_overflow_bitfield, /* complain_on_overflow */
476          0,                     /* special_function */
477          "R_REL",               /* name */
478          true,                  /* partial_inplace */
479          0xffff,                /* src_mask */
480          0xffff,                /* dst_mask */
481          false),                /* pcrel_offset */
482
483   /* Modifiable branch absolute.  */
484   HOWTO (0x18,                  /* type */
485          0,                     /* rightshift */
486          2,                     /* size (0 = byte, 1 = short, 2 = long) */
487          16,                    /* bitsize */
488          false,                 /* pc_relative */
489          0,                     /* bitpos */
490          complain_overflow_bitfield, /* complain_on_overflow */
491          0,                     /* special_function */
492          "R_RBA",               /* name */
493          true,                  /* partial_inplace */
494          0xffff,                /* src_mask */
495          0xffff,                /* dst_mask */
496          false),                /* pcrel_offset */
497
498   /* Modifiable branch absolute.  */
499   HOWTO (0x19,                  /* type */
500          0,                     /* rightshift */
501          2,                     /* size (0 = byte, 1 = short, 2 = long) */
502          16,                    /* bitsize */
503          false,                 /* pc_relative */
504          0,                     /* bitpos */
505          complain_overflow_bitfield, /* complain_on_overflow */
506          0,                     /* special_function */
507          "R_RBAC",              /* name */
508          true,                  /* partial_inplace */
509          0xffff,                /* src_mask */
510          0xffff,                /* dst_mask */
511          false),                /* pcrel_offset */
512
513   /* Modifiable branch relative.  */
514   HOWTO (0x1a,                  /* type */
515          0,                     /* rightshift */
516          2,                     /* size (0 = byte, 1 = short, 2 = long) */
517          26,                    /* bitsize */
518          false,                 /* pc_relative */
519          0,                     /* bitpos */
520          complain_overflow_signed, /* complain_on_overflow */
521          0,                     /* special_function */
522          "R_REL",               /* name */
523          true,                  /* partial_inplace */
524          0xffff,                /* src_mask */
525          0xffff,                /* dst_mask */
526          false),                /* pcrel_offset */
527
528   /* Modifiable branch absolute.  */
529   HOWTO (0x1b,                  /* type */
530          0,                     /* rightshift */
531          2,                     /* size (0 = byte, 1 = short, 2 = long) */
532          16,                    /* bitsize */
533          false,                 /* pc_relative */
534          0,                     /* bitpos */
535          complain_overflow_bitfield, /* complain_on_overflow */
536          0,                     /* special_function */
537          "R_REL",               /* name */
538          true,                  /* partial_inplace */
539          0xffff,                /* src_mask */
540          0xffff,                /* dst_mask */
541          false)                 /* pcrel_offset */
542 };
543
544 #define HOWTO_COUNT (sizeof nlm_powerpc_howto_table             \
545                      / sizeof nlm_powerpc_howto_table[0])
546
547 /* Read a PowerPC NLM reloc.  */
548
549 static boolean
550 nlm_powerpc_read_reloc (abfd, sym, secp, rel)
551      bfd *abfd;
552      nlmNAME(symbol_type) *sym;
553      asection **secp;
554      arelent *rel;
555 {
556   struct nlm32_powerpc_external_reloc ext;
557   bfd_vma l_vaddr;
558   unsigned long l_symndx;
559   int l_rtype;
560   int l_rsecnm;
561   asection *code_sec, *data_sec, *bss_sec;
562
563   /* Read the reloc from the file.  */
564   if (bfd_read (&ext, sizeof ext, 1, abfd) != sizeof ext)
565     return false;
566
567   /* Swap in the fields.  */
568   l_vaddr = bfd_h_get_32 (abfd, ext.l_vaddr);
569   l_symndx = bfd_h_get_32 (abfd, ext.l_symndx);
570   l_rtype = bfd_h_get_16 (abfd, ext.l_rtype);
571   l_rsecnm = bfd_h_get_16 (abfd, ext.l_rsecnm);
572
573   /* Get the sections now, for convenience.  */
574   code_sec = bfd_get_section_by_name (abfd, NLM_CODE_NAME);
575   data_sec = bfd_get_section_by_name (abfd, NLM_INITIALIZED_DATA_NAME);
576   bss_sec = bfd_get_section_by_name (abfd, NLM_UNINITIALIZED_DATA_NAME);
577
578   /* Work out the arelent fields.  */
579   if (sym != NULL)
580     {
581       /* This is an import.  sym_ptr_ptr is filled in by
582          nlm_canonicalize_reloc.  */
583       rel->sym_ptr_ptr = NULL;
584     }
585   else
586     {
587       asection *sec;
588
589       if (l_symndx == 0)
590         sec = code_sec;
591       else if (l_symndx == 1)
592         sec = data_sec;
593       else if (l_symndx == 2)
594         sec = bss_sec;
595       else
596         {
597           bfd_set_error (bfd_error_bad_value);
598           return false;
599         }
600
601       rel->sym_ptr_ptr = sec->symbol_ptr_ptr;
602     }
603
604   rel->addend = 0;
605
606   BFD_ASSERT ((l_rtype & 0xff) < HOWTO_COUNT);
607
608   rel->howto = nlm_powerpc_howto_table + (l_rtype & 0xff);
609
610   BFD_ASSERT (rel->howto->name != NULL
611               && ((l_rtype & 0x8000) != 0
612                   ? (rel->howto->complain_on_overflow
613                      == complain_overflow_signed)
614                   : (rel->howto->complain_on_overflow
615                      == complain_overflow_bitfield))
616               && ((l_rtype >> 8) & 0x1f) == rel->howto->bitsize - 1);
617
618   if (l_rsecnm == 0)
619     *secp = code_sec;
620   else if (l_rsecnm == 1)
621     {
622       *secp = data_sec;
623       l_vaddr -= bfd_section_size (abfd, code_sec);
624     }
625   else
626     {
627       bfd_set_error (bfd_error_bad_value);
628       return false;
629     }
630
631   rel->address = l_vaddr;
632
633   return true;
634 }
635
636 #endif /* OLDFORMAT */
637
638 /* Mangle PowerPC NLM relocs for output.  */
639
640 static boolean
641 nlm_powerpc_mangle_relocs (abfd, sec, data, offset, count)
642      bfd *abfd ATTRIBUTE_UNUSED;
643      asection *sec ATTRIBUTE_UNUSED;
644      PTR data ATTRIBUTE_UNUSED;
645      bfd_vma offset ATTRIBUTE_UNUSED;
646      bfd_size_type count ATTRIBUTE_UNUSED;
647 {
648   return true;
649 }
650
651 /* Read a PowerPC NLM import record */
652
653 static boolean
654 nlm_powerpc_read_import (abfd, sym)
655      bfd *abfd;
656      nlmNAME(symbol_type) *sym;
657 {
658   struct nlm_relent *nlm_relocs;        /* relocation records for symbol */
659   bfd_size_type rcount;                 /* number of relocs */
660   bfd_byte temp[NLM_TARGET_LONG_SIZE];  /* temporary 32-bit value */
661   unsigned char symlength;              /* length of symbol name */
662   char *name;
663
664   if (bfd_read ((PTR) &symlength, sizeof (symlength), 1, abfd)
665       != sizeof (symlength))
666     return (false);
667   sym -> symbol.the_bfd = abfd;
668   name = bfd_alloc (abfd, symlength + 1);
669   if (name == NULL)
670     return false;
671   if (bfd_read (name, symlength, 1, abfd) != symlength)
672     return (false);
673   name[symlength] = '\0';
674   sym -> symbol.name = name;
675   sym -> symbol.flags = 0;
676   sym -> symbol.value = 0;
677   sym -> symbol.section = bfd_und_section_ptr;
678   if (bfd_read ((PTR) temp, sizeof (temp), 1, abfd) != sizeof (temp))
679     return (false);
680   rcount = bfd_h_get_32 (abfd, temp);
681   nlm_relocs = ((struct nlm_relent *)
682                 bfd_alloc (abfd, rcount * sizeof (struct nlm_relent)));
683   if (nlm_relocs == (struct nlm_relent *) NULL)
684     return false;
685   sym -> relocs = nlm_relocs;
686   sym -> rcnt = 0;
687   while (sym -> rcnt < rcount)
688     {
689       asection *section;
690
691       if (nlm_powerpc_read_reloc (abfd, sym, &section,
692                                   &nlm_relocs -> reloc)
693           == false)
694         return false;
695       nlm_relocs -> section = section;
696       nlm_relocs++;
697       sym -> rcnt++;
698     }
699   return true;
700 }
701
702 #ifndef OLDFORMAT
703
704 /* Write a PowerPC NLM reloc.  */
705
706 static boolean
707 nlm_powerpc_write_import (abfd, sec, rel)
708      bfd *abfd;
709      asection *sec;
710      arelent *rel;
711 {
712   asymbol *sym;
713   bfd_vma val;
714   bfd_byte temp[4];
715
716   /* PowerPC NetWare only supports one kind of reloc.  */
717   if (rel->addend != 0
718       || rel->howto == NULL
719       || rel->howto->rightshift != 0
720       || rel->howto->size != 2
721       || rel->howto->bitsize != 32
722       || rel->howto->bitpos != 0
723       || rel->howto->pc_relative
724       || (rel->howto->src_mask != 0xffffffff && rel->addend != 0)
725       || rel->howto->dst_mask != 0xffffffff)
726     {
727       bfd_set_error (bfd_error_invalid_operation);
728       return false;
729     }
730
731   sym = *rel->sym_ptr_ptr;
732
733   /* The value we write out is the offset into the appropriate
734      segment, rightshifted by two.  This offset is the section vma,
735      adjusted by the vma of the lowest section in that segment, plus
736      the address of the relocation.  */
737   val = bfd_get_section_vma (abfd, sec) + rel->address;
738   if ((val & 3) != 0)
739     {
740       bfd_set_error (bfd_error_bad_value);
741       return false;
742     }
743   val >>= 2;
744
745   /* The high bit is 0 if the reloc is in the data section, or 1 if
746      the reloc is in the code section.  */
747   if (bfd_get_section_flags (abfd, sec) & SEC_DATA)
748     val -= nlm_get_data_low (abfd);
749   else
750     {
751       val -= nlm_get_text_low (abfd);
752       val |= NLM_HIBIT;
753     }
754
755   if (! bfd_is_und_section (bfd_get_section (sym)))
756     {
757       /* This is an internal relocation fixup.  The second most
758          significant bit is 0 if this is a reloc against the data
759          segment, or 1 if it is a reloc against the text segment.  */
760       if (bfd_get_section_flags (abfd, bfd_get_section (sym)) & SEC_CODE)
761         val |= NLM_HIBIT >> 1;
762     }
763
764   bfd_put_32 (abfd, val, temp);
765   if (bfd_write (temp, sizeof (temp), 1, abfd) != sizeof (temp))
766     return false;
767
768   return true;
769 }
770
771 #else /* OLDFORMAT */
772
773 /* This is used for the reloc handling in the old format.  */
774
775 /* Write a PowerPC NLM reloc.  */
776
777 static boolean
778 nlm_powerpc_write_reloc (abfd, sec, rel, indx)
779      bfd *abfd;
780      asection *sec;
781      arelent *rel;
782      int indx;
783 {
784   struct nlm32_powerpc_external_reloc ext;
785   asection *code_sec, *data_sec, *bss_sec;
786   asymbol *sym;
787   asection *symsec;
788   unsigned long l_symndx;
789   int l_rtype;
790   int l_rsecnm;
791   reloc_howto_type *howto;
792   bfd_size_type address;
793
794   /* Get the sections now, for convenience.  */
795   code_sec = bfd_get_section_by_name (abfd, NLM_CODE_NAME);
796   data_sec = bfd_get_section_by_name (abfd, NLM_INITIALIZED_DATA_NAME);
797   bss_sec = bfd_get_section_by_name (abfd, NLM_UNINITIALIZED_DATA_NAME);
798
799   sym = *rel->sym_ptr_ptr;
800   symsec = bfd_get_section (sym);
801   if (indx != -1)
802     {
803       BFD_ASSERT (bfd_is_und_section (symsec));
804       l_symndx = indx + 3;
805     }
806   else
807     {
808       if (symsec == code_sec)
809         l_symndx = 0;
810       else if (symsec == data_sec)
811         l_symndx = 1;
812       else if (symsec == bss_sec)
813         l_symndx = 2;
814       else
815         {
816           bfd_set_error (bfd_error_bad_value);
817           return false;
818         }
819     }
820
821   bfd_h_put_32 (abfd, (bfd_vma) l_symndx, ext.l_symndx);
822
823   for (howto = nlm_powerpc_howto_table;
824        howto < nlm_powerpc_howto_table + HOWTO_COUNT;
825        howto++)
826     {
827       if (howto->rightshift == rel->howto->rightshift
828           && howto->size == rel->howto->size
829           && howto->bitsize == rel->howto->bitsize
830           && howto->pc_relative == rel->howto->pc_relative
831           && howto->bitpos == rel->howto->bitpos
832           && (howto->partial_inplace == rel->howto->partial_inplace
833               || (! rel->howto->partial_inplace
834                   && rel->addend == 0))
835           && (howto->src_mask == rel->howto->src_mask
836               || (rel->howto->src_mask == 0
837                   && rel->addend == 0))
838           && howto->dst_mask == rel->howto->dst_mask
839           && howto->pcrel_offset == rel->howto->pcrel_offset)
840         break;
841     }
842   if (howto >= nlm_powerpc_howto_table + HOWTO_COUNT)
843     {
844       bfd_set_error (bfd_error_bad_value);
845       return false;
846     }
847
848   l_rtype = howto->type;
849   if (howto->complain_on_overflow == complain_overflow_signed)
850     l_rtype |= 0x8000;
851   l_rtype |= (howto->bitsize - 1) << 8;
852   bfd_h_put_16 (abfd, (bfd_vma) l_rtype, ext.l_rtype);
853
854   address = rel->address;
855
856   if (sec == code_sec)
857     l_rsecnm = 0;
858   else if (sec == data_sec)
859     {
860       l_rsecnm = 1;
861       address += bfd_section_size (abfd, code_sec);
862     }
863   else
864     {
865       bfd_set_error (bfd_error_bad_value);
866       return false;
867     }
868
869   bfd_h_put_16 (abfd, (bfd_vma) l_rsecnm, ext.l_rsecnm);
870   bfd_h_put_32 (abfd, (bfd_vma) address, ext.l_vaddr);
871
872   if (bfd_write (&ext, sizeof ext, 1, abfd) != sizeof ext)
873     return false;
874
875   return true;
876 }
877
878 /* Write a PowerPC NLM import.  */
879
880 static boolean
881 nlm_powerpc_write_import (abfd, sec, rel)
882      bfd *abfd;
883      asection *sec;
884      arelent *rel;
885 {
886   return nlm_powerpc_write_reloc (abfd, sec, rel, -1);
887 }
888
889 #endif /* OLDFORMAT */
890
891 /* Write a PowerPC NLM external symbol.  This routine keeps a static
892    count of the symbol index.  FIXME: I don't know if this is
893    necessary, and the index never gets reset.  */
894
895 static boolean
896 nlm_powerpc_write_external (abfd, count, sym, relocs)
897      bfd *abfd;
898      bfd_size_type count;
899      asymbol *sym;
900      struct reloc_and_sec *relocs;
901 {
902   unsigned int i;
903   bfd_byte len;
904   unsigned char temp[NLM_TARGET_LONG_SIZE];
905 #ifdef OLDFORMAT
906   static int indx;
907 #endif
908
909   len = strlen (sym->name);
910   if ((bfd_write (&len, sizeof (bfd_byte), 1, abfd) != sizeof (bfd_byte))
911       || bfd_write (sym->name, len, 1, abfd) != len)
912     return false;
913
914   bfd_put_32 (abfd, count, temp);
915   if (bfd_write (temp, sizeof (temp), 1, abfd) != sizeof (temp))
916     return false;
917
918   for (i = 0; i < count; i++)
919     {
920 #ifndef OLDFORMAT
921       if (! nlm_powerpc_write_import (abfd, relocs[i].sec, relocs[i].rel))
922         return false;
923 #else
924       if (! nlm_powerpc_write_reloc (abfd, relocs[i].sec,
925                                      relocs[i].rel, indx))
926         return false;
927 #endif
928     }
929
930 #ifdef OLDFORMAT
931   ++indx;
932 #endif
933
934   return true;
935 }
936 \f
937 #ifndef OLDFORMAT
938
939 /* PowerPC Netware uses a word offset, not a byte offset, for public
940    symbols.  */
941
942 /* Set the section for a public symbol.  */
943
944 static boolean
945 nlm_powerpc_set_public_section (abfd, sym)
946      bfd *abfd;
947      nlmNAME(symbol_type) *sym;
948 {
949   if (sym->symbol.value & NLM_HIBIT)
950     {
951       sym->symbol.value &= ~NLM_HIBIT;
952       sym->symbol.flags |= BSF_FUNCTION;
953       sym->symbol.section =
954         bfd_get_section_by_name (abfd, NLM_CODE_NAME);
955     }
956   else
957     {
958       sym->symbol.section =
959         bfd_get_section_by_name (abfd, NLM_INITIALIZED_DATA_NAME);
960     }
961
962   sym->symbol.value <<= 2;
963
964   return true;
965 }
966
967 /* Get the offset to write out for a public symbol.  */
968
969 static bfd_vma
970 nlm_powerpc_get_public_offset (abfd, sym)
971      bfd *abfd;
972      asymbol *sym;
973 {
974   bfd_vma offset;
975   asection *sec;
976
977   offset = bfd_asymbol_value (sym);
978   sec = bfd_get_section (sym);
979   if (sec->flags & SEC_CODE)
980     {
981       offset -= nlm_get_text_low (abfd);
982       offset |= NLM_HIBIT;
983     }
984   else if (sec->flags & (SEC_DATA | SEC_ALLOC))
985     {
986       /* SEC_ALLOC is for the .bss section.  */
987       offset -= nlm_get_data_low (abfd);
988     }
989   else
990     {
991       /* We can't handle an exported symbol that is not in the code or
992          data segment.  */
993       bfd_set_error (bfd_error_invalid_operation);
994       /* FIXME: No way to return error.  */
995       abort ();
996     }
997
998   return offset;
999 }
1000
1001 #endif /* ! defined (OLDFORMAT) */
1002 \f
1003 #include "nlmswap.h"
1004
1005 static const struct nlm_backend_data nlm32_powerpc_backend =
1006 {
1007   "NetWare PowerPC Module \032",
1008   sizeof (Nlm32_powerpc_External_Fixed_Header),
1009 #ifndef OLDFORMAT
1010   0,    /* optional_prefix_size */
1011 #else
1012   sizeof (struct nlm32_powerpc_external_prefix_header),
1013 #endif
1014   bfd_arch_powerpc,
1015   0,
1016   false,
1017 #ifndef OLDFORMAT
1018   0,    /* backend_object_p */
1019   0,    /* write_prefix */
1020 #else
1021   nlm_powerpc_backend_object_p,
1022   nlm_powerpc_write_prefix,
1023 #endif
1024   nlm_powerpc_read_reloc,
1025   nlm_powerpc_mangle_relocs,
1026   nlm_powerpc_read_import,
1027   nlm_powerpc_write_import,
1028 #ifndef OLDFORMAT
1029   nlm_powerpc_set_public_section,
1030   nlm_powerpc_get_public_offset,
1031 #else
1032   0,    /* set_public_section */
1033   0,    /* get_public_offset */
1034 #endif
1035   nlm_swap_fixed_header_in,
1036   nlm_swap_fixed_header_out,
1037   nlm_powerpc_write_external,
1038   0,    /* write_export */
1039 };
1040
1041 #define TARGET_BIG_NAME                 "nlm32-powerpc"
1042 #define TARGET_BIG_SYM                  nlmNAME(powerpc_vec)
1043 #define TARGET_BACKEND_DATA             &nlm32_powerpc_backend
1044
1045 #include "nlm-target.h"