[ gas/ChangeLog ]
[binutils.git] / bfd / nlm32-ppc.c
blob8b0d4009df836ff02f81df244124e78d1764de33
1 /* Support for 32-bit PowerPC NLM (NetWare Loadable Module)
2 Copyright 1994, 1995, 1999, 2000, 2001, 2002, 2003, 2004,
3 2005 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., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, 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
37 /* The prefix header is only used in the old format. */
39 /* PowerPC NLM's have a prefix header before the standard NLM. This
40 function reads it in, verifies the version, and seeks the bfd to
41 the location before the regular NLM header. */
43 static bfd_boolean
44 nlm_powerpc_backend_object_p (bfd *abfd)
46 struct nlm32_powerpc_external_prefix_header s;
48 if (bfd_bread (& s, (bfd_size_type) sizeof s, abfd) != sizeof s)
49 return FALSE;
51 if (memcmp (s.signature, NLM32_POWERPC_SIGNATURE, sizeof s.signature) != 0
52 || H_GET_32 (abfd, s.headerVersion) != NLM32_POWERPC_HEADER_VERSION)
53 return FALSE;
55 return TRUE;
58 /* Write out the prefix. */
60 static bfd_boolean
61 nlm_powerpc_write_prefix (bfd *abfd)
63 struct nlm32_powerpc_external_prefix_header s;
65 memset (&s, 0, sizeof s);
66 memcpy (s.signature, NLM32_POWERPC_SIGNATURE, sizeof s.signature);
67 H_PUT_32 (abfd, NLM32_POWERPC_HEADER_VERSION, s.headerVersion);
68 H_PUT_32 (abfd, 0, s.origins);
70 /* FIXME: What should we do about the date? */
72 if (bfd_bwrite (& s, (bfd_size_type) sizeof s, abfd) != sizeof s)
73 return FALSE;
75 return TRUE;
78 /* This reloc handling is only applicable to the old format. */
80 /* How to process the various reloc types. PowerPC NLMs use XCOFF
81 reloc types, and I have just copied the XCOFF reloc table here. */
83 static reloc_howto_type nlm_powerpc_howto_table[] =
85 /* Standard 32 bit relocation. */
86 HOWTO (0, /* Type. */
87 0, /* Rightshift. */
88 2, /* Size (0 = byte, 1 = short, 2 = long). */
89 32, /* Bitsize. */
90 FALSE, /* PC relative. */
91 0, /* Bitpos. */
92 complain_overflow_bitfield, /* Complain_on_overflow. */
93 0, /* Special_function. */
94 "R_POS", /* Name. */
95 TRUE, /* Partial_inplace. */
96 0xffffffff, /* Source mask. */
97 0xffffffff, /* Dest mask. */
98 FALSE), /* PC rel offset. */
100 /* 32 bit relocation, but store negative value. */
101 HOWTO (1, /* Type. */
102 0, /* Rightshift. */
103 -2, /* Size (0 = byte, 1 = short, 2 = long). */
104 32, /* Bitsize. */
105 FALSE, /* PC relative. */
106 0, /* Bitpos. */
107 complain_overflow_bitfield, /* Complain_on_overflow. */
108 0, /* Special_function. */
109 "R_NEG", /* Name. */
110 TRUE, /* Partial_inplace. */
111 0xffffffff, /* Source mask. */
112 0xffffffff, /* Dest mask. */
113 FALSE), /* PC rel offset. */
115 /* 32 bit PC relative relocation. */
116 HOWTO (2, /* Type. */
117 0, /* Rightshift. */
118 2, /* Size (0 = byte, 1 = short, 2 = long). */
119 32, /* Bitsize. */
120 TRUE, /* PC relative. */
121 0, /* Bitpos. */
122 complain_overflow_signed, /* Complain_on_overflow. */
123 0, /* Special_function. */
124 "R_REL", /* Name. */
125 TRUE, /* Partial_inplace. */
126 0xffffffff, /* Source mask. */
127 0xffffffff, /* Dest mask. */
128 FALSE), /* PC rel offset. */
130 /* 16 bit TOC relative relocation. */
131 HOWTO (3, /* Type. */
132 0, /* Rightshift. */
133 1, /* Size (0 = byte, 1 = short, 2 = long). */
134 16, /* Bitsize. */
135 FALSE, /* PC relative. */
136 0, /* Bitpos. */
137 complain_overflow_signed, /* Complain_on_overflow. */
138 0, /* Special_function. */
139 "R_TOC", /* Name. */
140 TRUE, /* Partial_inplace. */
141 0xffff, /* Source mask. */
142 0xffff, /* Dest mask. */
143 FALSE), /* PC rel offset. */
145 /* I don't really know what this is. */
146 HOWTO (4, /* Type. */
147 1, /* Rightshift. */
148 2, /* Size (0 = byte, 1 = short, 2 = long). */
149 32, /* Bitsize. */
150 FALSE, /* PC relative. */
151 0, /* Bitpos. */
152 complain_overflow_bitfield, /* Complain_on_overflow. */
153 0, /* Special_function. */
154 "R_RTB", /* Name. */
155 TRUE, /* Partial_inplace. */
156 0xffffffff, /* Source mask. */
157 0xffffffff, /* Dest mask. */
158 FALSE), /* PC rel offset. */
160 /* External TOC relative symbol. */
161 HOWTO (5, /* Type. */
162 0, /* Rightshift. */
163 2, /* Size (0 = byte, 1 = short, 2 = long). */
164 16, /* Bitsize. */
165 FALSE, /* PC relative. */
166 0, /* Bitpos. */
167 complain_overflow_bitfield, /* Complain_on_overflow. */
168 0, /* Special_function. */
169 "R_GL", /* Name. */
170 TRUE, /* Partial_inplace. */
171 0xffff, /* Source mask. */
172 0xffff, /* Dest mask. */
173 FALSE), /* PC rel offset. */
175 /* Local TOC relative symbol. */
176 HOWTO (6, /* Type. */
177 0, /* Rightshift. */
178 2, /* Size (0 = byte, 1 = short, 2 = long). */
179 16, /* Bitsize. */
180 FALSE, /* PC relative. */
181 0, /* Bitpos. */
182 complain_overflow_bitfield, /* Complain_on_overflow. */
183 0, /* Special_function. */
184 "R_TCL", /* Name. */
185 TRUE, /* Partial_inplace. */
186 0xffff, /* Source mask. */
187 0xffff, /* Dest mask. */
188 FALSE), /* PC rel offset. */
190 { 7 },
192 /* Non modifiable absolute branch. */
193 HOWTO (8, /* Type. */
194 0, /* Rightshift. */
195 2, /* Size (0 = byte, 1 = short, 2 = long). */
196 26, /* Bitsize. */
197 FALSE, /* PC relative. */
198 0, /* Bitpos. */
199 complain_overflow_bitfield, /* Complain_on_overflow. */
200 0, /* Special_function. */
201 "R_BA", /* Name. */
202 TRUE, /* Partial_inplace. */
203 0x3fffffc, /* Source mask. */
204 0x3fffffc, /* Dest mask. */
205 FALSE), /* PC rel offset. */
207 { 9 },
209 /* Non modifiable relative branch. */
210 HOWTO (0xa, /* Type. */
211 0, /* Rightshift. */
212 2, /* Size (0 = byte, 1 = short, 2 = long). */
213 26, /* Bitsize. */
214 TRUE, /* PC relative. */
215 0, /* Bitpos. */
216 complain_overflow_signed, /* Complain_on_overflow. */
217 0, /* Special_function. */
218 "R_BR", /* Name. */
219 TRUE, /* Partial_inplace. */
220 0x3fffffc, /* Source mask. */
221 0x3fffffc, /* Dest mask. */
222 FALSE), /* PC rel offset. */
224 { 0xb },
226 /* Indirect load. */
227 HOWTO (0xc, /* Type. */
228 0, /* Rightshift. */
229 2, /* Size (0 = byte, 1 = short, 2 = long). */
230 16, /* Bitsize. */
231 FALSE, /* PC relative. */
232 0, /* Bitpos. */
233 complain_overflow_bitfield, /* Complain_on_overflow. */
234 0, /* Special_function. */
235 "R_RL", /* Name. */
236 TRUE, /* Partial_inplace. */
237 0xffff, /* Source mask. */
238 0xffff, /* Dest mask. */
239 FALSE), /* PC rel offset. */
241 /* Load address. */
242 HOWTO (0xd, /* Type. */
243 0, /* Rightshift. */
244 2, /* Size (0 = byte, 1 = short, 2 = long). */
245 16, /* Bitsize. */
246 FALSE, /* PC relative. */
247 0, /* Bitpos. */
248 complain_overflow_bitfield, /* Complain_on_overflow. */
249 0, /* Special_function. */
250 "R_RLA", /* Name. */
251 TRUE, /* Partial_inplace. */
252 0xffff, /* Source mask. */
253 0xffff, /* Dest mask. */
254 FALSE), /* PC rel offset. */
256 { 0xe },
258 /* Non-relocating reference. */
259 HOWTO (0xf, /* Type. */
260 0, /* Rightshift. */
261 2, /* Size (0 = byte, 1 = short, 2 = long). */
262 32, /* Bitsize. */
263 FALSE, /* PC relative. */
264 0, /* Bitpos. */
265 complain_overflow_bitfield, /* Complain_on_overflow. */
266 0, /* Special_function. */
267 "R_REF", /* Name. */
268 FALSE, /* Partial_inplace. */
269 0, /* Source mask. */
270 0, /* Dest mask. */
271 FALSE), /* PC rel offset. */
273 { 0x10 },
274 { 0x11 },
276 /* TOC relative indirect load. */
277 HOWTO (0x12, /* Type. */
278 0, /* Rightshift. */
279 2, /* Size (0 = byte, 1 = short, 2 = long). */
280 16, /* Bitsize. */
281 FALSE, /* PC relative. */
282 0, /* Bitpos. */
283 complain_overflow_bitfield, /* Complain_on_overflow. */
284 0, /* Special_function. */
285 "R_TRL", /* Name. */
286 TRUE, /* Partial_inplace. */
287 0xffff, /* Source mask. */
288 0xffff, /* Dest mask. */
289 FALSE), /* PC rel offset. */
291 /* TOC relative load address. */
292 HOWTO (0x13, /* Type. */
293 0, /* Rightshift. */
294 2, /* Size (0 = byte, 1 = short, 2 = long). */
295 16, /* Bitsize. */
296 FALSE, /* PC relative. */
297 0, /* Bitpos. */
298 complain_overflow_bitfield, /* Complain_on_overflow. */
299 0, /* Special_function. */
300 "R_TRLA", /* Name. */
301 TRUE, /* Partial_inplace. */
302 0xffff, /* Source mask. */
303 0xffff, /* Dest mask. */
304 FALSE), /* PC rel offset. */
306 /* Modifiable relative branch. */
307 HOWTO (0x14, /* Type. */
308 1, /* Rightshift. */
309 2, /* Size (0 = byte, 1 = short, 2 = long). */
310 32, /* Bitsize. */
311 FALSE, /* PC relative. */
312 0, /* Bitpos. */
313 complain_overflow_bitfield, /* Complain_on_overflow. */
314 0, /* Special_function. */
315 "R_RRTBI", /* Name. */
316 TRUE, /* Partial_inplace. */
317 0xffffffff, /* Source mask. */
318 0xffffffff, /* Dest mask. */
319 FALSE), /* PC rel offset. */
321 /* Modifiable absolute branch. */
322 HOWTO (0x15, /* Type. */
323 1, /* Rightshift. */
324 2, /* Size (0 = byte, 1 = short, 2 = long). */
325 32, /* Bitsize. */
326 FALSE, /* PC relative. */
327 0, /* Bitpos. */
328 complain_overflow_bitfield, /* Complain_on_overflow. */
329 0, /* Special_function. */
330 "R_RRTBA", /* Name. */
331 TRUE, /* Partial_inplace. */
332 0xffffffff, /* Source mask. */
333 0xffffffff, /* Dest mask. */
334 FALSE), /* PC rel offset. */
336 /* Modifiable call absolute indirect. */
337 HOWTO (0x16, /* Type. */
338 0, /* Rightshift. */
339 2, /* Size (0 = byte, 1 = short, 2 = long). */
340 16, /* Bitsize. */
341 FALSE, /* PC relative. */
342 0, /* Bitpos. */
343 complain_overflow_bitfield, /* Complain_on_overflow. */
344 0, /* Special_function. */
345 "R_CAI", /* Name. */
346 TRUE, /* Partial_inplace. */
347 0xffff, /* Source mask. */
348 0xffff, /* Dest mask. */
349 FALSE), /* PC rel offset. */
351 /* Modifiable call relative. */
352 HOWTO (0x17, /* Type. */
353 0, /* Rightshift. */
354 2, /* Size (0 = byte, 1 = short, 2 = long). */
355 16, /* Bitsize. */
356 FALSE, /* PC relative. */
357 0, /* Bitpos. */
358 complain_overflow_bitfield, /* Complain_on_overflow. */
359 0, /* Special_function. */
360 "R_REL", /* Name. */
361 TRUE, /* Partial_inplace. */
362 0xffff, /* Source mask. */
363 0xffff, /* Dest mask. */
364 FALSE), /* PC rel offset. */
366 /* Modifiable branch absolute. */
367 HOWTO (0x18, /* Type. */
368 0, /* Rightshift. */
369 2, /* Size (0 = byte, 1 = short, 2 = long). */
370 16, /* Bitsize. */
371 FALSE, /* PC relative. */
372 0, /* Bitpos. */
373 complain_overflow_bitfield, /* Complain_on_overflow. */
374 0, /* Special_function. */
375 "R_RBA", /* Name. */
376 TRUE, /* Partial_inplace. */
377 0xffff, /* Source mask. */
378 0xffff, /* Dest mask. */
379 FALSE), /* PC rel offset. */
381 /* Modifiable branch absolute. */
382 HOWTO (0x19, /* Type. */
383 0, /* Rightshift. */
384 2, /* Size (0 = byte, 1 = short, 2 = long). */
385 16, /* Bitsize. */
386 FALSE, /* PC relative. */
387 0, /* Bitpos. */
388 complain_overflow_bitfield, /* Complain_on_overflow. */
389 0, /* Special_function. */
390 "R_RBAC", /* Name. */
391 TRUE, /* Partial_inplace. */
392 0xffff, /* Source mask. */
393 0xffff, /* Dest mask. */
394 FALSE), /* PC rel offset. */
396 /* Modifiable branch relative. */
397 HOWTO (0x1a, /* Type. */
398 0, /* Rightshift. */
399 2, /* Size (0 = byte, 1 = short, 2 = long). */
400 26, /* Bitsize. */
401 FALSE, /* PC relative. */
402 0, /* Bitpos. */
403 complain_overflow_signed, /* Complain_on_overflow. */
404 0, /* Special_function. */
405 "R_REL", /* Name. */
406 TRUE, /* Partial_inplace. */
407 0xffff, /* Source mask. */
408 0xffff, /* Dest mask. */
409 FALSE), /* PC rel offset. */
411 /* Modifiable branch absolute. */
412 HOWTO (0x1b, /* Type. */
413 0, /* Rightshift. */
414 2, /* Size (0 = byte, 1 = short, 2 = long). */
415 16, /* Bitsize. */
416 FALSE, /* PC relative. */
417 0, /* Bitpos. */
418 complain_overflow_bitfield, /* Complain_on_overflow. */
419 0, /* Special_function. */
420 "R_REL", /* Name. */
421 TRUE, /* Partial_inplace. */
422 0xffff, /* Source mask. */
423 0xffff, /* Dest mask. */
424 FALSE) /* PC rel offset. */
427 #define HOWTO_COUNT (sizeof nlm_powerpc_howto_table \
428 / sizeof nlm_powerpc_howto_table[0])
430 /* Read a PowerPC NLM reloc. */
432 static bfd_boolean
433 nlm_powerpc_read_reloc (bfd *abfd,
434 nlmNAME (symbol_type) *sym,
435 asection **secp,
436 arelent *rel)
438 struct nlm32_powerpc_external_reloc ext;
439 bfd_vma l_vaddr;
440 unsigned long l_symndx;
441 int l_rtype;
442 int l_rsecnm;
443 asection *code_sec, *data_sec, *bss_sec;
445 /* Read the reloc from the file. */
446 if (bfd_bread (&ext, (bfd_size_type) sizeof ext, abfd) != sizeof ext)
447 return FALSE;
449 /* Swap in the fields. */
450 l_vaddr = H_GET_32 (abfd, ext.l_vaddr);
451 l_symndx = H_GET_32 (abfd, ext.l_symndx);
452 l_rtype = H_GET_16 (abfd, ext.l_rtype);
453 l_rsecnm = H_GET_16 (abfd, ext.l_rsecnm);
455 /* Get the sections now, for convenience. */
456 code_sec = bfd_get_section_by_name (abfd, NLM_CODE_NAME);
457 data_sec = bfd_get_section_by_name (abfd, NLM_INITIALIZED_DATA_NAME);
458 bss_sec = bfd_get_section_by_name (abfd, NLM_UNINITIALIZED_DATA_NAME);
460 /* Work out the arelent fields. */
461 if (sym != NULL)
462 /* This is an import. sym_ptr_ptr is filled in by
463 nlm_canonicalize_reloc. */
464 rel->sym_ptr_ptr = NULL;
465 else
467 asection *sec;
469 if (l_symndx == 0)
470 sec = code_sec;
471 else if (l_symndx == 1)
472 sec = data_sec;
473 else if (l_symndx == 2)
474 sec = bss_sec;
475 else
477 bfd_set_error (bfd_error_bad_value);
478 return FALSE;
481 rel->sym_ptr_ptr = sec->symbol_ptr_ptr;
484 rel->addend = 0;
486 BFD_ASSERT ((l_rtype & 0xff) < HOWTO_COUNT);
488 rel->howto = nlm_powerpc_howto_table + (l_rtype & 0xff);
490 BFD_ASSERT (rel->howto->name != NULL
491 && ((l_rtype & 0x8000) != 0
492 ? (rel->howto->complain_on_overflow
493 == complain_overflow_signed)
494 : (rel->howto->complain_on_overflow
495 == complain_overflow_bitfield))
496 && ((l_rtype >> 8) & 0x1f) == rel->howto->bitsize - 1);
498 if (l_rsecnm == 0)
499 *secp = code_sec;
500 else if (l_rsecnm == 1)
502 *secp = data_sec;
503 l_vaddr -= code_sec->size;
505 else
507 bfd_set_error (bfd_error_bad_value);
508 return FALSE;
511 rel->address = l_vaddr;
513 return TRUE;
516 #else /* not OLDFORMAT */
518 /* There is only one type of reloc in a PowerPC NLM. */
520 static reloc_howto_type nlm_powerpc_howto =
521 HOWTO (0, /* Type. */
522 0, /* Rightshift. */
523 2, /* Size (0 = byte, 1 = short, 2 = long). */
524 32, /* Bitsize. */
525 FALSE, /* PC relative. */
526 0, /* Bitpos. */
527 complain_overflow_bitfield, /* Complain_on_overflow. */
528 0, /* Special_function. */
529 "32", /* Name. */
530 TRUE, /* Partial_inplace. */
531 0xffffffff, /* Source mask. */
532 0xffffffff, /* Dest mask. */
533 FALSE); /* PC rel_offset. */
535 /* Read a PowerPC NLM reloc. */
537 static bfd_boolean
538 nlm_powerpc_read_reloc (bfd *abfd,
539 nlmNAME (symbol_type) *sym,
540 asection **secp,
541 arelent *rel)
543 bfd_byte temp[4];
544 bfd_vma val;
545 const char *name;
547 if (bfd_bread (temp, (bfd_size_type) sizeof (temp), abfd) != sizeof (temp))
548 return FALSE;
550 val = bfd_get_32 (abfd, temp);
552 /* The value is a word offset into either the code or data segment.
553 This is the location which needs to be adjusted.
555 The high bit is 0 if the value is an offset into the data
556 segment, or 1 if the value is an offset into the text segment.
558 If this is a relocation fixup rather than an imported symbol (the
559 sym argument is NULL), then the second most significant bit is 0
560 if the address of the data segment should be added to the
561 location addressed by the value, or 1 if the address of the text
562 segment should be added.
564 If this is an imported symbol, the second most significant bit is
565 not used and must be 0. */
567 if ((val & NLM_HIBIT) == 0)
568 name = NLM_INITIALIZED_DATA_NAME;
569 else
571 name = NLM_CODE_NAME;
572 val &=~ NLM_HIBIT;
574 *secp = bfd_get_section_by_name (abfd, name);
576 if (sym == NULL)
578 if ((val & (NLM_HIBIT >> 1)) == 0)
579 name = NLM_INITIALIZED_DATA_NAME;
580 else
582 name = NLM_CODE_NAME;
583 val &=~ (NLM_HIBIT >> 1);
585 rel->sym_ptr_ptr = bfd_get_section_by_name (abfd, name)->symbol_ptr_ptr;
588 rel->howto = & nlm_powerpc_howto;
589 rel->address = val << 2;
590 rel->addend = 0;
592 return TRUE;
595 #endif /* not OLDFORMAT */
597 /* Mangle PowerPC NLM relocs for output. */
599 static bfd_boolean
600 nlm_powerpc_mangle_relocs (bfd *abfd ATTRIBUTE_UNUSED,
601 asection *sec ATTRIBUTE_UNUSED,
602 const void * data ATTRIBUTE_UNUSED,
603 bfd_vma offset ATTRIBUTE_UNUSED,
604 bfd_size_type count ATTRIBUTE_UNUSED)
606 return TRUE;
609 /* Read a PowerPC NLM import record */
611 static bfd_boolean
612 nlm_powerpc_read_import (bfd * abfd, nlmNAME (symbol_type) * sym)
614 struct nlm_relent *nlm_relocs; /* Relocation records for symbol. */
615 bfd_size_type rcount; /* Number of relocs. */
616 bfd_byte temp[NLM_TARGET_LONG_SIZE]; /* Temporary 32-bit value. */
617 unsigned char symlength; /* Length of symbol name. */
618 char *name;
620 if (bfd_bread (& symlength, (bfd_size_type) sizeof (symlength), abfd)
621 != sizeof (symlength))
622 return FALSE;
623 sym -> symbol.the_bfd = abfd;
624 name = bfd_alloc (abfd, (bfd_size_type) symlength + 1);
625 if (name == NULL)
626 return FALSE;
627 if (bfd_bread (name, (bfd_size_type) symlength, abfd) != symlength)
628 return FALSE;
629 name[symlength] = '\0';
630 sym -> symbol.name = name;
631 sym -> symbol.flags = 0;
632 sym -> symbol.value = 0;
633 sym -> symbol.section = bfd_und_section_ptr;
634 if (bfd_bread (temp, (bfd_size_type) sizeof (temp), abfd)
635 != sizeof (temp))
636 return FALSE;
637 rcount = H_GET_32 (abfd, temp);
638 nlm_relocs = bfd_alloc (abfd, rcount * sizeof (struct nlm_relent));
639 if (nlm_relocs == NULL)
640 return FALSE;
641 sym -> relocs = nlm_relocs;
642 sym -> rcnt = 0;
643 while (sym -> rcnt < rcount)
645 asection *section;
647 if (! nlm_powerpc_read_reloc (abfd, sym, &section, &nlm_relocs -> reloc))
648 return FALSE;
649 nlm_relocs -> section = section;
650 nlm_relocs++;
651 sym -> rcnt++;
653 return TRUE;
656 #ifndef OLDFORMAT
658 /* Write a PowerPC NLM reloc. */
660 static bfd_boolean
661 nlm_powerpc_write_import (bfd * abfd, asection * sec, arelent * rel)
663 asymbol *sym;
664 bfd_vma val;
665 bfd_byte temp[4];
667 /* PowerPC NetWare only supports one kind of reloc. */
668 if (rel->addend != 0
669 || rel->howto == NULL
670 || rel->howto->rightshift != 0
671 || rel->howto->size != 2
672 || rel->howto->bitsize != 32
673 || rel->howto->bitpos != 0
674 || rel->howto->pc_relative
675 || (rel->howto->src_mask != 0xffffffff && rel->addend != 0)
676 || rel->howto->dst_mask != 0xffffffff)
678 bfd_set_error (bfd_error_invalid_operation);
679 return FALSE;
682 sym = *rel->sym_ptr_ptr;
684 /* The value we write out is the offset into the appropriate
685 segment, rightshifted by two. This offset is the section vma,
686 adjusted by the vma of the lowest section in that segment, plus
687 the address of the relocation. */
688 val = bfd_get_section_vma (abfd, sec) + rel->address;
689 if ((val & 3) != 0)
691 bfd_set_error (bfd_error_bad_value);
692 return FALSE;
694 val >>= 2;
696 /* The high bit is 0 if the reloc is in the data section, or 1 if
697 the reloc is in the code section. */
698 if (bfd_get_section_flags (abfd, sec) & SEC_DATA)
699 val -= nlm_get_data_low (abfd);
700 else
702 val -= nlm_get_text_low (abfd);
703 val |= NLM_HIBIT;
706 if (! bfd_is_und_section (bfd_get_section (sym)))
708 /* This is an internal relocation fixup. The second most
709 significant bit is 0 if this is a reloc against the data
710 segment, or 1 if it is a reloc against the text segment. */
711 if (bfd_get_section_flags (abfd, bfd_get_section (sym)) & SEC_CODE)
712 val |= NLM_HIBIT >> 1;
715 bfd_put_32 (abfd, val, temp);
716 if (bfd_bwrite (temp, (bfd_size_type) sizeof (temp), abfd) != sizeof (temp))
717 return FALSE;
719 return TRUE;
722 #else /* OLDFORMAT */
724 /* This is used for the reloc handling in the old format. */
726 /* Write a PowerPC NLM reloc. */
728 static bfd_boolean
729 nlm_powerpc_write_reloc (bfd *abfd,
730 asection *sec,
731 arelent *rel,
732 int indx)
734 struct nlm32_powerpc_external_reloc ext;
735 asection *code_sec, *data_sec, *bss_sec;
736 asymbol *sym;
737 asection *symsec;
738 unsigned long l_symndx;
739 int l_rtype;
740 int l_rsecnm;
741 reloc_howto_type *howto;
742 bfd_size_type address;
744 /* Get the sections now, for convenience. */
745 code_sec = bfd_get_section_by_name (abfd, NLM_CODE_NAME);
746 data_sec = bfd_get_section_by_name (abfd, NLM_INITIALIZED_DATA_NAME);
747 bss_sec = bfd_get_section_by_name (abfd, NLM_UNINITIALIZED_DATA_NAME);
749 sym = *rel->sym_ptr_ptr;
750 symsec = bfd_get_section (sym);
751 if (indx != -1)
753 BFD_ASSERT (bfd_is_und_section (symsec));
754 l_symndx = indx + 3;
756 else
758 if (symsec == code_sec)
759 l_symndx = 0;
760 else if (symsec == data_sec)
761 l_symndx = 1;
762 else if (symsec == bss_sec)
763 l_symndx = 2;
764 else
766 bfd_set_error (bfd_error_bad_value);
767 return FALSE;
771 H_PUT_32 (abfd, l_symndx, ext.l_symndx);
773 for (howto = nlm_powerpc_howto_table;
774 howto < nlm_powerpc_howto_table + HOWTO_COUNT;
775 howto++)
777 if (howto->rightshift == rel->howto->rightshift
778 && howto->size == rel->howto->size
779 && howto->bitsize == rel->howto->bitsize
780 && howto->pc_relative == rel->howto->pc_relative
781 && howto->bitpos == rel->howto->bitpos
782 && (howto->partial_inplace == rel->howto->partial_inplace
783 || (! rel->howto->partial_inplace
784 && rel->addend == 0))
785 && (howto->src_mask == rel->howto->src_mask
786 || (rel->howto->src_mask == 0
787 && rel->addend == 0))
788 && howto->dst_mask == rel->howto->dst_mask
789 && howto->pcrel_offset == rel->howto->pcrel_offset)
790 break;
792 if (howto >= nlm_powerpc_howto_table + HOWTO_COUNT)
794 bfd_set_error (bfd_error_bad_value);
795 return FALSE;
798 l_rtype = howto->type;
799 if (howto->complain_on_overflow == complain_overflow_signed)
800 l_rtype |= 0x8000;
801 l_rtype |= (howto->bitsize - 1) << 8;
802 H_PUT_16 (abfd, l_rtype, ext.l_rtype);
804 address = rel->address;
806 if (sec == code_sec)
807 l_rsecnm = 0;
808 else if (sec == data_sec)
810 l_rsecnm = 1;
811 address += code_sec->size;
813 else
815 bfd_set_error (bfd_error_bad_value);
816 return FALSE;
819 H_PUT_16 (abfd, l_rsecnm, ext.l_rsecnm);
820 H_PUT_32 (abfd, address, ext.l_vaddr);
822 if (bfd_bwrite (&ext, (bfd_size_type) sizeof ext, abfd) != sizeof ext)
823 return FALSE;
825 return TRUE;
828 /* Write a PowerPC NLM import. */
830 static bfd_boolean
831 nlm_powerpc_write_import (bfd * abfd, asection * sec, arelent * rel)
833 return nlm_powerpc_write_reloc (abfd, sec, rel, -1);
836 #endif /* OLDFORMAT */
838 /* Write a PowerPC NLM external symbol. This routine keeps a static
839 count of the symbol index. FIXME: I don't know if this is
840 necessary, and the index never gets reset. */
842 static bfd_boolean
843 nlm_powerpc_write_external (bfd *abfd,
844 bfd_size_type count,
845 asymbol *sym,
846 struct reloc_and_sec *relocs)
848 unsigned int i;
849 bfd_byte len;
850 unsigned char temp[NLM_TARGET_LONG_SIZE];
851 #ifdef OLDFORMAT
852 static int indx;
853 #endif
855 len = strlen (sym->name);
856 if ((bfd_bwrite (&len, (bfd_size_type) sizeof (bfd_byte), abfd)
857 != sizeof (bfd_byte))
858 || bfd_bwrite (sym->name, (bfd_size_type) len, abfd) != len)
859 return FALSE;
861 bfd_put_32 (abfd, count, temp);
862 if (bfd_bwrite (temp, (bfd_size_type) sizeof (temp), abfd) != sizeof (temp))
863 return FALSE;
865 for (i = 0; i < count; i++)
867 #ifndef OLDFORMAT
868 if (! nlm_powerpc_write_import (abfd, relocs[i].sec, relocs[i].rel))
869 return FALSE;
870 #else
871 if (! nlm_powerpc_write_reloc (abfd, relocs[i].sec,
872 relocs[i].rel, indx))
873 return FALSE;
874 #endif
877 #ifdef OLDFORMAT
878 ++indx;
879 #endif
881 return TRUE;
884 #ifndef OLDFORMAT
886 /* PowerPC Netware uses a word offset, not a byte offset, for public
887 symbols. */
889 /* Set the section for a public symbol. */
891 static bfd_boolean
892 nlm_powerpc_set_public_section (bfd *abfd, nlmNAME (symbol_type) *sym)
894 if (sym->symbol.value & NLM_HIBIT)
896 sym->symbol.value &= ~NLM_HIBIT;
897 sym->symbol.flags |= BSF_FUNCTION;
898 sym->symbol.section =
899 bfd_get_section_by_name (abfd, NLM_CODE_NAME);
901 else
902 sym->symbol.section =
903 bfd_get_section_by_name (abfd, NLM_INITIALIZED_DATA_NAME);
905 sym->symbol.value <<= 2;
907 return TRUE;
910 /* Get the offset to write out for a public symbol. */
912 static bfd_vma
913 nlm_powerpc_get_public_offset (bfd *abfd, asymbol *sym)
915 bfd_vma offset;
916 asection *sec;
918 offset = bfd_asymbol_value (sym);
919 sec = bfd_get_section (sym);
920 if (sec->flags & SEC_CODE)
922 offset -= nlm_get_text_low (abfd);
923 offset |= NLM_HIBIT;
925 else if (sec->flags & (SEC_DATA | SEC_ALLOC))
927 /* SEC_ALLOC is for the .bss section. */
928 offset -= nlm_get_data_low (abfd);
930 else
932 /* We can't handle an exported symbol that is not in the code or
933 data segment. */
934 bfd_set_error (bfd_error_invalid_operation);
935 /* FIXME: No way to return error. */
936 abort ();
939 return offset;
942 #endif /* ! defined (OLDFORMAT) */
944 #include "nlmswap.h"
946 static const struct nlm_backend_data nlm32_powerpc_backend =
948 "NetWare PowerPC Module \032",
949 sizeof (Nlm32_powerpc_External_Fixed_Header),
950 #ifndef OLDFORMAT
951 0, /* Optional_prefix_size. */
952 #else
953 sizeof (struct nlm32_powerpc_external_prefix_header),
954 #endif
955 bfd_arch_powerpc,
957 FALSE,
958 #ifndef OLDFORMAT
959 0, /* Backend_object_p. */
960 0, /* Write_prefix. */
961 #else
962 nlm_powerpc_backend_object_p,
963 nlm_powerpc_write_prefix,
964 #endif
965 nlm_powerpc_read_reloc,
966 nlm_powerpc_mangle_relocs,
967 nlm_powerpc_read_import,
968 nlm_powerpc_write_import,
969 #ifndef OLDFORMAT
970 nlm_powerpc_set_public_section,
971 nlm_powerpc_get_public_offset,
972 #else
973 0, /* Set_public_section. */
974 0, /* Get_public_offset. */
975 #endif
976 nlm_swap_fixed_header_in,
977 nlm_swap_fixed_header_out,
978 nlm_powerpc_write_external,
979 0, /* Write_export. */
982 #define TARGET_BIG_NAME "nlm32-powerpc"
983 #define TARGET_BIG_SYM nlmNAME (powerpc_vec)
984 #define TARGET_BACKEND_DATA & nlm32_powerpc_backend
986 #include "nlm-target.h"