~ubuntu-branches/debian/squeeze/binutils/squeeze

« back to all changes in this revision

Viewing changes to gas/config/obj-coff-seh.c

  • Committer: Bazaar Package Importer
  • Author(s): Matthias Klose
  • Date: 2009-09-10 17:05:30 UTC
  • mfrom: (1.4.5 upstream) (6.1.3 sid)
  • Revision ID: james.westby@ubuntu.com-20090910170530-wa6gpju9pq5c56on
Tags: 2.19.91.20090910-1
* Snapshot, taken from the 2.20 release branch 20090910, corresponding
  to the 2.19.90 upstream snapshot.
* Fix Thumb-2 shared libraries (Daniel Jacobowitz), patch taken
  from the trunk.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* 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
}