]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - bfd/nlm32-alpha.c
Switch sources over to use the GPL version 3
[thirdparty/binutils-gdb.git] / bfd / nlm32-alpha.c
CommitLineData
252b5132 1/* Support for 32-bit Alpha NLM (NetWare Loadable Module)
3db64b00 2 Copyright 1993, 1994, 2000, 2001, 2002, 2003, 2004, 2005, 2007
0f867abe 3 Free Software Foundation, Inc.
252b5132
RH
4 Written by Ian Lance Taylor, Cygnus Support.
5
7920ce38 6 This file is part of BFD, the Binary File Descriptor library.
252b5132 7
7920ce38
NC
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
cd123cb7 10 the Free Software Foundation; either version 3 of the License, or
7920ce38 11 (at your option) any later version.
252b5132 12
7920ce38
NC
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.
252b5132 17
7920ce38
NC
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
cd123cb7
NC
20 Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
21 MA 02110-1301, USA. */
22
252b5132
RH
23
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. */
27
252b5132 28#include "sysdep.h"
3db64b00 29#include "bfd.h"
252b5132
RH
30#include "libbfd.h"
31
32#define ARCH_SIZE 32
33
34#include "nlm/alpha-ext.h"
35#define Nlm_External_Fixed_Header Nlm32_alpha_External_Fixed_Header
36
37#include "libnlm.h"
252b5132
RH
38\f
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. */
42
b34976b6 43static bfd_boolean
7920ce38 44nlm_alpha_backend_object_p (bfd *abfd)
252b5132
RH
45{
46 struct nlm32_alpha_external_prefix_header s;
dc810e39 47 file_ptr size;
252b5132 48
7920ce38 49 if (bfd_bread (&s, (bfd_size_type) sizeof s, abfd) != sizeof s)
b34976b6 50 return FALSE;
252b5132 51
dc810e39 52 if (H_GET_32 (abfd, s.magic) != NLM32_ALPHA_MAGIC)
b34976b6 53 return FALSE;
252b5132
RH
54
55 /* FIXME: Should we check the format number? */
56
57 /* Skip to the end of the header. */
dc810e39 58 size = H_GET_32 (abfd, s.size);
252b5132 59 if (bfd_seek (abfd, size, SEEK_SET) != 0)
b34976b6 60 return FALSE;
252b5132 61
b34976b6 62 return TRUE;
252b5132
RH
63}
64
65/* Write out the prefix. */
66
b34976b6 67static bfd_boolean
7920ce38 68nlm_alpha_write_prefix (bfd *abfd)
252b5132
RH
69{
70 struct nlm32_alpha_external_prefix_header s;
71
72 memset (&s, 0, sizeof s);
dc810e39
AM
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);
7920ce38 76 if (bfd_bwrite (&s, (bfd_size_type) sizeof s, abfd) != sizeof s)
b34976b6
AM
77 return FALSE;
78 return TRUE;
252b5132
RH
79}
80\f
1a101a42
AM
81#define ONES(n) (((bfd_vma) 1 << ((n) - 1) << 1) - 1)
82
252b5132
RH
83/* How to process the various reloc types. */
84
85static reloc_howto_type nlm32_alpha_howto_table[] =
86{
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. */
7920ce38
NC
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. */
252b5132
RH
103
104 /* A 32 bit reference to a symbol. */
7920ce38
NC
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. */
252b5132
RH
118
119 /* A 64 bit reference to a symbol. */
7920ce38
NC
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. */
252b5132
RH
133
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. */
7920ce38
NC
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. */
252b5132
RH
150
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. */
7920ce38
NC
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. */
252b5132
RH
167
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. */
7920ce38
NC
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. */
252b5132
RH
190
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. */
7920ce38
NC
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. */
252b5132
RH
215
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. */
7920ce38
NC
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. */
252b5132
RH
233
234 /* A hint for a jump to a register. */
7920ce38
NC
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. */
252b5132
RH
248
249 /* 16 bit PC relative offset. */
7920ce38
NC
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. */
252b5132
RH
263
264 /* 32 bit PC relative offset. */
7920ce38
NC
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. */
252b5132
RH
278
279 /* A 64 bit PC relative offset. */
7920ce38
NC
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. */
252b5132
RH
293
294 /* Push a value on the reloc evaluation stack. */
7920ce38
NC
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. */
252b5132
RH
308
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. */
7920ce38
NC
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. */
252b5132
RH
324
325 /* Subtract the reloc address from the value on the top of the
326 relocation stack. */
7920ce38
NC
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. */
252b5132
RH
340
341 /* Shift the value on the top of the relocation stack right by the
342 given value. */
7920ce38
NC
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. */
252b5132
RH
356
357 /* Adjust the GP value for a new range in the object file. */
7920ce38
NC
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. */
252b5132
RH
371};
372
373static reloc_howto_type nlm32_alpha_nw_howto =
7920ce38
NC
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. */
252b5132
RH
387
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. */
391
b34976b6 392static bfd_boolean
7920ce38
NC
393nlm_alpha_read_reloc (bfd *abfd,
394 nlmNAME (symbol_type) *sym,
395 asection **secp,
396 arelent *rel)
252b5132
RH
397{
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;
405
406 /* Read the reloc from the file. */
dc810e39 407 if (bfd_bread (&ext, (bfd_size_type) sizeof ext, abfd) != sizeof ext)
b34976b6 408 return FALSE;
252b5132
RH
409
410 /* Swap in the reloc information. */
dc810e39
AM
411 r_vaddr = H_GET_64 (abfd, ext.r_vaddr);
412 r_symndx = H_GET_32 (abfd, ext.r_symndx);
252b5132
RH
413
414 BFD_ASSERT (bfd_little_endian (abfd));
415
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);
424
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)
429 {
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;
436 }
437 else
438 {
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)
446 {
447 rel->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr;
448 rel->addend = 0;
449 }
450 else if (r_symndx == ALPHA_RELOC_SECTION_TEXT)
451 {
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;
455 }
456 else if (r_symndx == ALPHA_RELOC_SECTION_DATA)
457 {
458 rel->sym_ptr_ptr = data_sec->symbol_ptr_ptr;
459 rel->addend = - bfd_get_section_vma (abfd, data_sec);
460 }
461 else
462 {
463 BFD_ASSERT (0);
464 rel->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr;
465 rel->addend = 0;
466 }
467 }
468
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
eea6121a 473 || r_vaddr < code_sec->size)
252b5132
RH
474 {
475 *secp = code_sec;
476 rel->address = r_vaddr;
477 }
478 else
479 {
480 *secp = data_sec;
eea6121a 481 rel->address = r_vaddr - code_sec->size;
252b5132
RH
482 }
483
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);
487
488 switch (r_type)
489 {
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;
498
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;
505
506 case ALPHA_R_LITERAL:
507 BFD_ASSERT (! r_extern);
508 rel->addend += lita_address;
509 break;
510
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;
519
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;
526
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;
535
536 case ALPHA_R_GPVALUE:
537 /* Record the new gp value. */
538 gp_value += r_symndx;
539 rel->addend = gp_value;
540 break;
541
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;
552
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)
559 {
560 gp_value = r_vaddr;
561 rel->addend = 0;
562 }
563 else if (r_size == ALPHA_R_NW_RELOC_LITA)
564 {
565 lita_address = r_vaddr;
566 rel->addend = r_symndx + 1;
567 }
568 else
569 BFD_ASSERT (0);
570 rel->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr;
571 break;
572
573 default:
574 break;
575 }
576
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];
581
b34976b6 582 return TRUE;
252b5132
RH
583}
584
585/* Mangle Alpha NLM relocs for output. */
586
b34976b6 587static bfd_boolean
7920ce38
NC
588nlm_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)
252b5132 593{
b34976b6 594 return TRUE;
252b5132
RH
595}
596
7920ce38 597/* Read an ALPHA NLM import record. */
252b5132 598
b34976b6 599static bfd_boolean
7920ce38 600nlm_alpha_read_import (bfd *abfd, nlmNAME (symbol_type) * sym)
252b5132 601{
7920ce38
NC
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. */
252b5132 606 char *name;
dc810e39 607 bfd_size_type amt;
252b5132 608
7920ce38 609 if (bfd_bread (& symlength, (bfd_size_type) sizeof (symlength), abfd)
252b5132 610 != sizeof (symlength))
b34976b6 611 return FALSE;
252b5132 612 sym -> symbol.the_bfd = abfd;
dc810e39 613 name = bfd_alloc (abfd, (bfd_size_type) symlength + 1);
252b5132 614 if (name == NULL)
b34976b6 615 return FALSE;
dc810e39 616 if (bfd_bread (name, (bfd_size_type) symlength, abfd) != symlength)
b34976b6 617 return FALSE;
252b5132
RH
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;
7920ce38 623 if (bfd_bread (temp, (bfd_size_type) sizeof (temp), abfd)
dc810e39 624 != sizeof (temp))
b34976b6 625 return FALSE;
dc810e39
AM
626 rcount = H_GET_32 (abfd, temp);
627 amt = rcount * sizeof (struct nlm_relent);
7920ce38 628 nlm_relocs = bfd_alloc (abfd, amt);
252b5132 629 if (!nlm_relocs)
b34976b6 630 return FALSE;
252b5132
RH
631 sym -> relocs = nlm_relocs;
632 sym -> rcnt = 0;
633 while (sym -> rcnt < rcount)
634 {
635 asection *section;
1518639e 636
82e51918 637 if (! nlm_alpha_read_reloc (abfd, sym, &section, &nlm_relocs -> reloc))
b34976b6 638 return FALSE;
252b5132
RH
639 nlm_relocs -> section = section;
640 nlm_relocs++;
641 sym -> rcnt++;
642 }
643
b34976b6 644 return TRUE;
252b5132
RH
645}
646
647/* Write an Alpha NLM reloc. */
648
b34976b6 649static bfd_boolean
7920ce38 650nlm_alpha_write_import (bfd * abfd, asection * sec, arelent * rel)
252b5132
RH
651{
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;
657
658 sym = *rel->sym_ptr_ptr;
659
660 /* Get values for the relocation fields. */
661 r_type = rel->howto->type;
662 if (r_type != ALPHA_R_NW_RELOC)
663 {
664 r_vaddr = bfd_get_section_vma (abfd, sec) + rel->address;
665 if ((sec->flags & SEC_CODE) == 0)
eea6121a 666 r_vaddr += bfd_get_section_by_name (abfd, NLM_CODE_NAME) -> size;
252b5132
RH
667 if (bfd_is_und_section (bfd_get_section (sym)))
668 {
669 r_extern = 1;
670 r_symndx = 0;
671 }
672 else
673 {
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;
679 }
680 r_offset = 0;
681 r_size = 0;
682
683 switch (r_type)
684 {
685 case ALPHA_R_LITUSE:
686 case ALPHA_R_GPDISP:
687 r_symndx = rel->addend;
688 break;
689
690 case ALPHA_R_OP_STORE:
691 r_size = rel->addend & 0xff;
692 r_offset = (rel->addend >> 8) & 0xff;
693 break;
694
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;
700
701 case ALPHA_R_IGNORE:
702 r_vaddr = rel->address;
703 break;
704
705 default:
706 break;
707 }
708 }
709 else
710 {
7920ce38 711 /* r_type == ALPHA_R_NW_RELOC. */
252b5132
RH
712 r_vaddr = rel->address;
713 if (rel->addend == 0)
714 {
715 r_symndx = 0;
716 r_size = ALPHA_R_NW_RELOC_SETGP;
717 }
718 else
719 {
720 r_symndx = rel->addend - 1;
721 r_size = ALPHA_R_NW_RELOC_LITA;
722 }
723 r_extern = 0;
724 r_offset = 0;
725 }
726
727 /* Swap out the relocation fields. */
dc810e39
AM
728 H_PUT_64 (abfd, r_vaddr, ext.r_vaddr);
729 H_PUT_32 (abfd, r_symndx, ext.r_symndx);
252b5132
RH
730
731 BFD_ASSERT (bfd_little_endian (abfd));
732
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);
741
742 /* Write out the relocation. */
dc810e39 743 if (bfd_bwrite (&ext, (bfd_size_type) sizeof ext, abfd) != sizeof ext)
b34976b6 744 return FALSE;
252b5132 745
b34976b6 746 return TRUE;
252b5132
RH
747}
748\f
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. */
754
755/* Set the section for a public symbol. */
756
b34976b6 757static bfd_boolean
7920ce38 758nlm_alpha_set_public_section (bfd * abfd, nlmNAME (symbol_type) * sym)
252b5132
RH
759{
760 asection *code_sec, *data_sec;
761
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);
eea6121a 764 if (sym->symbol.value < code_sec->size)
252b5132
RH
765 {
766 sym->symbol.section = code_sec;
767 sym->symbol.flags |= BSF_FUNCTION;
768 }
769 else
770 {
771 sym->symbol.section = data_sec;
eea6121a 772 sym->symbol.value -= code_sec->size;
252b5132 773 /* The data segment had better be aligned. */
eea6121a 774 BFD_ASSERT ((code_sec->size & 0xf) == 0);
252b5132 775 }
b34976b6 776 return TRUE;
252b5132
RH
777}
778
779/* Get the offset to write out for a public symbol. */
780
781static bfd_vma
7920ce38 782nlm_alpha_get_public_offset (bfd * abfd ATTRIBUTE_UNUSED, asymbol * sym)
252b5132
RH
783{
784 return bfd_asymbol_value (sym);
785}
786\f
787/* Write an Alpha NLM external symbol. */
788
b34976b6 789static bfd_boolean
7920ce38
NC
790nlm_alpha_write_external (bfd *abfd,
791 bfd_size_type count,
792 asymbol *sym,
793 struct reloc_and_sec *relocs)
252b5132 794{
5d964dfa 795 bfd_size_type i;
252b5132
RH
796 bfd_byte len;
797 unsigned char temp[NLM_TARGET_LONG_SIZE];
798 arelent r;
799
800 len = strlen (sym->name);
dc810e39
AM
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)
b34976b6 804 return FALSE;
252b5132
RH
805
806 bfd_put_32 (abfd, count + 2, temp);
dc810e39 807 if (bfd_bwrite (temp, (bfd_size_type) sizeof (temp), abfd) != sizeof (temp))
b34976b6 808 return FALSE;
252b5132
RH
809
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;
814
815 r.address = nlm_alpha_backend_data (abfd)->lita_address;
816 r.addend = nlm_alpha_backend_data (abfd)->lita_size + 1;
7920ce38 817 if (! nlm_alpha_write_import (abfd, NULL, &r))
b34976b6 818 return FALSE;
252b5132
RH
819
820 r.address = nlm_alpha_backend_data (abfd)->gp;
821 r.addend = 0;
7920ce38 822 if (! nlm_alpha_write_import (abfd, NULL, &r))
b34976b6 823 return FALSE;
252b5132
RH
824
825 for (i = 0; i < count; i++)
7920ce38
NC
826 if (! nlm_alpha_write_import (abfd, relocs[i].sec, relocs[i].rel))
827 return FALSE;
252b5132 828
b34976b6 829 return TRUE;
252b5132
RH
830}
831
832#include "nlmswap.h"
833
834static const struct nlm_backend_data nlm32_alpha_backend =
835{
836 "NetWare Alpha Module \032",
837 sizeof (Nlm32_alpha_External_Fixed_Header),
838 sizeof (struct nlm32_alpha_external_prefix_header),
839 bfd_arch_alpha,
840 0,
7920ce38 841 TRUE, /* No uninitialized data permitted by Alpha NetWare. */
252b5132
RH
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,
7920ce38 853 0, /* Write_export. */
252b5132
RH
854};
855
856#define TARGET_LITTLE_NAME "nlm32-alpha"
7920ce38
NC
857#define TARGET_LITTLE_SYM nlmNAME (alpha_vec)
858#define TARGET_BACKEND_DATA & nlm32_alpha_backend
252b5132
RH
859
860#include "nlm-target.h"