sync toplevel with gcc
[deliverable/binutils-gdb.git] / bfd / nlm32-ppc.c
CommitLineData
252b5132 1/* Support for 32-bit PowerPC NLM (NetWare Loadable Module)
3db64b00
AM
2 Copyright 1994, 1995, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
3 2007 Free Software Foundation, Inc.
252b5132 4
7920ce38 5 This file is part of BFD, the Binary File Descriptor library.
252b5132 6
7920ce38
NC
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
cd123cb7 9 the Free Software Foundation; either version 3 of the License, or
7920ce38 10 (at your option) any later version.
252b5132 11
7920ce38
NC
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.
252b5132 16
7920ce38
NC
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
cd123cb7
NC
19 Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
20 MA 02110-1301, USA. */
252b5132
RH
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"
252b5132
RH
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
b34976b6 44static bfd_boolean
7920ce38 45nlm_powerpc_backend_object_p (bfd *abfd)
252b5132
RH
46{
47 struct nlm32_powerpc_external_prefix_header s;
48
7920ce38 49 if (bfd_bread (& s, (bfd_size_type) sizeof s, abfd) != sizeof s)
b34976b6 50 return FALSE;
252b5132
RH
51
52 if (memcmp (s.signature, NLM32_POWERPC_SIGNATURE, sizeof s.signature) != 0
dc810e39 53 || H_GET_32 (abfd, s.headerVersion) != NLM32_POWERPC_HEADER_VERSION)
b34976b6 54 return FALSE;
252b5132 55
b34976b6 56 return TRUE;
252b5132
RH
57}
58
59/* Write out the prefix. */
60
b34976b6 61static bfd_boolean
7920ce38 62nlm_powerpc_write_prefix (bfd *abfd)
252b5132
RH
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);
dc810e39
AM
68 H_PUT_32 (abfd, NLM32_POWERPC_HEADER_VERSION, s.headerVersion);
69 H_PUT_32 (abfd, 0, s.origins);
252b5132
RH
70
71 /* FIXME: What should we do about the date? */
72
7920ce38 73 if (bfd_bwrite (& s, (bfd_size_type) sizeof s, abfd) != sizeof s)
b34976b6 74 return FALSE;
252b5132 75
b34976b6 76 return TRUE;
252b5132
RH
77}
78
252b5132
RH
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
84static reloc_howto_type nlm_powerpc_howto_table[] =
85{
86 /* Standard 32 bit relocation. */
7920ce38
NC
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. */
252b5132
RH
100
101 /* 32 bit relocation, but store negative value. */
7920ce38
NC
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. */
252b5132
RH
115
116 /* 32 bit PC relative relocation. */
7920ce38
NC
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. */
1518639e 130
252b5132 131 /* 16 bit TOC relative relocation. */
7920ce38
NC
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. */
1518639e 145
252b5132 146 /* I don't really know what this is. */
7920ce38
NC
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. */
1518639e 160
252b5132 161 /* External TOC relative symbol. */
7920ce38
NC
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. */
1518639e 175
252b5132 176 /* Local TOC relative symbol. */
7920ce38
NC
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. */
1518639e 190
252b5132 191 { 7 },
1518639e 192
252b5132 193 /* Non modifiable absolute branch. */
7920ce38
NC
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. */
1518639e 207
252b5132
RH
208 { 9 },
209
210 /* Non modifiable relative branch. */
7920ce38
NC
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. */
1518639e 224
252b5132
RH
225 { 0xb },
226
227 /* Indirect load. */
7920ce38
NC
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. */
1518639e 241
252b5132 242 /* Load address. */
7920ce38
NC
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. */
1518639e 256
252b5132 257 { 0xe },
1518639e 258
252b5132 259 /* Non-relocating reference. */
7920ce38
NC
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. */
1518639e 273
252b5132
RH
274 { 0x10 },
275 { 0x11 },
1518639e 276
252b5132 277 /* TOC relative indirect load. */
7920ce38
NC
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. */
1518639e 291
252b5132 292 /* TOC relative load address. */
7920ce38
NC
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. */
1518639e 306
252b5132 307 /* Modifiable relative branch. */
7920ce38
NC
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. */
1518639e 321
252b5132 322 /* Modifiable absolute branch. */
7920ce38
NC
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. */
1518639e 336
252b5132 337 /* Modifiable call absolute indirect. */
7920ce38
NC
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. */
1518639e 351
252b5132 352 /* Modifiable call relative. */
7920ce38
NC
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. */
1518639e 366
252b5132 367 /* Modifiable branch absolute. */
7920ce38
NC
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. */
1518639e 381
252b5132 382 /* Modifiable branch absolute. */
7920ce38
NC
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. */
1518639e 396
252b5132 397 /* Modifiable branch relative. */
7920ce38
NC
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. */
1518639e 411
252b5132 412 /* Modifiable branch absolute. */
7920ce38
NC
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. */
252b5132
RH
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
b34976b6 433static bfd_boolean
7920ce38
NC
434nlm_powerpc_read_reloc (bfd *abfd,
435 nlmNAME (symbol_type) *sym,
436 asection **secp,
437 arelent *rel)
252b5132
RH
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. */
dc810e39 447 if (bfd_bread (&ext, (bfd_size_type) sizeof ext, abfd) != sizeof ext)
b34976b6 448 return FALSE;
252b5132
RH
449
450 /* Swap in the fields. */
dc810e39
AM
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);
252b5132
RH
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)
7920ce38
NC
463 /* This is an import. sym_ptr_ptr is filled in by
464 nlm_canonicalize_reloc. */
465 rel->sym_ptr_ptr = NULL;
252b5132
RH
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);
b34976b6 479 return FALSE;
252b5132
RH
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;
eea6121a 504 l_vaddr -= code_sec->size;
252b5132
RH
505 }
506 else
507 {
508 bfd_set_error (bfd_error_bad_value);
b34976b6 509 return FALSE;
252b5132
RH
510 }
511
512 rel->address = l_vaddr;
513
b34976b6 514 return TRUE;
252b5132
RH
515}
516
7920ce38
NC
517#else /* not OLDFORMAT */
518
519/* There is only one type of reloc in a PowerPC NLM. */
520
521static 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
538static bfd_boolean
539nlm_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 */
252b5132
RH
597
598/* Mangle PowerPC NLM relocs for output. */
599
b34976b6 600static bfd_boolean
7920ce38
NC
601nlm_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)
252b5132 606{
b34976b6 607 return TRUE;
252b5132
RH
608}
609
610/* Read a PowerPC NLM import record */
611
b34976b6 612static bfd_boolean
7920ce38 613nlm_powerpc_read_import (bfd * abfd, nlmNAME (symbol_type) * sym)
252b5132 614{
7920ce38
NC
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. */
252b5132
RH
619 char *name;
620
7920ce38 621 if (bfd_bread (& symlength, (bfd_size_type) sizeof (symlength), abfd)
252b5132 622 != sizeof (symlength))
b34976b6 623 return FALSE;
252b5132 624 sym -> symbol.the_bfd = abfd;
dc810e39 625 name = bfd_alloc (abfd, (bfd_size_type) symlength + 1);
252b5132 626 if (name == NULL)
b34976b6 627 return FALSE;
dc810e39 628 if (bfd_bread (name, (bfd_size_type) symlength, abfd) != symlength)
b34976b6 629 return FALSE;
252b5132
RH
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;
7920ce38 635 if (bfd_bread (temp, (bfd_size_type) sizeof (temp), abfd)
dc810e39 636 != sizeof (temp))
b34976b6 637 return FALSE;
dc810e39 638 rcount = H_GET_32 (abfd, temp);
7920ce38
NC
639 nlm_relocs = bfd_alloc (abfd, rcount * sizeof (struct nlm_relent));
640 if (nlm_relocs == NULL)
b34976b6 641 return FALSE;
252b5132
RH
642 sym -> relocs = nlm_relocs;
643 sym -> rcnt = 0;
644 while (sym -> rcnt < rcount)
645 {
646 asection *section;
1518639e 647
82e51918 648 if (! nlm_powerpc_read_reloc (abfd, sym, &section, &nlm_relocs -> reloc))
b34976b6 649 return FALSE;
252b5132
RH
650 nlm_relocs -> section = section;
651 nlm_relocs++;
652 sym -> rcnt++;
653 }
b34976b6 654 return TRUE;
252b5132
RH
655}
656
657#ifndef OLDFORMAT
658
659/* Write a PowerPC NLM reloc. */
660
b34976b6 661static bfd_boolean
7920ce38 662nlm_powerpc_write_import (bfd * abfd, asection * sec, arelent * rel)
252b5132
RH
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);
b34976b6 680 return FALSE;
252b5132
RH
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);
b34976b6 693 return FALSE;
252b5132
RH
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 }
1518639e 706
252b5132
RH
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);
dc810e39 717 if (bfd_bwrite (temp, (bfd_size_type) sizeof (temp), abfd) != sizeof (temp))
b34976b6 718 return FALSE;
252b5132 719
b34976b6 720 return TRUE;
252b5132
RH
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
b34976b6 729static bfd_boolean
7920ce38
NC
730nlm_powerpc_write_reloc (bfd *abfd,
731 asection *sec,
732 arelent *rel,
733 int indx)
252b5132
RH
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);
b34976b6 768 return FALSE;
252b5132
RH
769 }
770 }
771
dc810e39 772 H_PUT_32 (abfd, l_symndx, ext.l_symndx);
252b5132
RH
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);
b34976b6 796 return FALSE;
252b5132
RH
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;
dc810e39 803 H_PUT_16 (abfd, l_rtype, ext.l_rtype);
252b5132
RH
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;
eea6121a 812 address += code_sec->size;
252b5132
RH
813 }
814 else
815 {
816 bfd_set_error (bfd_error_bad_value);
b34976b6 817 return FALSE;
252b5132
RH
818 }
819
dc810e39
AM
820 H_PUT_16 (abfd, l_rsecnm, ext.l_rsecnm);
821 H_PUT_32 (abfd, address, ext.l_vaddr);
252b5132 822
dc810e39 823 if (bfd_bwrite (&ext, (bfd_size_type) sizeof ext, abfd) != sizeof ext)
b34976b6 824 return FALSE;
252b5132 825
b34976b6 826 return TRUE;
252b5132
RH
827}
828
829/* Write a PowerPC NLM import. */
830
b34976b6 831static bfd_boolean
7920ce38 832nlm_powerpc_write_import (bfd * abfd, asection * sec, arelent * rel)
252b5132
RH
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
b34976b6 843static bfd_boolean
7920ce38
NC
844nlm_powerpc_write_external (bfd *abfd,
845 bfd_size_type count,
846 asymbol *sym,
847 struct reloc_and_sec *relocs)
252b5132
RH
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);
dc810e39
AM
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)
b34976b6 860 return FALSE;
252b5132
RH
861
862 bfd_put_32 (abfd, count, temp);
dc810e39 863 if (bfd_bwrite (temp, (bfd_size_type) sizeof (temp), abfd) != sizeof (temp))
b34976b6 864 return FALSE;
252b5132
RH
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))
b34976b6 870 return FALSE;
252b5132
RH
871#else
872 if (! nlm_powerpc_write_reloc (abfd, relocs[i].sec,
873 relocs[i].rel, indx))
b34976b6 874 return FALSE;
252b5132
RH
875#endif
876 }
877
878#ifdef OLDFORMAT
879 ++indx;
880#endif
881
b34976b6 882 return TRUE;
252b5132
RH
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
b34976b6 892static bfd_boolean
7920ce38 893nlm_powerpc_set_public_section (bfd *abfd, nlmNAME (symbol_type) *sym)
252b5132
RH
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
7920ce38
NC
903 sym->symbol.section =
904 bfd_get_section_by_name (abfd, NLM_INITIALIZED_DATA_NAME);
252b5132
RH
905
906 sym->symbol.value <<= 2;
907
b34976b6 908 return TRUE;
252b5132
RH
909}
910
911/* Get the offset to write out for a public symbol. */
912
913static bfd_vma
7920ce38 914nlm_powerpc_get_public_offset (bfd *abfd, asymbol *sym)
252b5132
RH
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
947static const struct nlm_backend_data nlm32_powerpc_backend =
948{
949 "NetWare PowerPC Module \032",
950 sizeof (Nlm32_powerpc_External_Fixed_Header),
951#ifndef OLDFORMAT
7920ce38 952 0, /* Optional_prefix_size. */
252b5132
RH
953#else
954 sizeof (struct nlm32_powerpc_external_prefix_header),
955#endif
956 bfd_arch_powerpc,
957 0,
b34976b6 958 FALSE,
252b5132 959#ifndef OLDFORMAT
7920ce38
NC
960 0, /* Backend_object_p. */
961 0, /* Write_prefix. */
252b5132
RH
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
7920ce38
NC
974 0, /* Set_public_section. */
975 0, /* Get_public_offset. */
252b5132
RH
976#endif
977 nlm_swap_fixed_header_in,
978 nlm_swap_fixed_header_out,
979 nlm_powerpc_write_external,
7920ce38 980 0, /* Write_export. */
252b5132
RH
981};
982
983#define TARGET_BIG_NAME "nlm32-powerpc"
7920ce38
NC
984#define TARGET_BIG_SYM nlmNAME (powerpc_vec)
985#define TARGET_BACKEND_DATA & nlm32_powerpc_backend
252b5132
RH
986
987#include "nlm-target.h"
This page took 0.737385 seconds and 4 git commands to generate.