]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - bfd/nlm32-ppc.c
Switch sources over to use the GPL version 3
[thirdparty/binutils-gdb.git] / bfd / nlm32-ppc.c
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.
4
5 This file is part of BFD, the Binary File Descriptor library.
6
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.
11
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.
16
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. */
21
22 #include "bfd.h"
23 #include "sysdep.h"
24 #include "libbfd.h"
25
26 /* The format of a PowerPC NLM changed. Define OLDFORMAT to get the
27 old format. */
28
29 #define ARCH_SIZE 32
30
31 #include "nlm/ppc-ext.h"
32 #define Nlm_External_Fixed_Header Nlm32_powerpc_External_Fixed_Header
33
34 #include "libnlm.h"
35 \f
36 #ifdef OLDFORMAT
37
38 /* The prefix header is only used in the old format. */
39
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. */
43
44 static bfd_boolean
45 nlm_powerpc_backend_object_p (bfd *abfd)
46 {
47 struct nlm32_powerpc_external_prefix_header s;
48
49 if (bfd_bread (& s, (bfd_size_type) sizeof s, abfd) != sizeof s)
50 return FALSE;
51
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;
55
56 return TRUE;
57 }
58
59 /* Write out the prefix. */
60
61 static bfd_boolean
62 nlm_powerpc_write_prefix (bfd *abfd)
63 {
64 struct nlm32_powerpc_external_prefix_header s;
65
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);
70
71 /* FIXME: What should we do about the date? */
72
73 if (bfd_bwrite (& s, (bfd_size_type) sizeof s, abfd) != sizeof s)
74 return FALSE;
75
76 return TRUE;
77 }
78
79 /* This reloc handling is only applicable to the old format. */
80
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. */
83
84 static reloc_howto_type nlm_powerpc_howto_table[] =
85 {
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. */
100
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. */
115
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. */
130
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. */
145
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. */
160
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. */
175
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. */
190
191 { 7 },
192
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. */
207
208 { 9 },
209
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. */
224
225 { 0xb },
226
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. */
241
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. */
256
257 { 0xe },
258
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. */
273
274 { 0x10 },
275 { 0x11 },
276
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. */
291
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. */
306
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. */
321
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. */
336
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. */
351
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. */
366
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. */
381
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. */
396
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. */
411
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. */
426 };
427
428 #define HOWTO_COUNT (sizeof nlm_powerpc_howto_table \
429 / sizeof nlm_powerpc_howto_table[0])
430
431 /* Read a PowerPC NLM reloc. */
432
433 static bfd_boolean
434 nlm_powerpc_read_reloc (bfd *abfd,
435 nlmNAME (symbol_type) *sym,
436 asection **secp,
437 arelent *rel)
438 {
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;
445
446 /* Read the reloc from the file. */
447 if (bfd_bread (&ext, (bfd_size_type) sizeof ext, abfd) != sizeof ext)
448 return FALSE;
449
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);
455
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);
460
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
467 {
468 asection *sec;
469
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
477 {
478 bfd_set_error (bfd_error_bad_value);
479 return FALSE;
480 }
481
482 rel->sym_ptr_ptr = sec->symbol_ptr_ptr;
483 }
484
485 rel->addend = 0;
486
487 BFD_ASSERT ((l_rtype & 0xff) < HOWTO_COUNT);
488
489 rel->howto = nlm_powerpc_howto_table + (l_rtype & 0xff);
490
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);
498
499 if (l_rsecnm == 0)
500 *secp = code_sec;
501 else if (l_rsecnm == 1)
502 {
503 *secp = data_sec;
504 l_vaddr -= code_sec->size;
505 }
506 else
507 {
508 bfd_set_error (bfd_error_bad_value);
509 return FALSE;
510 }
511
512 rel->address = l_vaddr;
513
514 return TRUE;
515 }
516
517 #else /* not OLDFORMAT */
518
519 /* There is only one type of reloc in a PowerPC NLM. */
520
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. */
535
536 /* Read a PowerPC NLM reloc. */
537
538 static bfd_boolean
539 nlm_powerpc_read_reloc (bfd *abfd,
540 nlmNAME (symbol_type) *sym,
541 asection **secp,
542 arelent *rel)
543 {
544 bfd_byte temp[4];
545 bfd_vma val;
546 const char *name;
547
548 if (bfd_bread (temp, (bfd_size_type) sizeof (temp), abfd) != sizeof (temp))
549 return FALSE;
550
551 val = bfd_get_32 (abfd, temp);
552
553 /* The value is a word offset into either the code or data segment.
554 This is the location which needs to be adjusted.
555
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.
558
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.
564
565 If this is an imported symbol, the second most significant bit is
566 not used and must be 0. */
567
568 if ((val & NLM_HIBIT) == 0)
569 name = NLM_INITIALIZED_DATA_NAME;
570 else
571 {
572 name = NLM_CODE_NAME;
573 val &=~ NLM_HIBIT;
574 }
575 *secp = bfd_get_section_by_name (abfd, name);
576
577 if (sym == NULL)
578 {
579 if ((val & (NLM_HIBIT >> 1)) == 0)
580 name = NLM_INITIALIZED_DATA_NAME;
581 else
582 {
583 name = NLM_CODE_NAME;
584 val &=~ (NLM_HIBIT >> 1);
585 }
586 rel->sym_ptr_ptr = bfd_get_section_by_name (abfd, name)->symbol_ptr_ptr;
587 }
588
589 rel->howto = & nlm_powerpc_howto;
590 rel->address = val << 2;
591 rel->addend = 0;
592
593 return TRUE;
594 }
595
596 #endif /* not OLDFORMAT */
597
598 /* Mangle PowerPC NLM relocs for output. */
599
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)
606 {
607 return TRUE;
608 }
609
610 /* Read a PowerPC NLM import record */
611
612 static bfd_boolean
613 nlm_powerpc_read_import (bfd * abfd, nlmNAME (symbol_type) * sym)
614 {
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;
620
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)
645 {
646 asection *section;
647
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++;
653 }
654 return TRUE;
655 }
656
657 #ifndef OLDFORMAT
658
659 /* Write a PowerPC NLM reloc. */
660
661 static bfd_boolean
662 nlm_powerpc_write_import (bfd * abfd, asection * sec, arelent * rel)
663 {
664 asymbol *sym;
665 bfd_vma val;
666 bfd_byte temp[4];
667
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)
678 {
679 bfd_set_error (bfd_error_invalid_operation);
680 return FALSE;
681 }
682
683 sym = *rel->sym_ptr_ptr;
684
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)
691 {
692 bfd_set_error (bfd_error_bad_value);
693 return FALSE;
694 }
695 val >>= 2;
696
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
702 {
703 val -= nlm_get_text_low (abfd);
704 val |= NLM_HIBIT;
705 }
706
707 if (! bfd_is_und_section (bfd_get_section (sym)))
708 {
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;
714 }
715
716 bfd_put_32 (abfd, val, temp);
717 if (bfd_bwrite (temp, (bfd_size_type) sizeof (temp), abfd) != sizeof (temp))
718 return FALSE;
719
720 return TRUE;
721 }
722
723 #else /* OLDFORMAT */
724
725 /* This is used for the reloc handling in the old format. */
726
727 /* Write a PowerPC NLM reloc. */
728
729 static bfd_boolean
730 nlm_powerpc_write_reloc (bfd *abfd,
731 asection *sec,
732 arelent *rel,
733 int indx)
734 {
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;
744
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);
749
750 sym = *rel->sym_ptr_ptr;
751 symsec = bfd_get_section (sym);
752 if (indx != -1)
753 {
754 BFD_ASSERT (bfd_is_und_section (symsec));
755 l_symndx = indx + 3;
756 }
757 else
758 {
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
766 {
767 bfd_set_error (bfd_error_bad_value);
768 return FALSE;
769 }
770 }
771
772 H_PUT_32 (abfd, l_symndx, ext.l_symndx);
773
774 for (howto = nlm_powerpc_howto_table;
775 howto < nlm_powerpc_howto_table + HOWTO_COUNT;
776 howto++)
777 {
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;
792 }
793 if (howto >= nlm_powerpc_howto_table + HOWTO_COUNT)
794 {
795 bfd_set_error (bfd_error_bad_value);
796 return FALSE;
797 }
798
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);
804
805 address = rel->address;
806
807 if (sec == code_sec)
808 l_rsecnm = 0;
809 else if (sec == data_sec)
810 {
811 l_rsecnm = 1;
812 address += code_sec->size;
813 }
814 else
815 {
816 bfd_set_error (bfd_error_bad_value);
817 return FALSE;
818 }
819
820 H_PUT_16 (abfd, l_rsecnm, ext.l_rsecnm);
821 H_PUT_32 (abfd, address, ext.l_vaddr);
822
823 if (bfd_bwrite (&ext, (bfd_size_type) sizeof ext, abfd) != sizeof ext)
824 return FALSE;
825
826 return TRUE;
827 }
828
829 /* Write a PowerPC NLM import. */
830
831 static bfd_boolean
832 nlm_powerpc_write_import (bfd * abfd, asection * sec, arelent * rel)
833 {
834 return nlm_powerpc_write_reloc (abfd, sec, rel, -1);
835 }
836
837 #endif /* OLDFORMAT */
838
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. */
842
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)
848 {
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
855
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;
861
862 bfd_put_32 (abfd, count, temp);
863 if (bfd_bwrite (temp, (bfd_size_type) sizeof (temp), abfd) != sizeof (temp))
864 return FALSE;
865
866 for (i = 0; i < count; i++)
867 {
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
876 }
877
878 #ifdef OLDFORMAT
879 ++indx;
880 #endif
881
882 return TRUE;
883 }
884 \f
885 #ifndef OLDFORMAT
886
887 /* PowerPC Netware uses a word offset, not a byte offset, for public
888 symbols. */
889
890 /* Set the section for a public symbol. */
891
892 static bfd_boolean
893 nlm_powerpc_set_public_section (bfd *abfd, nlmNAME (symbol_type) *sym)
894 {
895 if (sym->symbol.value & NLM_HIBIT)
896 {
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);
901 }
902 else
903 sym->symbol.section =
904 bfd_get_section_by_name (abfd, NLM_INITIALIZED_DATA_NAME);
905
906 sym->symbol.value <<= 2;
907
908 return TRUE;
909 }
910
911 /* Get the offset to write out for a public symbol. */
912
913 static bfd_vma
914 nlm_powerpc_get_public_offset (bfd *abfd, asymbol *sym)
915 {
916 bfd_vma offset;
917 asection *sec;
918
919 offset = bfd_asymbol_value (sym);
920 sec = bfd_get_section (sym);
921 if (sec->flags & SEC_CODE)
922 {
923 offset -= nlm_get_text_low (abfd);
924 offset |= NLM_HIBIT;
925 }
926 else if (sec->flags & (SEC_DATA | SEC_ALLOC))
927 {
928 /* SEC_ALLOC is for the .bss section. */
929 offset -= nlm_get_data_low (abfd);
930 }
931 else
932 {
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 ();
938 }
939
940 return offset;
941 }
942
943 #endif /* ! defined (OLDFORMAT) */
944 \f
945 #include "nlmswap.h"
946
947 static const struct nlm_backend_data nlm32_powerpc_backend =
948 {
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,
957 0,
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. */
981 };
982
983 #define TARGET_BIG_NAME "nlm32-powerpc"
984 #define TARGET_BIG_SYM nlmNAME (powerpc_vec)
985 #define TARGET_BACKEND_DATA & nlm32_powerpc_backend
986
987 #include "nlm-target.h"