2001-02-09 Bo Thorsen <bo@suse.de>
[binutils.git] / bfd / nlm32-ppc.c
blob4eae8d08c059324a58de8415d70d6fe3f8d29dea
1 /* Support for 32-bit PowerPC NLM (NetWare Loadable Module)
2 Copyright (C) 1994, 1995, 1999 Free Software Foundation, Inc.
4 This file is part of BFD, the Binary File Descriptor library.
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.
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.
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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
20 #include "bfd.h"
21 #include "sysdep.h"
22 #include "libbfd.h"
24 /* The format of a PowerPC NLM changed. Define OLDFORMAT to get the
25 old format. */
27 #define ARCH_SIZE 32
29 #include "nlm/ppc-ext.h"
30 #define Nlm_External_Fixed_Header Nlm32_powerpc_External_Fixed_Header
32 #include "libnlm.h"
34 #ifdef OLDFORMAT
35 static boolean nlm_powerpc_backend_object_p
36 PARAMS ((bfd *));
37 static boolean nlm_powerpc_write_prefix
38 PARAMS ((bfd *));
39 #endif
41 static boolean nlm_powerpc_read_reloc
42 PARAMS ((bfd *, nlmNAME(symbol_type) *, asection **, arelent *));
43 static boolean nlm_powerpc_mangle_relocs
44 PARAMS ((bfd *, asection *, PTR, bfd_vma, bfd_size_type));
45 static boolean nlm_powerpc_read_import
46 PARAMS ((bfd *, nlmNAME(symbol_type) *));
48 #ifdef OLDFORMAT
49 static boolean nlm_powerpc_write_reloc
50 PARAMS ((bfd *, asection *, arelent *, int));
51 #endif
53 static boolean nlm_powerpc_write_import
54 PARAMS ((bfd *, asection *, arelent *));
55 static boolean nlm_powerpc_write_external
56 PARAMS ((bfd *, bfd_size_type, asymbol *, struct reloc_and_sec *));
58 #ifndef OLDFORMAT
59 static boolean nlm_powerpc_set_public_section
60 PARAMS ((bfd *, nlmNAME(symbol_type) *));
61 static bfd_vma nlm_powerpc_get_public_offset
62 PARAMS ((bfd *, asymbol *));
63 #endif
65 #ifdef OLDFORMAT
67 /* The prefix header is only used in the old format. */
69 /* PowerPC NLM's have a prefix header before the standard NLM. This
70 function reads it in, verifies the version, and seeks the bfd to
71 the location before the regular NLM header. */
73 static boolean
74 nlm_powerpc_backend_object_p (abfd)
75 bfd *abfd;
77 struct nlm32_powerpc_external_prefix_header s;
79 if (bfd_read ((PTR) &s, sizeof s, 1, abfd) != sizeof s)
80 return false;
82 if (memcmp (s.signature, NLM32_POWERPC_SIGNATURE, sizeof s.signature) != 0
83 || bfd_h_get_32 (abfd, s.headerVersion) != NLM32_POWERPC_HEADER_VERSION)
84 return false;
86 return true;
89 /* Write out the prefix. */
91 static boolean
92 nlm_powerpc_write_prefix (abfd)
93 bfd *abfd;
95 struct nlm32_powerpc_external_prefix_header s;
97 memset (&s, 0, sizeof s);
98 memcpy (s.signature, NLM32_POWERPC_SIGNATURE, sizeof s.signature);
99 bfd_h_put_32 (abfd, (bfd_vma) NLM32_POWERPC_HEADER_VERSION, s.headerVersion);
100 bfd_h_put_32 (abfd, (bfd_vma) 0, s.origins);
102 /* FIXME: What should we do about the date? */
104 if (bfd_write ((PTR) &s, sizeof s, 1, abfd) != sizeof s)
105 return false;
107 return true;
110 #endif /* OLDFORMAT */
112 #ifndef OLDFORMAT
114 /* There is only one type of reloc in a PowerPC NLM. */
116 static reloc_howto_type nlm_powerpc_howto =
117 HOWTO (0, /* type */
118 0, /* rightshift */
119 2, /* size (0 = byte, 1 = short, 2 = long) */
120 32, /* bitsize */
121 false, /* pc_relative */
122 0, /* bitpos */
123 complain_overflow_bitfield, /* complain_on_overflow */
124 0, /* special_function */
125 "32", /* name */
126 true, /* partial_inplace */
127 0xffffffff, /* src_mask */
128 0xffffffff, /* dst_mask */
129 false); /* pcrel_offset */
131 /* Read a PowerPC NLM reloc. */
133 static boolean
134 nlm_powerpc_read_reloc (abfd, sym, secp, rel)
135 bfd *abfd;
136 nlmNAME(symbol_type) *sym;
137 asection **secp;
138 arelent *rel;
140 bfd_byte temp[4];
141 bfd_vma val;
142 const char *name;
144 if (bfd_read (temp, sizeof (temp), 1, abfd) != sizeof (temp))
145 return false;
147 val = bfd_get_32 (abfd, temp);
149 /* The value is a word offset into either the code or data segment.
150 This is the location which needs to be adjusted.
152 The high bit is 0 if the value is an offset into the data
153 segment, or 1 if the value is an offset into the text segment.
155 If this is a relocation fixup rather than an imported symbol (the
156 sym argument is NULL), then the second most significant bit is 0
157 if the address of the data segment should be added to the
158 location addressed by the value, or 1 if the address of the text
159 segment should be added.
161 If this is an imported symbol, the second most significant bit is
162 not used and must be 0. */
164 if ((val & NLM_HIBIT) == 0)
165 name = NLM_INITIALIZED_DATA_NAME;
166 else
168 name = NLM_CODE_NAME;
169 val &=~ NLM_HIBIT;
171 *secp = bfd_get_section_by_name (abfd, name);
173 if (sym == NULL)
175 if ((val & (NLM_HIBIT >> 1)) == 0)
176 name = NLM_INITIALIZED_DATA_NAME;
177 else
179 name = NLM_CODE_NAME;
180 val &=~ (NLM_HIBIT >> 1);
182 rel->sym_ptr_ptr = bfd_get_section_by_name (abfd, name)->symbol_ptr_ptr;
185 rel->howto = &nlm_powerpc_howto;
187 rel->address = val << 2;
188 rel->addend = 0;
190 return true;
193 #else /* OLDFORMAT */
195 /* This reloc handling is only applicable to the old format. */
197 /* How to process the various reloc types. PowerPC NLMs use XCOFF
198 reloc types, and I have just copied the XCOFF reloc table here. */
200 static reloc_howto_type nlm_powerpc_howto_table[] =
202 /* Standard 32 bit relocation. */
203 HOWTO (0, /* type */
204 0, /* rightshift */
205 2, /* size (0 = byte, 1 = short, 2 = long) */
206 32, /* bitsize */
207 false, /* pc_relative */
208 0, /* bitpos */
209 complain_overflow_bitfield, /* complain_on_overflow */
210 0, /* special_function */
211 "R_POS", /* name */
212 true, /* partial_inplace */
213 0xffffffff, /* src_mask */
214 0xffffffff, /* dst_mask */
215 false), /* pcrel_offset */
217 /* 32 bit relocation, but store negative value. */
218 HOWTO (1, /* type */
219 0, /* rightshift */
220 -2, /* size (0 = byte, 1 = short, 2 = long) */
221 32, /* bitsize */
222 false, /* pc_relative */
223 0, /* bitpos */
224 complain_overflow_bitfield, /* complain_on_overflow */
225 0, /* special_function */
226 "R_NEG", /* name */
227 true, /* partial_inplace */
228 0xffffffff, /* src_mask */
229 0xffffffff, /* dst_mask */
230 false), /* pcrel_offset */
232 /* 32 bit PC relative relocation. */
233 HOWTO (2, /* type */
234 0, /* rightshift */
235 2, /* size (0 = byte, 1 = short, 2 = long) */
236 32, /* bitsize */
237 true, /* pc_relative */
238 0, /* bitpos */
239 complain_overflow_signed, /* complain_on_overflow */
240 0, /* special_function */
241 "R_REL", /* name */
242 true, /* partial_inplace */
243 0xffffffff, /* src_mask */
244 0xffffffff, /* dst_mask */
245 false), /* pcrel_offset */
247 /* 16 bit TOC relative relocation. */
248 HOWTO (3, /* type */
249 0, /* rightshift */
250 1, /* size (0 = byte, 1 = short, 2 = long) */
251 16, /* bitsize */
252 false, /* pc_relative */
253 0, /* bitpos */
254 complain_overflow_signed, /* complain_on_overflow */
255 0, /* special_function */
256 "R_TOC", /* name */
257 true, /* partial_inplace */
258 0xffff, /* src_mask */
259 0xffff, /* dst_mask */
260 false), /* pcrel_offset */
262 /* I don't really know what this is. */
263 HOWTO (4, /* type */
264 1, /* rightshift */
265 2, /* size (0 = byte, 1 = short, 2 = long) */
266 32, /* bitsize */
267 false, /* pc_relative */
268 0, /* bitpos */
269 complain_overflow_bitfield, /* complain_on_overflow */
270 0, /* special_function */
271 "R_RTB", /* name */
272 true, /* partial_inplace */
273 0xffffffff, /* src_mask */
274 0xffffffff, /* dst_mask */
275 false), /* pcrel_offset */
277 /* External TOC relative symbol. */
278 HOWTO (5, /* type */
279 0, /* rightshift */
280 2, /* size (0 = byte, 1 = short, 2 = long) */
281 16, /* bitsize */
282 false, /* pc_relative */
283 0, /* bitpos */
284 complain_overflow_bitfield, /* complain_on_overflow */
285 0, /* special_function */
286 "R_GL", /* name */
287 true, /* partial_inplace */
288 0xffff, /* src_mask */
289 0xffff, /* dst_mask */
290 false), /* pcrel_offset */
292 /* Local TOC relative symbol. */
293 HOWTO (6, /* type */
294 0, /* rightshift */
295 2, /* size (0 = byte, 1 = short, 2 = long) */
296 16, /* bitsize */
297 false, /* pc_relative */
298 0, /* bitpos */
299 complain_overflow_bitfield, /* complain_on_overflow */
300 0, /* special_function */
301 "R_TCL", /* name */
302 true, /* partial_inplace */
303 0xffff, /* src_mask */
304 0xffff, /* dst_mask */
305 false), /* pcrel_offset */
307 { 7 },
309 /* Non modifiable absolute branch. */
310 HOWTO (8, /* type */
311 0, /* rightshift */
312 2, /* size (0 = byte, 1 = short, 2 = long) */
313 26, /* bitsize */
314 false, /* pc_relative */
315 0, /* bitpos */
316 complain_overflow_bitfield, /* complain_on_overflow */
317 0, /* special_function */
318 "R_BA", /* name */
319 true, /* partial_inplace */
320 0x3fffffc, /* src_mask */
321 0x3fffffc, /* dst_mask */
322 false), /* pcrel_offset */
324 { 9 },
326 /* Non modifiable relative branch. */
327 HOWTO (0xa, /* type */
328 0, /* rightshift */
329 2, /* size (0 = byte, 1 = short, 2 = long) */
330 26, /* bitsize */
331 true, /* pc_relative */
332 0, /* bitpos */
333 complain_overflow_signed, /* complain_on_overflow */
334 0, /* special_function */
335 "R_BR", /* name */
336 true, /* partial_inplace */
337 0x3fffffc, /* src_mask */
338 0x3fffffc, /* dst_mask */
339 false), /* pcrel_offset */
341 { 0xb },
343 /* Indirect load. */
344 HOWTO (0xc, /* type */
345 0, /* rightshift */
346 2, /* size (0 = byte, 1 = short, 2 = long) */
347 16, /* bitsize */
348 false, /* pc_relative */
349 0, /* bitpos */
350 complain_overflow_bitfield, /* complain_on_overflow */
351 0, /* special_function */
352 "R_RL", /* name */
353 true, /* partial_inplace */
354 0xffff, /* src_mask */
355 0xffff, /* dst_mask */
356 false), /* pcrel_offset */
358 /* Load address. */
359 HOWTO (0xd, /* type */
360 0, /* rightshift */
361 2, /* size (0 = byte, 1 = short, 2 = long) */
362 16, /* bitsize */
363 false, /* pc_relative */
364 0, /* bitpos */
365 complain_overflow_bitfield, /* complain_on_overflow */
366 0, /* special_function */
367 "R_RLA", /* name */
368 true, /* partial_inplace */
369 0xffff, /* src_mask */
370 0xffff, /* dst_mask */
371 false), /* pcrel_offset */
373 { 0xe },
375 /* Non-relocating reference. */
376 HOWTO (0xf, /* type */
377 0, /* rightshift */
378 2, /* size (0 = byte, 1 = short, 2 = long) */
379 32, /* bitsize */
380 false, /* pc_relative */
381 0, /* bitpos */
382 complain_overflow_bitfield, /* complain_on_overflow */
383 0, /* special_function */
384 "R_REF", /* name */
385 false, /* partial_inplace */
386 0, /* src_mask */
387 0, /* dst_mask */
388 false), /* pcrel_offset */
390 { 0x10 },
391 { 0x11 },
393 /* TOC relative indirect load. */
394 HOWTO (0x12, /* type */
395 0, /* rightshift */
396 2, /* size (0 = byte, 1 = short, 2 = long) */
397 16, /* bitsize */
398 false, /* pc_relative */
399 0, /* bitpos */
400 complain_overflow_bitfield, /* complain_on_overflow */
401 0, /* special_function */
402 "R_TRL", /* name */
403 true, /* partial_inplace */
404 0xffff, /* src_mask */
405 0xffff, /* dst_mask */
406 false), /* pcrel_offset */
408 /* TOC relative load address. */
409 HOWTO (0x13, /* type */
410 0, /* rightshift */
411 2, /* size (0 = byte, 1 = short, 2 = long) */
412 16, /* bitsize */
413 false, /* pc_relative */
414 0, /* bitpos */
415 complain_overflow_bitfield, /* complain_on_overflow */
416 0, /* special_function */
417 "R_TRLA", /* name */
418 true, /* partial_inplace */
419 0xffff, /* src_mask */
420 0xffff, /* dst_mask */
421 false), /* pcrel_offset */
423 /* Modifiable relative branch. */
424 HOWTO (0x14, /* type */
425 1, /* rightshift */
426 2, /* size (0 = byte, 1 = short, 2 = long) */
427 32, /* bitsize */
428 false, /* pc_relative */
429 0, /* bitpos */
430 complain_overflow_bitfield, /* complain_on_overflow */
431 0, /* special_function */
432 "R_RRTBI", /* name */
433 true, /* partial_inplace */
434 0xffffffff, /* src_mask */
435 0xffffffff, /* dst_mask */
436 false), /* pcrel_offset */
438 /* Modifiable absolute branch. */
439 HOWTO (0x15, /* type */
440 1, /* rightshift */
441 2, /* size (0 = byte, 1 = short, 2 = long) */
442 32, /* bitsize */
443 false, /* pc_relative */
444 0, /* bitpos */
445 complain_overflow_bitfield, /* complain_on_overflow */
446 0, /* special_function */
447 "R_RRTBA", /* name */
448 true, /* partial_inplace */
449 0xffffffff, /* src_mask */
450 0xffffffff, /* dst_mask */
451 false), /* pcrel_offset */
453 /* Modifiable call absolute indirect. */
454 HOWTO (0x16, /* type */
455 0, /* rightshift */
456 2, /* size (0 = byte, 1 = short, 2 = long) */
457 16, /* bitsize */
458 false, /* pc_relative */
459 0, /* bitpos */
460 complain_overflow_bitfield, /* complain_on_overflow */
461 0, /* special_function */
462 "R_CAI", /* name */
463 true, /* partial_inplace */
464 0xffff, /* src_mask */
465 0xffff, /* dst_mask */
466 false), /* pcrel_offset */
468 /* Modifiable call relative. */
469 HOWTO (0x17, /* type */
470 0, /* rightshift */
471 2, /* size (0 = byte, 1 = short, 2 = long) */
472 16, /* bitsize */
473 false, /* pc_relative */
474 0, /* bitpos */
475 complain_overflow_bitfield, /* complain_on_overflow */
476 0, /* special_function */
477 "R_REL", /* name */
478 true, /* partial_inplace */
479 0xffff, /* src_mask */
480 0xffff, /* dst_mask */
481 false), /* pcrel_offset */
483 /* Modifiable branch absolute. */
484 HOWTO (0x18, /* type */
485 0, /* rightshift */
486 2, /* size (0 = byte, 1 = short, 2 = long) */
487 16, /* bitsize */
488 false, /* pc_relative */
489 0, /* bitpos */
490 complain_overflow_bitfield, /* complain_on_overflow */
491 0, /* special_function */
492 "R_RBA", /* name */
493 true, /* partial_inplace */
494 0xffff, /* src_mask */
495 0xffff, /* dst_mask */
496 false), /* pcrel_offset */
498 /* Modifiable branch absolute. */
499 HOWTO (0x19, /* type */
500 0, /* rightshift */
501 2, /* size (0 = byte, 1 = short, 2 = long) */
502 16, /* bitsize */
503 false, /* pc_relative */
504 0, /* bitpos */
505 complain_overflow_bitfield, /* complain_on_overflow */
506 0, /* special_function */
507 "R_RBAC", /* name */
508 true, /* partial_inplace */
509 0xffff, /* src_mask */
510 0xffff, /* dst_mask */
511 false), /* pcrel_offset */
513 /* Modifiable branch relative. */
514 HOWTO (0x1a, /* type */
515 0, /* rightshift */
516 2, /* size (0 = byte, 1 = short, 2 = long) */
517 26, /* bitsize */
518 false, /* pc_relative */
519 0, /* bitpos */
520 complain_overflow_signed, /* complain_on_overflow */
521 0, /* special_function */
522 "R_REL", /* name */
523 true, /* partial_inplace */
524 0xffff, /* src_mask */
525 0xffff, /* dst_mask */
526 false), /* pcrel_offset */
528 /* Modifiable branch absolute. */
529 HOWTO (0x1b, /* type */
530 0, /* rightshift */
531 2, /* size (0 = byte, 1 = short, 2 = long) */
532 16, /* bitsize */
533 false, /* pc_relative */
534 0, /* bitpos */
535 complain_overflow_bitfield, /* complain_on_overflow */
536 0, /* special_function */
537 "R_REL", /* name */
538 true, /* partial_inplace */
539 0xffff, /* src_mask */
540 0xffff, /* dst_mask */
541 false) /* pcrel_offset */
544 #define HOWTO_COUNT (sizeof nlm_powerpc_howto_table \
545 / sizeof nlm_powerpc_howto_table[0])
547 /* Read a PowerPC NLM reloc. */
549 static boolean
550 nlm_powerpc_read_reloc (abfd, sym, secp, rel)
551 bfd *abfd;
552 nlmNAME(symbol_type) *sym;
553 asection **secp;
554 arelent *rel;
556 struct nlm32_powerpc_external_reloc ext;
557 bfd_vma l_vaddr;
558 unsigned long l_symndx;
559 int l_rtype;
560 int l_rsecnm;
561 asection *code_sec, *data_sec, *bss_sec;
563 /* Read the reloc from the file. */
564 if (bfd_read (&ext, sizeof ext, 1, abfd) != sizeof ext)
565 return false;
567 /* Swap in the fields. */
568 l_vaddr = bfd_h_get_32 (abfd, ext.l_vaddr);
569 l_symndx = bfd_h_get_32 (abfd, ext.l_symndx);
570 l_rtype = bfd_h_get_16 (abfd, ext.l_rtype);
571 l_rsecnm = bfd_h_get_16 (abfd, ext.l_rsecnm);
573 /* Get the sections now, for convenience. */
574 code_sec = bfd_get_section_by_name (abfd, NLM_CODE_NAME);
575 data_sec = bfd_get_section_by_name (abfd, NLM_INITIALIZED_DATA_NAME);
576 bss_sec = bfd_get_section_by_name (abfd, NLM_UNINITIALIZED_DATA_NAME);
578 /* Work out the arelent fields. */
579 if (sym != NULL)
581 /* This is an import. sym_ptr_ptr is filled in by
582 nlm_canonicalize_reloc. */
583 rel->sym_ptr_ptr = NULL;
585 else
587 asection *sec;
589 if (l_symndx == 0)
590 sec = code_sec;
591 else if (l_symndx == 1)
592 sec = data_sec;
593 else if (l_symndx == 2)
594 sec = bss_sec;
595 else
597 bfd_set_error (bfd_error_bad_value);
598 return false;
601 rel->sym_ptr_ptr = sec->symbol_ptr_ptr;
604 rel->addend = 0;
606 BFD_ASSERT ((l_rtype & 0xff) < HOWTO_COUNT);
608 rel->howto = nlm_powerpc_howto_table + (l_rtype & 0xff);
610 BFD_ASSERT (rel->howto->name != NULL
611 && ((l_rtype & 0x8000) != 0
612 ? (rel->howto->complain_on_overflow
613 == complain_overflow_signed)
614 : (rel->howto->complain_on_overflow
615 == complain_overflow_bitfield))
616 && ((l_rtype >> 8) & 0x1f) == rel->howto->bitsize - 1);
618 if (l_rsecnm == 0)
619 *secp = code_sec;
620 else if (l_rsecnm == 1)
622 *secp = data_sec;
623 l_vaddr -= bfd_section_size (abfd, code_sec);
625 else
627 bfd_set_error (bfd_error_bad_value);
628 return false;
631 rel->address = l_vaddr;
633 return true;
636 #endif /* OLDFORMAT */
638 /* Mangle PowerPC NLM relocs for output. */
640 static boolean
641 nlm_powerpc_mangle_relocs (abfd, sec, data, offset, count)
642 bfd *abfd ATTRIBUTE_UNUSED;
643 asection *sec ATTRIBUTE_UNUSED;
644 PTR data ATTRIBUTE_UNUSED;
645 bfd_vma offset ATTRIBUTE_UNUSED;
646 bfd_size_type count ATTRIBUTE_UNUSED;
648 return true;
651 /* Read a PowerPC NLM import record */
653 static boolean
654 nlm_powerpc_read_import (abfd, sym)
655 bfd *abfd;
656 nlmNAME(symbol_type) *sym;
658 struct nlm_relent *nlm_relocs; /* relocation records for symbol */
659 bfd_size_type rcount; /* number of relocs */
660 bfd_byte temp[NLM_TARGET_LONG_SIZE]; /* temporary 32-bit value */
661 unsigned char symlength; /* length of symbol name */
662 char *name;
664 if (bfd_read ((PTR) &symlength, sizeof (symlength), 1, abfd)
665 != sizeof (symlength))
666 return (false);
667 sym -> symbol.the_bfd = abfd;
668 name = bfd_alloc (abfd, symlength + 1);
669 if (name == NULL)
670 return false;
671 if (bfd_read (name, symlength, 1, abfd) != symlength)
672 return (false);
673 name[symlength] = '\0';
674 sym -> symbol.name = name;
675 sym -> symbol.flags = 0;
676 sym -> symbol.value = 0;
677 sym -> symbol.section = bfd_und_section_ptr;
678 if (bfd_read ((PTR) temp, sizeof (temp), 1, abfd) != sizeof (temp))
679 return (false);
680 rcount = bfd_h_get_32 (abfd, temp);
681 nlm_relocs = ((struct nlm_relent *)
682 bfd_alloc (abfd, rcount * sizeof (struct nlm_relent)));
683 if (nlm_relocs == (struct nlm_relent *) NULL)
684 return false;
685 sym -> relocs = nlm_relocs;
686 sym -> rcnt = 0;
687 while (sym -> rcnt < rcount)
689 asection *section;
691 if (nlm_powerpc_read_reloc (abfd, sym, &section,
692 &nlm_relocs -> reloc)
693 == false)
694 return false;
695 nlm_relocs -> section = section;
696 nlm_relocs++;
697 sym -> rcnt++;
699 return true;
702 #ifndef OLDFORMAT
704 /* Write a PowerPC NLM reloc. */
706 static boolean
707 nlm_powerpc_write_import (abfd, sec, rel)
708 bfd *abfd;
709 asection *sec;
710 arelent *rel;
712 asymbol *sym;
713 bfd_vma val;
714 bfd_byte temp[4];
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)
727 bfd_set_error (bfd_error_invalid_operation);
728 return false;
731 sym = *rel->sym_ptr_ptr;
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)
740 bfd_set_error (bfd_error_bad_value);
741 return false;
743 val >>= 2;
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
751 val -= nlm_get_text_low (abfd);
752 val |= NLM_HIBIT;
755 if (! bfd_is_und_section (bfd_get_section (sym)))
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;
764 bfd_put_32 (abfd, val, temp);
765 if (bfd_write (temp, sizeof (temp), 1, abfd) != sizeof (temp))
766 return false;
768 return true;
771 #else /* OLDFORMAT */
773 /* This is used for the reloc handling in the old format. */
775 /* Write a PowerPC NLM reloc. */
777 static boolean
778 nlm_powerpc_write_reloc (abfd, sec, rel, indx)
779 bfd *abfd;
780 asection *sec;
781 arelent *rel;
782 int indx;
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;
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);
799 sym = *rel->sym_ptr_ptr;
800 symsec = bfd_get_section (sym);
801 if (indx != -1)
803 BFD_ASSERT (bfd_is_und_section (symsec));
804 l_symndx = indx + 3;
806 else
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
816 bfd_set_error (bfd_error_bad_value);
817 return false;
821 bfd_h_put_32 (abfd, (bfd_vma) l_symndx, ext.l_symndx);
823 for (howto = nlm_powerpc_howto_table;
824 howto < nlm_powerpc_howto_table + HOWTO_COUNT;
825 howto++)
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;
842 if (howto >= nlm_powerpc_howto_table + HOWTO_COUNT)
844 bfd_set_error (bfd_error_bad_value);
845 return false;
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 bfd_h_put_16 (abfd, (bfd_vma) l_rtype, ext.l_rtype);
854 address = rel->address;
856 if (sec == code_sec)
857 l_rsecnm = 0;
858 else if (sec == data_sec)
860 l_rsecnm = 1;
861 address += bfd_section_size (abfd, code_sec);
863 else
865 bfd_set_error (bfd_error_bad_value);
866 return false;
869 bfd_h_put_16 (abfd, (bfd_vma) l_rsecnm, ext.l_rsecnm);
870 bfd_h_put_32 (abfd, (bfd_vma) address, ext.l_vaddr);
872 if (bfd_write (&ext, sizeof ext, 1, abfd) != sizeof ext)
873 return false;
875 return true;
878 /* Write a PowerPC NLM import. */
880 static boolean
881 nlm_powerpc_write_import (abfd, sec, rel)
882 bfd *abfd;
883 asection *sec;
884 arelent *rel;
886 return nlm_powerpc_write_reloc (abfd, sec, rel, -1);
889 #endif /* OLDFORMAT */
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. */
895 static boolean
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;
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
909 len = strlen (sym->name);
910 if ((bfd_write (&len, sizeof (bfd_byte), 1, abfd) != sizeof (bfd_byte))
911 || bfd_write (sym->name, len, 1, abfd) != len)
912 return false;
914 bfd_put_32 (abfd, count, temp);
915 if (bfd_write (temp, sizeof (temp), 1, abfd) != sizeof (temp))
916 return false;
918 for (i = 0; i < count; i++)
920 #ifndef OLDFORMAT
921 if (! nlm_powerpc_write_import (abfd, relocs[i].sec, relocs[i].rel))
922 return false;
923 #else
924 if (! nlm_powerpc_write_reloc (abfd, relocs[i].sec,
925 relocs[i].rel, indx))
926 return false;
927 #endif
930 #ifdef OLDFORMAT
931 ++indx;
932 #endif
934 return true;
937 #ifndef OLDFORMAT
939 /* PowerPC Netware uses a word offset, not a byte offset, for public
940 symbols. */
942 /* Set the section for a public symbol. */
944 static boolean
945 nlm_powerpc_set_public_section (abfd, sym)
946 bfd *abfd;
947 nlmNAME(symbol_type) *sym;
949 if (sym->symbol.value & NLM_HIBIT)
951 sym->symbol.value &= ~NLM_HIBIT;
952 sym->symbol.flags |= BSF_FUNCTION;
953 sym->symbol.section =
954 bfd_get_section_by_name (abfd, NLM_CODE_NAME);
956 else
958 sym->symbol.section =
959 bfd_get_section_by_name (abfd, NLM_INITIALIZED_DATA_NAME);
962 sym->symbol.value <<= 2;
964 return true;
967 /* Get the offset to write out for a public symbol. */
969 static bfd_vma
970 nlm_powerpc_get_public_offset (abfd, sym)
971 bfd *abfd;
972 asymbol *sym;
974 bfd_vma offset;
975 asection *sec;
977 offset = bfd_asymbol_value (sym);
978 sec = bfd_get_section (sym);
979 if (sec->flags & SEC_CODE)
981 offset -= nlm_get_text_low (abfd);
982 offset |= NLM_HIBIT;
984 else if (sec->flags & (SEC_DATA | SEC_ALLOC))
986 /* SEC_ALLOC is for the .bss section. */
987 offset -= nlm_get_data_low (abfd);
989 else
991 /* We can't handle an exported symbol that is not in the code or
992 data segment. */
993 bfd_set_error (bfd_error_invalid_operation);
994 /* FIXME: No way to return error. */
995 abort ();
998 return offset;
1001 #endif /* ! defined (OLDFORMAT) */
1003 #include "nlmswap.h"
1005 static const struct nlm_backend_data nlm32_powerpc_backend =
1007 "NetWare PowerPC Module \032",
1008 sizeof (Nlm32_powerpc_External_Fixed_Header),
1009 #ifndef OLDFORMAT
1010 0, /* optional_prefix_size */
1011 #else
1012 sizeof (struct nlm32_powerpc_external_prefix_header),
1013 #endif
1014 bfd_arch_powerpc,
1016 false,
1017 #ifndef OLDFORMAT
1018 0, /* backend_object_p */
1019 0, /* write_prefix */
1020 #else
1021 nlm_powerpc_backend_object_p,
1022 nlm_powerpc_write_prefix,
1023 #endif
1024 nlm_powerpc_read_reloc,
1025 nlm_powerpc_mangle_relocs,
1026 nlm_powerpc_read_import,
1027 nlm_powerpc_write_import,
1028 #ifndef OLDFORMAT
1029 nlm_powerpc_set_public_section,
1030 nlm_powerpc_get_public_offset,
1031 #else
1032 0, /* set_public_section */
1033 0, /* get_public_offset */
1034 #endif
1035 nlm_swap_fixed_header_in,
1036 nlm_swap_fixed_header_out,
1037 nlm_powerpc_write_external,
1038 0, /* write_export */
1041 #define TARGET_BIG_NAME "nlm32-powerpc"
1042 #define TARGET_BIG_SYM nlmNAME(powerpc_vec)
1043 #define TARGET_BACKEND_DATA &nlm32_powerpc_backend
1045 #include "nlm-target.h"