OSDN Git Service

* aout-adobe.c: Don't compare against "true" or "false.
[pf3gnuchains/pf3gnuchains3x.git] / bfd / nlm32-ppc.c
1 /* Support for 32-bit PowerPC NLM (NetWare Loadable Module)
2    Copyright 1994, 1995, 2000, 2001, 2002 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_bread ((PTR) &s, (bfd_size_type) sizeof s, abfd) != sizeof s)
80     return false;
81
82   if (memcmp (s.signature, NLM32_POWERPC_SIGNATURE, sizeof s.signature) != 0
83       || 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   H_PUT_32 (abfd, NLM32_POWERPC_HEADER_VERSION, s.headerVersion);
100   H_PUT_32 (abfd, 0, s.origins);
101
102   /* FIXME: What should we do about the date?  */
103
104   if (bfd_bwrite ((PTR) &s, (bfd_size_type) sizeof s, 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_bread (temp, (bfd_size_type) sizeof (temp), 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_bread (&ext, (bfd_size_type) sizeof ext, abfd) != sizeof ext)
565     return false;
566
567   /* Swap in the fields.  */
568   l_vaddr = H_GET_32 (abfd, ext.l_vaddr);
569   l_symndx = H_GET_32 (abfd, ext.l_symndx);
570   l_rtype = H_GET_16 (abfd, ext.l_rtype);
571   l_rsecnm = 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_bread ((PTR) &symlength, (bfd_size_type) sizeof (symlength), abfd)
665       != sizeof (symlength))
666     return (false);
667   sym -> symbol.the_bfd = abfd;
668   name = bfd_alloc (abfd, (bfd_size_type) symlength + 1);
669   if (name == NULL)
670     return false;
671   if (bfd_bread (name, (bfd_size_type) symlength, 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_bread ((PTR) temp, (bfd_size_type) sizeof (temp), abfd)
679       != sizeof (temp))
680     return (false);
681   rcount = H_GET_32 (abfd, temp);
682   nlm_relocs = ((struct nlm_relent *)
683                 bfd_alloc (abfd, rcount * sizeof (struct nlm_relent)));
684   if (nlm_relocs == (struct nlm_relent *) NULL)
685     return false;
686   sym -> relocs = nlm_relocs;
687   sym -> rcnt = 0;
688   while (sym -> rcnt < rcount)
689     {
690       asection *section;
691
692       if (! nlm_powerpc_read_reloc (abfd, sym, &section, &nlm_relocs -> reloc))
693         return false;
694       nlm_relocs -> section = section;
695       nlm_relocs++;
696       sym -> rcnt++;
697     }
698   return true;
699 }
700
701 #ifndef OLDFORMAT
702
703 /* Write a PowerPC NLM reloc.  */
704
705 static boolean
706 nlm_powerpc_write_import (abfd, sec, rel)
707      bfd *abfd;
708      asection *sec;
709      arelent *rel;
710 {
711   asymbol *sym;
712   bfd_vma val;
713   bfd_byte temp[4];
714
715   /* PowerPC NetWare only supports one kind of reloc.  */
716   if (rel->addend != 0
717       || rel->howto == NULL
718       || rel->howto->rightshift != 0
719       || rel->howto->size != 2
720       || rel->howto->bitsize != 32
721       || rel->howto->bitpos != 0
722       || rel->howto->pc_relative
723       || (rel->howto->src_mask != 0xffffffff && rel->addend != 0)
724       || rel->howto->dst_mask != 0xffffffff)
725     {
726       bfd_set_error (bfd_error_invalid_operation);
727       return false;
728     }
729
730   sym = *rel->sym_ptr_ptr;
731
732   /* The value we write out is the offset into the appropriate
733      segment, rightshifted by two.  This offset is the section vma,
734      adjusted by the vma of the lowest section in that segment, plus
735      the address of the relocation.  */
736   val = bfd_get_section_vma (abfd, sec) + rel->address;
737   if ((val & 3) != 0)
738     {
739       bfd_set_error (bfd_error_bad_value);
740       return false;
741     }
742   val >>= 2;
743
744   /* The high bit is 0 if the reloc is in the data section, or 1 if
745      the reloc is in the code section.  */
746   if (bfd_get_section_flags (abfd, sec) & SEC_DATA)
747     val -= nlm_get_data_low (abfd);
748   else
749     {
750       val -= nlm_get_text_low (abfd);
751       val |= NLM_HIBIT;
752     }
753
754   if (! bfd_is_und_section (bfd_get_section (sym)))
755     {
756       /* This is an internal relocation fixup.  The second most
757          significant bit is 0 if this is a reloc against the data
758          segment, or 1 if it is a reloc against the text segment.  */
759       if (bfd_get_section_flags (abfd, bfd_get_section (sym)) & SEC_CODE)
760         val |= NLM_HIBIT >> 1;
761     }
762
763   bfd_put_32 (abfd, val, temp);
764   if (bfd_bwrite (temp, (bfd_size_type) sizeof (temp), abfd) != sizeof (temp))
765     return false;
766
767   return true;
768 }
769
770 #else /* OLDFORMAT */
771
772 /* This is used for the reloc handling in the old format.  */
773
774 /* Write a PowerPC NLM reloc.  */
775
776 static boolean
777 nlm_powerpc_write_reloc (abfd, sec, rel, indx)
778      bfd *abfd;
779      asection *sec;
780      arelent *rel;
781      int indx;
782 {
783   struct nlm32_powerpc_external_reloc ext;
784   asection *code_sec, *data_sec, *bss_sec;
785   asymbol *sym;
786   asection *symsec;
787   unsigned long l_symndx;
788   int l_rtype;
789   int l_rsecnm;
790   reloc_howto_type *howto;
791   bfd_size_type address;
792
793   /* Get the sections now, for convenience.  */
794   code_sec = bfd_get_section_by_name (abfd, NLM_CODE_NAME);
795   data_sec = bfd_get_section_by_name (abfd, NLM_INITIALIZED_DATA_NAME);
796   bss_sec = bfd_get_section_by_name (abfd, NLM_UNINITIALIZED_DATA_NAME);
797
798   sym = *rel->sym_ptr_ptr;
799   symsec = bfd_get_section (sym);
800   if (indx != -1)
801     {
802       BFD_ASSERT (bfd_is_und_section (symsec));
803       l_symndx = indx + 3;
804     }
805   else
806     {
807       if (symsec == code_sec)
808         l_symndx = 0;
809       else if (symsec == data_sec)
810         l_symndx = 1;
811       else if (symsec == bss_sec)
812         l_symndx = 2;
813       else
814         {
815           bfd_set_error (bfd_error_bad_value);
816           return false;
817         }
818     }
819
820   H_PUT_32 (abfd, l_symndx, ext.l_symndx);
821
822   for (howto = nlm_powerpc_howto_table;
823        howto < nlm_powerpc_howto_table + HOWTO_COUNT;
824        howto++)
825     {
826       if (howto->rightshift == rel->howto->rightshift
827           && howto->size == rel->howto->size
828           && howto->bitsize == rel->howto->bitsize
829           && howto->pc_relative == rel->howto->pc_relative
830           && howto->bitpos == rel->howto->bitpos
831           && (howto->partial_inplace == rel->howto->partial_inplace
832               || (! rel->howto->partial_inplace
833                   && rel->addend == 0))
834           && (howto->src_mask == rel->howto->src_mask
835               || (rel->howto->src_mask == 0
836                   && rel->addend == 0))
837           && howto->dst_mask == rel->howto->dst_mask
838           && howto->pcrel_offset == rel->howto->pcrel_offset)
839         break;
840     }
841   if (howto >= nlm_powerpc_howto_table + HOWTO_COUNT)
842     {
843       bfd_set_error (bfd_error_bad_value);
844       return false;
845     }
846
847   l_rtype = howto->type;
848   if (howto->complain_on_overflow == complain_overflow_signed)
849     l_rtype |= 0x8000;
850   l_rtype |= (howto->bitsize - 1) << 8;
851   H_PUT_16 (abfd, l_rtype, ext.l_rtype);
852
853   address = rel->address;
854
855   if (sec == code_sec)
856     l_rsecnm = 0;
857   else if (sec == data_sec)
858     {
859       l_rsecnm = 1;
860       address += bfd_section_size (abfd, code_sec);
861     }
862   else
863     {
864       bfd_set_error (bfd_error_bad_value);
865       return false;
866     }
867
868   H_PUT_16 (abfd, l_rsecnm, ext.l_rsecnm);
869   H_PUT_32 (abfd, address, ext.l_vaddr);
870
871   if (bfd_bwrite (&ext, (bfd_size_type) sizeof ext, abfd) != sizeof ext)
872     return false;
873
874   return true;
875 }
876
877 /* Write a PowerPC NLM import.  */
878
879 static boolean
880 nlm_powerpc_write_import (abfd, sec, rel)
881      bfd *abfd;
882      asection *sec;
883      arelent *rel;
884 {
885   return nlm_powerpc_write_reloc (abfd, sec, rel, -1);
886 }
887
888 #endif /* OLDFORMAT */
889
890 /* Write a PowerPC NLM external symbol.  This routine keeps a static
891    count of the symbol index.  FIXME: I don't know if this is
892    necessary, and the index never gets reset.  */
893
894 static boolean
895 nlm_powerpc_write_external (abfd, count, sym, relocs)
896      bfd *abfd;
897      bfd_size_type count;
898      asymbol *sym;
899      struct reloc_and_sec *relocs;
900 {
901   unsigned int i;
902   bfd_byte len;
903   unsigned char temp[NLM_TARGET_LONG_SIZE];
904 #ifdef OLDFORMAT
905   static int indx;
906 #endif
907
908   len = strlen (sym->name);
909   if ((bfd_bwrite (&len, (bfd_size_type) sizeof (bfd_byte), abfd)
910        != sizeof (bfd_byte))
911       || bfd_bwrite (sym->name, (bfd_size_type) len, abfd) != len)
912     return false;
913
914   bfd_put_32 (abfd, count, temp);
915   if (bfd_bwrite (temp, (bfd_size_type) sizeof (temp), 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"