OpenCores
URL https://opencores.org/ocsvn/open8_urisc/open8_urisc/trunk

Subversion Repositories open8_urisc

[/] [open8_urisc/] [trunk/] [gnu/] [binutils/] [bfd/] [nlm32-alpha.c] - Blame information for rev 303

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 14 khays
/* 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.
5
 
6
   This file is part of BFD, the Binary File Descriptor library.
7
 
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.
12
 
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.
17
 
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.  */
22
 
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
 
28
#include "sysdep.h"
29
#include "bfd.h"
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"
38
 
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
 
43
static bfd_boolean
44
nlm_alpha_backend_object_p (bfd *abfd)
45
{
46
  struct nlm32_alpha_external_prefix_header s;
47
  file_ptr size;
48
 
49
  if (bfd_bread (&s, (bfd_size_type) sizeof s, abfd) != sizeof s)
50
    return FALSE;
51
 
52
  if (H_GET_32 (abfd, s.magic) != NLM32_ALPHA_MAGIC)
53
    return FALSE;
54
 
55
  /* FIXME: Should we check the format number?  */
56
 
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;
61
 
62
  return TRUE;
63
}
64
 
65
/* Write out the prefix.  */
66
 
67
static bfd_boolean
68
nlm_alpha_write_prefix (bfd *abfd)
69
{
70
  struct nlm32_alpha_external_prefix_header s;
71
 
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;
79
}
80
 
81
#define ONES(n) (((bfd_vma) 1 << ((n) - 1) << 1) - 1)
82
 
83
/* How to process the various reloc types.  */
84
 
85
static 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.  */
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.  */
103
 
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.  */
118
 
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.  */
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.  */
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.  */
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.  */
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.  */
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.  */
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.  */
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.  */
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.  */
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.  */
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.  */
233
 
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.  */
248
 
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.  */
263
 
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.  */
278
 
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.  */
293
 
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.  */
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.  */
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.  */
324
 
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.  */
340
 
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.  */
356
 
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.  */
371
};
372
 
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.  */
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
 
392
static bfd_boolean
393
nlm_alpha_read_reloc (bfd *abfd,
394
                      nlmNAME (symbol_type) *sym,
395
                      asection **secp,
396
                      arelent *rel)
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.  */
407
  if (bfd_bread (&ext, (bfd_size_type) sizeof ext, abfd) != sizeof ext)
408
    return FALSE;
409
 
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);
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
473
      || r_vaddr < code_sec->size)
474
    {
475
      *secp = code_sec;
476
      rel->address = r_vaddr;
477
    }
478
  else
479
    {
480
      *secp = data_sec;
481
      rel->address = r_vaddr - code_sec->size;
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
 
582
  return TRUE;
583
}
584
 
585
/* Mangle Alpha NLM relocs for output.  */
586
 
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)
593
{
594
  return TRUE;
595
}
596
 
597
/* Read an ALPHA NLM import record.  */
598
 
599
static bfd_boolean
600
nlm_alpha_read_import (bfd *abfd, nlmNAME (symbol_type) * sym)
601
{
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;
608
 
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)
634
    {
635
      asection *section;
636
 
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++;
642
    }
643
 
644
  return TRUE;
645
}
646
 
647
/* Write an Alpha NLM reloc.  */
648
 
649
static bfd_boolean
650
nlm_alpha_write_import (bfd * abfd, asection * sec, arelent * rel)
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)
666
        r_vaddr += bfd_get_section_by_name (abfd, NLM_CODE_NAME) -> size;
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
    {
711
      /* r_type == ALPHA_R_NW_RELOC.  */
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.  */
728
  H_PUT_64 (abfd, r_vaddr, ext.r_vaddr);
729
  H_PUT_32 (abfd, r_symndx, ext.r_symndx);
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.  */
743
  if (bfd_bwrite (&ext, (bfd_size_type) sizeof ext, abfd) != sizeof ext)
744
    return FALSE;
745
 
746
  return TRUE;
747
}
748
 
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
 
757
static bfd_boolean
758
nlm_alpha_set_public_section (bfd * abfd, nlmNAME (symbol_type) * sym)
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);
764
  if (sym->symbol.value < code_sec->size)
765
    {
766
      sym->symbol.section = code_sec;
767
      sym->symbol.flags |= BSF_FUNCTION;
768
    }
769
  else
770
    {
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);
775
    }
776
  return TRUE;
777
}
778
 
779
/* Get the offset to write out for a public symbol.  */
780
 
781
static bfd_vma
782
nlm_alpha_get_public_offset (bfd * abfd ATTRIBUTE_UNUSED, asymbol * sym)
783
{
784
  return bfd_asymbol_value (sym);
785
}
786
 
787
/* Write an Alpha NLM external symbol.  */
788
 
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)
794
{
795
  bfd_size_type i;
796
  bfd_byte len;
797
  unsigned char temp[NLM_TARGET_LONG_SIZE];
798
  arelent r;
799
 
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;
805
 
806
  bfd_put_32 (abfd, count + 2, temp);
807
  if (bfd_bwrite (temp, (bfd_size_type) sizeof (temp), abfd) != sizeof (temp))
808
    return FALSE;
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;
817
  if (! nlm_alpha_write_import (abfd, NULL, &r))
818
    return FALSE;
819
 
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;
824
 
825
  for (i = 0; i < count; i++)
826
    if (! nlm_alpha_write_import (abfd, relocs[i].sec, relocs[i].rel))
827
      return FALSE;
828
 
829
  return TRUE;
830
}
831
 
832
#include "nlmswap.h"
833
 
834
static 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,
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.  */
854
};
855
 
856
#define TARGET_LITTLE_NAME              "nlm32-alpha"
857
#define TARGET_LITTLE_SYM               nlmNAME (alpha_vec)
858
#define TARGET_BACKEND_DATA             & nlm32_alpha_backend
859
 
860
#include "nlm-target.h"

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.