2004-04-21 Andrew Cagney <cagney@redhat.com>
[binutils.git] / bfd / nlm32-ppc.c
blobaafe2cc997152593af63c9f7c4f2c331164b932b
1 /* Support for 32-bit PowerPC NLM (NetWare Loadable Module)
2 Copyright 1994, 1995, 2000, 2001, 2002, 2003
3 Free Software Foundation, Inc.
5 This file is part of BFD, the Binary File Descriptor library.
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.
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.
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. */
21 #include "bfd.h"
22 #include "sysdep.h"
23 #include "libbfd.h"
25 /* The format of a PowerPC NLM changed. Define OLDFORMAT to get the
26 old format. */
28 #define ARCH_SIZE 32
30 #include "nlm/ppc-ext.h"
31 #define Nlm_External_Fixed_Header Nlm32_powerpc_External_Fixed_Header
33 #include "libnlm.h"
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
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) *));
49 #ifdef OLDFORMAT
50 static bfd_boolean nlm_powerpc_write_reloc
51 PARAMS ((bfd *, asection *, arelent *, int));
52 #endif
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 *));
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
66 #ifdef OLDFORMAT
68 /* The prefix header is only used in the old format. */
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. */
74 static bfd_boolean
75 nlm_powerpc_backend_object_p (abfd)
76 bfd *abfd;
78 struct nlm32_powerpc_external_prefix_header s;
80 if (bfd_bread ((PTR) &s, (bfd_size_type) sizeof s, abfd) != sizeof s)
81 return FALSE;
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;
87 return TRUE;
90 /* Write out the prefix. */
92 static bfd_boolean
93 nlm_powerpc_write_prefix (abfd)
94 bfd *abfd;
96 struct nlm32_powerpc_external_prefix_header s;
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);
103 /* FIXME: What should we do about the date? */
105 if (bfd_bwrite ((PTR) &s, (bfd_size_type) sizeof s, abfd) != sizeof s)
106 return FALSE;
108 return TRUE;
111 #endif /* OLDFORMAT */
113 #ifndef OLDFORMAT
115 /* There is only one type of reloc in a PowerPC NLM. */
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 */
132 /* Read a PowerPC NLM reloc. */
134 static bfd_boolean
135 nlm_powerpc_read_reloc (abfd, sym, secp, rel)
136 bfd *abfd;
137 nlmNAME(symbol_type) *sym;
138 asection **secp;
139 arelent *rel;
141 bfd_byte temp[4];
142 bfd_vma val;
143 const char *name;
145 if (bfd_bread (temp, (bfd_size_type) sizeof (temp), abfd) != sizeof (temp))
146 return FALSE;
148 val = bfd_get_32 (abfd, temp);
150 /* The value is a word offset into either the code or data segment.
151 This is the location which needs to be adjusted.
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.
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.
162 If this is an imported symbol, the second most significant bit is
163 not used and must be 0. */
165 if ((val & NLM_HIBIT) == 0)
166 name = NLM_INITIALIZED_DATA_NAME;
167 else
169 name = NLM_CODE_NAME;
170 val &=~ NLM_HIBIT;
172 *secp = bfd_get_section_by_name (abfd, name);
174 if (sym == NULL)
176 if ((val & (NLM_HIBIT >> 1)) == 0)
177 name = NLM_INITIALIZED_DATA_NAME;
178 else
180 name = NLM_CODE_NAME;
181 val &=~ (NLM_HIBIT >> 1);
183 rel->sym_ptr_ptr = bfd_get_section_by_name (abfd, name)->symbol_ptr_ptr;
186 rel->howto = &nlm_powerpc_howto;
188 rel->address = val << 2;
189 rel->addend = 0;
191 return TRUE;
194 #else /* OLDFORMAT */
196 /* This reloc handling is only applicable to the old format. */
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. */
201 static reloc_howto_type nlm_powerpc_howto_table[] =
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 */
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 */
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 */
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 */
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 */
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 */
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 */
308 { 7 },
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 */
325 { 9 },
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 */
342 { 0xb },
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 */
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 */
374 { 0xe },
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 */
391 { 0x10 },
392 { 0x11 },
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
545 #define HOWTO_COUNT (sizeof nlm_powerpc_howto_table \
546 / sizeof nlm_powerpc_howto_table[0])
548 /* Read a PowerPC NLM reloc. */
550 static bfd_boolean
551 nlm_powerpc_read_reloc (abfd, sym, secp, rel)
552 bfd *abfd;
553 nlmNAME(symbol_type) *sym;
554 asection **secp;
555 arelent *rel;
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;
564 /* Read the reloc from the file. */
565 if (bfd_bread (&ext, (bfd_size_type) sizeof ext, abfd) != sizeof ext)
566 return FALSE;
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);
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);
579 /* Work out the arelent fields. */
580 if (sym != NULL)
582 /* This is an import. sym_ptr_ptr is filled in by
583 nlm_canonicalize_reloc. */
584 rel->sym_ptr_ptr = NULL;
586 else
588 asection *sec;
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
598 bfd_set_error (bfd_error_bad_value);
599 return FALSE;
602 rel->sym_ptr_ptr = sec->symbol_ptr_ptr;
605 rel->addend = 0;
607 BFD_ASSERT ((l_rtype & 0xff) < HOWTO_COUNT);
609 rel->howto = nlm_powerpc_howto_table + (l_rtype & 0xff);
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);
619 if (l_rsecnm == 0)
620 *secp = code_sec;
621 else if (l_rsecnm == 1)
623 *secp = data_sec;
624 l_vaddr -= bfd_section_size (abfd, code_sec);
626 else
628 bfd_set_error (bfd_error_bad_value);
629 return FALSE;
632 rel->address = l_vaddr;
634 return TRUE;
637 #endif /* OLDFORMAT */
639 /* Mangle PowerPC NLM relocs for output. */
641 static bfd_boolean
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;
649 return TRUE;
652 /* Read a PowerPC NLM import record */
654 static bfd_boolean
655 nlm_powerpc_read_import (abfd, sym)
656 bfd *abfd;
657 nlmNAME(symbol_type) *sym;
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;
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)
691 asection *section;
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++;
699 return TRUE;
702 #ifndef OLDFORMAT
704 /* Write a PowerPC NLM reloc. */
706 static bfd_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_bwrite (temp, (bfd_size_type) sizeof (temp), 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 bfd_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 H_PUT_32 (abfd, 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 H_PUT_16 (abfd, 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 H_PUT_16 (abfd, l_rsecnm, ext.l_rsecnm);
870 H_PUT_32 (abfd, address, ext.l_vaddr);
872 if (bfd_bwrite (&ext, (bfd_size_type) sizeof ext, abfd) != sizeof ext)
873 return FALSE;
875 return TRUE;
878 /* Write a PowerPC NLM import. */
880 static bfd_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 bfd_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_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;
915 bfd_put_32 (abfd, count, temp);
916 if (bfd_bwrite (temp, (bfd_size_type) sizeof (temp), abfd) != sizeof (temp))
917 return FALSE;
919 for (i = 0; i < count; i++)
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
931 #ifdef OLDFORMAT
932 ++indx;
933 #endif
935 return TRUE;
938 #ifndef OLDFORMAT
940 /* PowerPC Netware uses a word offset, not a byte offset, for public
941 symbols. */
943 /* Set the section for a public symbol. */
945 static bfd_boolean
946 nlm_powerpc_set_public_section (abfd, sym)
947 bfd *abfd;
948 nlmNAME(symbol_type) *sym;
950 if (sym->symbol.value & NLM_HIBIT)
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);
957 else
959 sym->symbol.section =
960 bfd_get_section_by_name (abfd, NLM_INITIALIZED_DATA_NAME);
963 sym->symbol.value <<= 2;
965 return TRUE;
968 /* Get the offset to write out for a public symbol. */
970 static bfd_vma
971 nlm_powerpc_get_public_offset (abfd, sym)
972 bfd *abfd;
973 asymbol *sym;
975 bfd_vma offset;
976 asection *sec;
978 offset = bfd_asymbol_value (sym);
979 sec = bfd_get_section (sym);
980 if (sec->flags & SEC_CODE)
982 offset -= nlm_get_text_low (abfd);
983 offset |= NLM_HIBIT;
985 else if (sec->flags & (SEC_DATA | SEC_ALLOC))
987 /* SEC_ALLOC is for the .bss section. */
988 offset -= nlm_get_data_low (abfd);
990 else
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 ();
999 return offset;
1002 #endif /* ! defined (OLDFORMAT) */
1004 #include "nlmswap.h"
1006 static const struct nlm_backend_data nlm32_powerpc_backend =
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,
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 */
1042 #define TARGET_BIG_NAME "nlm32-powerpc"
1043 #define TARGET_BIG_SYM nlmNAME(powerpc_vec)
1044 #define TARGET_BACKEND_DATA &nlm32_powerpc_backend
1046 #include "nlm-target.h"