OSDN Git Service

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