source: trunk/src/binutils/bfd/nlm32-ppc.c@ 610

Last change on this file since 610 was 610, checked in by bird, 22 years ago

This commit was generated by cvs2svn to compensate for changes in r609,
which included commits to RCS files with non-trunk default branches.

  • Property cvs2svn:cvs-rev set to 1.1.1.2
  • Property svn:eol-style set to native
  • Property svn:executable set to *
File size: 30.4 KB
Line 
1/* Support for 32-bit PowerPC NLM (NetWare Loadable Module)
2 Copyright 1994, 1995, 2000, 2001, 2002 Free Software Foundation, Inc.
3
4This file is part of BFD, the Binary File Descriptor library.
5
6This program is free software; you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation; either version 2 of the License, or
9(at your option) any later version.
10
11This program is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with this program; if not, write to the Free Software
18Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
19
20#include "bfd.h"
21#include "sysdep.h"
22#include "libbfd.h"
23
24/* The format of a PowerPC NLM changed. Define OLDFORMAT to get the
25 old format. */
26
27#define ARCH_SIZE 32
28
29#include "nlm/ppc-ext.h"
30#define Nlm_External_Fixed_Header Nlm32_powerpc_External_Fixed_Header
31
32#include "libnlm.h"
33
34#ifdef OLDFORMAT
35static bfd_boolean nlm_powerpc_backend_object_p
36 PARAMS ((bfd *));
37static bfd_boolean nlm_powerpc_write_prefix
38 PARAMS ((bfd *));
39#endif
40
41static bfd_boolean nlm_powerpc_read_reloc
42 PARAMS ((bfd *, nlmNAME(symbol_type) *, asection **, arelent *));
43static bfd_boolean nlm_powerpc_mangle_relocs
44 PARAMS ((bfd *, asection *, PTR, bfd_vma, bfd_size_type));
45static bfd_boolean nlm_powerpc_read_import
46 PARAMS ((bfd *, nlmNAME(symbol_type) *));
47
48#ifdef OLDFORMAT
49static bfd_boolean nlm_powerpc_write_reloc
50 PARAMS ((bfd *, asection *, arelent *, int));
51#endif
52
53static bfd_boolean nlm_powerpc_write_import
54 PARAMS ((bfd *, asection *, arelent *));
55static bfd_boolean nlm_powerpc_write_external
56 PARAMS ((bfd *, bfd_size_type, asymbol *, struct reloc_and_sec *));
57
58#ifndef OLDFORMAT
59static bfd_boolean nlm_powerpc_set_public_section
60 PARAMS ((bfd *, nlmNAME(symbol_type) *));
61static bfd_vma nlm_powerpc_get_public_offset
62 PARAMS ((bfd *, asymbol *));
63#endif
64
65
66#ifdef OLDFORMAT
67
68/* The prefix header is only used in the old format. */
69
70/* PowerPC NLM's have a prefix header before the standard NLM. This
71 function reads it in, verifies the version, and seeks the bfd to
72 the location before the regular NLM header. */
73
74static bfd_boolean
75nlm_powerpc_backend_object_p (abfd)
76 bfd *abfd;
77{
78 struct nlm32_powerpc_external_prefix_header s;
79
80 if (bfd_bread ((PTR) &s, (bfd_size_type) sizeof s, abfd) != sizeof s)
81 return FALSE;
82
83 if (memcmp (s.signature, NLM32_POWERPC_SIGNATURE, sizeof s.signature) != 0
84 || H_GET_32 (abfd, s.headerVersion) != NLM32_POWERPC_HEADER_VERSION)
85 return FALSE;
86
87 return TRUE;
88}
89
90/* Write out the prefix. */
91
92static bfd_boolean
93nlm_powerpc_write_prefix (abfd)
94 bfd *abfd;
95{
96 struct nlm32_powerpc_external_prefix_header s;
97
98 memset (&s, 0, sizeof s);
99 memcpy (s.signature, NLM32_POWERPC_SIGNATURE, sizeof s.signature);
100 H_PUT_32 (abfd, NLM32_POWERPC_HEADER_VERSION, s.headerVersion);
101 H_PUT_32 (abfd, 0, s.origins);
102
103 /* FIXME: What should we do about the date? */
104
105 if (bfd_bwrite ((PTR) &s, (bfd_size_type) sizeof s, abfd) != sizeof s)
106 return FALSE;
107
108 return TRUE;
109}
110
111#endif /* OLDFORMAT */
112
113
114#ifndef OLDFORMAT
115
116/* There is only one type of reloc in a PowerPC NLM. */
117
118static reloc_howto_type nlm_powerpc_howto =
119 HOWTO (0, /* type */
120 0, /* rightshift */
121 2, /* size (0 = byte, 1 = short, 2 = long) */
122 32, /* bitsize */
123 FALSE, /* pc_relative */
124 0, /* bitpos */
125 complain_overflow_bitfield, /* complain_on_overflow */
126 0, /* special_function */
127 "32", /* name */
128 TRUE, /* partial_inplace */
129 0xffffffff, /* src_mask */
130 0xffffffff, /* dst_mask */
131 FALSE); /* pcrel_offset */
132
133/* Read a PowerPC NLM reloc. */
134
135static bfd_boolean
136nlm_powerpc_read_reloc (abfd, sym, secp, rel)
137 bfd *abfd;
138 nlmNAME(symbol_type) *sym;
139 asection **secp;
140 arelent *rel;
141{
142 bfd_byte temp[4];
143 bfd_vma val;
144 const char *name;
145
146 if (bfd_bread (temp, (bfd_size_type) sizeof (temp), abfd) != sizeof (temp))
147 return FALSE;
148
149 val = bfd_get_32 (abfd, temp);
150
151 /* The value is a word offset into either the code or data segment.
152 This is the location which needs to be adjusted.
153
154 The high bit is 0 if the value is an offset into the data
155 segment, or 1 if the value is an offset into the text segment.
156
157 If this is a relocation fixup rather than an imported symbol (the
158 sym argument is NULL), then the second most significant bit is 0
159 if the address of the data segment should be added to the
160 location addressed by the value, or 1 if the address of the text
161 segment should be added.
162
163 If this is an imported symbol, the second most significant bit is
164 not used and must be 0. */
165
166 if ((val & NLM_HIBIT) == 0)
167 name = NLM_INITIALIZED_DATA_NAME;
168 else
169 {
170 name = NLM_CODE_NAME;
171 val &=~ NLM_HIBIT;
172 }
173 *secp = bfd_get_section_by_name (abfd, name);
174
175 if (sym == NULL)
176 {
177 if ((val & (NLM_HIBIT >> 1)) == 0)
178 name = NLM_INITIALIZED_DATA_NAME;
179 else
180 {
181 name = NLM_CODE_NAME;
182 val &=~ (NLM_HIBIT >> 1);
183 }
184 rel->sym_ptr_ptr = bfd_get_section_by_name (abfd, name)->symbol_ptr_ptr;
185 }
186
187 rel->howto = &nlm_powerpc_howto;
188
189 rel->address = val << 2;
190 rel->addend = 0;
191
192 return TRUE;
193}
194
195#else /* OLDFORMAT */
196
197/* This reloc handling is only applicable to the old format. */
198
199/* How to process the various reloc types. PowerPC NLMs use XCOFF
200 reloc types, and I have just copied the XCOFF reloc table here. */
201
202static reloc_howto_type nlm_powerpc_howto_table[] =
203{
204 /* Standard 32 bit relocation. */
205 HOWTO (0, /* type */
206 0, /* rightshift */
207 2, /* size (0 = byte, 1 = short, 2 = long) */
208 32, /* bitsize */
209 FALSE, /* pc_relative */
210 0, /* bitpos */
211 complain_overflow_bitfield, /* complain_on_overflow */
212 0, /* special_function */
213 "R_POS", /* name */
214 TRUE, /* partial_inplace */
215 0xffffffff, /* src_mask */
216 0xffffffff, /* dst_mask */
217 FALSE), /* pcrel_offset */
218
219 /* 32 bit relocation, but store negative value. */
220 HOWTO (1, /* type */
221 0, /* rightshift */
222 -2, /* size (0 = byte, 1 = short, 2 = long) */
223 32, /* bitsize */
224 FALSE, /* pc_relative */
225 0, /* bitpos */
226 complain_overflow_bitfield, /* complain_on_overflow */
227 0, /* special_function */
228 "R_NEG", /* name */
229 TRUE, /* partial_inplace */
230 0xffffffff, /* src_mask */
231 0xffffffff, /* dst_mask */
232 FALSE), /* pcrel_offset */
233
234 /* 32 bit PC relative relocation. */
235 HOWTO (2, /* type */
236 0, /* rightshift */
237 2, /* size (0 = byte, 1 = short, 2 = long) */
238 32, /* bitsize */
239 TRUE, /* pc_relative */
240 0, /* bitpos */
241 complain_overflow_signed, /* complain_on_overflow */
242 0, /* special_function */
243 "R_REL", /* name */
244 TRUE, /* partial_inplace */
245 0xffffffff, /* src_mask */
246 0xffffffff, /* dst_mask */
247 FALSE), /* pcrel_offset */
248
249 /* 16 bit TOC relative relocation. */
250 HOWTO (3, /* type */
251 0, /* rightshift */
252 1, /* size (0 = byte, 1 = short, 2 = long) */
253 16, /* bitsize */
254 FALSE, /* pc_relative */
255 0, /* bitpos */
256 complain_overflow_signed, /* complain_on_overflow */
257 0, /* special_function */
258 "R_TOC", /* name */
259 TRUE, /* partial_inplace */
260 0xffff, /* src_mask */
261 0xffff, /* dst_mask */
262 FALSE), /* pcrel_offset */
263
264 /* I don't really know what this is. */
265 HOWTO (4, /* type */
266 1, /* rightshift */
267 2, /* size (0 = byte, 1 = short, 2 = long) */
268 32, /* bitsize */
269 FALSE, /* pc_relative */
270 0, /* bitpos */
271 complain_overflow_bitfield, /* complain_on_overflow */
272 0, /* special_function */
273 "R_RTB", /* name */
274 TRUE, /* partial_inplace */
275 0xffffffff, /* src_mask */
276 0xffffffff, /* dst_mask */
277 FALSE), /* pcrel_offset */
278
279 /* External TOC relative symbol. */
280 HOWTO (5, /* type */
281 0, /* rightshift */
282 2, /* size (0 = byte, 1 = short, 2 = long) */
283 16, /* bitsize */
284 FALSE, /* pc_relative */
285 0, /* bitpos */
286 complain_overflow_bitfield, /* complain_on_overflow */
287 0, /* special_function */
288 "R_GL", /* name */
289 TRUE, /* partial_inplace */
290 0xffff, /* src_mask */
291 0xffff, /* dst_mask */
292 FALSE), /* pcrel_offset */
293
294 /* Local TOC relative symbol. */
295 HOWTO (6, /* type */
296 0, /* rightshift */
297 2, /* size (0 = byte, 1 = short, 2 = long) */
298 16, /* bitsize */
299 FALSE, /* pc_relative */
300 0, /* bitpos */
301 complain_overflow_bitfield, /* complain_on_overflow */
302 0, /* special_function */
303 "R_TCL", /* name */
304 TRUE, /* partial_inplace */
305 0xffff, /* src_mask */
306 0xffff, /* dst_mask */
307 FALSE), /* pcrel_offset */
308
309 { 7 },
310
311 /* Non modifiable absolute branch. */
312 HOWTO (8, /* type */
313 0, /* rightshift */
314 2, /* size (0 = byte, 1 = short, 2 = long) */
315 26, /* bitsize */
316 FALSE, /* pc_relative */
317 0, /* bitpos */
318 complain_overflow_bitfield, /* complain_on_overflow */
319 0, /* special_function */
320 "R_BA", /* name */
321 TRUE, /* partial_inplace */
322 0x3fffffc, /* src_mask */
323 0x3fffffc, /* dst_mask */
324 FALSE), /* pcrel_offset */
325
326 { 9 },
327
328 /* Non modifiable relative branch. */
329 HOWTO (0xa, /* type */
330 0, /* rightshift */
331 2, /* size (0 = byte, 1 = short, 2 = long) */
332 26, /* bitsize */
333 TRUE, /* pc_relative */
334 0, /* bitpos */
335 complain_overflow_signed, /* complain_on_overflow */
336 0, /* special_function */
337 "R_BR", /* name */
338 TRUE, /* partial_inplace */
339 0x3fffffc, /* src_mask */
340 0x3fffffc, /* dst_mask */
341 FALSE), /* pcrel_offset */
342
343 { 0xb },
344
345 /* Indirect load. */
346 HOWTO (0xc, /* type */
347 0, /* rightshift */
348 2, /* size (0 = byte, 1 = short, 2 = long) */
349 16, /* bitsize */
350 FALSE, /* pc_relative */
351 0, /* bitpos */
352 complain_overflow_bitfield, /* complain_on_overflow */
353 0, /* special_function */
354 "R_RL", /* name */
355 TRUE, /* partial_inplace */
356 0xffff, /* src_mask */
357 0xffff, /* dst_mask */
358 FALSE), /* pcrel_offset */
359
360 /* Load address. */
361 HOWTO (0xd, /* type */
362 0, /* rightshift */
363 2, /* size (0 = byte, 1 = short, 2 = long) */
364 16, /* bitsize */
365 FALSE, /* pc_relative */
366 0, /* bitpos */
367 complain_overflow_bitfield, /* complain_on_overflow */
368 0, /* special_function */
369 "R_RLA", /* name */
370 TRUE, /* partial_inplace */
371 0xffff, /* src_mask */
372 0xffff, /* dst_mask */
373 FALSE), /* pcrel_offset */
374
375 { 0xe },
376
377 /* Non-relocating reference. */
378 HOWTO (0xf, /* type */
379 0, /* rightshift */
380 2, /* size (0 = byte, 1 = short, 2 = long) */
381 32, /* bitsize */
382 FALSE, /* pc_relative */
383 0, /* bitpos */
384 complain_overflow_bitfield, /* complain_on_overflow */
385 0, /* special_function */
386 "R_REF", /* name */
387 FALSE, /* partial_inplace */
388 0, /* src_mask */
389 0, /* dst_mask */
390 FALSE), /* pcrel_offset */
391
392 { 0x10 },
393 { 0x11 },
394
395 /* TOC relative indirect load. */
396 HOWTO (0x12, /* type */
397 0, /* rightshift */
398 2, /* size (0 = byte, 1 = short, 2 = long) */
399 16, /* bitsize */
400 FALSE, /* pc_relative */
401 0, /* bitpos */
402 complain_overflow_bitfield, /* complain_on_overflow */
403 0, /* special_function */
404 "R_TRL", /* name */
405 TRUE, /* partial_inplace */
406 0xffff, /* src_mask */
407 0xffff, /* dst_mask */
408 FALSE), /* pcrel_offset */
409
410 /* TOC relative load address. */
411 HOWTO (0x13, /* type */
412 0, /* rightshift */
413 2, /* size (0 = byte, 1 = short, 2 = long) */
414 16, /* bitsize */
415 FALSE, /* pc_relative */
416 0, /* bitpos */
417 complain_overflow_bitfield, /* complain_on_overflow */
418 0, /* special_function */
419 "R_TRLA", /* name */
420 TRUE, /* partial_inplace */
421 0xffff, /* src_mask */
422 0xffff, /* dst_mask */
423 FALSE), /* pcrel_offset */
424
425 /* Modifiable relative branch. */
426 HOWTO (0x14, /* type */
427 1, /* rightshift */
428 2, /* size (0 = byte, 1 = short, 2 = long) */
429 32, /* bitsize */
430 FALSE, /* pc_relative */
431 0, /* bitpos */
432 complain_overflow_bitfield, /* complain_on_overflow */
433 0, /* special_function */
434 "R_RRTBI", /* name */
435 TRUE, /* partial_inplace */
436 0xffffffff, /* src_mask */
437 0xffffffff, /* dst_mask */
438 FALSE), /* pcrel_offset */
439
440 /* Modifiable absolute branch. */
441 HOWTO (0x15, /* type */
442 1, /* rightshift */
443 2, /* size (0 = byte, 1 = short, 2 = long) */
444 32, /* bitsize */
445 FALSE, /* pc_relative */
446 0, /* bitpos */
447 complain_overflow_bitfield, /* complain_on_overflow */
448 0, /* special_function */
449 "R_RRTBA", /* name */
450 TRUE, /* partial_inplace */
451 0xffffffff, /* src_mask */
452 0xffffffff, /* dst_mask */
453 FALSE), /* pcrel_offset */
454
455 /* Modifiable call absolute indirect. */
456 HOWTO (0x16, /* type */
457 0, /* rightshift */
458 2, /* size (0 = byte, 1 = short, 2 = long) */
459 16, /* bitsize */
460 FALSE, /* pc_relative */
461 0, /* bitpos */
462 complain_overflow_bitfield, /* complain_on_overflow */
463 0, /* special_function */
464 "R_CAI", /* name */
465 TRUE, /* partial_inplace */
466 0xffff, /* src_mask */
467 0xffff, /* dst_mask */
468 FALSE), /* pcrel_offset */
469
470 /* Modifiable call relative. */
471 HOWTO (0x17, /* type */
472 0, /* rightshift */
473 2, /* size (0 = byte, 1 = short, 2 = long) */
474 16, /* bitsize */
475 FALSE, /* pc_relative */
476 0, /* bitpos */
477 complain_overflow_bitfield, /* complain_on_overflow */
478 0, /* special_function */
479 "R_REL", /* name */
480 TRUE, /* partial_inplace */
481 0xffff, /* src_mask */
482 0xffff, /* dst_mask */
483 FALSE), /* pcrel_offset */
484
485 /* Modifiable branch absolute. */
486 HOWTO (0x18, /* type */
487 0, /* rightshift */
488 2, /* size (0 = byte, 1 = short, 2 = long) */
489 16, /* bitsize */
490 FALSE, /* pc_relative */
491 0, /* bitpos */
492 complain_overflow_bitfield, /* complain_on_overflow */
493 0, /* special_function */
494 "R_RBA", /* name */
495 TRUE, /* partial_inplace */
496 0xffff, /* src_mask */
497 0xffff, /* dst_mask */
498 FALSE), /* pcrel_offset */
499
500 /* Modifiable branch absolute. */
501 HOWTO (0x19, /* type */
502 0, /* rightshift */
503 2, /* size (0 = byte, 1 = short, 2 = long) */
504 16, /* bitsize */
505 FALSE, /* pc_relative */
506 0, /* bitpos */
507 complain_overflow_bitfield, /* complain_on_overflow */
508 0, /* special_function */
509 "R_RBAC", /* name */
510 TRUE, /* partial_inplace */
511 0xffff, /* src_mask */
512 0xffff, /* dst_mask */
513 FALSE), /* pcrel_offset */
514
515 /* Modifiable branch relative. */
516 HOWTO (0x1a, /* type */
517 0, /* rightshift */
518 2, /* size (0 = byte, 1 = short, 2 = long) */
519 26, /* bitsize */
520 FALSE, /* pc_relative */
521 0, /* bitpos */
522 complain_overflow_signed, /* complain_on_overflow */
523 0, /* special_function */
524 "R_REL", /* name */
525 TRUE, /* partial_inplace */
526 0xffff, /* src_mask */
527 0xffff, /* dst_mask */
528 FALSE), /* pcrel_offset */
529
530 /* Modifiable branch absolute. */
531 HOWTO (0x1b, /* type */
532 0, /* rightshift */
533 2, /* size (0 = byte, 1 = short, 2 = long) */
534 16, /* bitsize */
535 FALSE, /* pc_relative */
536 0, /* bitpos */
537 complain_overflow_bitfield, /* complain_on_overflow */
538 0, /* special_function */
539 "R_REL", /* name */
540 TRUE, /* partial_inplace */
541 0xffff, /* src_mask */
542 0xffff, /* dst_mask */
543 FALSE) /* pcrel_offset */
544};
545
546#define HOWTO_COUNT (sizeof nlm_powerpc_howto_table \
547 / sizeof nlm_powerpc_howto_table[0])
548
549/* Read a PowerPC NLM reloc. */
550
551static bfd_boolean
552nlm_powerpc_read_reloc (abfd, sym, secp, rel)
553 bfd *abfd;
554 nlmNAME(symbol_type) *sym;
555 asection **secp;
556 arelent *rel;
557{
558 struct nlm32_powerpc_external_reloc ext;
559 bfd_vma l_vaddr;
560 unsigned long l_symndx;
561 int l_rtype;
562 int l_rsecnm;
563 asection *code_sec, *data_sec, *bss_sec;
564
565 /* Read the reloc from the file. */
566 if (bfd_bread (&ext, (bfd_size_type) sizeof ext, abfd) != sizeof ext)
567 return FALSE;
568
569 /* Swap in the fields. */
570 l_vaddr = H_GET_32 (abfd, ext.l_vaddr);
571 l_symndx = H_GET_32 (abfd, ext.l_symndx);
572 l_rtype = H_GET_16 (abfd, ext.l_rtype);
573 l_rsecnm = H_GET_16 (abfd, ext.l_rsecnm);
574
575 /* Get the sections now, for convenience. */
576 code_sec = bfd_get_section_by_name (abfd, NLM_CODE_NAME);
577 data_sec = bfd_get_section_by_name (abfd, NLM_INITIALIZED_DATA_NAME);
578 bss_sec = bfd_get_section_by_name (abfd, NLM_UNINITIALIZED_DATA_NAME);
579
580 /* Work out the arelent fields. */
581 if (sym != NULL)
582 {
583 /* This is an import. sym_ptr_ptr is filled in by
584 nlm_canonicalize_reloc. */
585 rel->sym_ptr_ptr = NULL;
586 }
587 else
588 {
589 asection *sec;
590
591 if (l_symndx == 0)
592 sec = code_sec;
593 else if (l_symndx == 1)
594 sec = data_sec;
595 else if (l_symndx == 2)
596 sec = bss_sec;
597 else
598 {
599 bfd_set_error (bfd_error_bad_value);
600 return FALSE;
601 }
602
603 rel->sym_ptr_ptr = sec->symbol_ptr_ptr;
604 }
605
606 rel->addend = 0;
607
608 BFD_ASSERT ((l_rtype & 0xff) < HOWTO_COUNT);
609
610 rel->howto = nlm_powerpc_howto_table + (l_rtype & 0xff);
611
612 BFD_ASSERT (rel->howto->name != NULL
613 && ((l_rtype & 0x8000) != 0
614 ? (rel->howto->complain_on_overflow
615 == complain_overflow_signed)
616 : (rel->howto->complain_on_overflow
617 == complain_overflow_bitfield))
618 && ((l_rtype >> 8) & 0x1f) == rel->howto->bitsize - 1);
619
620 if (l_rsecnm == 0)
621 *secp = code_sec;
622 else if (l_rsecnm == 1)
623 {
624 *secp = data_sec;
625 l_vaddr -= bfd_section_size (abfd, code_sec);
626 }
627 else
628 {
629 bfd_set_error (bfd_error_bad_value);
630 return FALSE;
631 }
632
633 rel->address = l_vaddr;
634
635 return TRUE;
636}
637
638#endif /* OLDFORMAT */
639
640/* Mangle PowerPC NLM relocs for output. */
641
642static bfd_boolean
643nlm_powerpc_mangle_relocs (abfd, sec, data, offset, count)
644 bfd *abfd ATTRIBUTE_UNUSED;
645 asection *sec ATTRIBUTE_UNUSED;
646 PTR data ATTRIBUTE_UNUSED;
647 bfd_vma offset ATTRIBUTE_UNUSED;
648 bfd_size_type count ATTRIBUTE_UNUSED;
649{
650 return TRUE;
651}
652
653/* Read a PowerPC NLM import record */
654
655static bfd_boolean
656nlm_powerpc_read_import (abfd, sym)
657 bfd *abfd;
658 nlmNAME(symbol_type) *sym;
659{
660 struct nlm_relent *nlm_relocs; /* relocation records for symbol */
661 bfd_size_type rcount; /* number of relocs */
662 bfd_byte temp[NLM_TARGET_LONG_SIZE]; /* temporary 32-bit value */
663 unsigned char symlength; /* length of symbol name */
664 char *name;
665
666 if (bfd_bread ((PTR) &symlength, (bfd_size_type) sizeof (symlength), abfd)
667 != sizeof (symlength))
668 return FALSE;
669 sym -> symbol.the_bfd = abfd;
670 name = bfd_alloc (abfd, (bfd_size_type) symlength + 1);
671 if (name == NULL)
672 return FALSE;
673 if (bfd_bread (name, (bfd_size_type) symlength, abfd) != symlength)
674 return FALSE;
675 name[symlength] = '\0';
676 sym -> symbol.name = name;
677 sym -> symbol.flags = 0;
678 sym -> symbol.value = 0;
679 sym -> symbol.section = bfd_und_section_ptr;
680 if (bfd_bread ((PTR) temp, (bfd_size_type) sizeof (temp), abfd)
681 != sizeof (temp))
682 return FALSE;
683 rcount = H_GET_32 (abfd, temp);
684 nlm_relocs = ((struct nlm_relent *)
685 bfd_alloc (abfd, rcount * sizeof (struct nlm_relent)));
686 if (nlm_relocs == (struct nlm_relent *) NULL)
687 return FALSE;
688 sym -> relocs = nlm_relocs;
689 sym -> rcnt = 0;
690 while (sym -> rcnt < rcount)
691 {
692 asection *section;
693
694 if (! nlm_powerpc_read_reloc (abfd, sym, &section, &nlm_relocs -> reloc))
695 return FALSE;
696 nlm_relocs -> section = section;
697 nlm_relocs++;
698 sym -> rcnt++;
699 }
700 return TRUE;
701}
702
703#ifndef OLDFORMAT
704
705/* Write a PowerPC NLM reloc. */
706
707static bfd_boolean
708nlm_powerpc_write_import (abfd, sec, rel)
709 bfd *abfd;
710 asection *sec;
711 arelent *rel;
712{
713 asymbol *sym;
714 bfd_vma val;
715 bfd_byte temp[4];
716
717 /* PowerPC NetWare only supports one kind of reloc. */
718 if (rel->addend != 0
719 || rel->howto == NULL
720 || rel->howto->rightshift != 0
721 || rel->howto->size != 2
722 || rel->howto->bitsize != 32
723 || rel->howto->bitpos != 0
724 || rel->howto->pc_relative
725 || (rel->howto->src_mask != 0xffffffff && rel->addend != 0)
726 || rel->howto->dst_mask != 0xffffffff)
727 {
728 bfd_set_error (bfd_error_invalid_operation);
729 return FALSE;
730 }
731
732 sym = *rel->sym_ptr_ptr;
733
734 /* The value we write out is the offset into the appropriate
735 segment, rightshifted by two. This offset is the section vma,
736 adjusted by the vma of the lowest section in that segment, plus
737 the address of the relocation. */
738 val = bfd_get_section_vma (abfd, sec) + rel->address;
739 if ((val & 3) != 0)
740 {
741 bfd_set_error (bfd_error_bad_value);
742 return FALSE;
743 }
744 val >>= 2;
745
746 /* The high bit is 0 if the reloc is in the data section, or 1 if
747 the reloc is in the code section. */
748 if (bfd_get_section_flags (abfd, sec) & SEC_DATA)
749 val -= nlm_get_data_low (abfd);
750 else
751 {
752 val -= nlm_get_text_low (abfd);
753 val |= NLM_HIBIT;
754 }
755
756 if (! bfd_is_und_section (bfd_get_section (sym)))
757 {
758 /* This is an internal relocation fixup. The second most
759 significant bit is 0 if this is a reloc against the data
760 segment, or 1 if it is a reloc against the text segment. */
761 if (bfd_get_section_flags (abfd, bfd_get_section (sym)) & SEC_CODE)
762 val |= NLM_HIBIT >> 1;
763 }
764
765 bfd_put_32 (abfd, val, temp);
766 if (bfd_bwrite (temp, (bfd_size_type) sizeof (temp), abfd) != sizeof (temp))
767 return FALSE;
768
769 return TRUE;
770}
771
772#else /* OLDFORMAT */
773
774/* This is used for the reloc handling in the old format. */
775
776/* Write a PowerPC NLM reloc. */
777
778static bfd_boolean
779nlm_powerpc_write_reloc (abfd, sec, rel, indx)
780 bfd *abfd;
781 asection *sec;
782 arelent *rel;
783 int indx;
784{
785 struct nlm32_powerpc_external_reloc ext;
786 asection *code_sec, *data_sec, *bss_sec;
787 asymbol *sym;
788 asection *symsec;
789 unsigned long l_symndx;
790 int l_rtype;
791 int l_rsecnm;
792 reloc_howto_type *howto;
793 bfd_size_type address;
794
795 /* Get the sections now, for convenience. */
796 code_sec = bfd_get_section_by_name (abfd, NLM_CODE_NAME);
797 data_sec = bfd_get_section_by_name (abfd, NLM_INITIALIZED_DATA_NAME);
798 bss_sec = bfd_get_section_by_name (abfd, NLM_UNINITIALIZED_DATA_NAME);
799
800 sym = *rel->sym_ptr_ptr;
801 symsec = bfd_get_section (sym);
802 if (indx != -1)
803 {
804 BFD_ASSERT (bfd_is_und_section (symsec));
805 l_symndx = indx + 3;
806 }
807 else
808 {
809 if (symsec == code_sec)
810 l_symndx = 0;
811 else if (symsec == data_sec)
812 l_symndx = 1;
813 else if (symsec == bss_sec)
814 l_symndx = 2;
815 else
816 {
817 bfd_set_error (bfd_error_bad_value);
818 return FALSE;
819 }
820 }
821
822 H_PUT_32 (abfd, l_symndx, ext.l_symndx);
823
824 for (howto = nlm_powerpc_howto_table;
825 howto < nlm_powerpc_howto_table + HOWTO_COUNT;
826 howto++)
827 {
828 if (howto->rightshift == rel->howto->rightshift
829 && howto->size == rel->howto->size
830 && howto->bitsize == rel->howto->bitsize
831 && howto->pc_relative == rel->howto->pc_relative
832 && howto->bitpos == rel->howto->bitpos
833 && (howto->partial_inplace == rel->howto->partial_inplace
834 || (! rel->howto->partial_inplace
835 && rel->addend == 0))
836 && (howto->src_mask == rel->howto->src_mask
837 || (rel->howto->src_mask == 0
838 && rel->addend == 0))
839 && howto->dst_mask == rel->howto->dst_mask
840 && howto->pcrel_offset == rel->howto->pcrel_offset)
841 break;
842 }
843 if (howto >= nlm_powerpc_howto_table + HOWTO_COUNT)
844 {
845 bfd_set_error (bfd_error_bad_value);
846 return FALSE;
847 }
848
849 l_rtype = howto->type;
850 if (howto->complain_on_overflow == complain_overflow_signed)
851 l_rtype |= 0x8000;
852 l_rtype |= (howto->bitsize - 1) << 8;
853 H_PUT_16 (abfd, l_rtype, ext.l_rtype);
854
855 address = rel->address;
856
857 if (sec == code_sec)
858 l_rsecnm = 0;
859 else if (sec == data_sec)
860 {
861 l_rsecnm = 1;
862 address += bfd_section_size (abfd, code_sec);
863 }
864 else
865 {
866 bfd_set_error (bfd_error_bad_value);
867 return FALSE;
868 }
869
870 H_PUT_16 (abfd, l_rsecnm, ext.l_rsecnm);
871 H_PUT_32 (abfd, address, ext.l_vaddr);
872
873 if (bfd_bwrite (&ext, (bfd_size_type) sizeof ext, abfd) != sizeof ext)
874 return FALSE;
875
876 return TRUE;
877}
878
879/* Write a PowerPC NLM import. */
880
881static bfd_boolean
882nlm_powerpc_write_import (abfd, sec, rel)
883 bfd *abfd;
884 asection *sec;
885 arelent *rel;
886{
887 return nlm_powerpc_write_reloc (abfd, sec, rel, -1);
888}
889
890#endif /* OLDFORMAT */
891
892/* Write a PowerPC NLM external symbol. This routine keeps a static
893 count of the symbol index. FIXME: I don't know if this is
894 necessary, and the index never gets reset. */
895
896static bfd_boolean
897nlm_powerpc_write_external (abfd, count, sym, relocs)
898 bfd *abfd;
899 bfd_size_type count;
900 asymbol *sym;
901 struct reloc_and_sec *relocs;
902{
903 unsigned int i;
904 bfd_byte len;
905 unsigned char temp[NLM_TARGET_LONG_SIZE];
906#ifdef OLDFORMAT
907 static int indx;
908#endif
909
910 len = strlen (sym->name);
911 if ((bfd_bwrite (&len, (bfd_size_type) sizeof (bfd_byte), abfd)
912 != sizeof (bfd_byte))
913 || bfd_bwrite (sym->name, (bfd_size_type) len, abfd) != len)
914 return FALSE;
915
916 bfd_put_32 (abfd, count, temp);
917 if (bfd_bwrite (temp, (bfd_size_type) sizeof (temp), abfd) != sizeof (temp))
918 return FALSE;
919
920 for (i = 0; i < count; i++)
921 {
922#ifndef OLDFORMAT
923 if (! nlm_powerpc_write_import (abfd, relocs[i].sec, relocs[i].rel))
924 return FALSE;
925#else
926 if (! nlm_powerpc_write_reloc (abfd, relocs[i].sec,
927 relocs[i].rel, indx))
928 return FALSE;
929#endif
930 }
931
932#ifdef OLDFORMAT
933 ++indx;
934#endif
935
936 return TRUE;
937}
938
939
940#ifndef OLDFORMAT
941
942/* PowerPC Netware uses a word offset, not a byte offset, for public
943 symbols. */
944
945/* Set the section for a public symbol. */
946
947static bfd_boolean
948nlm_powerpc_set_public_section (abfd, sym)
949 bfd *abfd;
950 nlmNAME(symbol_type) *sym;
951{
952 if (sym->symbol.value & NLM_HIBIT)
953 {
954 sym->symbol.value &= ~NLM_HIBIT;
955 sym->symbol.flags |= BSF_FUNCTION;
956 sym->symbol.section =
957 bfd_get_section_by_name (abfd, NLM_CODE_NAME);
958 }
959 else
960 {
961 sym->symbol.section =
962 bfd_get_section_by_name (abfd, NLM_INITIALIZED_DATA_NAME);
963 }
964
965 sym->symbol.value <<= 2;
966
967 return TRUE;
968}
969
970/* Get the offset to write out for a public symbol. */
971
972static bfd_vma
973nlm_powerpc_get_public_offset (abfd, sym)
974 bfd *abfd;
975 asymbol *sym;
976{
977 bfd_vma offset;
978 asection *sec;
979
980 offset = bfd_asymbol_value (sym);
981 sec = bfd_get_section (sym);
982 if (sec->flags & SEC_CODE)
983 {
984 offset -= nlm_get_text_low (abfd);
985 offset |= NLM_HIBIT;
986 }
987 else if (sec->flags & (SEC_DATA | SEC_ALLOC))
988 {
989 /* SEC_ALLOC is for the .bss section. */
990 offset -= nlm_get_data_low (abfd);
991 }
992 else
993 {
994 /* We can't handle an exported symbol that is not in the code or
995 data segment. */
996 bfd_set_error (bfd_error_invalid_operation);
997 /* FIXME: No way to return error. */
998 abort ();
999 }
1000
1001 return offset;
1002}
1003
1004#endif /* ! defined (OLDFORMAT) */
1005
1006
1007#include "nlmswap.h"
1008
1009static const struct nlm_backend_data nlm32_powerpc_backend =
1010{
1011 "NetWare PowerPC Module \032",
1012 sizeof (Nlm32_powerpc_External_Fixed_Header),
1013#ifndef OLDFORMAT
1014 0, /* optional_prefix_size */
1015#else
1016 sizeof (struct nlm32_powerpc_external_prefix_header),
1017#endif
1018 bfd_arch_powerpc,
1019 0,
1020 FALSE,
1021#ifndef OLDFORMAT
1022 0, /* backend_object_p */
1023 0, /* write_prefix */
1024#else
1025 nlm_powerpc_backend_object_p,
1026 nlm_powerpc_write_prefix,
1027#endif
1028 nlm_powerpc_read_reloc,
1029 nlm_powerpc_mangle_relocs,
1030 nlm_powerpc_read_import,
1031 nlm_powerpc_write_import,
1032#ifndef OLDFORMAT
1033 nlm_powerpc_set_public_section,
1034 nlm_powerpc_get_public_offset,
1035#else
1036 0, /* set_public_section */
1037 0, /* get_public_offset */
1038#endif
1039 nlm_swap_fixed_header_in,
1040 nlm_swap_fixed_header_out,
1041 nlm_powerpc_write_external,
1042 0, /* write_export */
1043};
1044
1045#define TARGET_BIG_NAME "nlm32-powerpc"
1046#define TARGET_BIG_SYM nlmNAME(powerpc_vec)
1047#define TARGET_BACKEND_DATA &nlm32_powerpc_backend
1048
1049#include "nlm-target.h"
Note: See TracBrowser for help on using the repository browser.