2008-01-30 Ralf Wildenhues <Ralf.Wildenhues@gmx.de>
[binutils.git] / bfd / nlm32-alpha.c
blob33bb5b31b6616738a23ec02a0667756d082f44ad
1 /* Support for 32-bit Alpha NLM (NetWare Loadable Module)
2 Copyright 1993, 1994, 2000, 2001, 2002, 2003, 2004, 2005, 2007
3 Free Software Foundation, Inc.
4 Written by Ian Lance Taylor, Cygnus Support.
6 This file is part of BFD, the Binary File Descriptor library.
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
21 MA 02110-1301, USA. */
24 /* This file describes the 32 bit Alpha NLM format. You might think
25 that an Alpha chip would use a 64 bit format, but, for some reason,
26 it doesn't. */
28 #include "sysdep.h"
29 #include "bfd.h"
30 #include "libbfd.h"
32 #define ARCH_SIZE 32
34 #include "nlm/alpha-ext.h"
35 #define Nlm_External_Fixed_Header Nlm32_alpha_External_Fixed_Header
37 #include "libnlm.h"
39 /* Alpha NLM's have a prefix header before the standard NLM. This
40 function reads it in, verifies the version, and seeks the bfd to
41 the location before the regular NLM header. */
43 static bfd_boolean
44 nlm_alpha_backend_object_p (bfd *abfd)
46 struct nlm32_alpha_external_prefix_header s;
47 file_ptr size;
49 if (bfd_bread (&s, (bfd_size_type) sizeof s, abfd) != sizeof s)
50 return FALSE;
52 if (H_GET_32 (abfd, s.magic) != NLM32_ALPHA_MAGIC)
53 return FALSE;
55 /* FIXME: Should we check the format number? */
57 /* Skip to the end of the header. */
58 size = H_GET_32 (abfd, s.size);
59 if (bfd_seek (abfd, size, SEEK_SET) != 0)
60 return FALSE;
62 return TRUE;
65 /* Write out the prefix. */
67 static bfd_boolean
68 nlm_alpha_write_prefix (bfd *abfd)
70 struct nlm32_alpha_external_prefix_header s;
72 memset (&s, 0, sizeof s);
73 H_PUT_32 (abfd, NLM32_ALPHA_MAGIC, s.magic);
74 H_PUT_32 (abfd, 2, s.format);
75 H_PUT_32 (abfd, sizeof s, s.size);
76 if (bfd_bwrite (&s, (bfd_size_type) sizeof s, abfd) != sizeof s)
77 return FALSE;
78 return TRUE;
81 #define ONES(n) (((bfd_vma) 1 << ((n) - 1) << 1) - 1)
83 /* How to process the various reloc types. */
85 static reloc_howto_type nlm32_alpha_howto_table[] =
87 /* Reloc type 0 is ignored by itself. However, it appears after a
88 GPDISP reloc to identify the location where the low order 16 bits
89 of the gp register are loaded. */
90 HOWTO (ALPHA_R_IGNORE, /* Type. */
91 0, /* Rightshift. */
92 0, /* Size (0 = byte, 1 = short, 2 = long). */
93 8, /* Bitsize. */
94 FALSE, /* PC_relative. */
95 0, /* Bitpos. */
96 complain_overflow_dont, /* Complain_on_overflow. */
97 0, /* Special_function. */
98 "IGNORE", /* Name. */
99 FALSE, /* Partial_inplace. */
100 0, /* Source mask. */
101 0, /* Dest mask. */
102 FALSE), /* PCrel_offset. */
104 /* A 32 bit reference to a symbol. */
105 HOWTO (ALPHA_R_REFLONG, /* Type. */
106 0, /* Rightshift. */
107 2, /* Size (0 = byte, 1 = short, 2 = long). */
108 32, /* Bitsize. */
109 FALSE, /* PC_relative. */
110 0, /* Bitpos. */
111 complain_overflow_bitfield, /* Complain_on_overflow. */
112 0, /* Special_function. */
113 "REFLONG", /* Name. */
114 TRUE, /* Partial_inplace. */
115 0xffffffff, /* Source mask. */
116 0xffffffff, /* Dest mask. */
117 FALSE), /* PCrel_offset. */
119 /* A 64 bit reference to a symbol. */
120 HOWTO (ALPHA_R_REFQUAD, /* Type. */
121 0, /* Rightshift. */
122 4, /* Size (0 = byte, 1 = short, 2 = long). */
123 64, /* Bitsize. */
124 FALSE, /* PC_relative. */
125 0, /* Bitpos. */
126 complain_overflow_bitfield, /* Complain_on_overflow. */
127 0, /* Special_function. */
128 "REFQUAD", /* Name. */
129 TRUE, /* Partial_inplace. */
130 ONES (64), /* Source mask. */
131 ONES (64), /* Dest mask. */
132 FALSE), /* PCrel_offset. */
134 /* A 32 bit GP relative offset. This is just like REFLONG except
135 that when the value is used the value of the gp register will be
136 added in. */
137 HOWTO (ALPHA_R_GPREL32, /* Type. */
138 0, /* Rightshift. */
139 2, /* Size (0 = byte, 1 = short, 2 = long). */
140 32, /* Bitsize. */
141 FALSE, /* PC_relative. */
142 0, /* Bitpos. */
143 complain_overflow_bitfield, /* Complain_on_overflow. */
144 0, /* Special_function. */
145 "GPREL32", /* Name. */
146 TRUE, /* Partial_inplace. */
147 0xffffffff, /* Source mask. */
148 0xffffffff, /* Dest mask. */
149 FALSE), /* PCrel_offset. */
151 /* Used for an instruction that refers to memory off the GP
152 register. The offset is 16 bits of the 32 bit instruction. This
153 reloc always seems to be against the .lita section. */
154 HOWTO (ALPHA_R_LITERAL, /* Type. */
155 0, /* Rightshift. */
156 2, /* Size (0 = byte, 1 = short, 2 = long). */
157 16, /* Bitsize. */
158 FALSE, /* PC_relative. */
159 0, /* Bitpos. */
160 complain_overflow_signed, /* Complain_on_overflow. */
161 0, /* Special_function. */
162 "LITERAL", /* Name. */
163 TRUE, /* Partial_inplace. */
164 0xffff, /* Source mask. */
165 0xffff, /* Dest mask. */
166 FALSE), /* PCrel_offset. */
168 /* This reloc only appears immediately following a LITERAL reloc.
169 It identifies a use of the literal. It seems that the linker can
170 use this to eliminate a portion of the .lita section. The symbol
171 index is special: 1 means the literal address is in the base
172 register of a memory format instruction; 2 means the literal
173 address is in the byte offset register of a byte-manipulation
174 instruction; 3 means the literal address is in the target
175 register of a jsr instruction. This does not actually do any
176 relocation. */
177 HOWTO (ALPHA_R_LITUSE, /* Type. */
178 0, /* Rightshift. */
179 2, /* Size (0 = byte, 1 = short, 2 = long). */
180 32, /* Bitsize. */
181 FALSE, /* PC_relative. */
182 0, /* Bitpos. */
183 complain_overflow_dont, /* Complain_on_overflow. */
184 0, /* Special_function. */
185 "LITUSE", /* Name. */
186 FALSE, /* Partial_inplace. */
187 0, /* Source mask. */
188 0, /* Dest mask. */
189 FALSE), /* PCrel_offset. */
191 /* Load the gp register. This is always used for a ldah instruction
192 which loads the upper 16 bits of the gp register. The next reloc
193 will be an IGNORE reloc which identifies the location of the lda
194 instruction which loads the lower 16 bits. The symbol index of
195 the GPDISP instruction appears to actually be the number of bytes
196 between the ldah and lda instructions. This gives two different
197 ways to determine where the lda instruction is; I don't know why
198 both are used. The value to use for the relocation is the
199 difference between the GP value and the current location; the
200 load will always be done against a register holding the current
201 address. */
202 HOWTO (ALPHA_R_GPDISP, /* Type. */
203 16, /* Rightshift. */
204 2, /* Size (0 = byte, 1 = short, 2 = long). */
205 16, /* Bitsize. */
206 TRUE, /* PC_relative. */
207 0, /* Bitpos. */
208 complain_overflow_dont, /* Complain_on_overflow. */
209 0, /* Special_function. */
210 "GPDISP", /* Name. */
211 TRUE, /* Partial_inplace. */
212 0xffff, /* Source mask. */
213 0xffff, /* Dest mask. */
214 TRUE), /* PCrel_offset. */
216 /* A 21 bit branch. The native assembler generates these for
217 branches within the text segment, and also fills in the PC
218 relative offset in the instruction. It seems to me that this
219 reloc, unlike the others, is not partial_inplace. */
220 HOWTO (ALPHA_R_BRADDR, /* Type. */
221 2, /* Rightshift. */
222 2, /* Size (0 = byte, 1 = short, 2 = long). */
223 21, /* Bitsize. */
224 TRUE, /* PC_relative. */
225 0, /* Bitpos. */
226 complain_overflow_signed, /* Complain_on_overflow. */
227 0, /* Special_function. */
228 "BRADDR", /* Name. */
229 FALSE, /* Partial_inplace. */
230 0, /* Source mask. */
231 0x1fffff, /* Dest mask. */
232 FALSE), /* PCrel_offset. */
234 /* A hint for a jump to a register. */
235 HOWTO (ALPHA_R_HINT, /* Type. */
236 2, /* Rightshift. */
237 2, /* Size (0 = byte, 1 = short, 2 = long). */
238 14, /* Bitsize. */
239 FALSE, /* PC_relative. */
240 0, /* Bitpos. */
241 complain_overflow_dont, /* Complain_on_overflow. */
242 0, /* Special_function. */
243 "HINT", /* Name. */
244 TRUE, /* Partial_inplace. */
245 0x3fff, /* Source mask. */
246 0x3fff, /* Dest mask. */
247 FALSE), /* PCrel_offset. */
249 /* 16 bit PC relative offset. */
250 HOWTO (ALPHA_R_SREL16, /* Type. */
251 0, /* Rightshift. */
252 1, /* Size (0 = byte, 1 = short, 2 = long). */
253 16, /* Bitsize. */
254 TRUE, /* PC_relative. */
255 0, /* Bitpos. */
256 complain_overflow_signed, /* Complain_on_overflow. */
257 0, /* Special_function. */
258 "SREL16", /* Name. */
259 TRUE, /* Partial_inplace. */
260 0xffff, /* Source mask. */
261 0xffff, /* Dest mask. */
262 FALSE), /* PCrel_offset. */
264 /* 32 bit PC relative offset. */
265 HOWTO (ALPHA_R_SREL32, /* Type. */
266 0, /* Rightshift. */
267 2, /* Size (0 = byte, 1 = short, 2 = long). */
268 32, /* Bitsize. */
269 TRUE, /* PC_relative. */
270 0, /* Bitpos. */
271 complain_overflow_signed, /* Complain_on_overflow. */
272 0, /* Special_function. */
273 "SREL32", /* Name. */
274 TRUE, /* Partial_inplace. */
275 0xffffffff, /* Source mask. */
276 0xffffffff, /* Dest mask. */
277 FALSE), /* PCrel_offset. */
279 /* A 64 bit PC relative offset. */
280 HOWTO (ALPHA_R_SREL64, /* Type. */
281 0, /* Rightshift. */
282 4, /* Size (0 = byte, 1 = short, 2 = long). */
283 64, /* Bitsize. */
284 TRUE, /* PC_relative. */
285 0, /* Bitpos. */
286 complain_overflow_signed, /* Complain_on_overflow. */
287 0, /* Special_function. */
288 "SREL64", /* Name. */
289 TRUE, /* Partial_inplace. */
290 ONES (64), /* Source mask. */
291 ONES (64), /* Dest mask. */
292 FALSE), /* PCrel_offset. */
294 /* Push a value on the reloc evaluation stack. */
295 HOWTO (ALPHA_R_OP_PUSH, /* Type. */
296 0, /* Rightshift. */
297 0, /* Size (0 = byte, 1 = short, 2 = long). */
298 0, /* Bitsize. */
299 FALSE, /* PC_relative. */
300 0, /* Bitpos. */
301 complain_overflow_dont, /* Complain_on_overflow. */
302 0, /* Special_function. */
303 "OP_PUSH", /* Name. */
304 FALSE, /* Partial_inplace. */
305 0, /* Source mask. */
306 0, /* Dest mask. */
307 FALSE), /* PCrel_offset. */
309 /* Store the value from the stack at the given address. Store it in
310 a bitfield of size r_size starting at bit position r_offset. */
311 HOWTO (ALPHA_R_OP_STORE, /* Type. */
312 0, /* Rightshift. */
313 4, /* Size (0 = byte, 1 = short, 2 = long). */
314 64, /* Bitsize. */
315 FALSE, /* PC_relative. */
316 0, /* Bitpos. */
317 complain_overflow_dont, /* Complain_on_overflow. */
318 0, /* Special_function. */
319 "OP_STORE", /* Name. */
320 FALSE, /* Partial_inplace. */
321 0, /* Source mask. */
322 ONES (64), /* Dest mask. */
323 FALSE), /* PCrel_offset. */
325 /* Subtract the reloc address from the value on the top of the
326 relocation stack. */
327 HOWTO (ALPHA_R_OP_PSUB, /* Type. */
328 0, /* Rightshift. */
329 0, /* Size (0 = byte, 1 = short, 2 = long). */
330 0, /* Bitsize. */
331 FALSE, /* PC_relative. */
332 0, /* Bitpos. */
333 complain_overflow_dont, /* Complain_on_overflow. */
334 0, /* Special_function. */
335 "OP_PSUB", /* Name. */
336 FALSE, /* Partial_inplace. */
337 0, /* Source mask. */
338 0, /* Dest mask. */
339 FALSE), /* PCrel_offset. */
341 /* Shift the value on the top of the relocation stack right by the
342 given value. */
343 HOWTO (ALPHA_R_OP_PRSHIFT, /* Type. */
344 0, /* Rightshift. */
345 0, /* Size (0 = byte, 1 = short, 2 = long). */
346 0, /* Bitsize. */
347 FALSE, /* PC_relative. */
348 0, /* Bitpos. */
349 complain_overflow_dont, /* Complain_on_overflow. */
350 0, /* Special_function. */
351 "OP_PRSHIFT", /* Name. */
352 FALSE, /* Partial_inplace. */
353 0, /* Source mask. */
354 0, /* Dest mask. */
355 FALSE), /* PCrel_offset. */
357 /* Adjust the GP value for a new range in the object file. */
358 HOWTO (ALPHA_R_GPVALUE, /* Type. */
359 0, /* Rightshift. */
360 0, /* Size (0 = byte, 1 = short, 2 = long). */
361 0, /* Bitsize. */
362 FALSE, /* PC_relative. */
363 0, /* Bitpos. */
364 complain_overflow_dont, /* Complain_on_overflow. */
365 0, /* Special_function. */
366 "GPVALUE", /* Name. */
367 FALSE, /* Partial_inplace. */
368 0, /* Source mask. */
369 0, /* Dest mask. */
370 FALSE) /* PCrel_offset. */
373 static reloc_howto_type nlm32_alpha_nw_howto =
374 HOWTO (ALPHA_R_NW_RELOC, /* Type. */
375 0, /* Rightshift. */
376 0, /* Size (0 = byte, 1 = short, 2 = long). */
377 0, /* Bitsize. */
378 FALSE, /* PC_relative. */
379 0, /* Bitpos. */
380 complain_overflow_dont, /* Complain_on_overflow. */
381 0, /* Special_function. */
382 "NW_RELOC", /* Name. */
383 FALSE, /* Partial_inplace. */
384 0, /* Source mask. */
385 0, /* Dest mask. */
386 FALSE); /* PCrel_offset. */
388 /* Read an Alpha NLM reloc. This routine keeps some static data which
389 it uses when handling local relocs. This only works correctly
390 because all the local relocs are read at once. */
392 static bfd_boolean
393 nlm_alpha_read_reloc (bfd *abfd,
394 nlmNAME (symbol_type) *sym,
395 asection **secp,
396 arelent *rel)
398 static bfd_vma gp_value;
399 static bfd_vma lita_address;
400 struct nlm32_alpha_external_reloc ext;
401 bfd_vma r_vaddr;
402 long r_symndx;
403 int r_type, r_extern, r_offset, r_size;
404 asection *code_sec, *data_sec;
406 /* Read the reloc from the file. */
407 if (bfd_bread (&ext, (bfd_size_type) sizeof ext, abfd) != sizeof ext)
408 return FALSE;
410 /* Swap in the reloc information. */
411 r_vaddr = H_GET_64 (abfd, ext.r_vaddr);
412 r_symndx = H_GET_32 (abfd, ext.r_symndx);
414 BFD_ASSERT (bfd_little_endian (abfd));
416 r_type = ((ext.r_bits[0] & RELOC_BITS0_TYPE_LITTLE)
417 >> RELOC_BITS0_TYPE_SH_LITTLE);
418 r_extern = (ext.r_bits[1] & RELOC_BITS1_EXTERN_LITTLE) != 0;
419 r_offset = ((ext.r_bits[1] & RELOC_BITS1_OFFSET_LITTLE)
420 >> RELOC_BITS1_OFFSET_SH_LITTLE);
421 /* Ignore the reserved bits. */
422 r_size = ((ext.r_bits[3] & RELOC_BITS3_SIZE_LITTLE)
423 >> RELOC_BITS3_SIZE_SH_LITTLE);
425 /* Fill in the BFD arelent structure. */
426 code_sec = bfd_get_section_by_name (abfd, NLM_CODE_NAME);
427 data_sec = bfd_get_section_by_name (abfd, NLM_INITIALIZED_DATA_NAME);
428 if (r_extern)
430 /* External relocations are only used for imports. */
431 BFD_ASSERT (sym != NULL);
432 /* We don't need to set sym_ptr_ptr for this case. It is set in
433 nlm_canonicalize_reloc. */
434 rel->sym_ptr_ptr = NULL;
435 rel->addend = 0;
437 else
439 /* Internal relocations are only used for local relocation
440 fixups. If they are not NW_RELOC or GPDISP or IGNORE, they
441 must be against .text or .data. */
442 BFD_ASSERT (r_type == ALPHA_R_NW_RELOC || sym == NULL);
443 if (r_type == ALPHA_R_NW_RELOC
444 || r_type == ALPHA_R_GPDISP
445 || r_type == ALPHA_R_IGNORE)
447 rel->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr;
448 rel->addend = 0;
450 else if (r_symndx == ALPHA_RELOC_SECTION_TEXT)
452 rel->sym_ptr_ptr = code_sec->symbol_ptr_ptr;
453 BFD_ASSERT (bfd_get_section_vma (abfd, code_sec) == 0);
454 rel->addend = 0;
456 else if (r_symndx == ALPHA_RELOC_SECTION_DATA)
458 rel->sym_ptr_ptr = data_sec->symbol_ptr_ptr;
459 rel->addend = - bfd_get_section_vma (abfd, data_sec);
461 else
463 BFD_ASSERT (0);
464 rel->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr;
465 rel->addend = 0;
469 /* We use the address to determine whether the reloc is in the .text
470 or .data section. R_NW_RELOC relocs don't really have a section,
471 so we put them in .text. */
472 if (r_type == ALPHA_R_NW_RELOC
473 || r_vaddr < code_sec->size)
475 *secp = code_sec;
476 rel->address = r_vaddr;
478 else
480 *secp = data_sec;
481 rel->address = r_vaddr - code_sec->size;
484 /* We must adjust the addend based on the type. */
485 BFD_ASSERT ((r_type >= 0 && r_type <= ALPHA_R_GPVALUE)
486 || r_type == ALPHA_R_NW_RELOC);
488 switch (r_type)
490 case ALPHA_R_BRADDR:
491 case ALPHA_R_SREL16:
492 case ALPHA_R_SREL32:
493 case ALPHA_R_SREL64:
494 /* The PC relative relocs do not seem to use the section VMA as
495 a negative addend. */
496 rel->addend = 0;
497 break;
499 case ALPHA_R_GPREL32:
500 /* Copy the gp value for this object file into the addend, to
501 ensure that we are not confused by the linker. */
502 if (! r_extern)
503 rel->addend += gp_value;
504 break;
506 case ALPHA_R_LITERAL:
507 BFD_ASSERT (! r_extern);
508 rel->addend += lita_address;
509 break;
511 case ALPHA_R_LITUSE:
512 case ALPHA_R_GPDISP:
513 /* The LITUSE and GPDISP relocs do not use a symbol, or an
514 addend, but they do use a special code. Put this code in the
515 addend field. */
516 rel->addend = r_symndx;
517 rel->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr;
518 break;
520 case ALPHA_R_OP_STORE:
521 /* The STORE reloc needs the size and offset fields. We store
522 them in the addend. */
523 BFD_ASSERT (r_offset < 256 && r_size < 256);
524 rel->addend = (r_offset << 8) + r_size;
525 break;
527 case ALPHA_R_OP_PUSH:
528 case ALPHA_R_OP_PSUB:
529 case ALPHA_R_OP_PRSHIFT:
530 /* The PUSH, PSUB and PRSHIFT relocs do not actually use an
531 address. I believe that the address supplied is really an
532 addend. */
533 rel->addend = r_vaddr;
534 break;
536 case ALPHA_R_GPVALUE:
537 /* Record the new gp value. */
538 gp_value += r_symndx;
539 rel->addend = gp_value;
540 break;
542 case ALPHA_R_IGNORE:
543 /* If the type is ALPHA_R_IGNORE, make sure this is a reference
544 to the absolute section so that the reloc is ignored. For
545 some reason the address of this reloc type is not adjusted by
546 the section vma. We record the gp value for this object file
547 here, for convenience when doing the GPDISP relocation. */
548 rel->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr;
549 rel->address = r_vaddr;
550 rel->addend = gp_value;
551 break;
553 case ALPHA_R_NW_RELOC:
554 /* If this is SETGP, we set the addend to 0. Otherwise we set
555 the addend to the size of the .lita section (this is
556 r_symndx) plus 1. We have already set the address of the
557 reloc to r_vaddr. */
558 if (r_size == ALPHA_R_NW_RELOC_SETGP)
560 gp_value = r_vaddr;
561 rel->addend = 0;
563 else if (r_size == ALPHA_R_NW_RELOC_LITA)
565 lita_address = r_vaddr;
566 rel->addend = r_symndx + 1;
568 else
569 BFD_ASSERT (0);
570 rel->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr;
571 break;
573 default:
574 break;
577 if (r_type == ALPHA_R_NW_RELOC)
578 rel->howto = &nlm32_alpha_nw_howto;
579 else
580 rel->howto = &nlm32_alpha_howto_table[r_type];
582 return TRUE;
585 /* Mangle Alpha NLM relocs for output. */
587 static bfd_boolean
588 nlm_alpha_mangle_relocs (bfd *abfd ATTRIBUTE_UNUSED,
589 asection *sec ATTRIBUTE_UNUSED,
590 const void * data ATTRIBUTE_UNUSED,
591 bfd_vma offset ATTRIBUTE_UNUSED,
592 bfd_size_type count ATTRIBUTE_UNUSED)
594 return TRUE;
597 /* Read an ALPHA NLM import record. */
599 static bfd_boolean
600 nlm_alpha_read_import (bfd *abfd, nlmNAME (symbol_type) * sym)
602 struct nlm_relent *nlm_relocs; /* Relocation records for symbol. */
603 bfd_size_type rcount; /* Number of relocs. */
604 bfd_byte temp[NLM_TARGET_LONG_SIZE]; /* Temporary 32-bit value. */
605 unsigned char symlength; /* Length of symbol name. */
606 char *name;
607 bfd_size_type amt;
609 if (bfd_bread (& symlength, (bfd_size_type) sizeof (symlength), abfd)
610 != sizeof (symlength))
611 return FALSE;
612 sym -> symbol.the_bfd = abfd;
613 name = bfd_alloc (abfd, (bfd_size_type) symlength + 1);
614 if (name == NULL)
615 return FALSE;
616 if (bfd_bread (name, (bfd_size_type) symlength, abfd) != symlength)
617 return FALSE;
618 name[symlength] = '\0';
619 sym -> symbol.name = name;
620 sym -> symbol.flags = 0;
621 sym -> symbol.value = 0;
622 sym -> symbol.section = bfd_und_section_ptr;
623 if (bfd_bread (temp, (bfd_size_type) sizeof (temp), abfd)
624 != sizeof (temp))
625 return FALSE;
626 rcount = H_GET_32 (abfd, temp);
627 amt = rcount * sizeof (struct nlm_relent);
628 nlm_relocs = bfd_alloc (abfd, amt);
629 if (!nlm_relocs)
630 return FALSE;
631 sym -> relocs = nlm_relocs;
632 sym -> rcnt = 0;
633 while (sym -> rcnt < rcount)
635 asection *section;
637 if (! nlm_alpha_read_reloc (abfd, sym, &section, &nlm_relocs -> reloc))
638 return FALSE;
639 nlm_relocs -> section = section;
640 nlm_relocs++;
641 sym -> rcnt++;
644 return TRUE;
647 /* Write an Alpha NLM reloc. */
649 static bfd_boolean
650 nlm_alpha_write_import (bfd * abfd, asection * sec, arelent * rel)
652 asymbol *sym;
653 bfd_vma r_vaddr;
654 long r_symndx;
655 int r_type, r_extern, r_offset, r_size;
656 struct nlm32_alpha_external_reloc ext;
658 sym = *rel->sym_ptr_ptr;
660 /* Get values for the relocation fields. */
661 r_type = rel->howto->type;
662 if (r_type != ALPHA_R_NW_RELOC)
664 r_vaddr = bfd_get_section_vma (abfd, sec) + rel->address;
665 if ((sec->flags & SEC_CODE) == 0)
666 r_vaddr += bfd_get_section_by_name (abfd, NLM_CODE_NAME) -> size;
667 if (bfd_is_und_section (bfd_get_section (sym)))
669 r_extern = 1;
670 r_symndx = 0;
672 else
674 r_extern = 0;
675 if (bfd_get_section_flags (abfd, bfd_get_section (sym)) & SEC_CODE)
676 r_symndx = ALPHA_RELOC_SECTION_TEXT;
677 else
678 r_symndx = ALPHA_RELOC_SECTION_DATA;
680 r_offset = 0;
681 r_size = 0;
683 switch (r_type)
685 case ALPHA_R_LITUSE:
686 case ALPHA_R_GPDISP:
687 r_symndx = rel->addend;
688 break;
690 case ALPHA_R_OP_STORE:
691 r_size = rel->addend & 0xff;
692 r_offset = (rel->addend >> 8) & 0xff;
693 break;
695 case ALPHA_R_OP_PUSH:
696 case ALPHA_R_OP_PSUB:
697 case ALPHA_R_OP_PRSHIFT:
698 r_vaddr = rel->addend;
699 break;
701 case ALPHA_R_IGNORE:
702 r_vaddr = rel->address;
703 break;
705 default:
706 break;
709 else
711 /* r_type == ALPHA_R_NW_RELOC. */
712 r_vaddr = rel->address;
713 if (rel->addend == 0)
715 r_symndx = 0;
716 r_size = ALPHA_R_NW_RELOC_SETGP;
718 else
720 r_symndx = rel->addend - 1;
721 r_size = ALPHA_R_NW_RELOC_LITA;
723 r_extern = 0;
724 r_offset = 0;
727 /* Swap out the relocation fields. */
728 H_PUT_64 (abfd, r_vaddr, ext.r_vaddr);
729 H_PUT_32 (abfd, r_symndx, ext.r_symndx);
731 BFD_ASSERT (bfd_little_endian (abfd));
733 ext.r_bits[0] = ((r_type << RELOC_BITS0_TYPE_SH_LITTLE)
734 & RELOC_BITS0_TYPE_LITTLE);
735 ext.r_bits[1] = ((r_extern ? RELOC_BITS1_EXTERN_LITTLE : 0)
736 | ((r_offset << RELOC_BITS1_OFFSET_SH_LITTLE)
737 & RELOC_BITS1_OFFSET_LITTLE));
738 ext.r_bits[2] = 0;
739 ext.r_bits[3] = ((r_size << RELOC_BITS3_SIZE_SH_LITTLE)
740 & RELOC_BITS3_SIZE_LITTLE);
742 /* Write out the relocation. */
743 if (bfd_bwrite (&ext, (bfd_size_type) sizeof ext, abfd) != sizeof ext)
744 return FALSE;
746 return TRUE;
749 /* Alpha NetWare does not use the high bit to determine whether a
750 public symbol is in the code segment or the data segment. Instead,
751 it just uses the address. The set_public_section and
752 get_public_offset routines override the default code which uses the
753 high bit. */
755 /* Set the section for a public symbol. */
757 static bfd_boolean
758 nlm_alpha_set_public_section (bfd * abfd, nlmNAME (symbol_type) * sym)
760 asection *code_sec, *data_sec;
762 code_sec = bfd_get_section_by_name (abfd, NLM_CODE_NAME);
763 data_sec = bfd_get_section_by_name (abfd, NLM_INITIALIZED_DATA_NAME);
764 if (sym->symbol.value < code_sec->size)
766 sym->symbol.section = code_sec;
767 sym->symbol.flags |= BSF_FUNCTION;
769 else
771 sym->symbol.section = data_sec;
772 sym->symbol.value -= code_sec->size;
773 /* The data segment had better be aligned. */
774 BFD_ASSERT ((code_sec->size & 0xf) == 0);
776 return TRUE;
779 /* Get the offset to write out for a public symbol. */
781 static bfd_vma
782 nlm_alpha_get_public_offset (bfd * abfd ATTRIBUTE_UNUSED, asymbol * sym)
784 return bfd_asymbol_value (sym);
787 /* Write an Alpha NLM external symbol. */
789 static bfd_boolean
790 nlm_alpha_write_external (bfd *abfd,
791 bfd_size_type count,
792 asymbol *sym,
793 struct reloc_and_sec *relocs)
795 bfd_size_type i;
796 bfd_byte len;
797 unsigned char temp[NLM_TARGET_LONG_SIZE];
798 arelent r;
800 len = strlen (sym->name);
801 if ((bfd_bwrite (&len, (bfd_size_type) sizeof (bfd_byte), abfd)
802 != sizeof (bfd_byte))
803 || bfd_bwrite (sym->name, (bfd_size_type) len, abfd) != len)
804 return FALSE;
806 bfd_put_32 (abfd, count + 2, temp);
807 if (bfd_bwrite (temp, (bfd_size_type) sizeof (temp), abfd) != sizeof (temp))
808 return FALSE;
810 /* The first two relocs for each external symbol are the .lita
811 address and the GP value. */
812 r.sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr;
813 r.howto = &nlm32_alpha_nw_howto;
815 r.address = nlm_alpha_backend_data (abfd)->lita_address;
816 r.addend = nlm_alpha_backend_data (abfd)->lita_size + 1;
817 if (! nlm_alpha_write_import (abfd, NULL, &r))
818 return FALSE;
820 r.address = nlm_alpha_backend_data (abfd)->gp;
821 r.addend = 0;
822 if (! nlm_alpha_write_import (abfd, NULL, &r))
823 return FALSE;
825 for (i = 0; i < count; i++)
826 if (! nlm_alpha_write_import (abfd, relocs[i].sec, relocs[i].rel))
827 return FALSE;
829 return TRUE;
832 #include "nlmswap.h"
834 static const struct nlm_backend_data nlm32_alpha_backend =
836 "NetWare Alpha Module \032",
837 sizeof (Nlm32_alpha_External_Fixed_Header),
838 sizeof (struct nlm32_alpha_external_prefix_header),
839 bfd_arch_alpha,
841 TRUE, /* No uninitialized data permitted by Alpha NetWare. */
842 nlm_alpha_backend_object_p,
843 nlm_alpha_write_prefix,
844 nlm_alpha_read_reloc,
845 nlm_alpha_mangle_relocs,
846 nlm_alpha_read_import,
847 nlm_alpha_write_import,
848 nlm_alpha_set_public_section,
849 nlm_alpha_get_public_offset,
850 nlm_swap_fixed_header_in,
851 nlm_swap_fixed_header_out,
852 nlm_alpha_write_external,
853 0, /* Write_export. */
856 #define TARGET_LITTLE_NAME "nlm32-alpha"
857 #define TARGET_LITTLE_SYM nlmNAME (alpha_vec)
858 #define TARGET_BACKEND_DATA & nlm32_alpha_backend
860 #include "nlm-target.h"