Subversion Repositories Kolibri OS

Rev

Rev 5222 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

  1. /* seh pdata/xdata coff object file format
  2.    Copyright (C) 2009-2015 Free Software Foundation, Inc.
  3.  
  4.    This file is part of GAS.
  5.  
  6.    GAS is free software; you can redistribute it and/or modify
  7.    it under the terms of the GNU General Public License as published by
  8.    the Free Software Foundation; either version 3, or (at your option)
  9.    any later version.
  10.  
  11.    GAS is distributed in the hope that it will be useful,
  12.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.    GNU General Public License for more details.
  15.  
  16.    You should have received a copy of the GNU General Public License
  17.    along with GAS; see the file COPYING.  If not, write to the Free
  18.    Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
  19.    02110-1301, USA.  */
  20.  
  21. #include "obj-coff-seh.h"
  22.  
  23.  
  24. /* Private segment collection list.  */
  25. struct seh_seg_list {
  26.   segT seg;
  27.   int subseg;
  28.   char *seg_name;
  29. };
  30.  
  31. /* Local data.  */
  32. static seh_context *seh_ctx_cur = NULL;
  33.  
  34. static struct hash_control *seh_hash;
  35.  
  36. static struct seh_seg_list *x_segcur = NULL;
  37. static struct seh_seg_list *p_segcur = NULL;
  38.  
  39. static void write_function_xdata (seh_context *);
  40. static void write_function_pdata (seh_context *);
  41.  
  42. /* Build based on segment the derived .pdata/.xdata
  43.    segment name containing origin segment's postfix name part.  */
  44. static char *
  45. get_pxdata_name (segT seg, const char *base_name)
  46. {
  47.   const char *name,*dollar, *dot;
  48.   char *sname;
  49.  
  50.   name = bfd_get_section_name (stdoutput, seg);
  51.  
  52.   dollar = strchr (name, '$');
  53.   dot = strchr (name + 1, '.');
  54.  
  55.   if (!dollar && !dot)
  56.     name = "";
  57.   else if (!dollar)
  58.     name = dot;
  59.   else if (!dot)
  60.     name = dollar;
  61.   else if (dot < dollar)
  62.     name = dot;
  63.   else
  64.     name = dollar;
  65.  
  66.   sname = concat (base_name, name, NULL);
  67.  
  68.   return sname;
  69. }
  70.  
  71. /* Allocate a seh_seg_list structure.  */
  72. static struct seh_seg_list *
  73. alloc_pxdata_item (segT seg, int subseg, char *name)
  74. {
  75.   struct seh_seg_list *r;
  76.  
  77.   r = (struct seh_seg_list *)
  78.     xmalloc (sizeof (struct seh_seg_list) + strlen (name));
  79.   r->seg = seg;
  80.   r->subseg = subseg;
  81.   r->seg_name = name;
  82.   return r;
  83. }
  84.  
  85. /* Generate pdata/xdata segment with same linkonce properties
  86.    of based segment.  */
  87. static segT
  88. make_pxdata_seg (segT cseg, char *name)
  89. {
  90.   segT save_seg = now_seg;
  91.   int save_subseg = now_subseg;
  92.   segT r;
  93.   flagword flags;
  94.  
  95.   r = subseg_new (name, 0);
  96.   /* Check if code segment is marked as linked once.  */
  97.   flags = bfd_get_section_flags (stdoutput, cseg)
  98.     & (SEC_LINK_ONCE | SEC_LINK_DUPLICATES_DISCARD
  99.        | SEC_LINK_DUPLICATES_ONE_ONLY | SEC_LINK_DUPLICATES_SAME_SIZE
  100.        | SEC_LINK_DUPLICATES_SAME_CONTENTS);
  101.  
  102.   /* Add standard section flags.  */
  103.   flags |= SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_DATA;
  104.  
  105.   /* Apply possibly linked once flags to new generated segment, too.  */
  106.   if (!bfd_set_section_flags (stdoutput, r, flags))
  107.     as_bad (_("bfd_set_section_flags: %s"),
  108.             bfd_errmsg (bfd_get_error ()));
  109.  
  110.   /* Restore to previous segment.  */
  111.   subseg_set (save_seg, save_subseg);
  112.   return r;
  113. }
  114.  
  115. static void
  116. seh_hash_insert (const char *name, struct seh_seg_list *item)
  117. {
  118.   const char *error_string;
  119.  
  120.   if ((error_string = hash_jam (seh_hash, name, (char *) item)))
  121.     as_fatal (_("Inserting \"%s\" into structure table failed: %s"),
  122.               name, error_string);
  123. }
  124.  
  125. static struct seh_seg_list *
  126. seh_hash_find (char *name)
  127. {
  128.   return (struct seh_seg_list *) hash_find (seh_hash, name);
  129. }
  130.  
  131. static struct seh_seg_list *
  132. seh_hash_find_or_make (segT cseg, const char *base_name)
  133. {
  134.   struct seh_seg_list *item;
  135.   char *name;
  136.  
  137.   /* Initialize seh_hash once.  */
  138.   if (!seh_hash)
  139.     seh_hash = hash_new ();
  140.  
  141.   name = get_pxdata_name (cseg, base_name);
  142.  
  143.   item = seh_hash_find (name);
  144.   if (!item)
  145.     {
  146.       item = alloc_pxdata_item (make_pxdata_seg (cseg, name), 0, name);
  147.  
  148.       seh_hash_insert (item->seg_name, item);
  149.     }
  150.   else
  151.     free (name);
  152.  
  153.   return item;
  154. }
  155.  
  156. /* Check if current segment has same name.  */
  157. static int
  158. seh_validate_seg (const char *directive)
  159. {
  160.   const char *cseg_name, *nseg_name;
  161.   if (seh_ctx_cur->code_seg == now_seg)
  162.     return 1;
  163.   cseg_name = bfd_get_section_name (stdoutput, seh_ctx_cur->code_seg);
  164.   nseg_name = bfd_get_section_name (stdoutput, now_seg);
  165.   as_bad (_("%s used in segment '%s' instead of expected '%s'"),
  166.           directive, nseg_name, cseg_name);
  167.   ignore_rest_of_line ();
  168.   return 0;
  169. }
  170.  
  171. /* Switch back to the code section, whatever that may be.  */
  172. static void
  173. obj_coff_seh_code (int ignored ATTRIBUTE_UNUSED)
  174. {
  175.   subseg_set (seh_ctx_cur->code_seg, 0);
  176. }
  177.  
  178. static void
  179. switch_xdata (int subseg, segT code_seg)
  180. {
  181.   x_segcur = seh_hash_find_or_make (code_seg, ".xdata");
  182.  
  183.   subseg_set (x_segcur->seg, subseg);
  184. }
  185.  
  186. static void
  187. switch_pdata (segT code_seg)
  188. {
  189.   p_segcur = seh_hash_find_or_make (code_seg, ".pdata");
  190.  
  191.   subseg_set (p_segcur->seg, p_segcur->subseg);
  192. }
  193. /* Parsing routines.  */
  194.  
  195. /* Return the style of SEH unwind info to generate.  */
  196.  
  197. static seh_kind
  198. seh_get_target_kind (void)
  199. {
  200.   if (!stdoutput)
  201.     return seh_kind_unknown;
  202.   switch (bfd_get_arch (stdoutput))
  203.     {
  204.     case bfd_arch_arm:
  205.     case bfd_arch_powerpc:
  206.     case bfd_arch_sh:
  207.       return seh_kind_arm;
  208.     case bfd_arch_i386:
  209.       switch (bfd_get_mach (stdoutput))
  210.         {
  211.         case bfd_mach_x86_64:
  212.         case bfd_mach_x86_64_intel_syntax:
  213.           return seh_kind_x64;
  214.         default:
  215.           break;
  216.         }
  217.       /* FALL THROUGH.  */
  218.     case bfd_arch_mips:
  219.       return seh_kind_mips;
  220.     case bfd_arch_ia64:
  221.       /* Should return seh_kind_x64.  But not implemented yet.  */
  222.       return seh_kind_unknown;
  223.     default:
  224.       break;
  225.     }
  226.   return seh_kind_unknown;
  227. }
  228.  
  229. /* Verify that we're in the context of a seh_proc.  */
  230.  
  231. static int
  232. verify_context (const char *directive)
  233. {
  234.   if (seh_ctx_cur == NULL)
  235.     {
  236.       as_bad (_("%s used outside of .seh_proc block"), directive);
  237.       ignore_rest_of_line ();
  238.       return 0;
  239.     }
  240.   return 1;
  241. }
  242.  
  243. /* Similar, except we also verify the appropriate target.  */
  244.  
  245. static int
  246. verify_context_and_target (const char *directive, seh_kind target)
  247. {
  248.   if (seh_get_target_kind () != target)
  249.     {
  250.       as_warn (_("%s ignored for this target"), directive);
  251.       ignore_rest_of_line ();
  252.       return 0;
  253.     }
  254.   return verify_context (directive);
  255. }
  256.  
  257. /* Skip whitespace and a comma.  Error if the comma is not seen.  */
  258.  
  259. static int
  260. skip_whitespace_and_comma (int required)
  261. {
  262.   SKIP_WHITESPACE ();
  263.   if (*input_line_pointer == ',')
  264.     {
  265.       input_line_pointer++;
  266.       SKIP_WHITESPACE ();
  267.       return 1;
  268.     }
  269.   else if (required)
  270.     {
  271.       as_bad (_("missing separator"));
  272.       ignore_rest_of_line ();
  273.     }
  274.   else
  275.     demand_empty_rest_of_line ();
  276.   return 0;
  277. }
  278.  
  279. /* Mark current context to use 32-bit instruction (arm).  */
  280.  
  281. static void
  282. obj_coff_seh_32 (int what)
  283. {
  284.   if (!verify_context_and_target ((what ? ".seh_32" : ".seh_no32"),
  285.                                   seh_kind_arm))
  286.     return;
  287.  
  288.   seh_ctx_cur->use_instruction_32 = (what ? 1 : 0);
  289.   demand_empty_rest_of_line ();
  290. }
  291.  
  292. /* Set for current context the handler and optional data (arm).  */
  293.  
  294. static void
  295. obj_coff_seh_eh (int what ATTRIBUTE_UNUSED)
  296. {
  297.   if (!verify_context_and_target (".seh_eh", seh_kind_arm))
  298.     return;
  299.  
  300.   /* Write block to .text if exception handler is set.  */
  301.   seh_ctx_cur->handler_written = 1;
  302.   emit_expr (&seh_ctx_cur->handler, 4);
  303.   emit_expr (&seh_ctx_cur->handler_data, 4);
  304.  
  305.   demand_empty_rest_of_line ();
  306. }
  307.  
  308. /* Set for current context the default handler (x64).  */
  309.  
  310. static void
  311. obj_coff_seh_handler (int what ATTRIBUTE_UNUSED)
  312. {
  313.   char *symbol_name;
  314.   char name_end;
  315.  
  316.   if (!verify_context (".seh_handler"))
  317.     return;
  318.  
  319.   if (*input_line_pointer == 0 || *input_line_pointer == '\n')
  320.     {
  321.       as_bad (_(".seh_handler requires a handler"));
  322.       demand_empty_rest_of_line ();
  323.       return;
  324.     }
  325.  
  326.   SKIP_WHITESPACE ();
  327.  
  328.   if (*input_line_pointer == '@')
  329.     {
  330.       name_end = get_symbol_name (&symbol_name);
  331.  
  332.       seh_ctx_cur->handler.X_op = O_constant;
  333.       seh_ctx_cur->handler.X_add_number = 0;
  334.  
  335.       if (strcasecmp (symbol_name, "@0") == 0
  336.           || strcasecmp (symbol_name, "@null") == 0)
  337.         ;
  338.       else if (strcasecmp (symbol_name, "@1") == 0)
  339.         seh_ctx_cur->handler.X_add_number = 1;
  340.       else
  341.         as_bad (_("unknown constant value '%s' for handler"), symbol_name);
  342.  
  343.       (void) restore_line_pointer (name_end);
  344.     }
  345.   else
  346.     expression (&seh_ctx_cur->handler);
  347.  
  348.   seh_ctx_cur->handler_data.X_op = O_constant;
  349.   seh_ctx_cur->handler_data.X_add_number = 0;
  350.   seh_ctx_cur->handler_flags = 0;
  351.  
  352.   if (!skip_whitespace_and_comma (0))
  353.     return;
  354.  
  355.   if (seh_get_target_kind () == seh_kind_x64)
  356.     {
  357.       do
  358.         {
  359.           name_end = get_symbol_name (&symbol_name);
  360.  
  361.           if (strcasecmp (symbol_name, "@unwind") == 0)
  362.             seh_ctx_cur->handler_flags |= UNW_FLAG_UHANDLER;
  363.           else if (strcasecmp (symbol_name, "@except") == 0)
  364.             seh_ctx_cur->handler_flags |= UNW_FLAG_EHANDLER;
  365.           else
  366.             as_bad (_(".seh_handler constant '%s' unknown"), symbol_name);
  367.  
  368.           (void) restore_line_pointer (name_end);
  369.         }
  370.       while (skip_whitespace_and_comma (0));
  371.     }
  372.   else
  373.     {
  374.       expression (&seh_ctx_cur->handler_data);
  375.       demand_empty_rest_of_line ();
  376.  
  377.       if (seh_ctx_cur->handler_written)
  378.         as_warn (_(".seh_handler after .seh_eh is ignored"));
  379.     }
  380. }
  381.  
  382. /* Switch to subsection for handler data for exception region (x64).  */
  383.  
  384. static void
  385. obj_coff_seh_handlerdata (int what ATTRIBUTE_UNUSED)
  386. {
  387.   if (!verify_context_and_target (".seh_handlerdata", seh_kind_x64))
  388.     return;
  389.   demand_empty_rest_of_line ();
  390.  
  391.   switch_xdata (seh_ctx_cur->subsection + 1, seh_ctx_cur->code_seg);
  392. }
  393.  
  394. /* Mark end of current context.  */
  395.  
  396. static void
  397. do_seh_endproc (void)
  398. {
  399.   seh_ctx_cur->end_addr = symbol_temp_new_now ();
  400.  
  401.   write_function_xdata (seh_ctx_cur);
  402.   write_function_pdata (seh_ctx_cur);
  403.   seh_ctx_cur = NULL;
  404. }
  405.  
  406. static void
  407. obj_coff_seh_endproc (int what ATTRIBUTE_UNUSED)
  408. {
  409.   demand_empty_rest_of_line ();
  410.   if (seh_ctx_cur == NULL)
  411.     {
  412.       as_bad (_(".seh_endproc used without .seh_proc"));
  413.       return;
  414.     }
  415.   seh_validate_seg (".seh_endproc");
  416.   do_seh_endproc ();
  417. }
  418.  
  419. /* Mark begin of new context.  */
  420.  
  421. static void
  422. obj_coff_seh_proc (int what ATTRIBUTE_UNUSED)
  423. {
  424.   char *symbol_name;
  425.   char name_end;
  426.  
  427.   if (seh_ctx_cur != NULL)
  428.     {
  429.       as_bad (_("previous SEH entry not closed (missing .seh_endproc)"));
  430.       do_seh_endproc ();
  431.     }
  432.  
  433.   if (*input_line_pointer == 0 || *input_line_pointer == '\n')
  434.     {
  435.       as_bad (_(".seh_proc requires function label name"));
  436.       demand_empty_rest_of_line ();
  437.       return;
  438.     }
  439.  
  440.   seh_ctx_cur = XCNEW (seh_context);
  441.  
  442.   seh_ctx_cur->code_seg = now_seg;
  443.  
  444.   if (seh_get_target_kind () == seh_kind_x64)
  445.     {
  446.       x_segcur = seh_hash_find_or_make (seh_ctx_cur->code_seg, ".xdata");
  447.       seh_ctx_cur->subsection = x_segcur->subseg;
  448.       x_segcur->subseg += 2;
  449.     }
  450.  
  451.   SKIP_WHITESPACE ();
  452.  
  453.   name_end = get_symbol_name (&symbol_name);
  454.   seh_ctx_cur->func_name = xstrdup (symbol_name);
  455.   (void) restore_line_pointer (name_end);
  456.  
  457.   demand_empty_rest_of_line ();
  458.  
  459.   seh_ctx_cur->start_addr = symbol_temp_new_now ();
  460. }
  461.  
  462. /* Mark end of prologue for current context.  */
  463.  
  464. static void
  465. obj_coff_seh_endprologue (int what ATTRIBUTE_UNUSED)
  466. {
  467.   if (!verify_context (".seh_endprologue")
  468.       || !seh_validate_seg (".seh_endprologue"))
  469.     return;
  470.   demand_empty_rest_of_line ();
  471.  
  472.   if (seh_ctx_cur->endprologue_addr != NULL)
  473.     as_warn (_("duplicate .seh_endprologue in .seh_proc block"));
  474.   else
  475.     seh_ctx_cur->endprologue_addr = symbol_temp_new_now ();
  476. }
  477.  
  478. /* End-of-file hook.  */
  479.  
  480. void
  481. obj_coff_seh_do_final (void)
  482. {
  483.   if (seh_ctx_cur != NULL)
  484.     {
  485.       as_bad (_("open SEH entry at end of file (missing .cfi_endproc)"));
  486.       do_seh_endproc ();
  487.     }
  488. }
  489.  
  490. /* Enter a prologue element into current context (x64).  */
  491.  
  492. static void
  493. seh_x64_make_prologue_element (int code, int info, offsetT off)
  494. {
  495.   seh_prologue_element *n;
  496.  
  497.   if (seh_ctx_cur == NULL)
  498.     return;
  499.   if (seh_ctx_cur->elems_count == seh_ctx_cur->elems_max)
  500.     {
  501.       seh_ctx_cur->elems_max += 8;
  502.       seh_ctx_cur->elems = XRESIZEVEC (seh_prologue_element,
  503.                                        seh_ctx_cur->elems,
  504.                                        seh_ctx_cur->elems_max);
  505.     }
  506.  
  507.   n = &seh_ctx_cur->elems[seh_ctx_cur->elems_count++];
  508.   n->code = code;
  509.   n->info = info;
  510.   n->off = off;
  511.   n->pc_addr = symbol_temp_new_now ();
  512. }
  513.  
  514. /* Helper to read a register name from input stream (x64).  */
  515.  
  516. static int
  517. seh_x64_read_reg (const char *directive, int kind)
  518. {
  519.   static const char * const int_regs[16] =
  520.     { "rax", "rcx", "rdx", "rbx", "rsp", "rbp","rsi","rdi",
  521.       "r8","r9","r10","r11","r12","r13","r14","r15" };
  522.   static const char * const xmm_regs[16] =
  523.     { "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7",
  524.       "xmm8", "xmm9", "xmm10","xmm11","xmm12","xmm13","xmm14","xmm15" };
  525.  
  526.   const char * const *regs = NULL;
  527.   char name_end;
  528.   char *symbol_name = NULL;
  529.   int i;
  530.  
  531.   switch (kind)
  532.     {
  533.     case 0:
  534.     case 1:
  535.       regs = int_regs;
  536.       break;
  537.     case 2:
  538.       regs = xmm_regs;
  539.       break;
  540.     default:
  541.       abort ();
  542.     }
  543.  
  544.   SKIP_WHITESPACE ();
  545.   if (*input_line_pointer == '%')
  546.     ++input_line_pointer;
  547.   name_end = get_symbol_name (& symbol_name);
  548.  
  549.   for (i = 0; i < 16; i++)
  550.     if (! strcasecmp (regs[i], symbol_name))
  551.       break;
  552.  
  553.   (void) restore_line_pointer (name_end);
  554.  
  555.   /* Error if register not found, or EAX used as a frame pointer.  */
  556.   if (i == 16 || (kind == 0 && i == 0))
  557.     {
  558.       as_bad (_("invalid register for %s"), directive);
  559.       return -1;
  560.     }
  561.  
  562.   return i;
  563. }
  564.  
  565. /* Add a register push-unwind token to the current context.  */
  566.  
  567. static void
  568. obj_coff_seh_pushreg (int what ATTRIBUTE_UNUSED)
  569. {
  570.   int reg;
  571.  
  572.   if (!verify_context_and_target (".seh_pushreg", seh_kind_x64)
  573.       || !seh_validate_seg (".seh_pushreg"))
  574.     return;
  575.  
  576.   reg = seh_x64_read_reg (".seh_pushreg", 1);
  577.   demand_empty_rest_of_line ();
  578.  
  579.   if (reg < 0)
  580.     return;
  581.  
  582.   seh_x64_make_prologue_element (UWOP_PUSH_NONVOL, reg, 0);
  583. }
  584.  
  585. /* Add a register frame-unwind token to the current context.  */
  586.  
  587. static void
  588. obj_coff_seh_pushframe (int what ATTRIBUTE_UNUSED)
  589. {
  590.   if (!verify_context_and_target (".seh_pushframe", seh_kind_x64)
  591.       || !seh_validate_seg (".seh_pushframe"))
  592.     return;
  593.   demand_empty_rest_of_line ();
  594.  
  595.   seh_x64_make_prologue_element (UWOP_PUSH_MACHFRAME, 0, 0);
  596. }
  597.  
  598. /* Add a register save-unwind token to current context.  */
  599.  
  600. static void
  601. obj_coff_seh_save (int what)
  602. {
  603.   const char *directive = (what == 1 ? ".seh_savereg" : ".seh_savexmm");
  604.   int code, reg, scale;
  605.   offsetT off;
  606.  
  607.   if (!verify_context_and_target (directive, seh_kind_x64)
  608.       || !seh_validate_seg (directive))
  609.     return;
  610.  
  611.   reg = seh_x64_read_reg (directive, what);
  612.  
  613.   if (!skip_whitespace_and_comma (1))
  614.     return;
  615.  
  616.   off = get_absolute_expression ();
  617.   demand_empty_rest_of_line ();
  618.  
  619.   if (reg < 0)
  620.     return;
  621.   if (off < 0)
  622.     {
  623.       as_bad (_("%s offset is negative"), directive);
  624.       return;
  625.     }
  626.  
  627.   scale = (what == 1 ? 8 : 16);
  628.  
  629.   if ((off & (scale - 1)) == 0 && off <= (offsetT) (0xffff * scale))
  630.     {
  631.       code = (what == 1 ? UWOP_SAVE_NONVOL : UWOP_SAVE_XMM128);
  632.       off /= scale;
  633.     }
  634.   else if (off < (offsetT) 0xffffffff)
  635.     code = (what == 1 ? UWOP_SAVE_NONVOL_FAR : UWOP_SAVE_XMM128_FAR);
  636.   else
  637.     {
  638.       as_bad (_("%s offset out of range"), directive);
  639.       return;
  640.     }
  641.  
  642.   seh_x64_make_prologue_element (code, reg, off);
  643. }
  644.  
  645. /* Add a stack-allocation token to current context.  */
  646.  
  647. static void
  648. obj_coff_seh_stackalloc (int what ATTRIBUTE_UNUSED)
  649. {
  650.   offsetT off;
  651.   int code, info;
  652.  
  653.   if (!verify_context_and_target (".seh_stackalloc", seh_kind_x64)
  654.       || !seh_validate_seg (".seh_stackalloc"))
  655.     return;
  656.  
  657.   off = get_absolute_expression ();
  658.   demand_empty_rest_of_line ();
  659.  
  660.   if (off == 0)
  661.     return;
  662.   if (off < 0)
  663.     {
  664.       as_bad (_(".seh_stackalloc offset is negative"));
  665.       return;
  666.     }
  667.  
  668.   if ((off & 7) == 0 && off <= 128)
  669.     code = UWOP_ALLOC_SMALL, info = (off - 8) >> 3, off = 0;
  670.   else if ((off & 7) == 0 && off <= (offsetT) (0xffff * 8))
  671.     code = UWOP_ALLOC_LARGE, info = 0, off >>= 3;
  672.   else if (off <= (offsetT) 0xffffffff)
  673.     code = UWOP_ALLOC_LARGE, info = 1;
  674.   else
  675.     {
  676.       as_bad (_(".seh_stackalloc offset out of range"));
  677.       return;
  678.     }
  679.  
  680.   seh_x64_make_prologue_element (code, info, off);
  681. }
  682.  
  683. /* Add a frame-pointer token to current context.  */
  684.  
  685. static void
  686. obj_coff_seh_setframe (int what ATTRIBUTE_UNUSED)
  687. {
  688.   offsetT off;
  689.   int reg;
  690.  
  691.   if (!verify_context_and_target (".seh_setframe", seh_kind_x64)
  692.       || !seh_validate_seg (".seh_setframe"))
  693.     return;
  694.  
  695.   reg = seh_x64_read_reg (".seh_setframe", 0);
  696.  
  697.   if (!skip_whitespace_and_comma (1))
  698.     return;
  699.  
  700.   off = get_absolute_expression ();
  701.   demand_empty_rest_of_line ();
  702.  
  703.   if (reg < 0)
  704.     return;
  705.   if (off < 0)
  706.     as_bad (_(".seh_setframe offset is negative"));
  707.   else if (off > 240)
  708.     as_bad (_(".seh_setframe offset out of range"));
  709.   else if (off & 15)
  710.     as_bad (_(".seh_setframe offset not a multiple of 16"));
  711.   else if (seh_ctx_cur->framereg != 0)
  712.     as_bad (_("duplicate .seh_setframe in current .seh_proc"));
  713.   else
  714.     {
  715.       seh_ctx_cur->framereg = reg;
  716.       seh_ctx_cur->frameoff = off;
  717.       seh_x64_make_prologue_element (UWOP_SET_FPREG, 0, 0);
  718.     }
  719. }
  720. /* Data writing routines.  */
  721.  
  722. /* Output raw integers in 1, 2, or 4 bytes.  */
  723.  
  724. static inline void
  725. out_one (int byte)
  726. {
  727.   FRAG_APPEND_1_CHAR (byte);
  728. }
  729.  
  730. static inline void
  731. out_two (int data)
  732. {
  733.   md_number_to_chars (frag_more (2), data, 2);
  734. }
  735.  
  736. static inline void
  737. out_four (int data)
  738. {
  739.   md_number_to_chars (frag_more (4), data, 4);
  740. }
  741.  
  742. /* Write out prologue data for x64.  */
  743.  
  744. static void
  745. seh_x64_write_prologue_data (const seh_context *c)
  746. {
  747.   int i;
  748.  
  749.   /* We have to store in reverse order.  */
  750.   for (i = c->elems_count - 1; i >= 0; --i)
  751.     {
  752.       const seh_prologue_element *e = c->elems + i;
  753.       expressionS exp;
  754.  
  755.       /* First comes byte offset in code.  */
  756.       exp.X_op = O_subtract;
  757.       exp.X_add_symbol = e->pc_addr;
  758.       exp.X_op_symbol = c->start_addr;
  759.       exp.X_add_number = 0;
  760.       emit_expr (&exp, 1);
  761.  
  762.       /* Second comes code+info packed into a byte.  */
  763.       out_one ((e->info << 4) | e->code);
  764.  
  765.       switch (e->code)
  766.         {
  767.         case UWOP_PUSH_NONVOL:
  768.         case UWOP_ALLOC_SMALL:
  769.         case UWOP_SET_FPREG:
  770.         case UWOP_PUSH_MACHFRAME:
  771.           /* These have no extra data.  */
  772.           break;
  773.  
  774.         case UWOP_ALLOC_LARGE:
  775.           if (e->info)
  776.             {
  777.         case UWOP_SAVE_NONVOL_FAR:
  778.         case UWOP_SAVE_XMM128_FAR:
  779.               /* An unscaled 4 byte offset.  */
  780.               out_four (e->off);
  781.               break;
  782.             }
  783.           /* FALLTHRU */
  784.  
  785.         case UWOP_SAVE_NONVOL:
  786.         case UWOP_SAVE_XMM128:
  787.           /* A scaled 2 byte offset.  */
  788.           out_two (e->off);
  789.           break;
  790.  
  791.         default:
  792.           abort ();
  793.         }
  794.     }
  795. }
  796.  
  797. static int
  798. seh_x64_size_prologue_data (const seh_context *c)
  799. {
  800.   int i, ret = 0;
  801.  
  802.   for (i = c->elems_count - 1; i >= 0; --i)
  803.     switch (c->elems[i].code)
  804.       {
  805.       case UWOP_PUSH_NONVOL:
  806.       case UWOP_ALLOC_SMALL:
  807.       case UWOP_SET_FPREG:
  808.       case UWOP_PUSH_MACHFRAME:
  809.         ret += 1;
  810.         break;
  811.  
  812.       case UWOP_SAVE_NONVOL:
  813.       case UWOP_SAVE_XMM128:
  814.         ret += 2;
  815.         break;
  816.  
  817.       case UWOP_SAVE_NONVOL_FAR:
  818.       case UWOP_SAVE_XMM128_FAR:
  819.         ret += 3;
  820.         break;
  821.  
  822.       case UWOP_ALLOC_LARGE:
  823.         ret += (c->elems[i].info ? 3 : 2);
  824.         break;
  825.  
  826.       default:
  827.         abort ();
  828.       }
  829.  
  830.   return ret;
  831. }
  832.  
  833. /* Write out the xdata information for one function (x64).  */
  834.  
  835. static void
  836. seh_x64_write_function_xdata (seh_context *c)
  837. {
  838.   int flags, count_unwind_codes;
  839.   expressionS exp;
  840.  
  841.   /* Set 4-byte alignment.  */
  842.   frag_align (2, 0, 0);
  843.  
  844.   c->xdata_addr = symbol_temp_new_now ();
  845.   flags = c->handler_flags;
  846.   count_unwind_codes = seh_x64_size_prologue_data (c);
  847.  
  848.   /* ubyte:3 version, ubyte:5 flags.  */
  849.   out_one ((flags << 3) | 1);
  850.  
  851.   /* Size of prologue.  */
  852.   if (c->endprologue_addr)
  853.     {
  854.       exp.X_op = O_subtract;
  855.       exp.X_add_symbol = c->endprologue_addr;
  856.       exp.X_op_symbol = c->start_addr;
  857.       exp.X_add_number = 0;
  858.       emit_expr (&exp, 1);
  859.     }
  860.   else
  861.     out_one (0);
  862.  
  863.   /* Number of slots (i.e. shorts) in the unwind codes array.  */
  864.   if (count_unwind_codes > 255)
  865.     as_fatal (_("too much unwind data in this .seh_proc"));
  866.   out_one (count_unwind_codes);
  867.  
  868.   /* ubyte:4 frame-reg, ubyte:4 frame-reg-offset.  */
  869.   /* Note that frameoff is already a multiple of 16, and therefore
  870.      the offset is already both scaled and shifted into place.  */
  871.   out_one (c->frameoff | c->framereg);
  872.  
  873.   seh_x64_write_prologue_data (c);
  874.  
  875.   /* We need to align prologue data.  */
  876.   if (count_unwind_codes & 1)
  877.     out_two (0);
  878.  
  879.   if (flags & (UNW_FLAG_EHANDLER | UNW_FLAG_UHANDLER))
  880.     {
  881.       /* Force the use of segment-relative relocations instead of absolute
  882.          valued expressions.  Don't adjust for constants (e.g. NULL).  */
  883.       if (c->handler.X_op == O_symbol)
  884.         c->handler.X_op = O_symbol_rva;
  885.       emit_expr (&c->handler, 4);
  886.     }
  887.  
  888.   /* Handler data will be tacked in here by subsections.  */
  889. }
  890.  
  891. /* Write out xdata for one function.  */
  892.  
  893. static void
  894. write_function_xdata (seh_context *c)
  895. {
  896.   segT save_seg = now_seg;
  897.   int save_subseg = now_subseg;
  898.  
  899.   /* MIPS, SH, ARM don't have xdata.  */
  900.   if (seh_get_target_kind () != seh_kind_x64)
  901.     return;
  902.  
  903.   switch_xdata (c->subsection, c->code_seg);
  904.  
  905.   seh_x64_write_function_xdata (c);
  906.  
  907.   subseg_set (save_seg, save_subseg);
  908. }
  909.  
  910. /* Write pdata section data for one function (arm).  */
  911.  
  912. static void
  913. seh_arm_write_function_pdata (seh_context *c)
  914. {
  915.   expressionS exp;
  916.   unsigned int prol_len = 0, func_len = 0;
  917.   unsigned int val;
  918.  
  919.   /* Start address of the function.  */
  920.   exp.X_op = O_symbol;
  921.   exp.X_add_symbol = c->start_addr;
  922.   exp.X_add_number = 0;
  923.   emit_expr (&exp, 4);
  924.  
  925.   exp.X_op = O_subtract;
  926.   exp.X_add_symbol = c->end_addr;
  927.   exp.X_op_symbol = c->start_addr;
  928.   exp.X_add_number = 0;
  929.   if (resolve_expression (&exp) && exp.X_op == O_constant)
  930.     func_len = exp.X_add_number;
  931.   else
  932.     as_bad (_(".seh_endproc in a different section from .seh_proc"));
  933.  
  934.   if (c->endprologue_addr)
  935.     {
  936.       exp.X_op = O_subtract;
  937.       exp.X_add_symbol = c->endprologue_addr;
  938.       exp.X_op_symbol = c->start_addr;
  939.       exp.X_add_number = 0;
  940.  
  941.       if (resolve_expression (&exp) && exp.X_op == O_constant)
  942.         prol_len = exp.X_add_number;
  943.       else
  944.         as_bad (_(".seh_endprologue in a different section from .seh_proc"));
  945.     }
  946.  
  947.   /* Both function and prologue are in units of instructions.  */
  948.   func_len >>= (c->use_instruction_32 ? 2 : 1);
  949.   prol_len >>= (c->use_instruction_32 ? 2 : 1);
  950.  
  951.   /* Assemble the second word of the pdata.  */
  952.   val  = prol_len & 0xff;
  953.   val |= (func_len & 0x3fffff) << 8;
  954.   if (c->use_instruction_32)
  955.     val |= 0x40000000U;
  956.   if (c->handler_written)
  957.     val |= 0x80000000U;
  958.   out_four (val);
  959. }
  960.  
  961. /* Write out pdata for one function.  */
  962.  
  963. static void
  964. write_function_pdata (seh_context *c)
  965. {
  966.   expressionS exp;
  967.   segT save_seg = now_seg;
  968.   int save_subseg = now_subseg;
  969.   memset (&exp, 0, sizeof (expressionS));
  970.   switch_pdata (c->code_seg);
  971.  
  972.   switch (seh_get_target_kind ())
  973.     {
  974.     case seh_kind_x64:
  975.       exp.X_op = O_symbol_rva;
  976.       exp.X_add_number = 0;
  977.  
  978.       exp.X_add_symbol = c->start_addr;
  979.       emit_expr (&exp, 4);
  980.       exp.X_op = O_symbol_rva;
  981.       exp.X_add_number = 0;
  982.       exp.X_add_symbol = c->end_addr;
  983.       emit_expr (&exp, 4);
  984.       exp.X_op = O_symbol_rva;
  985.       exp.X_add_number = 0;
  986.       exp.X_add_symbol = c->xdata_addr;
  987.       emit_expr (&exp, 4);
  988.       break;
  989.  
  990.     case seh_kind_mips:
  991.       exp.X_op = O_symbol;
  992.       exp.X_add_number = 0;
  993.  
  994.       exp.X_add_symbol = c->start_addr;
  995.       emit_expr (&exp, 4);
  996.       exp.X_add_symbol = c->end_addr;
  997.       emit_expr (&exp, 4);
  998.  
  999.       emit_expr (&c->handler, 4);
  1000.       emit_expr (&c->handler_data, 4);
  1001.  
  1002.       exp.X_add_symbol = (c->endprologue_addr
  1003.                           ? c->endprologue_addr
  1004.                           : c->start_addr);
  1005.       emit_expr (&exp, 4);
  1006.       break;
  1007.  
  1008.     case seh_kind_arm:
  1009.       seh_arm_write_function_pdata (c);
  1010.       break;
  1011.  
  1012.     default:
  1013.       abort ();
  1014.     }
  1015.  
  1016.   subseg_set (save_seg, save_subseg);
  1017. }
  1018.