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

Subversion Repositories openrisc_me

[/] [openrisc/] [trunk/] [gnu-src/] [binutils-2.20.1/] [gas/] [config/] [obj-coff-seh.c] - Blame information for rev 438

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

Line No. Rev Author Line
1 205 julius
/* seh pdata/xdata coff object file format
2
   Copyright 2009
3
   Free Software Foundation, Inc.
4
 
5
   This file is part of GAS.
6
 
7
   GAS is free software; you can redistribute it and/or modify
8
   it under the terms of the GNU General Public License as published by
9
   the Free Software Foundation; either version 3, or (at your option)
10
   any later version.
11
 
12
   GAS 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.
16
 
17
   You should have received a copy of the GNU General Public License
18
   along with GAS; see the file COPYING.  If not, write to the Free
19
   Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
20
   02110-1301, USA.  */
21
 
22
#include "obj-coff-seh.h"
23
 
24
/* Forward declarations.  */
25
static seh_kind seh_get_target_kind (void);
26
static int seh_symbol (bfd *, const char *, const char *, const char *, asection *, int, int);
27
static void seh_reloc (bfd *, bfd_size_type, int, int);
28
static void save_relocs (asection *sec);
29
static asection *quick_section (bfd *abfd, const char *name, int flags, int align);
30
static void seh_symbol_init (bfd *abfd, unsigned int added);
31
static void seh_emit_rva (const char *);
32
static void seh_emit_long (const char *);
33
static void seh_make_globl (char *);
34
static segT seh_make_section (void);
35
static segT seh_make_section2 (const char *section_name, unsigned flags);
36
static char *seh_make_xlbl_name (seh_context *);
37
static char *make_seh_text_label (seh_context *c, symbolS **addr);
38
 
39
static void seh_write_text_eh_data (const char *hnd, const char *hnd_data);
40
static void seh_emit_rva (const char *name);
41
static int seh_needed_unwind_info (seh_context *);
42
static void seh_fill_pcsyms (const seh_context *c, char **, int *);
43
static size_t seh_getelm_data_size (const seh_context *, int, int);
44
static size_t seh_getsize_of_unwind_entry (seh_context *, int, int, int);
45
static void seh_make_unwind_entry (const seh_context *, char *, int, int, int, unsigned char *, size_t *, int);
46
static size_t seh_getsize_unwind_data (seh_context *);
47
static void seh_create_unwind_data (seh_context *, unsigned char *, size_t);
48
static void seh_make_function_entry_xdata (seh_context *, char *, char *, char *, unsigned char *, size_t *,int);
49
static seh_scope_elem *seh_x64_makescope_elem (seh_context *, const char *, const char *, const char *, const char *);
50
 
51
/* Local data.  */
52
static asymbol **symtab;
53
static int symptr;
54
static arelent *reltab = 0;
55
static int relcount = 0, relsize = 0;
56
 
57
static seh_context *seh_ctx_root = NULL;
58
static seh_context *seh_ctx = NULL;
59
static seh_context *seh_ctx_cur = NULL;
60
 
61
/* Write xdata for arm, sh3, sh4, and ppc.  */
62
 
63
static void
64
seh_write_text_eh_data (const char *hnd, const char *hnd_data)
65
{
66
  if (!hnd || *hnd==0)
67
    return;
68
  if (hnd[0] == '@')
69
    seh_emit_long ("0");
70
  else
71
    seh_emit_long (hnd);
72
  if (!hnd_data || hnd_data[0] == '@')
73
    seh_emit_long ("0");
74
  else
75
    seh_emit_long (hnd_data);
76
}
77
 
78
/* Generate initial pdata for x64 and mips.  */
79
static void
80
make_function_entry_pdata (seh_context *c)
81
{
82
  segT sec = NULL;
83
  segT current_seg = now_seg;
84
  subsegT current_subseg = now_subseg;
85
 
86
  sec = seh_make_section ();
87
  switch (seh_get_target_kind ())
88
    {
89
    case seh_kind_x64:
90
      subseg_set (sec, 0);
91
      seh_emit_rva (c->func_name);
92
      seh_emit_rva (c->end_symbol);
93
      seh_emit_rva (c->xdata_first);
94
      break;
95
    case seh_kind_mips:
96
      subseg_set (sec, 0);
97
      seh_emit_long (c->func_name);
98
      seh_emit_long (c->end_symbol);
99
      if (c->handler_name == NULL)
100
        seh_emit_long ("0");
101
      else if (c->handler_name[0] == '@')
102
        {
103
          if (strcasecmp (c->handler_name, "@1") == 0)
104
            seh_emit_long ("1");
105
          else
106
            seh_emit_long ("0");
107
        }
108
      else
109
        seh_emit_long (c->handler_name);
110
      if (c->handler_data_name == NULL || c->handler_data_name[0] == '@')
111
        seh_emit_long ("0");
112
      else
113
        seh_emit_long (c->handler_data_name);
114
      seh_emit_long (c->endprologue_symbol ? c->endprologue_symbol : c->func_name);
115
      break;
116
    default:
117
      break;
118
    }
119
  subseg_set (current_seg, current_subseg);
120
}
121
 
122
static void
123
seh_x64_write_xdata (void)
124
{
125
  seh_context *h;
126
  size_t xdata_size = 0, count_syms = 0;
127
  size_t xdata_offs = 0;
128
  unsigned char *data;
129
  segT seg_xdata;
130
  bfd *abfd = stdoutput;
131
 
132
  h = seh_ctx_root;
133
  if (!h || h->done)
134
    return;
135
  while (h != NULL)
136
    {
137
      h->xdata_offset = xdata_size;
138
      xdata_size += seh_getsize_unwind_data (h);
139
      count_syms += h->count_syms;
140
      h = h->next;
141
    }
142
 
143
  if (xdata_size == 0)
144
    return;
145
 
146
  seh_symbol_init (abfd, count_syms);
147
  data = xmalloc (xdata_size);
148
  seg_xdata = quick_section (abfd, ".xdata", SEC_HAS_CONTENTS, 3);
149
  seg_xdata->contents = data;
150
  memset (data, 0, xdata_size);
151
  bfd_set_section_size (abfd, seg_xdata, xdata_size);
152
  h = seh_ctx_root;
153
  while (h != NULL)
154
    {
155
      xdata_offs = h->xdata_offset;
156
      h->section = seg_xdata;
157
      h->abfd = abfd;
158
      if (h->done == 0)
159
        {
160
          h->done = 1;
161
          seh_create_unwind_data (h, data, xdata_offs);
162
          h->done = 1;
163
        }
164
      h = h->next;
165
    }
166
  save_relocs (seg_xdata);
167
  bfd_set_symtab (abfd, symtab, symptr);
168
  bfd_set_section_contents (abfd, seg_xdata, data, 0, xdata_size);
169
}
170
 
171
static void
172
seh_arm_create_pdata (seh_context *c, unsigned char *data, size_t pdata_offs)
173
{
174
  int idx;
175
  unsigned int val;
176
  valueT func_len = 0;
177
  valueT prolog_len = 0;
178
  valueT start_len = 0;
179
 
180
  func_len = resolve_symbol_value (c->end_addr);
181
  start_len = resolve_symbol_value (c->start_addr);
182
  if (c->endprologue_addr)
183
    prolog_len = resolve_symbol_value (c->endprologue_addr);
184
  else
185
    prolog_len = start_len;
186
  func_len -= start_len;
187
  prolog_len -= start_len;
188
  if (!c || !data)
189
    return;
190
  /* $$$$ */
191
  idx = seh_symbol (c->abfd, c->start_symbol, "", "", UNDSEC, BSF_GLOBAL, 0);
192
  seh_reloc (c->abfd, pdata_offs, BFD_RELOC_32, idx);
193
  val = (unsigned int) func_len;
194
  val <<= 8;
195
  val |= ((unsigned int) prolog_len & 0xffU);
196
  if (c->use_instruction_32)
197
    val |= 0x40000000U;
198
  if (c->handler_written)
199
    val |= 0x80000000U;
200
  bfd_put_32 (c->abfd, (bfd_vma) val, data + pdata_offs + 4);
201
}
202
 
203
static void
204
seh_arm_write_pdata (void)
205
{
206
  seh_context *h;
207
  size_t pdata_size = 0, count_syms = 0;
208
  size_t pdata_offs = 0;
209
  unsigned char *data;
210
  segT seg_pdata;
211
  bfd *abfd = stdoutput;
212
 
213
  h = seh_ctx_root;
214
  if (h == NULL || h->done)
215
    return;
216
  while (h != NULL)
217
    {
218
      h->xdata_offset = pdata_size;
219
      pdata_size += 8;
220
      count_syms += 1;
221
      h = h->next;
222
    }
223
 
224
  if (pdata_size == 0)
225
    return;
226
 
227
  seh_symbol_init (abfd, count_syms);
228
  data = xmalloc (pdata_size);
229
  seg_pdata = quick_section (abfd, ".pdata", SEC_HAS_CONTENTS, 3);
230
  seg_pdata->contents = data;
231
  memset (data, 0, pdata_size);
232
  bfd_set_section_size (abfd, seg_pdata, pdata_size);
233
  h = seh_ctx_root;
234
  while (h != NULL)
235
    {
236
      pdata_offs = h->xdata_offset;
237
      h->section = seg_pdata;
238
      h->abfd = abfd;
239
      if (h->done != 0)
240
        {
241
          seh_arm_create_pdata (h, data, pdata_offs);
242
          h->done = 1;
243
        }
244
      h = h->next;
245
    }
246
  save_relocs (seg_pdata);
247
  bfd_set_symtab (abfd, symtab, symptr);
248
  bfd_set_section_contents (abfd, seg_pdata, data, 0, pdata_size);
249
}
250
 
251
void
252
obj_coff_seh_do_final (void)
253
{
254
  switch (seh_get_target_kind ())
255
    {
256
    case seh_kind_mips:
257
    default:
258
      break;
259
    case seh_kind_arm:
260
      seh_arm_write_pdata ();
261
      break;
262
    case seh_kind_x64:
263
      seh_x64_write_xdata ();
264
      break;
265
    }
266
}
267
 
268
static void
269
seh_x64_make_prologue_element (int kind, int reg, bfd_vma off)
270
{
271
  seh_prologue_element *n;
272
 
273
  if (seh_ctx_cur == NULL)
274
    return;
275
  if (seh_ctx_cur->elems_count == seh_ctx_cur->elems_max)
276
    {
277
      seh_ctx_cur->elems = (seh_prologue_element *)
278
        xrealloc (seh_ctx_cur->elems,
279
                  ((seh_ctx_cur->elems_max + 8) * sizeof (seh_prologue_element)));
280
      seh_ctx_cur->elems_max += 8;
281
    }
282
  n = &seh_ctx_cur->elems[seh_ctx_cur->elems_count];
283
  memset (n, 0, sizeof (seh_prologue_element));
284
  n->kind = kind;
285
  n->reg = reg;
286
  n->offset = off;
287
  n->pc_symbol = make_seh_text_label (seh_ctx_cur, &(n->pc_addr));
288
  seh_ctx_cur->elems_count += 1;
289
}
290
 
291
static int
292
seh_x64_read_reg (const char *tok, int kind, int *regno)
293
{
294
  static const char *frame_regs[16] =
295
    { "cfa", "rcx", "rdx", "rbx", "rsp", "rbp","rsi","rdi",
296
      "r8","r9","r10","r11","r12","r13","r14","r15" };
297
  static const char *int_regs[16] =
298
    { "rax", "rcx", "rdx", "rbx", "rsp", "rbp","rsi","rdi",
299
      "r8","r9","r10","r11","r12","r13","r14","r15" };
300
  static const char *xmm_regs[16] =
301
    { "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7",
302
      "xmm8", "xmm9", "xmm10","xmm11","xmm12","xmm13","xmm14","xmm15" };
303
  static const char *mm_regs[16] =
304
    { "xmm0", "mm1", "mm2", "mm3", "mm4", "mm5", "mm6", "mm7",
305
      "xmm8", "mm9", "mm10","mm11","mm12","mm13","mm14","mm15" };
306
  const char **p = NULL;
307
  char name_end;
308
  char *symbol_name = NULL;
309
  int i;
310
 
311
  while (*input_line_pointer == ' ' || *input_line_pointer == '\t')
312
    input_line_pointer++;
313
  while (*input_line_pointer == ' ' || *input_line_pointer == '\t')
314
    input_line_pointer++;
315
  switch (kind)
316
    {
317
    case 0:
318
      p = frame_regs;
319
      break;
320
    case 1:
321
      p = int_regs;
322
      break;
323
    case 2:
324
      p = mm_regs;
325
      break;
326
    case 3:
327
      p = xmm_regs;
328
      break;
329
    default:
330
      abort ();
331
    }
332
 
333
  if (*input_line_pointer == 0 || *input_line_pointer == '\n')
334
    return 0;
335
 
336
  if (*input_line_pointer == '%')
337
    ++input_line_pointer;
338
  symbol_name = input_line_pointer;
339
  name_end = get_symbol_end ();
340
 
341
  for (i = 0; i < 16; i++)
342
    if (! strcasecmp (p[i], symbol_name))
343
      break;
344
 
345
  if (i == 16)
346
    as_warn (_("In %s we found the invalid register name %s.\n"),
347
             tok, symbol_name);
348
 
349
  *input_line_pointer = name_end;
350
  while (*input_line_pointer == ' ' || *input_line_pointer == '\t')
351
    input_line_pointer++;
352
  if (*input_line_pointer == ',')
353
    ++input_line_pointer;
354
  while (*input_line_pointer == ' ' || *input_line_pointer == '\t')
355
    input_line_pointer++;
356
  *regno = i;
357
  return i != 16;
358
}
359
 
360
static int
361
seh_read_offset (const char *tok, bfd_vma *off)
362
{
363
  bfd_vma r, v = 0, base = 10;
364
  int had_one = 0;
365
 
366
  while (*input_line_pointer == ' ' || *input_line_pointer == '\t')
367
    input_line_pointer++;
368
  if (*input_line_pointer == '0')
369
    {
370
      ++input_line_pointer;
371
      had_one = 1;
372
      base = 8;
373
      switch ((*input_line_pointer))
374
        {
375
        case 'x':
376
        case 'X':
377
          base = 16;
378
          ++input_line_pointer;
379
          break;
380
        case 'd':
381
        case 'D':
382
          base = 10;
383
          input_line_pointer++;
384
          break;
385
        case 'o':
386
        case 'O':
387
          base = 8;
388
          input_line_pointer++;
389
          break;
390
        }
391
    }
392
  while (*input_line_pointer != 0)
393
    {
394
      if (input_line_pointer[0] >= '0' && input_line_pointer[0] <='9')
395
        r = (bfd_vma) (input_line_pointer[0] - '0');
396
      else if (base == 16 && input_line_pointer[0] >= 'a' && input_line_pointer[0] <='f')
397
        r = (bfd_vma) ((input_line_pointer[0] - 'a') + 10);
398
      else if (base == 16 && input_line_pointer[0] >= 'A' && input_line_pointer[0] <='F')
399
        r = (bfd_vma) ((input_line_pointer[0] - 'A') + 10);
400
      else
401
        break;
402
      input_line_pointer++;
403
      v *= base;
404
      v += r;
405
      had_one = 1;
406
    }
407
  *off = v;
408
  if (had_one == 0)
409
    {
410
      as_warn (_("In %s we expect a number.\n"),
411
               tok);
412
    }
413
  while (*input_line_pointer == ' ' || *input_line_pointer == '\t')
414
    input_line_pointer++;
415
  if (*input_line_pointer == ',')
416
    ++input_line_pointer;
417
  while (*input_line_pointer == ' ' || *input_line_pointer == '\t')
418
    input_line_pointer++;
419
  return had_one != 0;
420
}
421
 
422
static void
423
obj_coff_seh_32 (int what)
424
{
425
  if (seh_ctx_cur == NULL)
426
    {
427
      as_fatal (_(".seh_eh requires to be in .seh_proc/.seh_endproc block.\n"));
428
      demand_empty_rest_of_line ();
429
      return;
430
    }
431
  seh_ctx_cur->use_instruction_32 = (what ? 1 : 0);
432
  if (seh_get_target_kind () == seh_kind_arm)
433
    as_warn (_(".seh_%s32 is ignored for this target."), (what ? "" : "no"));
434
  demand_empty_rest_of_line ();
435
}
436
 
437
static void
438
obj_coff_seh_eh (int what ATTRIBUTE_UNUSED)
439
{
440
  if (seh_ctx_cur == NULL)
441
    {
442
      as_fatal (_(".seh_eh requires to be in .seh_proc/.seh_endproc block.\n"));
443
      demand_empty_rest_of_line ();
444
      return;
445
    }
446
  if (seh_get_target_kind () == seh_kind_arm)
447
    {
448
      seh_ctx_cur->handler_written = 1;
449
      /* write block to .text if exception handler is set.  */
450
      seh_write_text_eh_data (seh_ctx_cur->handler_name, seh_ctx_cur->handler_data_name);
451
    }
452
  demand_empty_rest_of_line ();
453
}
454
 
455
static void
456
obj_coff_seh_handler (int what ATTRIBUTE_UNUSED)
457
{
458
  char *symbol_name;
459
  char name_end;
460
 
461
  if (seh_ctx_cur == NULL)
462
    {
463
      as_fatal (_(".seh_handler requires to be in .seh_proc/.seh_endproc block.\n"));
464
      demand_empty_rest_of_line ();
465
      return;
466
    }
467
  if (*input_line_pointer == 0 || *input_line_pointer == '\n')
468
    {
469
      as_fatal (_(".seh_handler requires a handler lable name.\n"));
470
      demand_empty_rest_of_line ();
471
      return;
472
    }
473
 
474
  while (*input_line_pointer == ' ' || *input_line_pointer == '\t' || *input_line_pointer == ',')
475
    input_line_pointer++;
476
  symbol_name = input_line_pointer;
477
  name_end = get_symbol_end ();
478
  seh_ctx->handler_name = xstrdup (symbol_name);
479
  if (symbol_name[0] == '@')
480
    {
481
      if (strcasecmp (symbol_name, "@0") != 0 && strcasecmp (symbol_name, "@1") != 0
482
          && strcasecmp (symbol_name, "@null") != 0)
483
        as_warn (_("Unknown constant value ,%s' for handler."), symbol_name);
484
    }
485
  *input_line_pointer = name_end;
486
  seh_ctx->handler_data_name = NULL;
487
  while (*input_line_pointer == ' ' || *input_line_pointer == '\t' || *input_line_pointer == ',')
488
    input_line_pointer++;
489
  symbol_name = input_line_pointer;
490
  if (*input_line_pointer != '\n' && *input_line_pointer != 0)
491
    {
492
      name_end = get_symbol_end ();
493
      seh_ctx->handler_data_name = xstrdup (symbol_name);
494
      if (symbol_name[0] == '@')
495
        {
496
          if (seh_get_target_kind () != seh_kind_x64)
497
            as_fatal (_("For this target .seh_handler doesn't support constant user-data."));
498
          else if (strcasecmp (symbol_name, "@unwind") != 0 &&
499
                   strcasecmp (symbol_name, "@except") != 0)
500
            as_warn (_("For .seh_handler the constant ,%s' is ignored."), symbol_name);
501
        }
502
      *input_line_pointer = name_end;
503
    }
504
  if (seh_ctx_cur->handler_written)
505
    as_warn (_(".seh_handler is ignored as .seh_eh was seen before."));
506
  demand_empty_rest_of_line ();
507
}
508
 
509
static void
510
obj_coff_seh_scope (int what ATTRIBUTE_UNUSED)
511
{
512
  char *symbol_name,*beg = NULL,*end = NULL, *handl = NULL, *jmp = NULL;
513
  char name_end;
514
 
515
  if (seh_ctx_cur == NULL)
516
    {
517
      as_fatal (_(".seh_scope requires to be in .seh_proc/.seh_endproc block.\n"));
518
      demand_empty_rest_of_line ();
519
      return;
520
    }
521
 
522
  while (*input_line_pointer == ' ' || *input_line_pointer == '\t' || *input_line_pointer == ',')
523
    input_line_pointer++;
524
  if (*input_line_pointer == 0 || *input_line_pointer == '\n')
525
    {
526
      as_fatal (_(".seh_scope requires four symbol names.\n"));
527
      demand_empty_rest_of_line ();
528
      return;
529
    }
530
  symbol_name = input_line_pointer;
531
  name_end = get_symbol_end ();
532
  beg = xstrdup (symbol_name);
533
  *input_line_pointer = name_end;
534
  while (*input_line_pointer == ' ' || *input_line_pointer == '\t' || *input_line_pointer == ',')
535
    input_line_pointer++;
536
  if (*input_line_pointer == 0 || *input_line_pointer == '\n')
537
    {
538
      as_fatal (_(".seh_scope requires three more symbol names.\n"));
539
      demand_empty_rest_of_line ();
540
      return;
541
    }
542
  symbol_name = input_line_pointer;
543
  name_end = get_symbol_end ();
544
  end = xstrdup (symbol_name);
545
  *input_line_pointer = name_end;
546
  while (*input_line_pointer == ' ' || *input_line_pointer == '\t' || *input_line_pointer == ',')
547
    input_line_pointer++;
548
  if (*input_line_pointer == 0 || *input_line_pointer == '\n')
549
    {
550
      as_fatal (_(".seh_scope requires two more symbol names.\n"));
551
      demand_empty_rest_of_line ();
552
      return;
553
    }
554
  symbol_name = input_line_pointer;
555
  name_end = get_symbol_end ();
556
  handl = xstrdup (symbol_name);
557
  *input_line_pointer = name_end;
558
  if (*handl == '@')
559
    {
560
      if (strcasecmp (handl, "@0") != 0 && strcasecmp (handl, "@1") != 0
561
          && strcasecmp (handl, "@null") != 0)
562
        as_warn (_("Unknown constant for handler ,%s'."), handl);
563
    }
564
 
565
  while (*input_line_pointer == ' ' || *input_line_pointer == '\t' || *input_line_pointer == ',')
566
    input_line_pointer++;
567
  if (*input_line_pointer == 0 || *input_line_pointer == '\n')
568
    {
569
      as_fatal (_(".seh_scope requires one more symbol names.\n"));
570
      demand_empty_rest_of_line ();
571
      return;
572
    }
573
  symbol_name = input_line_pointer;
574
  name_end = get_symbol_end ();
575
  jmp = xstrdup (symbol_name);
576
  *input_line_pointer = name_end;
577
  if (*jmp == '@')
578
    {
579
      if (strcasecmp (jmp, "@0") != 0 && strcasecmp (handl, "@null") != 0)
580
        as_warn (_("Unknown constant for jump ,%s'."), jmp);
581
    }
582
 
583
  if (seh_get_target_kind () != seh_kind_x64)
584
    as_warn (_(".seh_scope is ignored for this target."));
585
  else
586
    seh_x64_makescope_elem (seh_ctx_cur, beg, end, handl, jmp);
587
  if (beg)
588
    free (beg);
589
  if (end)
590
    free (end);
591
  if (handl)
592
    free (handl);
593
  if (jmp)
594
    free (jmp);
595
  demand_empty_rest_of_line ();
596
}
597
 
598
static void
599
obj_coff_seh_proc (int what ATTRIBUTE_UNUSED)
600
{
601
  char *symbol_name;
602
  char name_end;
603
 
604
  if (seh_ctx_cur != NULL)
605
    {
606
      as_warn (_(".seh_proc has to be closed by .seh_endprog\n"));
607
      obj_coff_seh_endproc (0);
608
    }
609
 
610
  if (*input_line_pointer == 0 || *input_line_pointer == '\n')
611
    {
612
      as_fatal (_(".seh_proc requires function lable name.\n"));
613
      demand_empty_rest_of_line ();
614
      return;
615
    }
616
 
617
  while (*input_line_pointer == ' ' || *input_line_pointer == '\t' || *input_line_pointer == ',')
618
    input_line_pointer++;
619
  symbol_name = input_line_pointer;
620
  name_end = get_symbol_end ();
621
 
622
  if (seh_ctx == NULL)
623
    seh_ctx_root = seh_ctx = (seh_context *) xmalloc (sizeof (seh_context));
624
  else
625
    {
626
      seh_ctx->next = (seh_context *) xmalloc (sizeof (seh_context));
627
      seh_ctx = seh_ctx->next;
628
    }
629
  seh_ctx_cur = seh_ctx;
630
  memset (seh_ctx, 0, sizeof (seh_context));
631
 
632
  seh_ctx->func_name = xstrdup (symbol_name);
633
  *input_line_pointer = name_end;
634
  while (*input_line_pointer == ' ' || *input_line_pointer == '\t' || *input_line_pointer == ',')
635
    input_line_pointer++;
636
  seh_ctx->start_symbol = make_seh_text_label (seh_ctx_cur, &(seh_ctx_cur->start_addr));
637
  demand_empty_rest_of_line ();
638
}
639
 
640
static void
641
obj_coff_seh_endproc  (int what ATTRIBUTE_UNUSED)
642
{
643
  if (seh_ctx_cur == NULL)
644
    {
645
      as_warn (_(".seh_endprog without prior .seh_proc (ignored)\n"));
646
      demand_empty_rest_of_line ();
647
      return;
648
    }
649
  seh_ctx->end_symbol = make_seh_text_label (seh_ctx, &(seh_ctx->end_addr));
650
  seh_ctx->xdata_first = seh_make_xlbl_name (seh_ctx);
651
  make_function_entry_pdata (seh_ctx);
652
  seh_ctx_cur = NULL;
653
  demand_empty_rest_of_line ();
654
}
655
 
656
static void
657
obj_coff_seh_push  (int what)
658
{
659
  int reg = 0;
660
  int kind = -1;
661
 
662
  if (seh_ctx_cur == NULL)
663
    {
664
      as_warn (_(".seh_push used outside of .seh_proc block.\n"));
665
      demand_empty_rest_of_line ();
666
      return;
667
    }
668
  /* What 0:reg, 1:pushframe.  */
669
  switch (what)
670
    {
671
    case 0:
672
      if (seh_x64_read_reg (".seh_push", 1, &reg))
673
        kind = UWOP_PUSH_NONVOL;
674
      else
675
        as_warn (_(".seh_pushreg expects register argument."));
676
      break;
677
    case 1:
678
      kind = UWOP_PUSH_MACHFRAME;
679
      break;
680
    default:
681
      abort ();
682
    }
683
  if (seh_get_target_kind () != seh_kind_x64)
684
    as_warn (_(".seh_save... is ignored for this target.\n"));
685
  else if (kind != -1)
686
    seh_x64_make_prologue_element (kind, reg, 0);
687
  demand_empty_rest_of_line ();
688
}
689
 
690
static void
691
obj_coff_seh_save  (int what)
692
{
693
  int reg;
694
  bfd_vma off;
695
  int kind;
696
  int ok = 1;
697
 
698
  /* what 0:reg, 1:mm, 2:xmm.  */
699
  switch (what)
700
    {
701
    case 0:
702
      ok &= seh_x64_read_reg (".seh_savereg", 1, &reg);
703
      kind = UWOP_SAVE_NONVOL;
704
      break;
705
    case 1:
706
      ok &= seh_x64_read_reg (".seh_savemm", 2, &reg);
707
      kind = UWOP_SAVE_XMM;
708
      break;
709
    case 2:
710
      ok &= seh_x64_read_reg (".seh_savexmm", 3, &reg);
711
      kind = UWOP_SAVE_XMM128;
712
      break;
713
    default:
714
      abort ();
715
    }
716
  ok &= seh_read_offset (".seh_save", &off);
717
  if (seh_ctx_cur == NULL)
718
    {
719
      as_warn (_(".seh_save used outside of .seh_proc block.\n"));
720
      demand_empty_rest_of_line ();
721
      return;
722
    }
723
  if (seh_get_target_kind () != seh_kind_x64)
724
    as_warn (_(".seh_save... is ignored for this target.\n"));
725
  else
726
    seh_x64_make_prologue_element (kind, reg, off);
727
  demand_empty_rest_of_line ();
728
}
729
 
730
static void
731
obj_coff_seh_endprologue (int what ATTRIBUTE_UNUSED)
732
{
733
  if (seh_ctx_cur == NULL)
734
    {
735
      as_warn (_(".seh_endprologue used outside of .seh_proc block.\n"));
736
      demand_empty_rest_of_line ();
737
      return;
738
    }
739
  if (seh_ctx_cur->endprologue_symbol != NULL)
740
    as_warn (_(".seh_endprologue used more then once in .seh_proc block.\n"));
741
  else
742
    seh_ctx_cur->endprologue_symbol = make_seh_text_label (seh_ctx_cur, &seh_ctx_cur->endprologue_addr);
743
}
744
 
745
static void
746
obj_coff_seh_stack_alloc (int what ATTRIBUTE_UNUSED)
747
{
748
  bfd_vma size;
749
 
750
  if (seh_ctx_cur == NULL)
751
    {
752
      as_warn (_(".seh_stackalloc used outside of .seh_proc block.\n"));
753
      demand_empty_rest_of_line ();
754
      return;
755
    }
756
  if (seh_read_offset (".seh_stackalloc", &size))
757
    {
758
      if (seh_get_target_kind () != seh_kind_x64)
759
        as_warn (_(".seh_stackalloc is ignored for this target.\n"));
760
      else
761
        seh_x64_make_prologue_element (UWOP_ALLOC_LARGE, 0, size);
762
    }
763
}
764
 
765
static void
766
obj_coff_seh_setframe (int what ATTRIBUTE_UNUSED)
767
{
768
  int reg;
769
  int ok = 1;
770
  bfd_vma off;
771
 
772
  ok &= seh_x64_read_reg (".seh_setframe", 0, &reg);
773
  ok &= seh_read_offset (".seh_setframe", &off);
774
  if (seh_ctx_cur == NULL)
775
    {
776
      as_warn (_(".seh_setframe used outside of .seh_proc block.\n"));
777
      demand_empty_rest_of_line ();
778
      return;
779
    }
780
  if (ok)
781
    {
782
      seh_ctx_cur->framereg = reg;
783
      seh_ctx_cur->frameoff = off;
784
    }
785
  if (seh_get_target_kind () != seh_kind_x64)
786
    as_warn (_(".seh_setframe is ignored for this target.\n"));
787
  demand_empty_rest_of_line ();
788
}
789
 
790
/* Misc function helpers.  */
791
static void
792
seh_reloc (bfd *abfd, bfd_size_type address, int which_howto, int symidx)
793
{
794
  if (relcount >= relsize - 1)
795
    {
796
      relsize += 10;
797
      if (reltab)
798
        reltab = xrealloc (reltab, relsize * sizeof (arelent));
799
      else
800
        reltab = xmalloc (relsize * sizeof (arelent));
801
    }
802
  reltab[relcount].address = address;
803
  reltab[relcount].addend = 0;
804
  reltab[relcount].howto = bfd_reloc_type_lookup (abfd, which_howto);
805
  reltab[relcount].sym_ptr_ptr = symtab + symidx;
806
  relcount++;
807
}
808
 
809
static void
810
save_relocs (asection *sec)
811
{
812
  int i;
813
 
814
  sec->relocation = reltab;
815
  sec->reloc_count = relcount;
816
  sec->orelocation = xmalloc ((relcount + 1) * sizeof (arelent *));
817
  for (i = 0; i < relcount; i++)
818
    sec->orelocation[i] = sec->relocation + i;
819
  sec->orelocation[relcount] = 0;
820
  sec->flags |= SEC_RELOC;
821
  reltab = 0;
822
  relcount = relsize = 0;
823
}
824
 
825
static void
826
seh_symbol_init (bfd *abfd, unsigned int added)
827
{
828
  unsigned int oldcount;
829
 
830
  oldcount = bfd_get_symcount (abfd);
831
  symptr = oldcount;
832
  symtab = xmalloc ((oldcount + added + 6) * sizeof (asymbol *));
833
  if (oldcount > 0)
834
    memcpy (symtab, bfd_get_outsymbols (abfd), sizeof (asymbol *) * oldcount);
835
}
836
 
837
static int
838
seh_symbol (bfd *abfd, const char *n1, const char *n2, const char *n3,
839
            asection *sec, int flags, int addr)
840
{
841
  asymbol *sym;
842
  char *name = xmalloc (strlen (n1) + strlen (n2) + strlen (n3) + 1);
843
  int ret = symptr;
844
 
845
  strcpy (name, n1);
846
  strcat (name, n2);
847
  strcat (name, n3);
848
  sym = bfd_make_empty_symbol (abfd);
849
  sym->name = name;
850
  sym->section = sec;
851
  sym->flags = flags;
852
  sym->value = addr;
853
  symtab[symptr++] = sym;
854
  return ret;
855
}
856
 
857
static asection *
858
quick_section (bfd *abfd, const char *name, int flags, int align)
859
{
860
  asection *sec;
861
  asymbol *sym;
862
 
863
  sec = seh_make_section2 (name, flags);
864
  bfd_set_section_alignment (abfd, sec, align);
865
  /* Remember to undo this before trying to link internally!  */
866
 
867
  sym = bfd_make_empty_symbol (abfd);
868
  symtab[symptr++] = sym;
869
  sym->name = sec->name;
870
  sym->section = sec;
871
  sym->flags = BSF_LOCAL;
872
  sym->value = 0;
873
 
874
  return sec;
875
}
876
 
877
static seh_kind
878
seh_get_target_kind (void)
879
{
880
  if (!stdoutput)
881
    return seh_kind_unknown;
882
  switch (bfd_get_arch (stdoutput))
883
    {
884
    case bfd_arch_arm:
885
    case bfd_arch_powerpc:
886
    case bfd_arch_sh:
887
      return seh_kind_arm;
888
    case bfd_arch_i386:
889
      switch (bfd_get_mach (stdoutput))
890
        {
891
        case bfd_mach_x86_64:
892
        case bfd_mach_x86_64_intel_syntax:
893
          return seh_kind_x64;
894
        default:
895
          break;
896
        }
897
      /* FALL THROUGH.  */
898
    case bfd_arch_mips:
899
      return seh_kind_mips;
900
    case bfd_arch_ia64:
901
      /* Should return seh_kind_x64.  But not implemented yet.  */
902
      return seh_kind_unknown;
903
    default:
904
      break;
905
    }
906
  return seh_kind_unknown;
907
}
908
 
909
static void
910
seh_emit_rva (const char *name)
911
{
912
  char *p = (char *) xmalloc (strlen (name) + 1);
913
  char *s = input_line_pointer;
914
 
915
  strcpy (p, name);
916
  input_line_pointer = p;
917
  s_rva (4);
918
  input_line_pointer = s;
919
}
920
 
921
static void
922
seh_emit_long (const char *name)
923
{
924
  char *p = (char *) xmalloc (strlen (name) + 1);
925
  char *s = input_line_pointer;
926
 
927
  strcpy (p, name);
928
  input_line_pointer = p;
929
  cons (4);
930
  input_line_pointer = s;
931
}
932
 
933
static void
934
seh_make_globl (char *sym_name)
935
{
936
  char *s = input_line_pointer;
937
 
938
  input_line_pointer = sym_name;
939
  s_globl (4);
940
  input_line_pointer = s;
941
}
942
 
943
static segT
944
seh_make_section2 (const char *section_name, unsigned flags)
945
{
946
  char *name;
947
  segT sec;
948
 
949
  name = xmalloc (strlen (section_name) + 1);
950
  strcpy (name, section_name);
951
 
952
  sec = subseg_new (name, (subsegT) 0);
953
  bfd_set_section_flags (stdoutput, sec,
954
                         ((SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_DATA | flags)
955
                          & bfd_applicable_section_flags (stdoutput)));
956
 
957
  return sec;
958
}
959
 
960
static segT
961
seh_make_section (void)
962
{
963
  static segT seg_pdata = NULL;
964
  segT sec = NULL;
965
 
966
  if (!seg_pdata)
967
    seg_pdata = seh_make_section2 (".pdata", 0);
968
  sec = seg_pdata;
969
  return sec;
970
}
971
 
972
static char *
973
seh_make_xlbl_name (seh_context *c)
974
{
975
  size_t len = strlen (".seh_xlbl_") + strlen (c->func_name) + 9 + 1;
976
  char *ret = (char*) xmalloc (len);
977
 
978
  if (!ret)
979
    as_fatal (_("Out of memory for xdata lable for %s"), c->func_name);
980
  else
981
    sprintf (ret, ".seh_xlbl_%s_%x", c->func_name, + c->xlbl_count);
982
  c->xlbl_count += 1;
983
  return ret;
984
}
985
 
986
static char *
987
make_seh_text_label (seh_context *c, symbolS **addr)
988
{
989
  char *sym_name;
990
  size_t len = strlen (".seh_tlbl_") + strlen (c->func_name) + 9 + 1;
991
 
992
  sym_name = (char *) xmalloc (len);
993
  if (!sym_name)
994
    as_fatal (_("Allocating memory for SEH's text symbol for %s failed"), c->func_name);
995
  sprintf (sym_name, ".seh_tlbl_%s_%x", c->func_name, c->tlbl_count);
996
  c->tlbl_count += 1;
997
  if (addr)
998
    {
999
      seh_make_globl (sym_name);
1000
      *addr = colon (sym_name);
1001
    }
1002
  return sym_name;
1003
}
1004
 
1005
/* x64 secific functions.  */
1006
 
1007
static void
1008
seh_fill_pcsyms (const seh_context *c, char **names, int *idx)
1009
{
1010
  size_t i;
1011
  int count = 1;
1012
  valueT start_off = resolve_symbol_value (c->start_addr);
1013
  valueT un_off;
1014
  seh_prologue_element *e = c->elems;
1015
 
1016
  names[0] = c->start_symbol;
1017
  idx[0] = 0;
1018
  if (c->elems_count == 0)
1019
    return;
1020
  for (i = 0; i < c->elems_count; i++)
1021
    {
1022
      un_off = resolve_symbol_value (e[i].pc_addr);
1023
      if ((un_off - start_off) > 255)
1024
        {
1025
          names[count] = e[i].pc_symbol;
1026
          idx[count] = (int) i;
1027
          count++;
1028
          start_off = un_off;
1029
        }
1030
    }
1031
}
1032
 
1033
static int
1034
seh_needed_unwind_info (seh_context *c)
1035
{
1036
  size_t i;
1037
  int count = 1;
1038
  valueT start_off = resolve_symbol_value (c->start_addr);
1039
  valueT un_off;
1040
  seh_prologue_element *e = c->elems;
1041
 
1042
  if (c->elems_count == 0)
1043
    return count;
1044
  for (i = 0; i < c->elems_count; i++)
1045
    {
1046
      un_off = resolve_symbol_value (e[i].pc_addr);
1047
      if ((un_off - start_off) > 255)
1048
        {
1049
          count++;
1050
          start_off = un_off;
1051
        }
1052
    }
1053
  return count;
1054
}
1055
 
1056
static size_t
1057
seh_getelm_data_size (const seh_context *c, int elm_start, int elm_end)
1058
{
1059
  size_t ret = PEX64_UWI_SIZEOF_UWCODE_ARRAY (elm_end - elm_start);
1060
 
1061
  while (elm_start < elm_end)
1062
    {
1063
      switch (c->elems[elm_start].kind)
1064
        {
1065
        case UWOP_PUSH_NONVOL:
1066
        case UWOP_PUSH_MACHFRAME:
1067
          ret += 2;
1068
          break;
1069
        case UWOP_SAVE_NONVOL:
1070
        case UWOP_SAVE_XMM:
1071
        case UWOP_SAVE_XMM128:
1072
          if ((c->elems[elm_start].offset & 7) != 0 ||
1073
              ((c->elems[elm_start].offset / 8) > 0xffff))
1074
            ret += 6;
1075
          else
1076
            ret += 4;
1077
          break;
1078
        case UWOP_ALLOC_LARGE:
1079
          ret += 4;
1080
          break;
1081
        default:
1082
          break;
1083
        }
1084
      elm_start++;
1085
    }
1086
  return ret;
1087
}
1088
 
1089
static size_t
1090
seh_getsize_of_unwind_entry (seh_context *c, int elm_start, int elm_end, int bechain)
1091
{
1092
  size_t ret = seh_getelm_data_size(c, elm_start, elm_end);
1093
 
1094
  c->count_syms += 1;
1095
  if (bechain)
1096
    {
1097
      ret += 4 + 4;
1098
      c->count_syms += 1;
1099
      c->count_reloc += 1;
1100
    }
1101
  else
1102
    {
1103
      ret += 4;
1104
      if (c->handler_name != NULL)
1105
        {
1106
          if (c->handler_data_name != NULL
1107
              && c->handler_data_name[0] != '@')
1108
            {
1109
              ret += 4;
1110
              c->count_syms += 2;
1111
              c->count_reloc += 2;
1112
            }
1113
          else
1114
            {
1115
              ret += 8 + (c->scope_count * 4) * 4;
1116
              c->count_syms += (c->scope_count * 4) + 1;
1117
              c->count_reloc += (c->scope_count * 4) + 1;
1118
            }
1119
        }
1120
    }
1121
  return ret;
1122
}
1123
 
1124
static void
1125
seh_make_unwind_entry (const seh_context *c, char *name, int elm_start, int elm_end, int bechain,
1126
                       unsigned char *data, size_t *poffs, int no)
1127
{
1128
  size_t off = *poffs;
1129
  size_t it;
1130
  valueT start_off = resolve_symbol_value (c->start_addr);
1131
  valueT end_prologue;
1132
  size_t uwcodes = seh_getelm_data_size(c, elm_start, elm_end);
1133
  unsigned int flag = UNW_FLAG_NHANDLER;
1134
  int idx;
1135
 
1136
  if (c->handler_name != NULL)
1137
    {
1138
      flag = UNW_FLAG_EHANDLER;
1139
      if (c->handler_data_name != NULL && c->handler_data_name[0] != '@')
1140
        flag = UNW_FLAG_FHANDLER;
1141
      else if (c->handler_data_name != NULL &&
1142
               strcasecmp (c->handler_data_name, "@unwind") == 0)
1143
        flag = UNW_FLAG_UHANDLER;
1144
    }
1145
  if (!c->endprologue_addr)
1146
    end_prologue = start_off;
1147
  else
1148
    end_prologue = resolve_symbol_value (c->endprologue_addr);
1149
  seh_symbol (c->abfd, name, "", "", c->section, BSF_GLOBAL, (int) off);
1150
  data[off++] = (1 | ((bechain ? UNW_FLAG_CHAININFO : flag) << 3));
1151
  if (elm_start != 0)
1152
    start_off = (valueT) c->elems[elm_start].offset;
1153
  end_prologue -= start_off;
1154
  if (end_prologue > 255)
1155
    end_prologue = 255;
1156
  data[off++] = (unsigned char) end_prologue;
1157
  data[off++] = (unsigned char) (uwcodes / 2);
1158
  data[off] = (unsigned char) c->framereg;
1159
  data[off++] |= (unsigned char) ((c->frameoff / 16) << 4);
1160
  off += uwcodes;
1161
  if (bechain)
1162
    {
1163
      char n[100];
1164
 
1165
      sprintf (n,"%x", no);
1166
      idx = seh_symbol (c->abfd, ".xdata_fct", c->func_name, n, UNDSEC, BSF_GLOBAL, (int) off);
1167
      seh_reloc (c->abfd, off, BFD_RELOC_RVA, idx);
1168
      off += 4;
1169
    }
1170
  else if (c->handler_name != NULL)
1171
    {
1172
      if (flag == UNW_FLAG_FHANDLER)
1173
        {
1174
          if (strcasecmp (c->handler_name, "@1") == 0)
1175
            bfd_put_32 (c->abfd, (bfd_vma) 1, &data[off]);
1176
          else if (c->handler_name[0] != '@')
1177
            {
1178
              idx = seh_symbol (c->abfd, c->handler_name, "", "", UNDSEC, BSF_GLOBAL, 0);
1179
              seh_reloc (c->abfd, off, BFD_RELOC_RVA, idx);
1180
            }
1181
          off += 4;
1182
          idx = seh_symbol (c->abfd, c->handler_data_name, "", "", UNDSEC, BSF_GLOBAL, 0);
1183
          seh_reloc (c->abfd, off, BFD_RELOC_RVA, idx);
1184
          off += 4;
1185
        }
1186
      else if (flag == UNW_FLAG_UHANDLER || flag == UNW_FLAG_EHANDLER)
1187
        {
1188
          if (strcasecmp (c->handler_name, "@1") == 0)
1189
            bfd_put_32 (c->abfd, (bfd_vma) 1, &data[off]);
1190
          else if (c->handler_name[0] != '@')
1191
            {
1192
              idx = seh_symbol (c->abfd, c->handler_name, "", "", UNDSEC, BSF_GLOBAL, 0);
1193
              seh_reloc (c->abfd, off, BFD_RELOC_RVA, idx);
1194
            }
1195
          off += 4;
1196
          bfd_put_32 (c->abfd, (bfd_vma) c->scope_count, &data[off]);
1197
          off += 4;
1198
          for (it = 0; it < c->scope_count; it++)
1199
            {
1200
              idx = seh_symbol (c->abfd, c->scopes[it].begin_addr, "", "", UNDSEC, BSF_GLOBAL, 0);
1201
              seh_reloc (c->abfd, off, BFD_RELOC_RVA, idx);
1202
              off += 4;
1203
              idx = seh_symbol (c->abfd, c->scopes[it].end_addr, "", "", UNDSEC, BSF_GLOBAL, 0);
1204
              seh_reloc (c->abfd, off, BFD_RELOC_RVA, idx);
1205
              off += 4;
1206
              if (c->scopes[it].handler_addr[0] == '@')
1207
                {
1208
                  if (strcasecmp (c->scopes[it].handler_addr, "@1") == 0)
1209
                    bfd_put_32 (c->abfd, (bfd_vma) 1, &data[off]);
1210
                }
1211
              else
1212
                {
1213
                  idx = seh_symbol (c->abfd, c->scopes[it].handler_addr, "", "", UNDSEC, BSF_GLOBAL, 0);
1214
                  seh_reloc (c->abfd, off, BFD_RELOC_RVA, idx);
1215
                }
1216
              off += 4;
1217
              if (c->scopes[it].jump_addr[0] == '@')
1218
                {
1219
                  if (strcasecmp (c->scopes[it].jump_addr, "@1") == 0)
1220
                    bfd_put_32 (c->abfd, (bfd_vma) 1, &data[off]);
1221
                }
1222
              else
1223
                {
1224
                  idx = seh_symbol (c->abfd, c->scopes[it].jump_addr, "", "", UNDSEC, BSF_GLOBAL, 0);
1225
                  seh_reloc (c->abfd, off, BFD_RELOC_RVA, idx);
1226
                }
1227
              off += 4;
1228
            }
1229
        }
1230
    }
1231
  *poffs = off;
1232
}
1233
 
1234
static size_t
1235
seh_getsize_unwind_data (seh_context *c)
1236
{
1237
  int need = seh_needed_unwind_info (c);
1238
  int i;
1239
  char **names = (char **) xmalloc (sizeof (char *) * need);
1240
  char **pc_syms = (char **) xmalloc (sizeof (char *) * need);
1241
  int *elm_start = (int *) xmalloc (sizeof (int) * (need + 1));
1242
  size_t xdata_sz = 0;
1243
 
1244
  seh_fill_pcsyms (c, pc_syms, elm_start);
1245
  elm_start[need] = c->elems_count;
1246
 
1247
  xdata_sz += ((12 * (size_t) need));
1248
  c->count_syms += 5 * need;
1249
  xdata_sz += (seh_getsize_of_unwind_entry (c, elm_start[0], elm_start[1], 1 != need) + 7) & ~7;
1250
  for (i = 1; i < need; i++)
1251
    xdata_sz += (seh_getsize_of_unwind_entry (c, elm_start[i], elm_start[i + 1], 1 != need) + 7) & ~7;
1252
 
1253
  /* Create lable names for .xdata unwind info.  */
1254
  names[0] = c->xdata_first;
1255
  for (i = 1; i < need; i++)
1256
    names[i] = seh_make_xlbl_name (c);
1257
  c->xdata_names = names;
1258
  c->xdata_pcsyms = pc_syms;
1259
  c->xdata_elm_start = elm_start;
1260
  c->xdata_sz = xdata_sz;
1261
  return xdata_sz;
1262
}
1263
 
1264
static void
1265
seh_create_unwind_data (seh_context *c, unsigned char *data, size_t offs)
1266
{
1267
  int need = seh_needed_unwind_info (c);
1268
  int i;
1269
  char **names = c->xdata_names;
1270
  char **pc_syms = c->xdata_pcsyms;
1271
  int *elm_start = c->xdata_elm_start;
1272
 
1273
  for (i = 1; i < need; i++)
1274
    seh_make_function_entry_xdata (c, pc_syms[i], c->end_symbol, names[i], data, &offs, i);
1275
 
1276
  /* Generate the function entry. Remark, that just
1277
     first is in .pdata section and already emitted.  */
1278
  seh_make_unwind_entry (c, c->xdata_first, elm_start[0], elm_start[1], 1 != need, data, &offs, 1);
1279
  for (i = 1; i < need; i++)
1280
    seh_make_unwind_entry (c, names[i], elm_start[i], elm_start[i + 1], (i + 1) != need, data, &offs, i + 1);
1281
 
1282
  for (i = 1; i < need; i++)
1283
    free (names[i]);
1284
  free (names);
1285
  free (pc_syms);
1286
  free (elm_start);
1287
  c->xdata_names = NULL;
1288
  c->xdata_pcsyms = NULL;
1289
  c->xdata_elm_start = NULL;
1290
}
1291
 
1292
static void
1293
seh_make_function_entry_xdata (seh_context *c, char *pc_start, char *pc_end, char *pc_xdata, unsigned char *data, size_t *poffs,int no)
1294
{
1295
  bfd_vma addr = (bfd_vma) *poffs;
1296
  int idx;
1297
  char s[100];
1298
 
1299
  if (!data)
1300
    return;
1301
  sprintf (s,"%x",no);
1302
  seh_symbol (c->abfd, ".xdata_fct",c->func_name, s, c->section, BSF_GLOBAL, (int) poffs[0]);
1303
  idx = seh_symbol (c->abfd, pc_start,"","", UNDSEC, BSF_GLOBAL,0);
1304
  seh_reloc (c->abfd, addr, BFD_RELOC_RVA, idx);
1305
  idx = seh_symbol (c->abfd, pc_end,"","", UNDSEC, BSF_GLOBAL,0);
1306
  seh_reloc (c->abfd, addr + 4, BFD_RELOC_RVA, idx);
1307
  idx = seh_symbol (c->abfd, pc_xdata,"","", UNDSEC, BSF_GLOBAL,0);
1308
  seh_reloc (c->abfd, addr + 8, BFD_RELOC_RVA, idx);
1309
  poffs[0] += 12;
1310
}
1311
 
1312
static seh_scope_elem *
1313
seh_x64_makescope_elem (seh_context *c, const char *begin, const char *end,
1314
                        const char *handler, const char *jmp)
1315
{
1316
  seh_scope_elem *r;
1317
 
1318
  if (!end || !begin)
1319
    return NULL;
1320
  if (c->scope_count >= c->scope_max)
1321
    {
1322
      seh_scope_elem *h = (seh_scope_elem *) xmalloc (sizeof (seh_scope_elem) * (c->scope_max + 8));
1323
      memset (h, 0, sizeof (seh_scope_elem) * (c->scope_max + 8));
1324
      if (c->scopes != NULL)
1325
        memcpy (h, c->scopes, sizeof (seh_scope_elem) * c->scope_max);
1326
      if (c->scopes != NULL)
1327
        free (c->scopes);
1328
      c->scopes = h;
1329
      c->scope_max += 8;
1330
    }
1331
  r = &c->scopes[c->scope_count++];
1332
  r->begin_addr = xstrdup (begin);
1333
  r->end_addr = xstrdup (end);
1334
  r->handler_addr = (!handler ? NULL : xstrdup (handler));
1335
  r->jump_addr = (!jmp ? NULL : xstrdup (jmp));
1336
  return r;
1337
}

powered by: WebSVN 2.1.0

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