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