OSDN Git Service

Touches most files in bfd/, so likely will be blamed for everything..
[pf3gnuchains/pf3gnuchains3x.git] / bfd / nlm32-ppc.c
1 /* Support for 32-bit PowerPC NLM (NetWare Loadable Module)
2    Copyright 1994, 1995, 2000, 2001 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,
693                                   &nlm_relocs -> reloc)
694           == false)
695         return false;
696       nlm_relocs -> section = section;
697       nlm_relocs++;
698       sym -> rcnt++;
699     }
700   return true;
701 }
702
703 #ifndef OLDFORMAT
704
705 /* Write a PowerPC NLM reloc.  */
706
707 static boolean
708 nlm_powerpc_write_import (abfd, sec, rel)
709      bfd *abfd;
710      asection *sec;
711      arelent *rel;
712 {
713   asymbol *sym;
714   bfd_vma val;
715   bfd_byte temp[4];
716
717   /* PowerPC NetWare only supports one kind of reloc.  */
718   if (rel->addend != 0
719       || rel->howto == NULL
720       || rel->howto->rightshift != 0
721       || rel->howto->size != 2
722       || rel->howto->bitsize != 32
723       || rel->howto->bitpos != 0
724       || rel->howto->pc_relative
725       || (rel->howto->src_mask != 0xffffffff && rel->addend != 0)
726       || rel->howto->dst_mask != 0xffffffff)
727     {
728       bfd_set_error (bfd_error_invalid_operation);
729       return false;
730     }
731
732   sym = *rel->sym_ptr_ptr;
733
734   /* The value we write out is the offset into the appropriate
735      segment, rightshifted by two.  This offset is the section vma,
736      adjusted by the vma of the lowest section in that segment, plus
737      the address of the relocation.  */
738   val = bfd_get_section_vma (abfd, sec) + rel->address;
739   if ((val & 3) != 0)
740     {
741       bfd_set_error (bfd_error_bad_value);
742       return false;
743     }
744   val >>= 2;
745
746   /* The high bit is 0 if the reloc is in the data section, or 1 if
747      the reloc is in the code section.  */
748   if (bfd_get_section_flags (abfd, sec) & SEC_DATA)
749     val -= nlm_get_data_low (abfd);
750   else
751     {
752       val -= nlm_get_text_low (abfd);
753       val |= NLM_HIBIT;
754     }
755
756   if (! bfd_is_und_section (bfd_get_section (sym)))
757     {
758       /* This is an internal relocation fixup.  The second most
759          significant bit is 0 if this is a reloc against the data
760          segment, or 1 if it is a reloc against the text segment.  */
761       if (bfd_get_section_flags (abfd, bfd_get_section (sym)) & SEC_CODE)
762         val |= NLM_HIBIT >> 1;
763     }
764
765   bfd_put_32 (abfd, val, temp);
766   if (bfd_bwrite (temp, (bfd_size_type) sizeof (temp), abfd) != sizeof (temp))
767     return false;
768
769   return true;
770 }
771
772 #else /* OLDFORMAT */
773
774 /* This is used for the reloc handling in the old format.  */
775
776 /* Write a PowerPC NLM reloc.  */
777
778 static boolean
779 nlm_powerpc_write_reloc (abfd, sec, rel, indx)
780      bfd *abfd;
781      asection *sec;
782      arelent *rel;
783      int indx;
784 {
785   struct nlm32_powerpc_external_reloc ext;
786   asection *code_sec, *data_sec, *bss_sec;
787   asymbol *sym;
788   asection *symsec;
789   unsigned long l_symndx;
790   int l_rtype;
791   int l_rsecnm;
792   reloc_howto_type *howto;
793   bfd_size_type address;
794
795   /* Get the sections now, for convenience.  */
796   code_sec = bfd_get_section_by_name (abfd, NLM_CODE_NAME);
797   data_sec = bfd_get_section_by_name (abfd, NLM_INITIALIZED_DATA_NAME);
798   bss_sec = bfd_get_section_by_name (abfd, NLM_UNINITIALIZED_DATA_NAME);
799
800   sym = *rel->sym_ptr_ptr;
801   symsec = bfd_get_section (sym);
802   if (indx != -1)
803     {
804       BFD_ASSERT (bfd_is_und_section (symsec));
805       l_symndx = indx + 3;
806     }
807   else
808     {
809       if (symsec == code_sec)
810         l_symndx = 0;
811       else if (symsec == data_sec)
812         l_symndx = 1;
813       else if (symsec == bss_sec)
814         l_symndx = 2;
815       else
816         {
817           bfd_set_error (bfd_error_bad_value);
818           return false;
819         }
820     }
821
822   H_PUT_32 (abfd, l_symndx, ext.l_symndx);
823
824   for (howto = nlm_powerpc_howto_table;
825        howto < nlm_powerpc_howto_table + HOWTO_COUNT;
826        howto++)
827     {
828       if (howto->rightshift == rel->howto->rightshift
829           && howto->size == rel->howto->size
830           && howto->bitsize == rel->howto->bitsize
831           && howto->pc_relative == rel->howto->pc_relative
832           && howto->bitpos == rel->howto->bitpos
833           && (howto->partial_inplace == rel->howto->partial_inplace
834               || (! rel->howto->partial_inplace
835                   && rel->addend == 0))
836           && (howto->src_mask == rel->howto->src_mask
837               || (rel->howto->src_mask == 0
838                   && rel->addend == 0))
839           && howto->dst_mask == rel->howto->dst_mask
840           && howto->pcrel_offset == rel->howto->pcrel_offset)
841         break;
842     }
843   if (howto >= nlm_powerpc_howto_table + HOWTO_COUNT)
844     {
845       bfd_set_error (bfd_error_bad_value);
846       return false;
847     }
848
849   l_rtype = howto->type;
850   if (howto->complain_on_overflow == complain_overflow_signed)
851     l_rtype |= 0x8000;
852   l_rtype |= (howto->bitsize - 1) << 8;
853   H_PUT_16 (abfd, l_rtype, ext.l_rtype);
854
855   address = rel->address;
856
857   if (sec == code_sec)
858     l_rsecnm = 0;
859   else if (sec == data_sec)
860     {
861       l_rsecnm = 1;
862       address += bfd_section_size (abfd, code_sec);
863     }
864   else
865     {
866       bfd_set_error (bfd_error_bad_value);
867       return false;
868     }
869
870   H_PUT_16 (abfd, l_rsecnm, ext.l_rsecnm);
871   H_PUT_32 (abfd, address, ext.l_vaddr);
872
873   if (bfd_bwrite (&ext, (bfd_size_type) sizeof ext, abfd) != sizeof ext)
874     return false;
875
876   return true;
877 }
878
879 /* Write a PowerPC NLM import.  */
880
881 static boolean
882 nlm_powerpc_write_import (abfd, sec, rel)
883      bfd *abfd;
884      asection *sec;
885      arelent *rel;
886 {
887   return nlm_powerpc_write_reloc (abfd, sec, rel, -1);
888 }
889
890 #endif /* OLDFORMAT */
891
892 /* Write a PowerPC NLM external symbol.  This routine keeps a static
893    count of the symbol index.  FIXME: I don't know if this is
894    necessary, and the index never gets reset.  */
895
896 static boolean
897 nlm_powerpc_write_external (abfd, count, sym, relocs)
898      bfd *abfd;
899      bfd_size_type count;
900      asymbol *sym;
901      struct reloc_and_sec *relocs;
902 {
903   unsigned int i;
904   bfd_byte len;
905   unsigned char temp[NLM_TARGET_LONG_SIZE];
906 #ifdef OLDFORMAT
907   static int indx;
908 #endif
909
910   len = strlen (sym->name);
911   if ((bfd_bwrite (&len, (bfd_size_type) sizeof (bfd_byte), abfd)
912        != sizeof (bfd_byte))
913       || bfd_bwrite (sym->name, (bfd_size_type) len, abfd) != len)
914     return false;
915
916   bfd_put_32 (abfd, count, temp);
917   if (bfd_bwrite (temp, (bfd_size_type) sizeof (temp), abfd) != sizeof (temp))
918     return false;
919
920   for (i = 0; i < count; i++)
921     {
922 #ifndef OLDFORMAT
923       if (! nlm_powerpc_write_import (abfd, relocs[i].sec, relocs[i].rel))
924         return false;
925 #else
926       if (! nlm_powerpc_write_reloc (abfd, relocs[i].sec,
927                                      relocs[i].rel, indx))
928         return false;
929 #endif
930     }
931
932 #ifdef OLDFORMAT
933   ++indx;
934 #endif
935
936   return true;
937 }
938 \f
939 #ifndef OLDFORMAT
940
941 /* PowerPC Netware uses a word offset, not a byte offset, for public
942    symbols.  */
943
944 /* Set the section for a public symbol.  */
945
946 static boolean
947 nlm_powerpc_set_public_section (abfd, sym)
948      bfd *abfd;
949      nlmNAME(symbol_type) *sym;
950 {
951   if (sym->symbol.value & NLM_HIBIT)
952     {
953       sym->symbol.value &= ~NLM_HIBIT;
954       sym->symbol.flags |= BSF_FUNCTION;
955       sym->symbol.section =
956         bfd_get_section_by_name (abfd, NLM_CODE_NAME);
957     }
958   else
959     {
960       sym->symbol.section =
961         bfd_get_section_by_name (abfd, NLM_INITIALIZED_DATA_NAME);
962     }
963
964   sym->symbol.value <<= 2;
965
966   return true;
967 }
968
969 /* Get the offset to write out for a public symbol.  */
970
971 static bfd_vma
972 nlm_powerpc_get_public_offset (abfd, sym)
973      bfd *abfd;
974      asymbol *sym;
975 {
976   bfd_vma offset;
977   asection *sec;
978
979   offset = bfd_asymbol_value (sym);
980   sec = bfd_get_section (sym);
981   if (sec->flags & SEC_CODE)
982     {
983       offset -= nlm_get_text_low (abfd);
984       offset |= NLM_HIBIT;
985     }
986   else if (sec->flags & (SEC_DATA | SEC_ALLOC))
987     {
988       /* SEC_ALLOC is for the .bss section.  */
989       offset -= nlm_get_data_low (abfd);
990     }
991   else
992     {
993       /* We can't handle an exported symbol that is not in the code or
994          data segment.  */
995       bfd_set_error (bfd_error_invalid_operation);
996       /* FIXME: No way to return error.  */
997       abort ();
998     }
999
1000   return offset;
1001 }
1002
1003 #endif /* ! defined (OLDFORMAT) */
1004 \f
1005 #include "nlmswap.h"
1006
1007 static const struct nlm_backend_data nlm32_powerpc_backend =
1008 {
1009   "NetWare PowerPC Module \032",
1010   sizeof (Nlm32_powerpc_External_Fixed_Header),
1011 #ifndef OLDFORMAT
1012   0,    /* optional_prefix_size */
1013 #else
1014   sizeof (struct nlm32_powerpc_external_prefix_header),
1015 #endif
1016   bfd_arch_powerpc,
1017   0,
1018   false,
1019 #ifndef OLDFORMAT
1020   0,    /* backend_object_p */
1021   0,    /* write_prefix */
1022 #else
1023   nlm_powerpc_backend_object_p,
1024   nlm_powerpc_write_prefix,
1025 #endif
1026   nlm_powerpc_read_reloc,
1027   nlm_powerpc_mangle_relocs,
1028   nlm_powerpc_read_import,
1029   nlm_powerpc_write_import,
1030 #ifndef OLDFORMAT
1031   nlm_powerpc_set_public_section,
1032   nlm_powerpc_get_public_offset,
1033 #else
1034   0,    /* set_public_section */
1035   0,    /* get_public_offset */
1036 #endif
1037   nlm_swap_fixed_header_in,
1038   nlm_swap_fixed_header_out,
1039   nlm_powerpc_write_external,
1040   0,    /* write_export */
1041 };
1042
1043 #define TARGET_BIG_NAME                 "nlm32-powerpc"
1044 #define TARGET_BIG_SYM                  nlmNAME(powerpc_vec)
1045 #define TARGET_BACKEND_DATA             &nlm32_powerpc_backend
1046
1047 #include "nlm-target.h"