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