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