2009-07-02 Tristan Gingold <gingold@adacore.com>
[binutils.git] / bfd / nlm32-ppc.c
blobb8c5852d909d7b415320582a0fb484b5ce0091fb
1 /* Support for 32-bit PowerPC NLM (NetWare Loadable Module)
2 Copyright 1994, 1995, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
3 2007 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 3 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., 51 Franklin Street - Fifth Floor, Boston,
20 MA 02110-1301, USA. */
22 #include "bfd.h"
23 #include "sysdep.h"
24 #include "libbfd.h"
26 /* The format of a PowerPC NLM changed. Define OLDFORMAT to get the
27 old format. */
29 #define ARCH_SIZE 32
31 #include "nlm/ppc-ext.h"
32 #define Nlm_External_Fixed_Header Nlm32_powerpc_External_Fixed_Header
34 #include "libnlm.h"
36 #ifdef OLDFORMAT
38 /* The prefix header is only used in the old format. */
40 /* PowerPC NLM's have a prefix header before the standard NLM. This
41 function reads it in, verifies the version, and seeks the bfd to
42 the location before the regular NLM header. */
44 static bfd_boolean
45 nlm_powerpc_backend_object_p (bfd *abfd)
47 struct nlm32_powerpc_external_prefix_header s;
49 if (bfd_bread (& s, (bfd_size_type) sizeof s, abfd) != sizeof s)
50 return FALSE;
52 if (memcmp (s.signature, NLM32_POWERPC_SIGNATURE, sizeof s.signature) != 0
53 || H_GET_32 (abfd, s.headerVersion) != NLM32_POWERPC_HEADER_VERSION)
54 return FALSE;
56 return TRUE;
59 /* Write out the prefix. */
61 static bfd_boolean
62 nlm_powerpc_write_prefix (bfd *abfd)
64 struct nlm32_powerpc_external_prefix_header s;
66 memset (&s, 0, sizeof s);
67 memcpy (s.signature, NLM32_POWERPC_SIGNATURE, sizeof s.signature);
68 H_PUT_32 (abfd, NLM32_POWERPC_HEADER_VERSION, s.headerVersion);
69 H_PUT_32 (abfd, 0, s.origins);
71 /* FIXME: What should we do about the date? */
73 if (bfd_bwrite (& s, (bfd_size_type) sizeof s, abfd) != sizeof s)
74 return FALSE;
76 return TRUE;
79 /* This reloc handling is only applicable to the old format. */
81 /* How to process the various reloc types. PowerPC NLMs use XCOFF
82 reloc types, and I have just copied the XCOFF reloc table here. */
84 static reloc_howto_type nlm_powerpc_howto_table[] =
86 /* Standard 32 bit relocation. */
87 HOWTO (0, /* Type. */
88 0, /* Rightshift. */
89 2, /* Size (0 = byte, 1 = short, 2 = long). */
90 32, /* Bitsize. */
91 FALSE, /* PC relative. */
92 0, /* Bitpos. */
93 complain_overflow_bitfield, /* Complain_on_overflow. */
94 0, /* Special_function. */
95 "R_POS", /* Name. */
96 TRUE, /* Partial_inplace. */
97 0xffffffff, /* Source mask. */
98 0xffffffff, /* Dest mask. */
99 FALSE), /* PC rel offset. */
101 /* 32 bit relocation, but store negative value. */
102 HOWTO (1, /* Type. */
103 0, /* Rightshift. */
104 -2, /* Size (0 = byte, 1 = short, 2 = long). */
105 32, /* Bitsize. */
106 FALSE, /* PC relative. */
107 0, /* Bitpos. */
108 complain_overflow_bitfield, /* Complain_on_overflow. */
109 0, /* Special_function. */
110 "R_NEG", /* Name. */
111 TRUE, /* Partial_inplace. */
112 0xffffffff, /* Source mask. */
113 0xffffffff, /* Dest mask. */
114 FALSE), /* PC rel offset. */
116 /* 32 bit PC relative relocation. */
117 HOWTO (2, /* Type. */
118 0, /* Rightshift. */
119 2, /* Size (0 = byte, 1 = short, 2 = long). */
120 32, /* Bitsize. */
121 TRUE, /* PC relative. */
122 0, /* Bitpos. */
123 complain_overflow_signed, /* Complain_on_overflow. */
124 0, /* Special_function. */
125 "R_REL", /* Name. */
126 TRUE, /* Partial_inplace. */
127 0xffffffff, /* Source mask. */
128 0xffffffff, /* Dest mask. */
129 FALSE), /* PC rel offset. */
131 /* 16 bit TOC relative relocation. */
132 HOWTO (3, /* Type. */
133 0, /* Rightshift. */
134 1, /* Size (0 = byte, 1 = short, 2 = long). */
135 16, /* Bitsize. */
136 FALSE, /* PC relative. */
137 0, /* Bitpos. */
138 complain_overflow_signed, /* Complain_on_overflow. */
139 0, /* Special_function. */
140 "R_TOC", /* Name. */
141 TRUE, /* Partial_inplace. */
142 0xffff, /* Source mask. */
143 0xffff, /* Dest mask. */
144 FALSE), /* PC rel offset. */
146 /* I don't really know what this is. */
147 HOWTO (4, /* Type. */
148 1, /* Rightshift. */
149 2, /* Size (0 = byte, 1 = short, 2 = long). */
150 32, /* Bitsize. */
151 FALSE, /* PC relative. */
152 0, /* Bitpos. */
153 complain_overflow_bitfield, /* Complain_on_overflow. */
154 0, /* Special_function. */
155 "R_RTB", /* Name. */
156 TRUE, /* Partial_inplace. */
157 0xffffffff, /* Source mask. */
158 0xffffffff, /* Dest mask. */
159 FALSE), /* PC rel offset. */
161 /* External TOC relative symbol. */
162 HOWTO (5, /* Type. */
163 0, /* Rightshift. */
164 2, /* Size (0 = byte, 1 = short, 2 = long). */
165 16, /* Bitsize. */
166 FALSE, /* PC relative. */
167 0, /* Bitpos. */
168 complain_overflow_bitfield, /* Complain_on_overflow. */
169 0, /* Special_function. */
170 "R_GL", /* Name. */
171 TRUE, /* Partial_inplace. */
172 0xffff, /* Source mask. */
173 0xffff, /* Dest mask. */
174 FALSE), /* PC rel offset. */
176 /* Local TOC relative symbol. */
177 HOWTO (6, /* Type. */
178 0, /* Rightshift. */
179 2, /* Size (0 = byte, 1 = short, 2 = long). */
180 16, /* Bitsize. */
181 FALSE, /* PC relative. */
182 0, /* Bitpos. */
183 complain_overflow_bitfield, /* Complain_on_overflow. */
184 0, /* Special_function. */
185 "R_TCL", /* Name. */
186 TRUE, /* Partial_inplace. */
187 0xffff, /* Source mask. */
188 0xffff, /* Dest mask. */
189 FALSE), /* PC rel offset. */
191 { 7 },
193 /* Non modifiable absolute branch. */
194 HOWTO (8, /* Type. */
195 0, /* Rightshift. */
196 2, /* Size (0 = byte, 1 = short, 2 = long). */
197 26, /* Bitsize. */
198 FALSE, /* PC relative. */
199 0, /* Bitpos. */
200 complain_overflow_bitfield, /* Complain_on_overflow. */
201 0, /* Special_function. */
202 "R_BA", /* Name. */
203 TRUE, /* Partial_inplace. */
204 0x3fffffc, /* Source mask. */
205 0x3fffffc, /* Dest mask. */
206 FALSE), /* PC rel offset. */
208 { 9 },
210 /* Non modifiable relative branch. */
211 HOWTO (0xa, /* Type. */
212 0, /* Rightshift. */
213 2, /* Size (0 = byte, 1 = short, 2 = long). */
214 26, /* Bitsize. */
215 TRUE, /* PC relative. */
216 0, /* Bitpos. */
217 complain_overflow_signed, /* Complain_on_overflow. */
218 0, /* Special_function. */
219 "R_BR", /* Name. */
220 TRUE, /* Partial_inplace. */
221 0x3fffffc, /* Source mask. */
222 0x3fffffc, /* Dest mask. */
223 FALSE), /* PC rel offset. */
225 { 0xb },
227 /* Indirect load. */
228 HOWTO (0xc, /* Type. */
229 0, /* Rightshift. */
230 2, /* Size (0 = byte, 1 = short, 2 = long). */
231 16, /* Bitsize. */
232 FALSE, /* PC relative. */
233 0, /* Bitpos. */
234 complain_overflow_bitfield, /* Complain_on_overflow. */
235 0, /* Special_function. */
236 "R_RL", /* Name. */
237 TRUE, /* Partial_inplace. */
238 0xffff, /* Source mask. */
239 0xffff, /* Dest mask. */
240 FALSE), /* PC rel offset. */
242 /* Load address. */
243 HOWTO (0xd, /* Type. */
244 0, /* Rightshift. */
245 2, /* Size (0 = byte, 1 = short, 2 = long). */
246 16, /* Bitsize. */
247 FALSE, /* PC relative. */
248 0, /* Bitpos. */
249 complain_overflow_bitfield, /* Complain_on_overflow. */
250 0, /* Special_function. */
251 "R_RLA", /* Name. */
252 TRUE, /* Partial_inplace. */
253 0xffff, /* Source mask. */
254 0xffff, /* Dest mask. */
255 FALSE), /* PC rel offset. */
257 { 0xe },
259 /* Non-relocating reference. */
260 HOWTO (0xf, /* Type. */
261 0, /* Rightshift. */
262 2, /* Size (0 = byte, 1 = short, 2 = long). */
263 32, /* Bitsize. */
264 FALSE, /* PC relative. */
265 0, /* Bitpos. */
266 complain_overflow_bitfield, /* Complain_on_overflow. */
267 0, /* Special_function. */
268 "R_REF", /* Name. */
269 FALSE, /* Partial_inplace. */
270 0, /* Source mask. */
271 0, /* Dest mask. */
272 FALSE), /* PC rel offset. */
274 { 0x10 },
275 { 0x11 },
277 /* TOC relative indirect load. */
278 HOWTO (0x12, /* 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_TRL", /* Name. */
287 TRUE, /* Partial_inplace. */
288 0xffff, /* Source mask. */
289 0xffff, /* Dest mask. */
290 FALSE), /* PC rel offset. */
292 /* TOC relative load address. */
293 HOWTO (0x13, /* 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_TRLA", /* Name. */
302 TRUE, /* Partial_inplace. */
303 0xffff, /* Source mask. */
304 0xffff, /* Dest mask. */
305 FALSE), /* PC rel offset. */
307 /* Modifiable relative branch. */
308 HOWTO (0x14, /* Type. */
309 1, /* Rightshift. */
310 2, /* Size (0 = byte, 1 = short, 2 = long). */
311 32, /* Bitsize. */
312 FALSE, /* PC relative. */
313 0, /* Bitpos. */
314 complain_overflow_bitfield, /* Complain_on_overflow. */
315 0, /* Special_function. */
316 "R_RRTBI", /* Name. */
317 TRUE, /* Partial_inplace. */
318 0xffffffff, /* Source mask. */
319 0xffffffff, /* Dest mask. */
320 FALSE), /* PC rel offset. */
322 /* Modifiable absolute branch. */
323 HOWTO (0x15, /* Type. */
324 1, /* Rightshift. */
325 2, /* Size (0 = byte, 1 = short, 2 = long). */
326 32, /* Bitsize. */
327 FALSE, /* PC relative. */
328 0, /* Bitpos. */
329 complain_overflow_bitfield, /* Complain_on_overflow. */
330 0, /* Special_function. */
331 "R_RRTBA", /* Name. */
332 TRUE, /* Partial_inplace. */
333 0xffffffff, /* Source mask. */
334 0xffffffff, /* Dest mask. */
335 FALSE), /* PC rel offset. */
337 /* Modifiable call absolute indirect. */
338 HOWTO (0x16, /* Type. */
339 0, /* Rightshift. */
340 2, /* Size (0 = byte, 1 = short, 2 = long). */
341 16, /* Bitsize. */
342 FALSE, /* PC relative. */
343 0, /* Bitpos. */
344 complain_overflow_bitfield, /* Complain_on_overflow. */
345 0, /* Special_function. */
346 "R_CAI", /* Name. */
347 TRUE, /* Partial_inplace. */
348 0xffff, /* Source mask. */
349 0xffff, /* Dest mask. */
350 FALSE), /* PC rel offset. */
352 /* Modifiable call relative. */
353 HOWTO (0x17, /* Type. */
354 0, /* Rightshift. */
355 2, /* Size (0 = byte, 1 = short, 2 = long). */
356 16, /* Bitsize. */
357 FALSE, /* PC relative. */
358 0, /* Bitpos. */
359 complain_overflow_bitfield, /* Complain_on_overflow. */
360 0, /* Special_function. */
361 "R_REL", /* Name. */
362 TRUE, /* Partial_inplace. */
363 0xffff, /* Source mask. */
364 0xffff, /* Dest mask. */
365 FALSE), /* PC rel offset. */
367 /* Modifiable branch absolute. */
368 HOWTO (0x18, /* Type. */
369 0, /* Rightshift. */
370 2, /* Size (0 = byte, 1 = short, 2 = long). */
371 16, /* Bitsize. */
372 FALSE, /* PC relative. */
373 0, /* Bitpos. */
374 complain_overflow_bitfield, /* Complain_on_overflow. */
375 0, /* Special_function. */
376 "R_RBA", /* Name. */
377 TRUE, /* Partial_inplace. */
378 0xffff, /* Source mask. */
379 0xffff, /* Dest mask. */
380 FALSE), /* PC rel offset. */
382 /* Modifiable branch absolute. */
383 HOWTO (0x19, /* Type. */
384 0, /* Rightshift. */
385 2, /* Size (0 = byte, 1 = short, 2 = long). */
386 16, /* Bitsize. */
387 FALSE, /* PC relative. */
388 0, /* Bitpos. */
389 complain_overflow_bitfield, /* Complain_on_overflow. */
390 0, /* Special_function. */
391 "R_RBAC", /* Name. */
392 TRUE, /* Partial_inplace. */
393 0xffff, /* Source mask. */
394 0xffff, /* Dest mask. */
395 FALSE), /* PC rel offset. */
397 /* Modifiable branch relative. */
398 HOWTO (0x1a, /* Type. */
399 0, /* Rightshift. */
400 2, /* Size (0 = byte, 1 = short, 2 = long). */
401 26, /* Bitsize. */
402 FALSE, /* PC relative. */
403 0, /* Bitpos. */
404 complain_overflow_signed, /* Complain_on_overflow. */
405 0, /* Special_function. */
406 "R_REL", /* Name. */
407 TRUE, /* Partial_inplace. */
408 0xffff, /* Source mask. */
409 0xffff, /* Dest mask. */
410 FALSE), /* PC rel offset. */
412 /* Modifiable branch absolute. */
413 HOWTO (0x1b, /* Type. */
414 0, /* Rightshift. */
415 2, /* Size (0 = byte, 1 = short, 2 = long). */
416 16, /* Bitsize. */
417 FALSE, /* PC relative. */
418 0, /* Bitpos. */
419 complain_overflow_bitfield, /* Complain_on_overflow. */
420 0, /* Special_function. */
421 "R_REL", /* Name. */
422 TRUE, /* Partial_inplace. */
423 0xffff, /* Source mask. */
424 0xffff, /* Dest mask. */
425 FALSE) /* PC rel offset. */
428 #define HOWTO_COUNT (sizeof nlm_powerpc_howto_table \
429 / sizeof nlm_powerpc_howto_table[0])
431 /* Read a PowerPC NLM reloc. */
433 static bfd_boolean
434 nlm_powerpc_read_reloc (bfd *abfd,
435 nlmNAME (symbol_type) *sym,
436 asection **secp,
437 arelent *rel)
439 struct nlm32_powerpc_external_reloc ext;
440 bfd_vma l_vaddr;
441 unsigned long l_symndx;
442 int l_rtype;
443 int l_rsecnm;
444 asection *code_sec, *data_sec, *bss_sec;
446 /* Read the reloc from the file. */
447 if (bfd_bread (&ext, (bfd_size_type) sizeof ext, abfd) != sizeof ext)
448 return FALSE;
450 /* Swap in the fields. */
451 l_vaddr = H_GET_32 (abfd, ext.l_vaddr);
452 l_symndx = H_GET_32 (abfd, ext.l_symndx);
453 l_rtype = H_GET_16 (abfd, ext.l_rtype);
454 l_rsecnm = H_GET_16 (abfd, ext.l_rsecnm);
456 /* Get the sections now, for convenience. */
457 code_sec = bfd_get_section_by_name (abfd, NLM_CODE_NAME);
458 data_sec = bfd_get_section_by_name (abfd, NLM_INITIALIZED_DATA_NAME);
459 bss_sec = bfd_get_section_by_name (abfd, NLM_UNINITIALIZED_DATA_NAME);
461 /* Work out the arelent fields. */
462 if (sym != NULL)
463 /* This is an import. sym_ptr_ptr is filled in by
464 nlm_canonicalize_reloc. */
465 rel->sym_ptr_ptr = NULL;
466 else
468 asection *sec;
470 if (l_symndx == 0)
471 sec = code_sec;
472 else if (l_symndx == 1)
473 sec = data_sec;
474 else if (l_symndx == 2)
475 sec = bss_sec;
476 else
478 bfd_set_error (bfd_error_bad_value);
479 return FALSE;
482 rel->sym_ptr_ptr = sec->symbol_ptr_ptr;
485 rel->addend = 0;
487 BFD_ASSERT ((l_rtype & 0xff) < HOWTO_COUNT);
489 rel->howto = nlm_powerpc_howto_table + (l_rtype & 0xff);
491 BFD_ASSERT (rel->howto->name != NULL
492 && ((l_rtype & 0x8000) != 0
493 ? (rel->howto->complain_on_overflow
494 == complain_overflow_signed)
495 : (rel->howto->complain_on_overflow
496 == complain_overflow_bitfield))
497 && ((l_rtype >> 8) & 0x1f) == rel->howto->bitsize - 1);
499 if (l_rsecnm == 0)
500 *secp = code_sec;
501 else if (l_rsecnm == 1)
503 *secp = data_sec;
504 l_vaddr -= code_sec->size;
506 else
508 bfd_set_error (bfd_error_bad_value);
509 return FALSE;
512 rel->address = l_vaddr;
514 return TRUE;
517 #else /* not OLDFORMAT */
519 /* There is only one type of reloc in a PowerPC NLM. */
521 static reloc_howto_type nlm_powerpc_howto =
522 HOWTO (0, /* Type. */
523 0, /* Rightshift. */
524 2, /* Size (0 = byte, 1 = short, 2 = long). */
525 32, /* Bitsize. */
526 FALSE, /* PC relative. */
527 0, /* Bitpos. */
528 complain_overflow_bitfield, /* Complain_on_overflow. */
529 0, /* Special_function. */
530 "32", /* Name. */
531 TRUE, /* Partial_inplace. */
532 0xffffffff, /* Source mask. */
533 0xffffffff, /* Dest mask. */
534 FALSE); /* PC rel_offset. */
536 /* Read a PowerPC NLM reloc. */
538 static bfd_boolean
539 nlm_powerpc_read_reloc (bfd *abfd,
540 nlmNAME (symbol_type) *sym,
541 asection **secp,
542 arelent *rel)
544 bfd_byte temp[4];
545 bfd_vma val;
546 const char *name;
548 if (bfd_bread (temp, (bfd_size_type) sizeof (temp), abfd) != sizeof (temp))
549 return FALSE;
551 val = bfd_get_32 (abfd, temp);
553 /* The value is a word offset into either the code or data segment.
554 This is the location which needs to be adjusted.
556 The high bit is 0 if the value is an offset into the data
557 segment, or 1 if the value is an offset into the text segment.
559 If this is a relocation fixup rather than an imported symbol (the
560 sym argument is NULL), then the second most significant bit is 0
561 if the address of the data segment should be added to the
562 location addressed by the value, or 1 if the address of the text
563 segment should be added.
565 If this is an imported symbol, the second most significant bit is
566 not used and must be 0. */
568 if ((val & NLM_HIBIT) == 0)
569 name = NLM_INITIALIZED_DATA_NAME;
570 else
572 name = NLM_CODE_NAME;
573 val &=~ NLM_HIBIT;
575 *secp = bfd_get_section_by_name (abfd, name);
577 if (sym == NULL)
579 if ((val & (NLM_HIBIT >> 1)) == 0)
580 name = NLM_INITIALIZED_DATA_NAME;
581 else
583 name = NLM_CODE_NAME;
584 val &=~ (NLM_HIBIT >> 1);
586 rel->sym_ptr_ptr = bfd_get_section_by_name (abfd, name)->symbol_ptr_ptr;
589 rel->howto = & nlm_powerpc_howto;
590 rel->address = val << 2;
591 rel->addend = 0;
593 return TRUE;
596 #endif /* not OLDFORMAT */
598 /* Mangle PowerPC NLM relocs for output. */
600 static bfd_boolean
601 nlm_powerpc_mangle_relocs (bfd *abfd ATTRIBUTE_UNUSED,
602 asection *sec ATTRIBUTE_UNUSED,
603 const void * data ATTRIBUTE_UNUSED,
604 bfd_vma offset ATTRIBUTE_UNUSED,
605 bfd_size_type count ATTRIBUTE_UNUSED)
607 return TRUE;
610 /* Read a PowerPC NLM import record */
612 static bfd_boolean
613 nlm_powerpc_read_import (bfd * abfd, nlmNAME (symbol_type) * sym)
615 struct nlm_relent *nlm_relocs; /* Relocation records for symbol. */
616 bfd_size_type rcount; /* Number of relocs. */
617 bfd_byte temp[NLM_TARGET_LONG_SIZE]; /* Temporary 32-bit value. */
618 unsigned char symlength; /* Length of symbol name. */
619 char *name;
621 if (bfd_bread (& symlength, (bfd_size_type) sizeof (symlength), abfd)
622 != sizeof (symlength))
623 return FALSE;
624 sym -> symbol.the_bfd = abfd;
625 name = bfd_alloc (abfd, (bfd_size_type) symlength + 1);
626 if (name == NULL)
627 return FALSE;
628 if (bfd_bread (name, (bfd_size_type) symlength, abfd) != symlength)
629 return FALSE;
630 name[symlength] = '\0';
631 sym -> symbol.name = name;
632 sym -> symbol.flags = 0;
633 sym -> symbol.value = 0;
634 sym -> symbol.section = bfd_und_section_ptr;
635 if (bfd_bread (temp, (bfd_size_type) sizeof (temp), abfd)
636 != sizeof (temp))
637 return FALSE;
638 rcount = H_GET_32 (abfd, temp);
639 nlm_relocs = bfd_alloc (abfd, rcount * sizeof (struct nlm_relent));
640 if (nlm_relocs == NULL)
641 return FALSE;
642 sym -> relocs = nlm_relocs;
643 sym -> rcnt = 0;
644 while (sym -> rcnt < rcount)
646 asection *section;
648 if (! nlm_powerpc_read_reloc (abfd, sym, &section, &nlm_relocs -> reloc))
649 return FALSE;
650 nlm_relocs -> section = section;
651 nlm_relocs++;
652 sym -> rcnt++;
654 return TRUE;
657 #ifndef OLDFORMAT
659 /* Write a PowerPC NLM reloc. */
661 static bfd_boolean
662 nlm_powerpc_write_import (bfd * abfd, asection * sec, arelent * rel)
664 asymbol *sym;
665 bfd_vma val;
666 bfd_byte temp[4];
668 /* PowerPC NetWare only supports one kind of reloc. */
669 if (rel->addend != 0
670 || rel->howto == NULL
671 || rel->howto->rightshift != 0
672 || rel->howto->size != 2
673 || rel->howto->bitsize != 32
674 || rel->howto->bitpos != 0
675 || rel->howto->pc_relative
676 || (rel->howto->src_mask != 0xffffffff && rel->addend != 0)
677 || rel->howto->dst_mask != 0xffffffff)
679 bfd_set_error (bfd_error_invalid_operation);
680 return FALSE;
683 sym = *rel->sym_ptr_ptr;
685 /* The value we write out is the offset into the appropriate
686 segment, rightshifted by two. This offset is the section vma,
687 adjusted by the vma of the lowest section in that segment, plus
688 the address of the relocation. */
689 val = bfd_get_section_vma (abfd, sec) + rel->address;
690 if ((val & 3) != 0)
692 bfd_set_error (bfd_error_bad_value);
693 return FALSE;
695 val >>= 2;
697 /* The high bit is 0 if the reloc is in the data section, or 1 if
698 the reloc is in the code section. */
699 if (bfd_get_section_flags (abfd, sec) & SEC_DATA)
700 val -= nlm_get_data_low (abfd);
701 else
703 val -= nlm_get_text_low (abfd);
704 val |= NLM_HIBIT;
707 if (! bfd_is_und_section (bfd_get_section (sym)))
709 /* This is an internal relocation fixup. The second most
710 significant bit is 0 if this is a reloc against the data
711 segment, or 1 if it is a reloc against the text segment. */
712 if (bfd_get_section_flags (abfd, bfd_get_section (sym)) & SEC_CODE)
713 val |= NLM_HIBIT >> 1;
716 bfd_put_32 (abfd, val, temp);
717 if (bfd_bwrite (temp, (bfd_size_type) sizeof (temp), abfd) != sizeof (temp))
718 return FALSE;
720 return TRUE;
723 #else /* OLDFORMAT */
725 /* This is used for the reloc handling in the old format. */
727 /* Write a PowerPC NLM reloc. */
729 static bfd_boolean
730 nlm_powerpc_write_reloc (bfd *abfd,
731 asection *sec,
732 arelent *rel,
733 int indx)
735 struct nlm32_powerpc_external_reloc ext;
736 asection *code_sec, *data_sec, *bss_sec;
737 asymbol *sym;
738 asection *symsec;
739 unsigned long l_symndx;
740 int l_rtype;
741 int l_rsecnm;
742 reloc_howto_type *howto;
743 bfd_size_type address;
745 /* Get the sections now, for convenience. */
746 code_sec = bfd_get_section_by_name (abfd, NLM_CODE_NAME);
747 data_sec = bfd_get_section_by_name (abfd, NLM_INITIALIZED_DATA_NAME);
748 bss_sec = bfd_get_section_by_name (abfd, NLM_UNINITIALIZED_DATA_NAME);
750 sym = *rel->sym_ptr_ptr;
751 symsec = bfd_get_section (sym);
752 if (indx != -1)
754 BFD_ASSERT (bfd_is_und_section (symsec));
755 l_symndx = indx + 3;
757 else
759 if (symsec == code_sec)
760 l_symndx = 0;
761 else if (symsec == data_sec)
762 l_symndx = 1;
763 else if (symsec == bss_sec)
764 l_symndx = 2;
765 else
767 bfd_set_error (bfd_error_bad_value);
768 return FALSE;
772 H_PUT_32 (abfd, l_symndx, ext.l_symndx);
774 for (howto = nlm_powerpc_howto_table;
775 howto < nlm_powerpc_howto_table + HOWTO_COUNT;
776 howto++)
778 if (howto->rightshift == rel->howto->rightshift
779 && howto->size == rel->howto->size
780 && howto->bitsize == rel->howto->bitsize
781 && howto->pc_relative == rel->howto->pc_relative
782 && howto->bitpos == rel->howto->bitpos
783 && (howto->partial_inplace == rel->howto->partial_inplace
784 || (! rel->howto->partial_inplace
785 && rel->addend == 0))
786 && (howto->src_mask == rel->howto->src_mask
787 || (rel->howto->src_mask == 0
788 && rel->addend == 0))
789 && howto->dst_mask == rel->howto->dst_mask
790 && howto->pcrel_offset == rel->howto->pcrel_offset)
791 break;
793 if (howto >= nlm_powerpc_howto_table + HOWTO_COUNT)
795 bfd_set_error (bfd_error_bad_value);
796 return FALSE;
799 l_rtype = howto->type;
800 if (howto->complain_on_overflow == complain_overflow_signed)
801 l_rtype |= 0x8000;
802 l_rtype |= (howto->bitsize - 1) << 8;
803 H_PUT_16 (abfd, l_rtype, ext.l_rtype);
805 address = rel->address;
807 if (sec == code_sec)
808 l_rsecnm = 0;
809 else if (sec == data_sec)
811 l_rsecnm = 1;
812 address += code_sec->size;
814 else
816 bfd_set_error (bfd_error_bad_value);
817 return FALSE;
820 H_PUT_16 (abfd, l_rsecnm, ext.l_rsecnm);
821 H_PUT_32 (abfd, address, ext.l_vaddr);
823 if (bfd_bwrite (&ext, (bfd_size_type) sizeof ext, abfd) != sizeof ext)
824 return FALSE;
826 return TRUE;
829 /* Write a PowerPC NLM import. */
831 static bfd_boolean
832 nlm_powerpc_write_import (bfd * abfd, asection * sec, arelent * rel)
834 return nlm_powerpc_write_reloc (abfd, sec, rel, -1);
837 #endif /* OLDFORMAT */
839 /* Write a PowerPC NLM external symbol. This routine keeps a static
840 count of the symbol index. FIXME: I don't know if this is
841 necessary, and the index never gets reset. */
843 static bfd_boolean
844 nlm_powerpc_write_external (bfd *abfd,
845 bfd_size_type count,
846 asymbol *sym,
847 struct reloc_and_sec *relocs)
849 unsigned int i;
850 bfd_byte len;
851 unsigned char temp[NLM_TARGET_LONG_SIZE];
852 #ifdef OLDFORMAT
853 static int indx;
854 #endif
856 len = strlen (sym->name);
857 if ((bfd_bwrite (&len, (bfd_size_type) sizeof (bfd_byte), abfd)
858 != sizeof (bfd_byte))
859 || bfd_bwrite (sym->name, (bfd_size_type) len, abfd) != len)
860 return FALSE;
862 bfd_put_32 (abfd, count, temp);
863 if (bfd_bwrite (temp, (bfd_size_type) sizeof (temp), abfd) != sizeof (temp))
864 return FALSE;
866 for (i = 0; i < count; i++)
868 #ifndef OLDFORMAT
869 if (! nlm_powerpc_write_import (abfd, relocs[i].sec, relocs[i].rel))
870 return FALSE;
871 #else
872 if (! nlm_powerpc_write_reloc (abfd, relocs[i].sec,
873 relocs[i].rel, indx))
874 return FALSE;
875 #endif
878 #ifdef OLDFORMAT
879 ++indx;
880 #endif
882 return TRUE;
885 #ifndef OLDFORMAT
887 /* PowerPC Netware uses a word offset, not a byte offset, for public
888 symbols. */
890 /* Set the section for a public symbol. */
892 static bfd_boolean
893 nlm_powerpc_set_public_section (bfd *abfd, nlmNAME (symbol_type) *sym)
895 if (sym->symbol.value & NLM_HIBIT)
897 sym->symbol.value &= ~NLM_HIBIT;
898 sym->symbol.flags |= BSF_FUNCTION;
899 sym->symbol.section =
900 bfd_get_section_by_name (abfd, NLM_CODE_NAME);
902 else
903 sym->symbol.section =
904 bfd_get_section_by_name (abfd, NLM_INITIALIZED_DATA_NAME);
906 sym->symbol.value <<= 2;
908 return TRUE;
911 /* Get the offset to write out for a public symbol. */
913 static bfd_vma
914 nlm_powerpc_get_public_offset (bfd *abfd, asymbol *sym)
916 bfd_vma offset;
917 asection *sec;
919 offset = bfd_asymbol_value (sym);
920 sec = bfd_get_section (sym);
921 if (sec->flags & SEC_CODE)
923 offset -= nlm_get_text_low (abfd);
924 offset |= NLM_HIBIT;
926 else if (sec->flags & (SEC_DATA | SEC_ALLOC))
928 /* SEC_ALLOC is for the .bss section. */
929 offset -= nlm_get_data_low (abfd);
931 else
933 /* We can't handle an exported symbol that is not in the code or
934 data segment. */
935 bfd_set_error (bfd_error_invalid_operation);
936 /* FIXME: No way to return error. */
937 abort ();
940 return offset;
943 #endif /* ! defined (OLDFORMAT) */
945 #include "nlmswap.h"
947 static const struct nlm_backend_data nlm32_powerpc_backend =
949 "NetWare PowerPC Module \032",
950 sizeof (Nlm32_powerpc_External_Fixed_Header),
951 #ifndef OLDFORMAT
952 0, /* Optional_prefix_size. */
953 #else
954 sizeof (struct nlm32_powerpc_external_prefix_header),
955 #endif
956 bfd_arch_powerpc,
958 FALSE,
959 #ifndef OLDFORMAT
960 0, /* Backend_object_p. */
961 0, /* Write_prefix. */
962 #else
963 nlm_powerpc_backend_object_p,
964 nlm_powerpc_write_prefix,
965 #endif
966 nlm_powerpc_read_reloc,
967 nlm_powerpc_mangle_relocs,
968 nlm_powerpc_read_import,
969 nlm_powerpc_write_import,
970 #ifndef OLDFORMAT
971 nlm_powerpc_set_public_section,
972 nlm_powerpc_get_public_offset,
973 #else
974 0, /* Set_public_section. */
975 0, /* Get_public_offset. */
976 #endif
977 nlm_swap_fixed_header_in,
978 nlm_swap_fixed_header_out,
979 nlm_powerpc_write_external,
980 0, /* Write_export. */
983 #define TARGET_BIG_NAME "nlm32-powerpc"
984 #define TARGET_BIG_SYM nlmNAME (powerpc_vec)
985 #define TARGET_BACKEND_DATA & nlm32_powerpc_backend
987 #include "nlm-target.h"