1 /* Support for 32-bit PowerPC NLM (NetWare Loadable Module)
2 Copyright (C) 1994 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., 675 Mass Ave, Cambridge, MA 02139, USA. */
26 #include "nlm/ppc-ext.h"
27 #define Nlm_External_Fixed_Header Nlm32_powerpc_External_Fixed_Header
31 static boolean nlm_powerpc_backend_object_p
33 static boolean nlm_powerpc_write_prefix
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 *));
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. */
53 nlm_powerpc_backend_object_p (abfd)
56 struct nlm32_powerpc_external_prefix_header s;
58 if (bfd_read ((PTR) &s, sizeof s, 1, abfd) != sizeof s)
61 if (memcmp (s.signature, NLM32_POWERPC_SIGNATURE, sizeof s.signature) != 0
62 || bfd_h_get_32 (abfd, s.headerVersion) != NLM32_POWERPC_HEADER_VERSION)
68 /* Write out the prefix. */
71 nlm_powerpc_write_prefix (abfd)
74 struct nlm32_powerpc_external_prefix_header s;
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);
81 /* FIXME: What should we do about the date? */
83 if (bfd_write ((PTR) &s, sizeof s, 1, abfd) != sizeof s)
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. */
92 static reloc_howto_type nlm_powerpc_howto_table[] =
94 /* Standard 32 bit relocation. */
97 2, /* size (0 = byte, 1 = short, 2 = long) */
99 false, /* pc_relative */
101 complain_overflow_bitfield, /* complain_on_overflow */
102 0, /* special_function */
104 true, /* partial_inplace */
105 0xffffffff, /* src_mask */
106 0xffffffff, /* dst_mask */
107 false), /* pcrel_offset */
109 /* 32 bit relocation, but store negative value. */
112 -2, /* size (0 = byte, 1 = short, 2 = long) */
114 false, /* pc_relative */
116 complain_overflow_bitfield, /* complain_on_overflow */
117 0, /* special_function */
119 true, /* partial_inplace */
120 0xffffffff, /* src_mask */
121 0xffffffff, /* dst_mask */
122 false), /* pcrel_offset */
124 /* 32 bit PC relative relocation. */
127 2, /* size (0 = byte, 1 = short, 2 = long) */
129 true, /* pc_relative */
131 complain_overflow_signed, /* complain_on_overflow */
132 0, /* special_function */
134 true, /* partial_inplace */
135 0xffffffff, /* src_mask */
136 0xffffffff, /* dst_mask */
137 false), /* pcrel_offset */
139 /* 16 bit TOC relative relocation. */
142 1, /* size (0 = byte, 1 = short, 2 = long) */
144 false, /* pc_relative */
146 complain_overflow_signed, /* complain_on_overflow */
147 0, /* special_function */
149 true, /* partial_inplace */
150 0xffff, /* src_mask */
151 0xffff, /* dst_mask */
152 false), /* pcrel_offset */
154 /* I don't really know what this is. */
157 2, /* size (0 = byte, 1 = short, 2 = long) */
159 false, /* pc_relative */
161 complain_overflow_bitfield, /* complain_on_overflow */
162 0, /* special_function */
164 true, /* partial_inplace */
165 0xffffffff, /* src_mask */
166 0xffffffff, /* dst_mask */
167 false), /* pcrel_offset */
169 /* External TOC relative symbol. */
172 2, /* size (0 = byte, 1 = short, 2 = long) */
174 false, /* pc_relative */
176 complain_overflow_bitfield, /* complain_on_overflow */
177 0, /* special_function */
179 true, /* partial_inplace */
180 0xffff, /* src_mask */
181 0xffff, /* dst_mask */
182 false), /* pcrel_offset */
184 /* Local TOC relative symbol. */
187 2, /* size (0 = byte, 1 = short, 2 = long) */
189 false, /* pc_relative */
191 complain_overflow_bitfield, /* complain_on_overflow */
192 0, /* special_function */
194 true, /* partial_inplace */
195 0xffff, /* src_mask */
196 0xffff, /* dst_mask */
197 false), /* pcrel_offset */
201 /* Non modifiable absolute branch. */
204 2, /* size (0 = byte, 1 = short, 2 = long) */
206 false, /* pc_relative */
208 complain_overflow_bitfield, /* complain_on_overflow */
209 0, /* special_function */
211 true, /* partial_inplace */
212 0x3fffffc, /* src_mask */
213 0x3fffffc, /* dst_mask */
214 false), /* pcrel_offset */
218 /* Non modifiable relative branch. */
219 HOWTO (0xa, /* type */
221 2, /* size (0 = byte, 1 = short, 2 = long) */
223 true, /* pc_relative */
225 complain_overflow_signed, /* complain_on_overflow */
226 0, /* special_function */
228 true, /* partial_inplace */
229 0x3fffffc, /* src_mask */
230 0x3fffffc, /* dst_mask */
231 false), /* pcrel_offset */
236 HOWTO (0xc, /* type */
238 2, /* size (0 = byte, 1 = short, 2 = long) */
240 false, /* pc_relative */
242 complain_overflow_bitfield, /* complain_on_overflow */
243 0, /* special_function */
245 true, /* partial_inplace */
246 0xffff, /* src_mask */
247 0xffff, /* dst_mask */
248 false), /* pcrel_offset */
251 HOWTO (0xd, /* type */
253 2, /* size (0 = byte, 1 = short, 2 = long) */
255 false, /* pc_relative */
257 complain_overflow_bitfield, /* complain_on_overflow */
258 0, /* special_function */
260 true, /* partial_inplace */
261 0xffff, /* src_mask */
262 0xffff, /* dst_mask */
263 false), /* pcrel_offset */
267 /* Non-relocating reference. */
268 HOWTO (0xf, /* type */
270 2, /* size (0 = byte, 1 = short, 2 = long) */
272 false, /* pc_relative */
274 complain_overflow_bitfield, /* complain_on_overflow */
275 0, /* special_function */
277 false, /* partial_inplace */
280 false), /* pcrel_offset */
285 /* TOC relative indirect load. */
286 HOWTO (0x12, /* type */
288 2, /* size (0 = byte, 1 = short, 2 = long) */
290 false, /* pc_relative */
292 complain_overflow_bitfield, /* complain_on_overflow */
293 0, /* special_function */
295 true, /* partial_inplace */
296 0xffff, /* src_mask */
297 0xffff, /* dst_mask */
298 false), /* pcrel_offset */
300 /* TOC relative load address. */
301 HOWTO (0x13, /* type */
303 2, /* size (0 = byte, 1 = short, 2 = long) */
305 false, /* pc_relative */
307 complain_overflow_bitfield, /* complain_on_overflow */
308 0, /* special_function */
310 true, /* partial_inplace */
311 0xffff, /* src_mask */
312 0xffff, /* dst_mask */
313 false), /* pcrel_offset */
315 /* Modifiable relative branch. */
316 HOWTO (0x14, /* type */
318 2, /* size (0 = byte, 1 = short, 2 = long) */
320 false, /* pc_relative */
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 */
330 /* Modifiable absolute branch. */
331 HOWTO (0x15, /* type */
333 2, /* size (0 = byte, 1 = short, 2 = long) */
335 false, /* pc_relative */
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 */
345 /* Modifiable call absolute indirect. */
346 HOWTO (0x16, /* type */
348 2, /* size (0 = byte, 1 = short, 2 = long) */
350 false, /* pc_relative */
352 complain_overflow_bitfield, /* complain_on_overflow */
353 0, /* special_function */
355 true, /* partial_inplace */
356 0xffff, /* src_mask */
357 0xffff, /* dst_mask */
358 false), /* pcrel_offset */
360 /* Modifiable call relative. */
361 HOWTO (0x17, /* type */
363 2, /* size (0 = byte, 1 = short, 2 = long) */
365 false, /* pc_relative */
367 complain_overflow_bitfield, /* complain_on_overflow */
368 0, /* special_function */
370 true, /* partial_inplace */
371 0xffff, /* src_mask */
372 0xffff, /* dst_mask */
373 false), /* pcrel_offset */
375 /* Modifiable branch absolute. */
376 HOWTO (0x18, /* type */
378 2, /* size (0 = byte, 1 = short, 2 = long) */
380 false, /* pc_relative */
382 complain_overflow_bitfield, /* complain_on_overflow */
383 0, /* special_function */
385 true, /* partial_inplace */
386 0xffff, /* src_mask */
387 0xffff, /* dst_mask */
388 false), /* pcrel_offset */
390 /* Modifiable branch absolute. */
391 HOWTO (0x19, /* type */
393 2, /* size (0 = byte, 1 = short, 2 = long) */
395 false, /* pc_relative */
397 complain_overflow_bitfield, /* complain_on_overflow */
398 0, /* special_function */
400 true, /* partial_inplace */
401 0xffff, /* src_mask */
402 0xffff, /* dst_mask */
403 false), /* pcrel_offset */
405 /* Modifiable branch relative. */
406 HOWTO (0x1a, /* type */
408 2, /* size (0 = byte, 1 = short, 2 = long) */
410 false, /* pc_relative */
412 complain_overflow_signed, /* complain_on_overflow */
413 0, /* special_function */
415 true, /* partial_inplace */
416 0xffff, /* src_mask */
417 0xffff, /* dst_mask */
418 false), /* pcrel_offset */
420 /* Modifiable branch absolute. */
421 HOWTO (0x1b, /* type */
423 2, /* size (0 = byte, 1 = short, 2 = long) */
425 false, /* pc_relative */
427 complain_overflow_bitfield, /* complain_on_overflow */
428 0, /* special_function */
430 true, /* partial_inplace */
431 0xffff, /* src_mask */
432 0xffff, /* dst_mask */
433 false) /* pcrel_offset */
436 #define HOWTO_COUNT (sizeof nlm_powerpc_howto_table \
437 / sizeof nlm_powerpc_howto_table[0])
439 /* Read a PowerPC NLM reloc. */
442 nlm_powerpc_read_reloc (abfd, sym, secp, rel)
444 nlmNAME(symbol_type) *sym;
448 struct nlm32_powerpc_external_reloc ext;
450 unsigned long l_symndx;
453 asection *code_sec, *data_sec, *bss_sec;
455 /* Read the reloc from the file. */
456 if (bfd_read (&ext, sizeof ext, 1, abfd) != sizeof ext)
459 /* Swap in the fields. */
460 l_vaddr = bfd_h_get_32 (abfd, ext.l_vaddr);
461 l_symndx = bfd_h_get_32 (abfd, ext.l_symndx);
462 l_rtype = bfd_h_get_16 (abfd, ext.l_rtype);
463 l_rsecnm = bfd_h_get_16 (abfd, ext.l_rsecnm);
465 /* Get the sections now, for convenience. */
466 code_sec = bfd_get_section_by_name (abfd, NLM_CODE_NAME);
467 data_sec = bfd_get_section_by_name (abfd, NLM_INITIALIZED_DATA_NAME);
468 bss_sec = bfd_get_section_by_name (abfd, NLM_UNINITIALIZED_DATA_NAME);
470 /* Work out the arelent fields. */
473 /* This is an import. sym_ptr_ptr is filled in by
474 nlm_canonicalize_reloc. */
475 rel->sym_ptr_ptr = NULL;
483 else if (l_symndx == 1)
485 else if (l_symndx == 2)
489 bfd_set_error (bfd_error_bad_value);
493 rel->sym_ptr_ptr = sec->symbol_ptr_ptr;
498 BFD_ASSERT ((l_rtype & 0xff) < HOWTO_COUNT);
500 rel->howto = nlm_powerpc_howto_table + (l_rtype & 0xff);
502 BFD_ASSERT (rel->howto->name != NULL
503 && ((l_rtype & 0x8000) != 0
504 ? (rel->howto->complain_on_overflow
505 == complain_overflow_signed)
506 : (rel->howto->complain_on_overflow
507 == complain_overflow_bitfield))
508 && ((l_rtype >> 8) & 0x1f) == rel->howto->bitsize - 1);
512 else if (l_rsecnm == 1)
515 l_vaddr -= bfd_section_size (abfd, code_sec);
519 bfd_set_error (bfd_error_bad_value);
523 rel->address = l_vaddr;
528 /* Mangle PowerPC NLM relocs for output. */
531 nlm_powerpc_mangle_relocs (abfd, sec, data, offset, count)
541 /* Read a PowerPC NLM import record */
544 nlm_powerpc_read_import (abfd, sym)
546 nlmNAME(symbol_type) *sym;
548 struct nlm_relent *nlm_relocs; /* relocation records for symbol */
549 bfd_size_type rcount; /* number of relocs */
550 bfd_byte temp[NLM_TARGET_LONG_SIZE]; /* temporary 32-bit value */
551 unsigned char symlength; /* length of symbol name */
554 if (bfd_read ((PTR) &symlength, sizeof (symlength), 1, abfd)
555 != sizeof (symlength))
557 sym -> symbol.the_bfd = abfd;
558 name = bfd_alloc (abfd, symlength + 1);
561 bfd_set_error (bfd_error_no_memory);
564 if (bfd_read (name, symlength, 1, abfd) != symlength)
566 name[symlength] = '\0';
567 sym -> symbol.name = name;
568 sym -> symbol.flags = 0;
569 sym -> symbol.value = 0;
570 sym -> symbol.section = &bfd_und_section;
571 if (bfd_read ((PTR) temp, sizeof (temp), 1, abfd) != sizeof (temp))
573 rcount = bfd_h_get_32 (abfd, temp);
574 nlm_relocs = ((struct nlm_relent *)
575 bfd_alloc (abfd, rcount * sizeof (struct nlm_relent)));
576 if (nlm_relocs == (struct nlm_relent *) NULL)
578 bfd_set_error (bfd_error_no_memory);
581 sym -> relocs = nlm_relocs;
583 while (sym -> rcnt < rcount)
587 if (nlm_powerpc_read_reloc (abfd, sym, §ion,
588 &nlm_relocs -> reloc)
591 nlm_relocs -> section = section;
598 /* Write a PowerPC NLM reloc. */
601 nlm_powerpc_write_reloc (abfd, sec, rel, indx)
607 struct nlm32_powerpc_external_reloc ext;
608 asection *code_sec, *data_sec, *bss_sec;
611 unsigned long l_symndx;
614 const reloc_howto_type *howto;
615 bfd_size_type address;
617 /* Get the sections now, for convenience. */
618 code_sec = bfd_get_section_by_name (abfd, NLM_CODE_NAME);
619 data_sec = bfd_get_section_by_name (abfd, NLM_INITIALIZED_DATA_NAME);
620 bss_sec = bfd_get_section_by_name (abfd, NLM_UNINITIALIZED_DATA_NAME);
622 sym = *rel->sym_ptr_ptr;
623 symsec = bfd_get_section (sym);
626 BFD_ASSERT (symsec == &bfd_und_section);
631 if (symsec == code_sec)
633 else if (symsec == data_sec)
635 else if (symsec == bss_sec)
639 bfd_set_error (bfd_error_bad_value);
644 bfd_h_put_32 (abfd, (bfd_vma) l_symndx, ext.l_symndx);
646 for (howto = nlm_powerpc_howto_table;
647 howto < nlm_powerpc_howto_table + HOWTO_COUNT;
650 if (howto->rightshift == rel->howto->rightshift
651 && howto->size == rel->howto->size
652 && howto->bitsize == rel->howto->bitsize
653 && howto->pc_relative == rel->howto->pc_relative
654 && howto->bitpos == rel->howto->bitpos
655 && (howto->partial_inplace == rel->howto->partial_inplace
656 || (! rel->howto->partial_inplace
657 && rel->addend == 0))
658 && (howto->src_mask == rel->howto->src_mask
659 || (rel->howto->src_mask == 0
660 && rel->addend == 0))
661 && howto->dst_mask == rel->howto->dst_mask
662 && howto->pcrel_offset == rel->howto->pcrel_offset)
665 if (howto >= nlm_powerpc_howto_table + HOWTO_COUNT)
667 bfd_set_error (bfd_error_bad_value);
671 l_rtype = howto->type;
672 if (howto->complain_on_overflow == complain_overflow_signed)
674 l_rtype |= (howto->bitsize - 1) << 8;
675 bfd_h_put_16 (abfd, (bfd_vma) l_rtype, ext.l_rtype);
677 address = rel->address;
681 else if (sec == data_sec)
684 address += bfd_section_size (abfd, code_sec);
688 bfd_set_error (bfd_error_bad_value);
692 bfd_h_put_16 (abfd, (bfd_vma) l_rsecnm, ext.l_rsecnm);
693 bfd_h_put_32 (abfd, (bfd_vma) address, ext.l_vaddr);
695 if (bfd_write (&ext, sizeof ext, 1, abfd) != sizeof ext)
701 /* Write a PowerPC NLM import. */
704 nlm_powerpc_write_import (abfd, sec, rel)
709 return nlm_powerpc_write_reloc (abfd, sec, rel, -1);
712 /* Write a PowerPC NLM external symbol. This routine keeps a static
713 count of the symbol index. FIXME: I don't know if this is
714 necessary, and the index never gets reset. */
717 nlm_powerpc_write_external (abfd, count, sym, relocs)
721 struct reloc_and_sec *relocs;
725 unsigned char temp[NLM_TARGET_LONG_SIZE];
728 len = strlen (sym->name);
729 if ((bfd_write (&len, sizeof (bfd_byte), 1, abfd) != sizeof(bfd_byte))
730 || bfd_write (sym->name, len, 1, abfd) != len)
733 bfd_put_32 (abfd, count, temp);
734 if (bfd_write (temp, sizeof(temp), 1, abfd) != sizeof (temp))
737 for (i = 0; i < count; i++)
739 if (nlm_powerpc_write_reloc (abfd, relocs[i].sec,
740 relocs[i].rel, indx) == false)
751 static const struct nlm_backend_data nlm32_powerpc_backend =
753 "NetWare PowerPC Module \032",
754 sizeof (Nlm32_powerpc_External_Fixed_Header),
755 sizeof (struct nlm32_powerpc_external_prefix_header),
759 nlm_powerpc_backend_object_p,
760 nlm_powerpc_write_prefix,
761 nlm_powerpc_read_reloc,
762 nlm_powerpc_mangle_relocs,
763 nlm_powerpc_read_import,
764 nlm_powerpc_write_import,
765 0, /* set_public_section */
766 0, /* get_public_offset */
767 nlm_swap_fixed_header_in,
768 nlm_swap_fixed_header_out,
769 nlm_powerpc_write_external,
770 0, /* write_export */
773 #define TARGET_BIG_NAME "nlm32-powerpc"
774 #define TARGET_BIG_SYM nlmNAME(powerpc_vec)
775 #define TARGET_BACKEND_DATA &nlm32_powerpc_backend
777 #include "nlm-target.h"