* nlm32-i386.c (nlm_i386_read_import): Null terminate the symbol
[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     {
458       bfd_set_error (bfd_error_system_call);
459       return false;
460     }
461
462   /* Swap in the fields.  */
463   l_vaddr = bfd_h_get_32 (abfd, ext.l_vaddr);
464   l_symndx = bfd_h_get_32 (abfd, ext.l_symndx);
465   l_rtype = bfd_h_get_16 (abfd, ext.l_rtype);
466   l_rsecnm = bfd_h_get_16 (abfd, ext.l_rsecnm);
467
468   /* Get the sections now, for convenience.  */
469   code_sec = bfd_get_section_by_name (abfd, NLM_CODE_NAME);
470   data_sec = bfd_get_section_by_name (abfd, NLM_INITIALIZED_DATA_NAME);
471   bss_sec = bfd_get_section_by_name (abfd, NLM_UNINITIALIZED_DATA_NAME);
472
473   /* Work out the arelent fields.  */
474   if (sym != NULL)
475     {
476       /* This is an import.  sym_ptr_ptr is filled in by
477          nlm_canonicalize_reloc.  */
478       rel->sym_ptr_ptr = NULL;
479     }
480   else
481     {
482       asection *sec;
483
484       if (l_symndx == 0)
485         sec = code_sec;
486       else if (l_symndx == 1)
487         sec = data_sec;
488       else if (l_symndx == 2)
489         sec = bss_sec;
490       else
491         {
492           bfd_set_error (bfd_error_bad_value);
493           return false;
494         }
495
496       rel->sym_ptr_ptr = sec->symbol_ptr_ptr;
497     }
498
499   rel->addend = 0;
500
501   BFD_ASSERT ((l_rtype & 0xff) < HOWTO_COUNT);
502
503   rel->howto = nlm_powerpc_howto_table + (l_rtype & 0xff);
504
505   BFD_ASSERT (rel->howto->name != NULL
506               && ((l_rtype & 0x8000) != 0
507                   ? (rel->howto->complain_on_overflow
508                      == complain_overflow_signed)
509                   : (rel->howto->complain_on_overflow
510                      == complain_overflow_bitfield))
511               && ((l_rtype >> 8) & 0x1f) == rel->howto->bitsize - 1);
512
513   if (l_rsecnm == 0)
514     *secp = code_sec;
515   else if (l_rsecnm == 1)
516     {
517       *secp = data_sec;
518       l_vaddr -= bfd_section_size (abfd, code_sec);
519     }
520   else
521     {
522       bfd_set_error (bfd_error_bad_value);
523       return false;
524     }
525
526   rel->address = l_vaddr;
527
528   return true;
529 }
530
531 /* Mangle PowerPC NLM relocs for output.  */
532
533 static boolean
534 nlm_powerpc_mangle_relocs (abfd, sec, data, offset, count)
535      bfd *abfd;
536      asection *sec;
537      PTR data;
538      bfd_vma offset;
539      bfd_size_type count;
540 {
541   return true;
542 }
543
544 /* Read a PowerPC NLM import record */
545
546 static boolean
547 nlm_powerpc_read_import (abfd, sym)
548      bfd *abfd;
549      nlmNAME(symbol_type) *sym;
550 {
551   struct nlm_relent *nlm_relocs;        /* relocation records for symbol */
552   bfd_size_type rcount;                 /* number of relocs */
553   bfd_byte temp[NLM_TARGET_LONG_SIZE];  /* temporary 32-bit value */
554   unsigned char symlength;              /* length of symbol name */
555   char *name;
556
557   if (bfd_read ((PTR) &symlength, sizeof (symlength), 1, abfd)
558       != sizeof (symlength))
559     {
560       bfd_set_error (bfd_error_system_call);
561       return (false);
562     }
563   sym -> symbol.the_bfd = abfd;
564   name = bfd_alloc (abfd, symlength + 1);
565   if (name == NULL)
566     {
567       bfd_set_error (bfd_error_no_memory);
568       return false;
569     }
570   if (bfd_read (name, symlength, 1, abfd) != symlength)
571     {
572       bfd_set_error (bfd_error_system_call);
573       return (false);
574     }
575   name[symlength] = '\0';
576   sym -> symbol.name = name;
577   sym -> symbol.flags = 0;
578   sym -> symbol.value = 0;
579   sym -> symbol.section = &bfd_und_section;
580   if (bfd_read ((PTR) temp, sizeof (temp), 1, abfd) != sizeof (temp))
581     {
582       bfd_set_error (bfd_error_system_call);
583       return (false);
584     }
585   rcount = bfd_h_get_32 (abfd, temp);
586   nlm_relocs = ((struct nlm_relent *)
587                 bfd_alloc (abfd, rcount * sizeof (struct nlm_relent)));
588   if (nlm_relocs == (struct nlm_relent *) NULL)
589     {
590       bfd_set_error (bfd_error_no_memory);
591       return false;
592     }
593   sym -> relocs = nlm_relocs;
594   sym -> rcnt = 0;
595   while (sym -> rcnt < rcount)
596     {
597       asection *section;
598       
599       if (nlm_powerpc_read_reloc (abfd, sym, &section,
600                                   &nlm_relocs -> reloc)
601           == false)
602         return false;
603       nlm_relocs -> section = section;
604       nlm_relocs++;
605       sym -> rcnt++;
606     }
607   return true;
608 }
609
610 /* Write a PowerPC NLM reloc.  */
611
612 static boolean
613 nlm_powerpc_write_reloc (abfd, sec, rel, indx)
614      bfd *abfd;
615      asection *sec;
616      arelent *rel;
617      int indx;
618 {
619   struct nlm32_powerpc_external_reloc ext;
620   asection *code_sec, *data_sec, *bss_sec;
621   asymbol *sym;
622   asection *symsec;
623   unsigned long l_symndx;
624   int l_rtype;
625   int l_rsecnm;
626   const reloc_howto_type *howto;
627   bfd_size_type address;
628
629   /* Get the sections now, for convenience.  */
630   code_sec = bfd_get_section_by_name (abfd, NLM_CODE_NAME);
631   data_sec = bfd_get_section_by_name (abfd, NLM_INITIALIZED_DATA_NAME);
632   bss_sec = bfd_get_section_by_name (abfd, NLM_UNINITIALIZED_DATA_NAME);
633
634   sym = *rel->sym_ptr_ptr;
635   symsec = bfd_get_section (sym);
636   if (indx != -1)
637     {
638       BFD_ASSERT (symsec == &bfd_und_section);
639       l_symndx = indx + 3;
640     }
641   else
642     {
643       if (symsec == code_sec)
644         l_symndx = 0;
645       else if (symsec == data_sec)
646         l_symndx = 1;
647       else if (symsec == bss_sec)
648         l_symndx = 2;
649       else
650         {
651           bfd_set_error (bfd_error_bad_value);
652           return false;
653         }
654     }
655
656   bfd_h_put_32 (abfd, (bfd_vma) l_symndx, ext.l_symndx);
657
658   for (howto = nlm_powerpc_howto_table;
659        howto < nlm_powerpc_howto_table + HOWTO_COUNT;
660        howto++)
661     {
662       if (howto->rightshift == rel->howto->rightshift
663           && howto->size == rel->howto->size
664           && howto->bitsize == rel->howto->bitsize
665           && howto->pc_relative == rel->howto->pc_relative
666           && howto->bitpos == rel->howto->bitpos
667           && (howto->partial_inplace == rel->howto->partial_inplace
668               || (! rel->howto->partial_inplace
669                   && rel->addend == 0))
670           && (howto->src_mask == rel->howto->src_mask
671               || (rel->howto->src_mask == 0
672                   && rel->addend == 0))
673           && howto->dst_mask == rel->howto->dst_mask
674           && howto->pcrel_offset == rel->howto->pcrel_offset)
675         break;
676     }
677   if (howto >= nlm_powerpc_howto_table + HOWTO_COUNT)
678     {
679       bfd_set_error (bfd_error_bad_value);
680       return false;
681     }
682
683   l_rtype = howto->type;
684   if (howto->complain_on_overflow == complain_overflow_signed)
685     l_rtype |= 0x8000;
686   l_rtype |= (howto->bitsize - 1) << 8;
687   bfd_h_put_16 (abfd, (bfd_vma) l_rtype, ext.l_rtype);
688
689   address = rel->address;
690
691   if (sec == code_sec)
692     l_rsecnm = 0;
693   else if (sec == data_sec)
694     {
695       l_rsecnm = 1;
696       address += bfd_section_size (abfd, code_sec);
697     }
698   else
699     {
700       bfd_set_error (bfd_error_bad_value);
701       return false;
702     }
703
704   bfd_h_put_16 (abfd, (bfd_vma) l_rsecnm, ext.l_rsecnm);
705   bfd_h_put_32 (abfd, (bfd_vma) address, ext.l_vaddr);
706
707   if (bfd_write (&ext, sizeof ext, 1, abfd) != sizeof ext)
708     return false;
709
710   return true;
711 }
712
713 /* Write a PowerPC NLM import.  */
714
715 static boolean
716 nlm_powerpc_write_import (abfd, sec, rel)
717      bfd *abfd;
718      asection *sec;
719      arelent *rel;
720 {
721   return nlm_powerpc_write_reloc (abfd, sec, rel, -1);
722 }
723
724 /* Write a PowerPC NLM external symbol.  This routine keeps a static
725    count of the symbol index.  FIXME: I don't know if this is
726    necessary, and the index never gets reset.  */
727
728 static boolean
729 nlm_powerpc_write_external (abfd, count, sym, relocs)
730      bfd *abfd;
731      bfd_size_type count;
732      asymbol *sym;
733      struct reloc_and_sec *relocs;
734 {
735   int i;
736   bfd_byte len;
737   unsigned char temp[NLM_TARGET_LONG_SIZE];
738   static int indx;
739
740   len = strlen (sym->name);
741   if ((bfd_write (&len, sizeof (bfd_byte), 1, abfd) != sizeof(bfd_byte))
742       || bfd_write (sym->name, len, 1, abfd) != len)
743     {
744       bfd_set_error (bfd_error_system_call);
745       return false;
746     }
747
748   bfd_put_32 (abfd, count, temp);
749   if (bfd_write (temp, sizeof(temp), 1, abfd) != sizeof (temp))
750     {
751       bfd_set_error (bfd_error_system_call);
752       return false;
753     }
754
755   for (i = 0; i < count; i++)
756     {
757       if (nlm_powerpc_write_reloc (abfd, relocs[i].sec,
758                                    relocs[i].rel, indx) == false)
759         return false;
760     }
761
762   ++indx;
763
764   return true;
765 }
766
767 #include "nlmswap.h"
768
769 static const struct nlm_backend_data nlm32_powerpc_backend =
770 {
771   "NetWare PowerPC Module \032",
772   sizeof (Nlm32_powerpc_External_Fixed_Header),
773   sizeof (struct nlm32_powerpc_external_prefix_header),
774   bfd_arch_powerpc,
775   0,
776   false,
777   nlm_powerpc_backend_object_p,
778   nlm_powerpc_write_prefix,
779   nlm_powerpc_read_reloc,
780   nlm_powerpc_mangle_relocs,
781   nlm_powerpc_read_import,
782   nlm_powerpc_write_import,
783   0,    /* set_public_section */
784   0,    /* get_public_offset */
785   nlm_swap_fixed_header_in,
786   nlm_swap_fixed_header_out,
787   nlm_powerpc_write_external,
788   0,    /* write_export */
789 };
790
791 #define TARGET_BIG_NAME                 "nlm32-powerpc"
792 #define TARGET_BIG_SYM                  nlmNAME(powerpc_vec)
793 #define TARGET_BACKEND_DATA             &nlm32_powerpc_backend
794
795 #include "nlm-target.h"