Made sure that every call to bfd_read, bfd_write, and bfd_seek
[external/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 #define ARCH_SIZE 32
25
26 #include "nlm/ppc-ext.h"
27 #define Nlm_External_Fixed_Header       Nlm32_powerpc_External_Fixed_Header
28
29 #include "libnlm.h"
30
31 static boolean nlm_powerpc_backend_object_p
32   PARAMS ((bfd *));
33 static boolean nlm_powerpc_write_prefix
34   PARAMS ((bfd *));
35 static boolean nlm_powerpc_read_reloc
36   PARAMS ((bfd *, nlmNAME(symbol_type) *, asection **, arelent *));
37 static boolean nlm_powerpc_mangle_relocs
38   PARAMS ((bfd *, asection *, PTR, bfd_vma, bfd_size_type));
39 static boolean nlm_powerpc_read_import
40   PARAMS ((bfd *, nlmNAME(symbol_type) *));
41 static boolean nlm_powerpc_write_reloc
42   PARAMS ((bfd *, asection *, arelent *, int));
43 static boolean nlm_powerpc_write_import
44   PARAMS ((bfd *, asection *, arelent *));
45 static boolean nlm_powerpc_write_external
46   PARAMS ((bfd *, bfd_size_type, asymbol *, struct reloc_and_sec *));
47 \f
48 /* PowerPC NLM's have a prefix header before the standard NLM.  This
49    function reads it in, verifies the version, and seeks the bfd to
50    the location before the regular NLM header.  */
51
52 static boolean
53 nlm_powerpc_backend_object_p (abfd)
54      bfd *abfd;
55 {
56   struct nlm32_powerpc_external_prefix_header s;
57
58   if (bfd_read ((PTR) &s, sizeof s, 1, abfd) != sizeof s)
59     return false;
60
61   if (memcmp (s.signature, NLM32_POWERPC_SIGNATURE, sizeof s.signature) != 0
62       || bfd_h_get_32 (abfd, s.headerVersion) != NLM32_POWERPC_HEADER_VERSION)
63     return false;
64
65   return true;
66 }
67
68 /* Write out the prefix.  */
69
70 static boolean
71 nlm_powerpc_write_prefix (abfd)
72      bfd *abfd;
73 {
74   struct nlm32_powerpc_external_prefix_header s;
75
76   memset (&s, 0, sizeof s);
77   memcpy (s.signature, NLM32_POWERPC_SIGNATURE, sizeof s.signature);
78   bfd_h_put_32 (abfd, (bfd_vma) NLM32_POWERPC_HEADER_VERSION, s.headerVersion);
79   bfd_h_put_32 (abfd, (bfd_vma) 0, s.origins);
80
81   /* FIXME: What should we do about the date?  */
82
83   if (bfd_write ((PTR) &s, sizeof s, 1, abfd) != sizeof s)
84     return false;
85
86   return true;
87 }
88 \f
89 /* How to process the various reloc types.  PowerPC NLMs use XCOFF
90    reloc types, and I have just copied the XCOFF reloc table here.  */
91
92 static reloc_howto_type nlm_powerpc_howto_table[] =
93 {
94   /* Standard 32 bit relocation.  */
95   HOWTO (0,                     /* type */                                 
96          0,                     /* rightshift */                           
97          2,                     /* size (0 = byte, 1 = short, 2 = long) */ 
98          32,                    /* bitsize */                   
99          false,                 /* pc_relative */                          
100          0,                     /* bitpos */                               
101          complain_overflow_bitfield, /* complain_on_overflow */
102          0,                     /* special_function */                     
103          "R_POS",               /* name */                                 
104          true,                  /* partial_inplace */                      
105          0xffffffff,            /* src_mask */                             
106          0xffffffff,            /* dst_mask */                             
107          false),                /* pcrel_offset */
108
109   /* 32 bit relocation, but store negative value.  */
110   HOWTO (1,                     /* type */                                 
111          0,                     /* rightshift */                           
112          -2,                    /* size (0 = byte, 1 = short, 2 = long) */ 
113          32,                    /* bitsize */                   
114          false,                 /* pc_relative */                          
115          0,                     /* bitpos */                               
116          complain_overflow_bitfield, /* complain_on_overflow */
117          0,                     /* special_function */                     
118          "R_NEG",               /* name */                                 
119          true,                  /* partial_inplace */                      
120          0xffffffff,            /* src_mask */                             
121          0xffffffff,            /* dst_mask */                             
122          false),                /* pcrel_offset */
123
124   /* 32 bit PC relative relocation.  */
125   HOWTO (2,                     /* type */                                 
126          0,                     /* rightshift */                           
127          2,                     /* size (0 = byte, 1 = short, 2 = long) */ 
128          32,                    /* bitsize */                   
129          true,                  /* pc_relative */                          
130          0,                     /* bitpos */                               
131          complain_overflow_signed, /* complain_on_overflow */
132          0,                     /* special_function */                     
133          "R_REL",               /* name */                                 
134          true,                  /* partial_inplace */                      
135          0xffffffff,            /* src_mask */                             
136          0xffffffff,            /* dst_mask */                             
137          false),                /* pcrel_offset */
138   
139   /* 16 bit TOC relative relocation.  */
140   HOWTO (3,                     /* type */                                 
141          0,                     /* rightshift */                           
142          1,                     /* size (0 = byte, 1 = short, 2 = long) */ 
143          16,                    /* bitsize */                   
144          false,                 /* pc_relative */                          
145          0,                     /* bitpos */                               
146          complain_overflow_signed, /* complain_on_overflow */
147          0,                     /* special_function */                     
148          "R_TOC",               /* name */                                 
149          true,                  /* partial_inplace */                      
150          0xffff,                /* src_mask */                             
151          0xffff,                /* dst_mask */                             
152          false),                /* pcrel_offset */
153   
154   /* I don't really know what this is.  */
155   HOWTO (4,                     /* type */                                 
156          1,                     /* rightshift */                           
157          2,                     /* size (0 = byte, 1 = short, 2 = long) */ 
158          32,                    /* bitsize */                   
159          false,                 /* pc_relative */                          
160          0,                     /* bitpos */                               
161          complain_overflow_bitfield, /* complain_on_overflow */
162          0,                     /* special_function */                     
163          "R_RTB",               /* name */                                 
164          true,                  /* partial_inplace */                      
165          0xffffffff,            /* src_mask */                             
166          0xffffffff,            /* dst_mask */                             
167          false),                /* pcrel_offset */
168   
169   /* External TOC relative symbol.  */
170   HOWTO (5,                     /* type */                                 
171          0,                     /* rightshift */                           
172          2,                     /* size (0 = byte, 1 = short, 2 = long) */ 
173          16,                    /* bitsize */                   
174          false,                 /* pc_relative */                          
175          0,                     /* bitpos */                               
176          complain_overflow_bitfield, /* complain_on_overflow */
177          0,                     /* special_function */                     
178          "R_GL",                /* name */                                 
179          true,                  /* partial_inplace */                      
180          0xffff,                /* src_mask */                             
181          0xffff,                /* dst_mask */                             
182          false),                /* pcrel_offset */
183   
184   /* Local TOC relative symbol.  */
185   HOWTO (6,                     /* type */                                 
186          0,                     /* rightshift */                           
187          2,                     /* size (0 = byte, 1 = short, 2 = long) */ 
188          16,                    /* bitsize */                   
189          false,                 /* pc_relative */                          
190          0,                     /* bitpos */                               
191          complain_overflow_bitfield, /* complain_on_overflow */
192          0,                     /* special_function */                     
193          "R_TCL",               /* name */                                 
194          true,                  /* partial_inplace */                      
195          0xffff,                /* src_mask */                             
196          0xffff,                /* dst_mask */                             
197          false),                /* pcrel_offset */
198   
199   { 7 },
200   
201   /* Non modifiable absolute branch.  */
202   HOWTO (8,                     /* type */                                 
203          0,                     /* rightshift */                           
204          2,                     /* size (0 = byte, 1 = short, 2 = long) */ 
205          26,                    /* bitsize */                   
206          false,                 /* pc_relative */                          
207          0,                     /* bitpos */                               
208          complain_overflow_bitfield, /* complain_on_overflow */
209          0,                     /* special_function */                     
210          "R_BA",                /* name */                                 
211          true,                  /* partial_inplace */                      
212          0x3fffffc,             /* src_mask */                             
213          0x3fffffc,             /* dst_mask */                             
214          false),                /* pcrel_offset */
215   
216   { 9 },
217
218   /* Non modifiable relative branch.  */
219   HOWTO (0xa,                   /* type */                                 
220          0,                     /* rightshift */                           
221          2,                     /* size (0 = byte, 1 = short, 2 = long) */ 
222          26,                    /* bitsize */                   
223          true,                  /* pc_relative */                          
224          0,                     /* bitpos */                               
225          complain_overflow_signed, /* complain_on_overflow */
226          0,                     /* special_function */                     
227          "R_BR",                /* name */                                 
228          true,                  /* partial_inplace */                      
229          0x3fffffc,             /* src_mask */                             
230          0x3fffffc,             /* dst_mask */                             
231          false),                /* pcrel_offset */
232   
233   { 0xb },
234
235   /* Indirect load.  */
236   HOWTO (0xc,                   /* type */                                 
237          0,                     /* rightshift */                           
238          2,                     /* size (0 = byte, 1 = short, 2 = long) */ 
239          16,                    /* bitsize */                   
240          false,                 /* pc_relative */                          
241          0,                     /* bitpos */                               
242          complain_overflow_bitfield, /* complain_on_overflow */
243          0,                     /* special_function */                     
244          "R_RL",                /* name */                                 
245          true,                  /* partial_inplace */                      
246          0xffff,                /* src_mask */                             
247          0xffff,                /* dst_mask */                             
248          false),                /* pcrel_offset */
249   
250   /* Load address.  */
251   HOWTO (0xd,                   /* type */                                 
252          0,                     /* rightshift */                           
253          2,                     /* size (0 = byte, 1 = short, 2 = long) */ 
254          16,                    /* bitsize */                   
255          false,                 /* pc_relative */                          
256          0,                     /* bitpos */                               
257          complain_overflow_bitfield, /* complain_on_overflow */
258          0,                     /* special_function */                     
259          "R_RLA",               /* name */                                 
260          true,                  /* partial_inplace */                      
261          0xffff,                /* src_mask */                             
262          0xffff,                /* dst_mask */                             
263          false),                /* pcrel_offset */
264   
265   { 0xe },
266   
267   /* Non-relocating reference.  */
268   HOWTO (0xf,                   /* type */                                 
269          0,                     /* rightshift */                           
270          2,                     /* size (0 = byte, 1 = short, 2 = long) */ 
271          32,                    /* bitsize */                   
272          false,                 /* pc_relative */                          
273          0,                     /* bitpos */                               
274          complain_overflow_bitfield, /* complain_on_overflow */
275          0,                     /* special_function */                     
276          "R_REF",               /* name */                                 
277          false,                 /* partial_inplace */                      
278          0,                     /* src_mask */                             
279          0,                     /* dst_mask */                             
280          false),                /* pcrel_offset */
281   
282   { 0x10 },
283   { 0x11 },
284   
285   /* TOC relative indirect load.  */
286   HOWTO (0x12,                  /* type */                                 
287          0,                     /* rightshift */                           
288          2,                     /* size (0 = byte, 1 = short, 2 = long) */ 
289          16,                    /* bitsize */                   
290          false,                 /* pc_relative */                          
291          0,                     /* bitpos */                               
292          complain_overflow_bitfield, /* complain_on_overflow */
293          0,                     /* special_function */                     
294          "R_TRL",               /* name */                                 
295          true,                  /* partial_inplace */                      
296          0xffff,                /* src_mask */                             
297          0xffff,                /* dst_mask */                             
298          false),                /* pcrel_offset */
299   
300   /* TOC relative load address.  */
301   HOWTO (0x13,                  /* type */                                 
302          0,                     /* rightshift */                           
303          2,                     /* size (0 = byte, 1 = short, 2 = long) */ 
304          16,                    /* bitsize */                   
305          false,                 /* pc_relative */                          
306          0,                     /* bitpos */                               
307          complain_overflow_bitfield, /* complain_on_overflow */
308          0,                     /* special_function */                     
309          "R_TRLA",              /* name */                                 
310          true,                  /* partial_inplace */                      
311          0xffff,                /* src_mask */                             
312          0xffff,                /* dst_mask */                             
313          false),                /* pcrel_offset */
314   
315   /* Modifiable relative branch.  */
316   HOWTO (0x14,                  /* type */                                 
317          1,                     /* rightshift */                           
318          2,                     /* size (0 = byte, 1 = short, 2 = long) */ 
319          32,                    /* bitsize */                   
320          false,                 /* pc_relative */                          
321          0,                     /* bitpos */                               
322          complain_overflow_bitfield, /* complain_on_overflow */
323          0,                     /* special_function */                     
324          "R_RRTBI",             /* name */                                 
325          true,                  /* partial_inplace */                      
326          0xffffffff,            /* src_mask */                             
327          0xffffffff,            /* dst_mask */                             
328          false),                /* pcrel_offset */
329   
330   /* Modifiable absolute branch.  */
331   HOWTO (0x15,                  /* type */                                 
332          1,                     /* rightshift */                           
333          2,                     /* size (0 = byte, 1 = short, 2 = long) */ 
334          32,                    /* bitsize */                   
335          false,                 /* pc_relative */                          
336          0,                     /* bitpos */                               
337          complain_overflow_bitfield, /* complain_on_overflow */
338          0,                     /* special_function */                     
339          "R_RRTBA",             /* name */                                 
340          true,                  /* partial_inplace */                      
341          0xffffffff,            /* src_mask */                             
342          0xffffffff,            /* dst_mask */                             
343          false),                /* pcrel_offset */
344   
345   /* Modifiable call absolute indirect.  */
346   HOWTO (0x16,                  /* type */                                 
347          0,                     /* rightshift */                           
348          2,                     /* size (0 = byte, 1 = short, 2 = long) */ 
349          16,                    /* bitsize */                   
350          false,                 /* pc_relative */                          
351          0,                     /* bitpos */                               
352          complain_overflow_bitfield, /* complain_on_overflow */
353          0,                     /* special_function */                     
354          "R_CAI",               /* name */                                 
355          true,                  /* partial_inplace */                      
356          0xffff,                /* src_mask */                             
357          0xffff,                /* dst_mask */                             
358          false),                /* pcrel_offset */
359   
360   /* Modifiable call relative.  */
361   HOWTO (0x17,                  /* type */                                 
362          0,                     /* rightshift */                           
363          2,                     /* size (0 = byte, 1 = short, 2 = long) */ 
364          16,                    /* bitsize */                   
365          false,                 /* pc_relative */                          
366          0,                     /* bitpos */                               
367          complain_overflow_bitfield, /* complain_on_overflow */
368          0,                     /* special_function */                     
369          "R_REL",               /* name */                                 
370          true,                  /* partial_inplace */                      
371          0xffff,                /* src_mask */                             
372          0xffff,                /* dst_mask */                             
373          false),                /* pcrel_offset */
374   
375   /* Modifiable branch absolute.  */
376   HOWTO (0x18,                  /* type */                                 
377          0,                     /* rightshift */                           
378          2,                     /* size (0 = byte, 1 = short, 2 = long) */ 
379          16,                    /* bitsize */                   
380          false,                 /* pc_relative */                          
381          0,                     /* bitpos */                               
382          complain_overflow_bitfield, /* complain_on_overflow */
383          0,                     /* special_function */                     
384          "R_RBA",               /* name */                                 
385          true,                  /* partial_inplace */                      
386          0xffff,                /* src_mask */                             
387          0xffff,                /* dst_mask */                             
388          false),                /* pcrel_offset */
389   
390   /* Modifiable branch absolute.  */
391   HOWTO (0x19,                  /* type */                                 
392          0,                     /* rightshift */                           
393          2,                     /* size (0 = byte, 1 = short, 2 = long) */ 
394          16,                    /* bitsize */                   
395          false,                 /* pc_relative */                          
396          0,                     /* bitpos */                               
397          complain_overflow_bitfield, /* complain_on_overflow */
398          0,                     /* special_function */                     
399          "R_RBAC",              /* name */                                 
400          true,                  /* partial_inplace */                      
401          0xffff,                /* src_mask */                             
402          0xffff,                /* dst_mask */                             
403          false),                /* pcrel_offset */
404   
405   /* Modifiable branch relative.  */
406   HOWTO (0x1a,                  /* type */                                 
407          0,                     /* rightshift */                           
408          2,                     /* size (0 = byte, 1 = short, 2 = long) */ 
409          26,                    /* bitsize */                   
410          false,                 /* pc_relative */                          
411          0,                     /* bitpos */                               
412          complain_overflow_signed, /* complain_on_overflow */
413          0,                     /* special_function */                     
414          "R_REL",               /* name */                                 
415          true,                  /* partial_inplace */                      
416          0xffff,                /* src_mask */                             
417          0xffff,                /* dst_mask */                             
418          false),                /* pcrel_offset */
419   
420   /* Modifiable branch absolute.  */
421   HOWTO (0x1b,                  /* type */                                 
422          0,                     /* rightshift */                           
423          2,                     /* size (0 = byte, 1 = short, 2 = long) */ 
424          16,                    /* bitsize */                   
425          false,                 /* pc_relative */                          
426          0,                     /* bitpos */                               
427          complain_overflow_bitfield, /* complain_on_overflow */
428          0,                     /* special_function */                     
429          "R_REL",               /* name */                                 
430          true,                  /* partial_inplace */                      
431          0xffff,                /* src_mask */                             
432          0xffff,                /* dst_mask */                             
433          false)                 /* pcrel_offset */
434 };
435
436 #define HOWTO_COUNT (sizeof nlm_powerpc_howto_table             \
437                      / sizeof nlm_powerpc_howto_table[0])
438
439 /* Read a PowerPC NLM reloc.  */
440
441 static boolean
442 nlm_powerpc_read_reloc (abfd, sym, secp, rel)
443      bfd *abfd;
444      nlmNAME(symbol_type) *sym;
445      asection **secp;
446      arelent *rel;
447 {
448   struct nlm32_powerpc_external_reloc ext;
449   bfd_vma l_vaddr;
450   unsigned long l_symndx;
451   int l_rtype;
452   int l_rsecnm;
453   asection *code_sec, *data_sec, *bss_sec;
454
455   /* Read the reloc from the file.  */
456   if (bfd_read (&ext, sizeof ext, 1, abfd) != sizeof ext)
457     return false;
458
459   /* Swap in the fields.  */
460   l_vaddr = bfd_h_get_32 (abfd, ext.l_vaddr);
461   l_symndx = bfd_h_get_32 (abfd, ext.l_symndx);
462   l_rtype = bfd_h_get_16 (abfd, ext.l_rtype);
463   l_rsecnm = bfd_h_get_16 (abfd, ext.l_rsecnm);
464
465   /* Get the sections now, for convenience.  */
466   code_sec = bfd_get_section_by_name (abfd, NLM_CODE_NAME);
467   data_sec = bfd_get_section_by_name (abfd, NLM_INITIALIZED_DATA_NAME);
468   bss_sec = bfd_get_section_by_name (abfd, NLM_UNINITIALIZED_DATA_NAME);
469
470   /* Work out the arelent fields.  */
471   if (sym != NULL)
472     {
473       /* This is an import.  sym_ptr_ptr is filled in by
474          nlm_canonicalize_reloc.  */
475       rel->sym_ptr_ptr = NULL;
476     }
477   else
478     {
479       asection *sec;
480
481       if (l_symndx == 0)
482         sec = code_sec;
483       else if (l_symndx == 1)
484         sec = data_sec;
485       else if (l_symndx == 2)
486         sec = bss_sec;
487       else
488         {
489           bfd_set_error (bfd_error_bad_value);
490           return false;
491         }
492
493       rel->sym_ptr_ptr = sec->symbol_ptr_ptr;
494     }
495
496   rel->addend = 0;
497
498   BFD_ASSERT ((l_rtype & 0xff) < HOWTO_COUNT);
499
500   rel->howto = nlm_powerpc_howto_table + (l_rtype & 0xff);
501
502   BFD_ASSERT (rel->howto->name != NULL
503               && ((l_rtype & 0x8000) != 0
504                   ? (rel->howto->complain_on_overflow
505                      == complain_overflow_signed)
506                   : (rel->howto->complain_on_overflow
507                      == complain_overflow_bitfield))
508               && ((l_rtype >> 8) & 0x1f) == rel->howto->bitsize - 1);
509
510   if (l_rsecnm == 0)
511     *secp = code_sec;
512   else if (l_rsecnm == 1)
513     {
514       *secp = data_sec;
515       l_vaddr -= bfd_section_size (abfd, code_sec);
516     }
517   else
518     {
519       bfd_set_error (bfd_error_bad_value);
520       return false;
521     }
522
523   rel->address = l_vaddr;
524
525   return true;
526 }
527
528 /* Mangle PowerPC NLM relocs for output.  */
529
530 static boolean
531 nlm_powerpc_mangle_relocs (abfd, sec, data, offset, count)
532      bfd *abfd;
533      asection *sec;
534      PTR data;
535      bfd_vma offset;
536      bfd_size_type count;
537 {
538   return true;
539 }
540
541 /* Read a PowerPC NLM import record */
542
543 static boolean
544 nlm_powerpc_read_import (abfd, sym)
545      bfd *abfd;
546      nlmNAME(symbol_type) *sym;
547 {
548   struct nlm_relent *nlm_relocs;        /* relocation records for symbol */
549   bfd_size_type rcount;                 /* number of relocs */
550   bfd_byte temp[NLM_TARGET_LONG_SIZE];  /* temporary 32-bit value */
551   unsigned char symlength;              /* length of symbol name */
552   char *name;
553
554   if (bfd_read ((PTR) &symlength, sizeof (symlength), 1, abfd)
555       != sizeof (symlength))
556     return (false);
557   sym -> symbol.the_bfd = abfd;
558   name = bfd_alloc (abfd, symlength + 1);
559   if (name == NULL)
560     {
561       bfd_set_error (bfd_error_no_memory);
562       return false;
563     }
564   if (bfd_read (name, symlength, 1, abfd) != symlength)
565     return (false);
566   name[symlength] = '\0';
567   sym -> symbol.name = name;
568   sym -> symbol.flags = 0;
569   sym -> symbol.value = 0;
570   sym -> symbol.section = &bfd_und_section;
571   if (bfd_read ((PTR) temp, sizeof (temp), 1, abfd) != sizeof (temp))
572     return (false);
573   rcount = bfd_h_get_32 (abfd, temp);
574   nlm_relocs = ((struct nlm_relent *)
575                 bfd_alloc (abfd, rcount * sizeof (struct nlm_relent)));
576   if (nlm_relocs == (struct nlm_relent *) NULL)
577     {
578       bfd_set_error (bfd_error_no_memory);
579       return false;
580     }
581   sym -> relocs = nlm_relocs;
582   sym -> rcnt = 0;
583   while (sym -> rcnt < rcount)
584     {
585       asection *section;
586       
587       if (nlm_powerpc_read_reloc (abfd, sym, &section,
588                                   &nlm_relocs -> reloc)
589           == false)
590         return false;
591       nlm_relocs -> section = section;
592       nlm_relocs++;
593       sym -> rcnt++;
594     }
595   return true;
596 }
597
598 /* Write a PowerPC NLM reloc.  */
599
600 static boolean
601 nlm_powerpc_write_reloc (abfd, sec, rel, indx)
602      bfd *abfd;
603      asection *sec;
604      arelent *rel;
605      int indx;
606 {
607   struct nlm32_powerpc_external_reloc ext;
608   asection *code_sec, *data_sec, *bss_sec;
609   asymbol *sym;
610   asection *symsec;
611   unsigned long l_symndx;
612   int l_rtype;
613   int l_rsecnm;
614   const reloc_howto_type *howto;
615   bfd_size_type address;
616
617   /* Get the sections now, for convenience.  */
618   code_sec = bfd_get_section_by_name (abfd, NLM_CODE_NAME);
619   data_sec = bfd_get_section_by_name (abfd, NLM_INITIALIZED_DATA_NAME);
620   bss_sec = bfd_get_section_by_name (abfd, NLM_UNINITIALIZED_DATA_NAME);
621
622   sym = *rel->sym_ptr_ptr;
623   symsec = bfd_get_section (sym);
624   if (indx != -1)
625     {
626       BFD_ASSERT (symsec == &bfd_und_section);
627       l_symndx = indx + 3;
628     }
629   else
630     {
631       if (symsec == code_sec)
632         l_symndx = 0;
633       else if (symsec == data_sec)
634         l_symndx = 1;
635       else if (symsec == bss_sec)
636         l_symndx = 2;
637       else
638         {
639           bfd_set_error (bfd_error_bad_value);
640           return false;
641         }
642     }
643
644   bfd_h_put_32 (abfd, (bfd_vma) l_symndx, ext.l_symndx);
645
646   for (howto = nlm_powerpc_howto_table;
647        howto < nlm_powerpc_howto_table + HOWTO_COUNT;
648        howto++)
649     {
650       if (howto->rightshift == rel->howto->rightshift
651           && howto->size == rel->howto->size
652           && howto->bitsize == rel->howto->bitsize
653           && howto->pc_relative == rel->howto->pc_relative
654           && howto->bitpos == rel->howto->bitpos
655           && (howto->partial_inplace == rel->howto->partial_inplace
656               || (! rel->howto->partial_inplace
657                   && rel->addend == 0))
658           && (howto->src_mask == rel->howto->src_mask
659               || (rel->howto->src_mask == 0
660                   && rel->addend == 0))
661           && howto->dst_mask == rel->howto->dst_mask
662           && howto->pcrel_offset == rel->howto->pcrel_offset)
663         break;
664     }
665   if (howto >= nlm_powerpc_howto_table + HOWTO_COUNT)
666     {
667       bfd_set_error (bfd_error_bad_value);
668       return false;
669     }
670
671   l_rtype = howto->type;
672   if (howto->complain_on_overflow == complain_overflow_signed)
673     l_rtype |= 0x8000;
674   l_rtype |= (howto->bitsize - 1) << 8;
675   bfd_h_put_16 (abfd, (bfd_vma) l_rtype, ext.l_rtype);
676
677   address = rel->address;
678
679   if (sec == code_sec)
680     l_rsecnm = 0;
681   else if (sec == data_sec)
682     {
683       l_rsecnm = 1;
684       address += bfd_section_size (abfd, code_sec);
685     }
686   else
687     {
688       bfd_set_error (bfd_error_bad_value);
689       return false;
690     }
691
692   bfd_h_put_16 (abfd, (bfd_vma) l_rsecnm, ext.l_rsecnm);
693   bfd_h_put_32 (abfd, (bfd_vma) address, ext.l_vaddr);
694
695   if (bfd_write (&ext, sizeof ext, 1, abfd) != sizeof ext)
696     return false;
697
698   return true;
699 }
700
701 /* Write a PowerPC NLM import.  */
702
703 static boolean
704 nlm_powerpc_write_import (abfd, sec, rel)
705      bfd *abfd;
706      asection *sec;
707      arelent *rel;
708 {
709   return nlm_powerpc_write_reloc (abfd, sec, rel, -1);
710 }
711
712 /* Write a PowerPC NLM external symbol.  This routine keeps a static
713    count of the symbol index.  FIXME: I don't know if this is
714    necessary, and the index never gets reset.  */
715
716 static boolean
717 nlm_powerpc_write_external (abfd, count, sym, relocs)
718      bfd *abfd;
719      bfd_size_type count;
720      asymbol *sym;
721      struct reloc_and_sec *relocs;
722 {
723   int i;
724   bfd_byte len;
725   unsigned char temp[NLM_TARGET_LONG_SIZE];
726   static int indx;
727
728   len = strlen (sym->name);
729   if ((bfd_write (&len, sizeof (bfd_byte), 1, abfd) != sizeof(bfd_byte))
730       || bfd_write (sym->name, len, 1, abfd) != len)
731     return false;
732
733   bfd_put_32 (abfd, count, temp);
734   if (bfd_write (temp, sizeof(temp), 1, abfd) != sizeof (temp))
735     return false;
736
737   for (i = 0; i < count; i++)
738     {
739       if (nlm_powerpc_write_reloc (abfd, relocs[i].sec,
740                                    relocs[i].rel, indx) == false)
741         return false;
742     }
743
744   ++indx;
745
746   return true;
747 }
748
749 #include "nlmswap.h"
750
751 static const struct nlm_backend_data nlm32_powerpc_backend =
752 {
753   "NetWare PowerPC Module \032",
754   sizeof (Nlm32_powerpc_External_Fixed_Header),
755   sizeof (struct nlm32_powerpc_external_prefix_header),
756   bfd_arch_powerpc,
757   0,
758   false,
759   nlm_powerpc_backend_object_p,
760   nlm_powerpc_write_prefix,
761   nlm_powerpc_read_reloc,
762   nlm_powerpc_mangle_relocs,
763   nlm_powerpc_read_import,
764   nlm_powerpc_write_import,
765   0,    /* set_public_section */
766   0,    /* get_public_offset */
767   nlm_swap_fixed_header_in,
768   nlm_swap_fixed_header_out,
769   nlm_powerpc_write_external,
770   0,    /* write_export */
771 };
772
773 #define TARGET_BIG_NAME                 "nlm32-powerpc"
774 #define TARGET_BIG_SYM                  nlmNAME(powerpc_vec)
775 #define TARGET_BACKEND_DATA             &nlm32_powerpc_backend
776
777 #include "nlm-target.h"