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
)
458 bfd_set_error (bfd_error_system_call
);
462 /* Swap in the fields. */
463 l_vaddr
= bfd_h_get_32 (abfd
, ext
.l_vaddr
);
464 l_symndx
= bfd_h_get_32 (abfd
, ext
.l_symndx
);
465 l_rtype
= bfd_h_get_16 (abfd
, ext
.l_rtype
);
466 l_rsecnm
= bfd_h_get_16 (abfd
, ext
.l_rsecnm
);
468 /* Get the sections now, for convenience. */
469 code_sec
= bfd_get_section_by_name (abfd
, NLM_CODE_NAME
);
470 data_sec
= bfd_get_section_by_name (abfd
, NLM_INITIALIZED_DATA_NAME
);
471 bss_sec
= bfd_get_section_by_name (abfd
, NLM_UNINITIALIZED_DATA_NAME
);
473 /* Work out the arelent fields. */
476 /* This is an import. sym_ptr_ptr is filled in by
477 nlm_canonicalize_reloc. */
478 rel
->sym_ptr_ptr
= NULL
;
486 else if (l_symndx
== 1)
488 else if (l_symndx
== 2)
492 bfd_set_error (bfd_error_bad_value
);
496 rel
->sym_ptr_ptr
= sec
->symbol_ptr_ptr
;
501 BFD_ASSERT ((l_rtype
& 0xff) < HOWTO_COUNT
);
503 rel
->howto
= nlm_powerpc_howto_table
+ (l_rtype
& 0xff);
505 BFD_ASSERT (rel
->howto
->name
!= NULL
506 && ((l_rtype
& 0x8000) != 0
507 ? (rel
->howto
->complain_on_overflow
508 == complain_overflow_signed
)
509 : (rel
->howto
->complain_on_overflow
510 == complain_overflow_bitfield
))
511 && ((l_rtype
>> 8) & 0x1f) == rel
->howto
->bitsize
- 1);
515 else if (l_rsecnm
== 1)
518 l_vaddr
-= bfd_section_size (abfd
, code_sec
);
522 bfd_set_error (bfd_error_bad_value
);
526 rel
->address
= l_vaddr
;
531 /* Mangle PowerPC NLM relocs for output. */
534 nlm_powerpc_mangle_relocs (abfd
, sec
, data
, offset
, count
)
544 /* Read a PowerPC NLM import record */
547 nlm_powerpc_read_import (abfd
, sym
)
549 nlmNAME(symbol_type
) *sym
;
551 struct nlm_relent
*nlm_relocs
; /* relocation records for symbol */
552 bfd_size_type rcount
; /* number of relocs */
553 bfd_byte temp
[NLM_TARGET_LONG_SIZE
]; /* temporary 32-bit value */
554 unsigned char symlength
; /* length of symbol name */
557 if (bfd_read ((PTR
) &symlength
, sizeof (symlength
), 1, abfd
)
558 != sizeof (symlength
))
560 bfd_set_error (bfd_error_system_call
);
563 sym
-> symbol
.the_bfd
= abfd
;
564 name
= bfd_alloc (abfd
, symlength
+ 1);
567 bfd_set_error (bfd_error_no_memory
);
570 if (bfd_read (name
, symlength
, 1, abfd
) != symlength
)
572 bfd_set_error (bfd_error_system_call
);
575 name
[symlength
] = '\0';
576 sym
-> symbol
.name
= name
;
577 sym
-> symbol
.flags
= 0;
578 sym
-> symbol
.value
= 0;
579 sym
-> symbol
.section
= &bfd_und_section
;
580 if (bfd_read ((PTR
) temp
, sizeof (temp
), 1, abfd
) != sizeof (temp
))
582 bfd_set_error (bfd_error_system_call
);
585 rcount
= bfd_h_get_32 (abfd
, temp
);
586 nlm_relocs
= ((struct nlm_relent
*)
587 bfd_alloc (abfd
, rcount
* sizeof (struct nlm_relent
)));
588 if (nlm_relocs
== (struct nlm_relent
*) NULL
)
590 bfd_set_error (bfd_error_no_memory
);
593 sym
-> relocs
= nlm_relocs
;
595 while (sym
-> rcnt
< rcount
)
599 if (nlm_powerpc_read_reloc (abfd
, sym
, §ion
,
600 &nlm_relocs
-> reloc
)
603 nlm_relocs
-> section
= section
;
610 /* Write a PowerPC NLM reloc. */
613 nlm_powerpc_write_reloc (abfd
, sec
, rel
, indx
)
619 struct nlm32_powerpc_external_reloc ext
;
620 asection
*code_sec
, *data_sec
, *bss_sec
;
623 unsigned long l_symndx
;
626 const reloc_howto_type
*howto
;
627 bfd_size_type address
;
629 /* Get the sections now, for convenience. */
630 code_sec
= bfd_get_section_by_name (abfd
, NLM_CODE_NAME
);
631 data_sec
= bfd_get_section_by_name (abfd
, NLM_INITIALIZED_DATA_NAME
);
632 bss_sec
= bfd_get_section_by_name (abfd
, NLM_UNINITIALIZED_DATA_NAME
);
634 sym
= *rel
->sym_ptr_ptr
;
635 symsec
= bfd_get_section (sym
);
638 BFD_ASSERT (symsec
== &bfd_und_section
);
643 if (symsec
== code_sec
)
645 else if (symsec
== data_sec
)
647 else if (symsec
== bss_sec
)
651 bfd_set_error (bfd_error_bad_value
);
656 bfd_h_put_32 (abfd
, (bfd_vma
) l_symndx
, ext
.l_symndx
);
658 for (howto
= nlm_powerpc_howto_table
;
659 howto
< nlm_powerpc_howto_table
+ HOWTO_COUNT
;
662 if (howto
->rightshift
== rel
->howto
->rightshift
663 && howto
->size
== rel
->howto
->size
664 && howto
->bitsize
== rel
->howto
->bitsize
665 && howto
->pc_relative
== rel
->howto
->pc_relative
666 && howto
->bitpos
== rel
->howto
->bitpos
667 && (howto
->partial_inplace
== rel
->howto
->partial_inplace
668 || (! rel
->howto
->partial_inplace
669 && rel
->addend
== 0))
670 && (howto
->src_mask
== rel
->howto
->src_mask
671 || (rel
->howto
->src_mask
== 0
672 && rel
->addend
== 0))
673 && howto
->dst_mask
== rel
->howto
->dst_mask
674 && howto
->pcrel_offset
== rel
->howto
->pcrel_offset
)
677 if (howto
>= nlm_powerpc_howto_table
+ HOWTO_COUNT
)
679 bfd_set_error (bfd_error_bad_value
);
683 l_rtype
= howto
->type
;
684 if (howto
->complain_on_overflow
== complain_overflow_signed
)
686 l_rtype
|= (howto
->bitsize
- 1) << 8;
687 bfd_h_put_16 (abfd
, (bfd_vma
) l_rtype
, ext
.l_rtype
);
689 address
= rel
->address
;
693 else if (sec
== data_sec
)
696 address
+= bfd_section_size (abfd
, code_sec
);
700 bfd_set_error (bfd_error_bad_value
);
704 bfd_h_put_16 (abfd
, (bfd_vma
) l_rsecnm
, ext
.l_rsecnm
);
705 bfd_h_put_32 (abfd
, (bfd_vma
) address
, ext
.l_vaddr
);
707 if (bfd_write (&ext
, sizeof ext
, 1, abfd
) != sizeof ext
)
713 /* Write a PowerPC NLM import. */
716 nlm_powerpc_write_import (abfd
, sec
, rel
)
721 return nlm_powerpc_write_reloc (abfd
, sec
, rel
, -1);
724 /* Write a PowerPC NLM external symbol. This routine keeps a static
725 count of the symbol index. FIXME: I don't know if this is
726 necessary, and the index never gets reset. */
729 nlm_powerpc_write_external (abfd
, count
, sym
, relocs
)
733 struct reloc_and_sec
*relocs
;
737 unsigned char temp
[NLM_TARGET_LONG_SIZE
];
740 len
= strlen (sym
->name
);
741 if ((bfd_write (&len
, sizeof (bfd_byte
), 1, abfd
) != sizeof(bfd_byte
))
742 || bfd_write (sym
->name
, len
, 1, abfd
) != len
)
744 bfd_set_error (bfd_error_system_call
);
748 bfd_put_32 (abfd
, count
, temp
);
749 if (bfd_write (temp
, sizeof(temp
), 1, abfd
) != sizeof (temp
))
751 bfd_set_error (bfd_error_system_call
);
755 for (i
= 0; i
< count
; i
++)
757 if (nlm_powerpc_write_reloc (abfd
, relocs
[i
].sec
,
758 relocs
[i
].rel
, indx
) == false)
769 static const struct nlm_backend_data nlm32_powerpc_backend
=
771 "NetWare PowerPC Module \032",
772 sizeof (Nlm32_powerpc_External_Fixed_Header
),
773 sizeof (struct nlm32_powerpc_external_prefix_header
),
777 nlm_powerpc_backend_object_p
,
778 nlm_powerpc_write_prefix
,
779 nlm_powerpc_read_reloc
,
780 nlm_powerpc_mangle_relocs
,
781 nlm_powerpc_read_import
,
782 nlm_powerpc_write_import
,
783 0, /* set_public_section */
784 0, /* get_public_offset */
785 nlm_swap_fixed_header_in
,
786 nlm_swap_fixed_header_out
,
787 nlm_powerpc_write_external
,
788 0, /* write_export */
791 #define TARGET_BIG_NAME "nlm32-powerpc"
792 #define TARGET_BIG_SYM nlmNAME(powerpc_vec)
793 #define TARGET_BACKEND_DATA &nlm32_powerpc_backend
795 #include "nlm-target.h"