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"