]>
Commit | Line | Data |
---|---|---|
3af0f479 ILT |
1 | /* Support for 32-bit PowerPC NLM (NetWare Loadable Module) |
2 | Copyright (C) 1994 Free Software Foundation, Inc. | |
3 | ||
4 | This file is part of BFD, the Binary File Descriptor library. | |
5 | ||
6 | This program is free software; you can redistribute it and/or modify | |
7 | it under the terms of the GNU General Public License as published by | |
8 | the Free Software Foundation; either version 2 of the License, or | |
9 | (at your option) any later version. | |
10 | ||
11 | This program is distributed in the hope that it will be useful, | |
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 | GNU General Public License for more details. | |
15 | ||
16 | You should have received a copy of the GNU General Public License | |
17 | along with this program; if not, write to the Free Software | |
18 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ | |
19 | ||
20 | #include "bfd.h" | |
21 | #include "sysdep.h" | |
22 | #include "libbfd.h" | |
23 | ||
24 | #define ARCH_SIZE 32 | |
25 | ||
26 | #include "nlm/ppc-ext.h" | |
27 | #define Nlm_External_Fixed_Header Nlm32_powerpc_External_Fixed_Header | |
28 | ||
29 | #include "libnlm.h" | |
30 | ||
31 | static boolean nlm_powerpc_backend_object_p | |
32 | PARAMS ((bfd *)); | |
33 | static boolean nlm_powerpc_write_prefix | |
34 | PARAMS ((bfd *)); | |
35 | static boolean nlm_powerpc_read_reloc | |
36 | PARAMS ((bfd *, nlmNAME(symbol_type) *, asection **, arelent *)); | |
37 | static boolean nlm_powerpc_mangle_relocs | |
38 | PARAMS ((bfd *, asection *, PTR, bfd_vma, bfd_size_type)); | |
39 | static boolean nlm_powerpc_read_import | |
40 | PARAMS ((bfd *, nlmNAME(symbol_type) *)); | |
41 | static boolean nlm_powerpc_write_reloc | |
42 | PARAMS ((bfd *, asection *, arelent *, int)); | |
43 | static boolean nlm_powerpc_write_import | |
44 | PARAMS ((bfd *, asection *, arelent *)); | |
45 | static boolean nlm_powerpc_write_external | |
46 | PARAMS ((bfd *, bfd_size_type, asymbol *, struct reloc_and_sec *)); | |
47 | \f | |
48 | /* PowerPC NLM's have a prefix header before the standard NLM. This | |
49 | function reads it in, verifies the version, and seeks the bfd to | |
50 | the location before the regular NLM header. */ | |
51 | ||
52 | static boolean | |
53 | nlm_powerpc_backend_object_p (abfd) | |
54 | bfd *abfd; | |
55 | { | |
56 | struct nlm32_powerpc_external_prefix_header s; | |
57 | ||
58 | if (bfd_read ((PTR) &s, sizeof s, 1, abfd) != sizeof s) | |
59 | return false; | |
60 | ||
61 | if (memcmp (s.signature, NLM32_POWERPC_SIGNATURE, sizeof s.signature) != 0 | |
62 | || bfd_h_get_32 (abfd, s.headerVersion) != NLM32_POWERPC_HEADER_VERSION) | |
63 | return false; | |
64 | ||
65 | return true; | |
66 | } | |
67 | ||
68 | /* Write out the prefix. */ | |
69 | ||
70 | static boolean | |
71 | nlm_powerpc_write_prefix (abfd) | |
72 | bfd *abfd; | |
73 | { | |
74 | struct nlm32_powerpc_external_prefix_header s; | |
75 | ||
76 | memset (&s, 0, sizeof s); | |
77 | memcpy (s.signature, NLM32_POWERPC_SIGNATURE, sizeof s.signature); | |
78 | bfd_h_put_32 (abfd, (bfd_vma) NLM32_POWERPC_HEADER_VERSION, s.headerVersion); | |
79 | bfd_h_put_32 (abfd, (bfd_vma) 0, s.origins); | |
80 | ||
81 | /* FIXME: What should we do about the date? */ | |
82 | ||
83 | if (bfd_write ((PTR) &s, sizeof s, 1, abfd) != sizeof s) | |
84 | return false; | |
85 | ||
86 | return true; | |
87 | } | |
88 | \f | |
89 | /* How to process the various reloc types. PowerPC NLMs use XCOFF | |
90 | reloc types, and I have just copied the XCOFF reloc table here. */ | |
91 | ||
92 | static reloc_howto_type nlm_powerpc_howto_table[] = | |
93 | { | |
94 | /* Standard 32 bit relocation. */ | |
95 | HOWTO (0, /* type */ | |
96 | 0, /* rightshift */ | |
97 | 2, /* size (0 = byte, 1 = short, 2 = long) */ | |
98 | 32, /* bitsize */ | |
99 | false, /* pc_relative */ | |
100 | 0, /* bitpos */ | |
101 | complain_overflow_bitfield, /* complain_on_overflow */ | |
102 | 0, /* special_function */ | |
103 | "R_POS", /* name */ | |
104 | true, /* partial_inplace */ | |
105 | 0xffffffff, /* src_mask */ | |
106 | 0xffffffff, /* dst_mask */ | |
107 | false), /* pcrel_offset */ | |
108 | ||
109 | /* 32 bit relocation, but store negative value. */ | |
110 | HOWTO (1, /* type */ | |
111 | 0, /* rightshift */ | |
112 | -2, /* size (0 = byte, 1 = short, 2 = long) */ | |
113 | 32, /* bitsize */ | |
114 | false, /* pc_relative */ | |
115 | 0, /* bitpos */ | |
116 | complain_overflow_bitfield, /* complain_on_overflow */ | |
117 | 0, /* special_function */ | |
118 | "R_NEG", /* name */ | |
119 | true, /* partial_inplace */ | |
120 | 0xffffffff, /* src_mask */ | |
121 | 0xffffffff, /* dst_mask */ | |
122 | false), /* pcrel_offset */ | |
123 | ||
124 | /* 32 bit PC relative relocation. */ | |
125 | HOWTO (2, /* type */ | |
126 | 0, /* rightshift */ | |
127 | 2, /* size (0 = byte, 1 = short, 2 = long) */ | |
128 | 32, /* bitsize */ | |
129 | true, /* pc_relative */ | |
130 | 0, /* bitpos */ | |
131 | complain_overflow_signed, /* complain_on_overflow */ | |
132 | 0, /* special_function */ | |
133 | "R_REL", /* name */ | |
134 | true, /* partial_inplace */ | |
135 | 0xffffffff, /* src_mask */ | |
136 | 0xffffffff, /* dst_mask */ | |
137 | false), /* pcrel_offset */ | |
138 | ||
139 | /* 16 bit TOC relative relocation. */ | |
140 | HOWTO (3, /* type */ | |
141 | 0, /* rightshift */ | |
142 | 1, /* size (0 = byte, 1 = short, 2 = long) */ | |
143 | 16, /* bitsize */ | |
144 | false, /* pc_relative */ | |
145 | 0, /* bitpos */ | |
146 | complain_overflow_signed, /* complain_on_overflow */ | |
147 | 0, /* special_function */ | |
148 | "R_TOC", /* name */ | |
149 | true, /* partial_inplace */ | |
150 | 0xffff, /* src_mask */ | |
151 | 0xffff, /* dst_mask */ | |
152 | false), /* pcrel_offset */ | |
153 | ||
154 | /* I don't really know what this is. */ | |
155 | HOWTO (4, /* type */ | |
156 | 1, /* rightshift */ | |
157 | 2, /* size (0 = byte, 1 = short, 2 = long) */ | |
158 | 32, /* bitsize */ | |
159 | false, /* pc_relative */ | |
160 | 0, /* bitpos */ | |
161 | complain_overflow_bitfield, /* complain_on_overflow */ | |
162 | 0, /* special_function */ | |
163 | "R_RTB", /* name */ | |
164 | true, /* partial_inplace */ | |
165 | 0xffffffff, /* src_mask */ | |
166 | 0xffffffff, /* dst_mask */ | |
167 | false), /* pcrel_offset */ | |
168 | ||
169 | /* External TOC relative symbol. */ | |
170 | HOWTO (5, /* type */ | |
171 | 0, /* rightshift */ | |
172 | 2, /* size (0 = byte, 1 = short, 2 = long) */ | |
173 | 16, /* bitsize */ | |
174 | false, /* pc_relative */ | |
175 | 0, /* bitpos */ | |
176 | complain_overflow_bitfield, /* complain_on_overflow */ | |
177 | 0, /* special_function */ | |
178 | "R_GL", /* name */ | |
179 | true, /* partial_inplace */ | |
180 | 0xffff, /* src_mask */ | |
181 | 0xffff, /* dst_mask */ | |
182 | false), /* pcrel_offset */ | |
183 | ||
184 | /* Local TOC relative symbol. */ | |
185 | HOWTO (6, /* type */ | |
186 | 0, /* rightshift */ | |
187 | 2, /* size (0 = byte, 1 = short, 2 = long) */ | |
188 | 16, /* bitsize */ | |
189 | false, /* pc_relative */ | |
190 | 0, /* bitpos */ | |
191 | complain_overflow_bitfield, /* complain_on_overflow */ | |
192 | 0, /* special_function */ | |
193 | "R_TCL", /* name */ | |
194 | true, /* partial_inplace */ | |
195 | 0xffff, /* src_mask */ | |
196 | 0xffff, /* dst_mask */ | |
197 | false), /* pcrel_offset */ | |
198 | ||
199 | { 7 }, | |
200 | ||
201 | /* Non modifiable absolute branch. */ | |
202 | HOWTO (8, /* type */ | |
203 | 0, /* rightshift */ | |
204 | 2, /* size (0 = byte, 1 = short, 2 = long) */ | |
205 | 26, /* bitsize */ | |
206 | false, /* pc_relative */ | |
207 | 0, /* bitpos */ | |
208 | complain_overflow_bitfield, /* complain_on_overflow */ | |
209 | 0, /* special_function */ | |
210 | "R_BA", /* name */ | |
211 | true, /* partial_inplace */ | |
212 | 0x3fffffc, /* src_mask */ | |
213 | 0x3fffffc, /* dst_mask */ | |
214 | false), /* pcrel_offset */ | |
215 | ||
216 | { 9 }, | |
217 | ||
218 | /* Non modifiable relative branch. */ | |
219 | HOWTO (0xa, /* type */ | |
220 | 0, /* rightshift */ | |
221 | 2, /* size (0 = byte, 1 = short, 2 = long) */ | |
222 | 26, /* bitsize */ | |
223 | true, /* pc_relative */ | |
224 | 0, /* bitpos */ | |
225 | complain_overflow_signed, /* complain_on_overflow */ | |
226 | 0, /* special_function */ | |
227 | "R_BR", /* name */ | |
228 | true, /* partial_inplace */ | |
229 | 0x3fffffc, /* src_mask */ | |
230 | 0x3fffffc, /* dst_mask */ | |
231 | false), /* pcrel_offset */ | |
232 | ||
233 | { 0xb }, | |
234 | ||
235 | /* Indirect load. */ | |
236 | HOWTO (0xc, /* type */ | |
237 | 0, /* rightshift */ | |
238 | 2, /* size (0 = byte, 1 = short, 2 = long) */ | |
239 | 16, /* bitsize */ | |
240 | false, /* pc_relative */ | |
241 | 0, /* bitpos */ | |
242 | complain_overflow_bitfield, /* complain_on_overflow */ | |
243 | 0, /* special_function */ | |
244 | "R_RL", /* name */ | |
245 | true, /* partial_inplace */ | |
246 | 0xffff, /* src_mask */ | |
247 | 0xffff, /* dst_mask */ | |
248 | false), /* pcrel_offset */ | |
249 | ||
250 | /* Load address. */ | |
251 | HOWTO (0xd, /* type */ | |
252 | 0, /* rightshift */ | |
253 | 2, /* size (0 = byte, 1 = short, 2 = long) */ | |
254 | 16, /* bitsize */ | |
255 | false, /* pc_relative */ | |
256 | 0, /* bitpos */ | |
257 | complain_overflow_bitfield, /* complain_on_overflow */ | |
258 | 0, /* special_function */ | |
259 | "R_RLA", /* name */ | |
260 | true, /* partial_inplace */ | |
261 | 0xffff, /* src_mask */ | |
262 | 0xffff, /* dst_mask */ | |
263 | false), /* pcrel_offset */ | |
264 | ||
265 | { 0xe }, | |
266 | ||
267 | /* Non-relocating reference. */ | |
268 | HOWTO (0xf, /* type */ | |
269 | 0, /* rightshift */ | |
270 | 2, /* size (0 = byte, 1 = short, 2 = long) */ | |
271 | 32, /* bitsize */ | |
272 | false, /* pc_relative */ | |
273 | 0, /* bitpos */ | |
274 | complain_overflow_bitfield, /* complain_on_overflow */ | |
275 | 0, /* special_function */ | |
276 | "R_REF", /* name */ | |
277 | false, /* partial_inplace */ | |
278 | 0, /* src_mask */ | |
279 | 0, /* dst_mask */ | |
280 | false), /* pcrel_offset */ | |
281 | ||
282 | { 0x10 }, | |
283 | { 0x11 }, | |
284 | ||
285 | /* TOC relative indirect load. */ | |
286 | HOWTO (0x12, /* type */ | |
287 | 0, /* rightshift */ | |
288 | 2, /* size (0 = byte, 1 = short, 2 = long) */ | |
289 | 16, /* bitsize */ | |
290 | false, /* pc_relative */ | |
291 | 0, /* bitpos */ | |
292 | complain_overflow_bitfield, /* complain_on_overflow */ | |
293 | 0, /* special_function */ | |
294 | "R_TRL", /* name */ | |
295 | true, /* partial_inplace */ | |
296 | 0xffff, /* src_mask */ | |
297 | 0xffff, /* dst_mask */ | |
298 | false), /* pcrel_offset */ | |
299 | ||
300 | /* TOC relative load address. */ | |
301 | HOWTO (0x13, /* type */ | |
302 | 0, /* rightshift */ | |
303 | 2, /* size (0 = byte, 1 = short, 2 = long) */ | |
304 | 16, /* bitsize */ | |
305 | false, /* pc_relative */ | |
306 | 0, /* bitpos */ | |
307 | complain_overflow_bitfield, /* complain_on_overflow */ | |
308 | 0, /* special_function */ | |
309 | "R_TRLA", /* name */ | |
310 | true, /* partial_inplace */ | |
311 | 0xffff, /* src_mask */ | |
312 | 0xffff, /* dst_mask */ | |
313 | false), /* pcrel_offset */ | |
314 | ||
315 | /* Modifiable relative branch. */ | |
316 | HOWTO (0x14, /* type */ | |
317 | 1, /* rightshift */ | |
318 | 2, /* size (0 = byte, 1 = short, 2 = long) */ | |
319 | 32, /* bitsize */ | |
320 | false, /* pc_relative */ | |
321 | 0, /* bitpos */ | |
322 | complain_overflow_bitfield, /* complain_on_overflow */ | |
323 | 0, /* special_function */ | |
324 | "R_RRTBI", /* name */ | |
325 | true, /* partial_inplace */ | |
326 | 0xffffffff, /* src_mask */ | |
327 | 0xffffffff, /* dst_mask */ | |
328 | false), /* pcrel_offset */ | |
329 | ||
330 | /* Modifiable absolute branch. */ | |
331 | HOWTO (0x15, /* type */ | |
332 | 1, /* rightshift */ | |
333 | 2, /* size (0 = byte, 1 = short, 2 = long) */ | |
334 | 32, /* bitsize */ | |
335 | false, /* pc_relative */ | |
336 | 0, /* bitpos */ | |
337 | complain_overflow_bitfield, /* complain_on_overflow */ | |
338 | 0, /* special_function */ | |
339 | "R_RRTBA", /* name */ | |
340 | true, /* partial_inplace */ | |
341 | 0xffffffff, /* src_mask */ | |
342 | 0xffffffff, /* dst_mask */ | |
343 | false), /* pcrel_offset */ | |
344 | ||
345 | /* Modifiable call absolute indirect. */ | |
346 | HOWTO (0x16, /* 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_CAI", /* name */ | |
355 | true, /* partial_inplace */ | |
356 | 0xffff, /* src_mask */ | |
357 | 0xffff, /* dst_mask */ | |
358 | false), /* pcrel_offset */ | |
359 | ||
360 | /* Modifiable call relative. */ | |
361 | HOWTO (0x17, /* 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_REL", /* name */ | |
370 | true, /* partial_inplace */ | |
371 | 0xffff, /* src_mask */ | |
372 | 0xffff, /* dst_mask */ | |
373 | false), /* pcrel_offset */ | |
374 | ||
375 | /* Modifiable branch absolute. */ | |
376 | HOWTO (0x18, /* type */ | |
377 | 0, /* rightshift */ | |
378 | 2, /* size (0 = byte, 1 = short, 2 = long) */ | |
379 | 16, /* bitsize */ | |
380 | false, /* pc_relative */ | |
381 | 0, /* bitpos */ | |
382 | complain_overflow_bitfield, /* complain_on_overflow */ | |
383 | 0, /* special_function */ | |
384 | "R_RBA", /* name */ | |
385 | true, /* partial_inplace */ | |
386 | 0xffff, /* src_mask */ | |
387 | 0xffff, /* dst_mask */ | |
388 | false), /* pcrel_offset */ | |
389 | ||
390 | /* Modifiable branch absolute. */ | |
391 | HOWTO (0x19, /* type */ | |
392 | 0, /* rightshift */ | |
393 | 2, /* size (0 = byte, 1 = short, 2 = long) */ | |
394 | 16, /* bitsize */ | |
395 | false, /* pc_relative */ | |
396 | 0, /* bitpos */ | |
397 | complain_overflow_bitfield, /* complain_on_overflow */ | |
398 | 0, /* special_function */ | |
399 | "R_RBAC", /* name */ | |
400 | true, /* partial_inplace */ | |
401 | 0xffff, /* src_mask */ | |
402 | 0xffff, /* dst_mask */ | |
403 | false), /* pcrel_offset */ | |
404 | ||
405 | /* Modifiable branch relative. */ | |
406 | HOWTO (0x1a, /* type */ | |
407 | 0, /* rightshift */ | |
408 | 2, /* size (0 = byte, 1 = short, 2 = long) */ | |
409 | 26, /* bitsize */ | |
410 | false, /* pc_relative */ | |
411 | 0, /* bitpos */ | |
412 | complain_overflow_signed, /* complain_on_overflow */ | |
413 | 0, /* special_function */ | |
414 | "R_REL", /* name */ | |
415 | true, /* partial_inplace */ | |
416 | 0xffff, /* src_mask */ | |
417 | 0xffff, /* dst_mask */ | |
418 | false), /* pcrel_offset */ | |
419 | ||
420 | /* Modifiable branch absolute. */ | |
421 | HOWTO (0x1b, /* type */ | |
422 | 0, /* rightshift */ | |
423 | 2, /* size (0 = byte, 1 = short, 2 = long) */ | |
424 | 16, /* bitsize */ | |
425 | false, /* pc_relative */ | |
426 | 0, /* bitpos */ | |
427 | complain_overflow_bitfield, /* complain_on_overflow */ | |
428 | 0, /* special_function */ | |
429 | "R_REL", /* name */ | |
430 | true, /* partial_inplace */ | |
431 | 0xffff, /* src_mask */ | |
432 | 0xffff, /* dst_mask */ | |
433 | false) /* pcrel_offset */ | |
434 | }; | |
435 | ||
436 | #define HOWTO_COUNT (sizeof nlm_powerpc_howto_table \ | |
437 | / sizeof nlm_powerpc_howto_table[0]) | |
438 | ||
439 | /* Read a PowerPC NLM reloc. */ | |
440 | ||
441 | static boolean | |
442 | nlm_powerpc_read_reloc (abfd, sym, secp, rel) | |
443 | bfd *abfd; | |
444 | nlmNAME(symbol_type) *sym; | |
445 | asection **secp; | |
446 | arelent *rel; | |
447 | { | |
448 | struct nlm32_powerpc_external_reloc ext; | |
449 | bfd_vma l_vaddr; | |
450 | unsigned long l_symndx; | |
451 | int l_rtype; | |
452 | int l_rsecnm; | |
453 | asection *code_sec, *data_sec, *bss_sec; | |
454 | ||
455 | /* Read the reloc from the file. */ | |
456 | if (bfd_read (&ext, sizeof ext, 1, abfd) != sizeof ext) | |
457 | { | |
458 | bfd_set_error (bfd_error_system_call); | |
459 | return false; | |
460 | } | |
461 | ||
462 | /* Swap in the fields. */ | |
463 | l_vaddr = bfd_h_get_32 (abfd, ext.l_vaddr); | |
464 | l_symndx = bfd_h_get_32 (abfd, ext.l_symndx); | |
465 | l_rtype = bfd_h_get_16 (abfd, ext.l_rtype); | |
466 | l_rsecnm = bfd_h_get_16 (abfd, ext.l_rsecnm); | |
467 | ||
468 | /* Get the sections now, for convenience. */ | |
469 | code_sec = bfd_get_section_by_name (abfd, NLM_CODE_NAME); | |
470 | data_sec = bfd_get_section_by_name (abfd, NLM_INITIALIZED_DATA_NAME); | |
471 | bss_sec = bfd_get_section_by_name (abfd, NLM_UNINITIALIZED_DATA_NAME); | |
472 | ||
473 | /* Work out the arelent fields. */ | |
474 | if (sym != NULL) | |
475 | { | |
476 | /* This is an import. sym_ptr_ptr is filled in by | |
477 | nlm_canonicalize_reloc. */ | |
478 | rel->sym_ptr_ptr = NULL; | |
479 | } | |
480 | else | |
481 | { | |
482 | asection *sec; | |
483 | ||
484 | if (l_symndx == 0) | |
485 | sec = code_sec; | |
486 | else if (l_symndx == 1) | |
487 | sec = data_sec; | |
488 | else if (l_symndx == 2) | |
489 | sec = bss_sec; | |
490 | else | |
491 | { | |
492 | bfd_set_error (bfd_error_bad_value); | |
493 | return false; | |
494 | } | |
495 | ||
496 | rel->sym_ptr_ptr = sec->symbol_ptr_ptr; | |
497 | } | |
498 | ||
499 | rel->addend = 0; | |
500 | ||
501 | BFD_ASSERT ((l_rtype & 0xff) < HOWTO_COUNT); | |
502 | ||
503 | rel->howto = nlm_powerpc_howto_table + (l_rtype & 0xff); | |
504 | ||
505 | BFD_ASSERT (rel->howto->name != NULL | |
506 | && ((l_rtype & 0x8000) != 0 | |
507 | ? (rel->howto->complain_on_overflow | |
508 | == complain_overflow_signed) | |
509 | : (rel->howto->complain_on_overflow | |
510 | == complain_overflow_bitfield)) | |
511 | && ((l_rtype >> 8) & 0x1f) == rel->howto->bitsize - 1); | |
512 | ||
513 | if (l_rsecnm == 0) | |
514 | *secp = code_sec; | |
515 | else if (l_rsecnm == 1) | |
516 | { | |
517 | *secp = data_sec; | |
518 | l_vaddr -= bfd_section_size (abfd, code_sec); | |
519 | } | |
520 | else | |
521 | { | |
522 | bfd_set_error (bfd_error_bad_value); | |
523 | return false; | |
524 | } | |
525 | ||
526 | rel->address = l_vaddr; | |
527 | ||
528 | return true; | |
529 | } | |
530 | ||
531 | /* Mangle PowerPC NLM relocs for output. */ | |
532 | ||
533 | static boolean | |
534 | nlm_powerpc_mangle_relocs (abfd, sec, data, offset, count) | |
535 | bfd *abfd; | |
536 | asection *sec; | |
537 | PTR data; | |
538 | bfd_vma offset; | |
539 | bfd_size_type count; | |
540 | { | |
541 | return true; | |
542 | } | |
543 | ||
544 | /* Read a PowerPC NLM import record */ | |
545 | ||
546 | static boolean | |
547 | nlm_powerpc_read_import (abfd, sym) | |
548 | bfd *abfd; | |
549 | nlmNAME(symbol_type) *sym; | |
550 | { | |
551 | struct nlm_relent *nlm_relocs; /* relocation records for symbol */ | |
552 | bfd_size_type rcount; /* number of relocs */ | |
553 | bfd_byte temp[NLM_TARGET_LONG_SIZE]; /* temporary 32-bit value */ | |
554 | unsigned char symlength; /* length of symbol name */ | |
555 | char *name; | |
556 | ||
557 | if (bfd_read ((PTR) &symlength, sizeof (symlength), 1, abfd) | |
558 | != sizeof (symlength)) | |
559 | { | |
560 | bfd_set_error (bfd_error_system_call); | |
561 | return (false); | |
562 | } | |
563 | sym -> symbol.the_bfd = abfd; | |
564 | name = bfd_alloc (abfd, symlength + 1); | |
565 | if (name == NULL) | |
566 | { | |
567 | bfd_set_error (bfd_error_no_memory); | |
568 | return false; | |
569 | } | |
570 | if (bfd_read (name, symlength, 1, abfd) != symlength) | |
571 | { | |
572 | bfd_set_error (bfd_error_system_call); | |
573 | return (false); | |
574 | } | |
575 | name[symlength] = '\0'; | |
576 | sym -> symbol.name = name; | |
577 | sym -> symbol.flags = 0; | |
578 | sym -> symbol.value = 0; | |
579 | sym -> symbol.section = &bfd_und_section; | |
580 | if (bfd_read ((PTR) temp, sizeof (temp), 1, abfd) != sizeof (temp)) | |
581 | { | |
582 | bfd_set_error (bfd_error_system_call); | |
583 | return (false); | |
584 | } | |
585 | rcount = bfd_h_get_32 (abfd, temp); | |
586 | nlm_relocs = ((struct nlm_relent *) | |
587 | bfd_alloc (abfd, rcount * sizeof (struct nlm_relent))); | |
588 | if (nlm_relocs == (struct nlm_relent *) NULL) | |
589 | { | |
590 | bfd_set_error (bfd_error_no_memory); | |
591 | return false; | |
592 | } | |
593 | sym -> relocs = nlm_relocs; | |
594 | sym -> rcnt = 0; | |
595 | while (sym -> rcnt < rcount) | |
596 | { | |
597 | asection *section; | |
598 | ||
599 | if (nlm_powerpc_read_reloc (abfd, sym, §ion, | |
600 | &nlm_relocs -> reloc) | |
601 | == false) | |
602 | return false; | |
603 | nlm_relocs -> section = section; | |
604 | nlm_relocs++; | |
605 | sym -> rcnt++; | |
606 | } | |
607 | return true; | |
608 | } | |
609 | ||
610 | /* Write a PowerPC NLM reloc. */ | |
611 | ||
612 | static boolean | |
613 | nlm_powerpc_write_reloc (abfd, sec, rel, indx) | |
614 | bfd *abfd; | |
615 | asection *sec; | |
616 | arelent *rel; | |
617 | int indx; | |
618 | { | |
619 | struct nlm32_powerpc_external_reloc ext; | |
620 | asection *code_sec, *data_sec, *bss_sec; | |
621 | asymbol *sym; | |
622 | asection *symsec; | |
623 | unsigned long l_symndx; | |
624 | int l_rtype; | |
625 | int l_rsecnm; | |
626 | const reloc_howto_type *howto; | |
627 | bfd_size_type address; | |
628 | ||
629 | /* Get the sections now, for convenience. */ | |
630 | code_sec = bfd_get_section_by_name (abfd, NLM_CODE_NAME); | |
631 | data_sec = bfd_get_section_by_name (abfd, NLM_INITIALIZED_DATA_NAME); | |
632 | bss_sec = bfd_get_section_by_name (abfd, NLM_UNINITIALIZED_DATA_NAME); | |
633 | ||
634 | sym = *rel->sym_ptr_ptr; | |
635 | symsec = bfd_get_section (sym); | |
636 | if (indx != -1) | |
637 | { | |
638 | BFD_ASSERT (symsec == &bfd_und_section); | |
639 | l_symndx = indx + 3; | |
640 | } | |
641 | else | |
642 | { | |
643 | if (symsec == code_sec) | |
644 | l_symndx = 0; | |
645 | else if (symsec == data_sec) | |
646 | l_symndx = 1; | |
647 | else if (symsec == bss_sec) | |
648 | l_symndx = 2; | |
649 | else | |
650 | { | |
651 | bfd_set_error (bfd_error_bad_value); | |
652 | return false; | |
653 | } | |
654 | } | |
655 | ||
656 | bfd_h_put_32 (abfd, (bfd_vma) l_symndx, ext.l_symndx); | |
657 | ||
658 | for (howto = nlm_powerpc_howto_table; | |
659 | howto < nlm_powerpc_howto_table + HOWTO_COUNT; | |
660 | howto++) | |
661 | { | |
662 | if (howto->rightshift == rel->howto->rightshift | |
663 | && howto->size == rel->howto->size | |
664 | && howto->bitsize == rel->howto->bitsize | |
665 | && howto->pc_relative == rel->howto->pc_relative | |
666 | && howto->bitpos == rel->howto->bitpos | |
667 | && (howto->partial_inplace == rel->howto->partial_inplace | |
668 | || (! rel->howto->partial_inplace | |
669 | && rel->addend == 0)) | |
670 | && (howto->src_mask == rel->howto->src_mask | |
671 | || (rel->howto->src_mask == 0 | |
672 | && rel->addend == 0)) | |
673 | && howto->dst_mask == rel->howto->dst_mask | |
674 | && howto->pcrel_offset == rel->howto->pcrel_offset) | |
675 | break; | |
676 | } | |
677 | if (howto >= nlm_powerpc_howto_table + HOWTO_COUNT) | |
678 | { | |
679 | bfd_set_error (bfd_error_bad_value); | |
680 | return false; | |
681 | } | |
682 | ||
683 | l_rtype = howto->type; | |
684 | if (howto->complain_on_overflow == complain_overflow_signed) | |
685 | l_rtype |= 0x8000; | |
686 | l_rtype |= (howto->bitsize - 1) << 8; | |
687 | bfd_h_put_16 (abfd, (bfd_vma) l_rtype, ext.l_rtype); | |
688 | ||
689 | address = rel->address; | |
690 | ||
691 | if (sec == code_sec) | |
692 | l_rsecnm = 0; | |
693 | else if (sec == data_sec) | |
694 | { | |
695 | l_rsecnm = 1; | |
696 | address += bfd_section_size (abfd, code_sec); | |
697 | } | |
698 | else | |
699 | { | |
700 | bfd_set_error (bfd_error_bad_value); | |
701 | return false; | |
702 | } | |
703 | ||
704 | bfd_h_put_16 (abfd, (bfd_vma) l_rsecnm, ext.l_rsecnm); | |
705 | bfd_h_put_32 (abfd, (bfd_vma) address, ext.l_vaddr); | |
706 | ||
707 | if (bfd_write (&ext, sizeof ext, 1, abfd) != sizeof ext) | |
708 | return false; | |
709 | ||
710 | return true; | |
711 | } | |
712 | ||
713 | /* Write a PowerPC NLM import. */ | |
714 | ||
715 | static boolean | |
716 | nlm_powerpc_write_import (abfd, sec, rel) | |
717 | bfd *abfd; | |
718 | asection *sec; | |
719 | arelent *rel; | |
720 | { | |
721 | return nlm_powerpc_write_reloc (abfd, sec, rel, -1); | |
722 | } | |
723 | ||
724 | /* Write a PowerPC NLM external symbol. This routine keeps a static | |
725 | count of the symbol index. FIXME: I don't know if this is | |
726 | necessary, and the index never gets reset. */ | |
727 | ||
728 | static boolean | |
729 | nlm_powerpc_write_external (abfd, count, sym, relocs) | |
730 | bfd *abfd; | |
731 | bfd_size_type count; | |
732 | asymbol *sym; | |
733 | struct reloc_and_sec *relocs; | |
734 | { | |
735 | int i; | |
736 | bfd_byte len; | |
737 | unsigned char temp[NLM_TARGET_LONG_SIZE]; | |
738 | static int indx; | |
739 | ||
740 | len = strlen (sym->name); | |
741 | if ((bfd_write (&len, sizeof (bfd_byte), 1, abfd) != sizeof(bfd_byte)) | |
742 | || bfd_write (sym->name, len, 1, abfd) != len) | |
743 | { | |
744 | bfd_set_error (bfd_error_system_call); | |
745 | return false; | |
746 | } | |
747 | ||
748 | bfd_put_32 (abfd, count, temp); | |
749 | if (bfd_write (temp, sizeof(temp), 1, abfd) != sizeof (temp)) | |
750 | { | |
751 | bfd_set_error (bfd_error_system_call); | |
752 | return false; | |
753 | } | |
754 | ||
755 | for (i = 0; i < count; i++) | |
756 | { | |
757 | if (nlm_powerpc_write_reloc (abfd, relocs[i].sec, | |
758 | relocs[i].rel, indx) == false) | |
759 | return false; | |
760 | } | |
761 | ||
762 | ++indx; | |
763 | ||
764 | return true; | |
765 | } | |
766 | ||
767 | #include "nlmswap.h" | |
768 | ||
769 | static const struct nlm_backend_data nlm32_powerpc_backend = | |
770 | { | |
771 | "NetWare PowerPC Module \032", | |
772 | sizeof (Nlm32_powerpc_External_Fixed_Header), | |
773 | sizeof (struct nlm32_powerpc_external_prefix_header), | |
774 | bfd_arch_powerpc, | |
775 | 0, | |
776 | false, | |
777 | nlm_powerpc_backend_object_p, | |
778 | nlm_powerpc_write_prefix, | |
779 | nlm_powerpc_read_reloc, | |
780 | nlm_powerpc_mangle_relocs, | |
781 | nlm_powerpc_read_import, | |
782 | nlm_powerpc_write_import, | |
783 | 0, /* set_public_section */ | |
784 | 0, /* get_public_offset */ | |
785 | nlm_swap_fixed_header_in, | |
786 | nlm_swap_fixed_header_out, | |
787 | nlm_powerpc_write_external, | |
788 | 0, /* write_export */ | |
789 | }; | |
790 | ||
791 | #define TARGET_BIG_NAME "nlm32-powerpc" | |
792 | #define TARGET_BIG_SYM nlmNAME(powerpc_vec) | |
793 | #define TARGET_BACKEND_DATA &nlm32_powerpc_backend | |
794 | ||
795 | #include "nlm-target.h" |