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