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