2010-07-15 Kai Tietz <kai.tietz@onevision.com>

* config/obj-coff-seh.c
	(seh_getelm_data_size): New.
	(seh_read_offset): Handle negative values.
	(obj_coff_seh_push): Handle offset for save-register store.
	(obj_coff_seh_setframe): Add unwind-information for frame.
	(seh_store_elm_data): New.
	(seh_getelm_data_size): Return additionally unaligned element count.
	(seh_make_unwind_entry): Correct tweak about element count.
This commit is contained in:
Kai Tietz 2010-07-15 13:42:20 +00:00
parent f14ead0d15
commit 1e17085dea
2 changed files with 178 additions and 11 deletions

View File

@ -1,3 +1,14 @@
2010-07-15 Kai Tietz <kai.tietz@onevision.com>
* config/obj-coff-seh.c
(seh_getelm_data_size): New.
(seh_read_offset): Handle negative values.
(obj_coff_seh_push): Handle offset for save-register store.
(obj_coff_seh_setframe): Add unwind-information for frame.
(seh_store_elm_data): New.
(seh_getelm_data_size): Return additionally unaligned element count.
(seh_make_unwind_entry): Correct tweak about element count.
2010-07-12 H.J. Lu <hongjiu.lu@intel.com>
PR gas/11806

View File

@ -40,7 +40,9 @@ static void seh_write_text_eh_data (const char *hnd, const char *hnd_data);
static void seh_emit_rva (const char *name);
static int seh_needed_unwind_info (seh_context *);
static void seh_fill_pcsyms (const seh_context *c, char **, int *);
static size_t seh_getelm_data_size (const seh_context *, int, int);
static size_t seh_getelm_data_size (const seh_context *, int, int, size_t *);
static void seh_store_elm_data (const seh_context *, int, int, unsigned char *, valueT base_off);
static size_t seh_getsize_of_unwind_entry (seh_context *, int, int, int);
static void seh_make_unwind_entry (const seh_context *, char *, int, int, int, unsigned char *, size_t *, int);
static size_t seh_getsize_unwind_data (seh_context *);
@ -119,6 +121,7 @@ make_function_entry_pdata (seh_context *c)
subseg_set (current_seg, current_subseg);
}
/* Create and write xdata section. */
static void
seh_x64_write_xdata (void)
{
@ -168,6 +171,8 @@ seh_x64_write_xdata (void)
bfd_set_section_contents (abfd, seg_xdata, data, 0, xdata_size);
}
/* Create pdata section data for arm. */
static void
seh_arm_create_pdata (seh_context *c, unsigned char *data, size_t pdata_offs)
{
@ -200,6 +205,7 @@ seh_arm_create_pdata (seh_context *c, unsigned char *data, size_t pdata_offs)
bfd_put_32 (c->abfd, (bfd_vma) val, data + pdata_offs + 4);
}
/* Write pdata section for arm. */
static void
seh_arm_write_pdata (void)
{
@ -248,6 +254,8 @@ seh_arm_write_pdata (void)
bfd_set_section_contents (abfd, seg_pdata, data, 0, pdata_size);
}
/* Do object finalization to generate and write pdata/xdata
for arm and x64 target. */
void
obj_coff_seh_do_final (void)
{
@ -265,6 +273,7 @@ obj_coff_seh_do_final (void)
}
}
/* Enter a prologue element into current context. */
static void
seh_x64_make_prologue_element (int kind, int reg, bfd_vma off)
{
@ -288,6 +297,7 @@ seh_x64_make_prologue_element (int kind, int reg, bfd_vma off)
seh_ctx_cur->elems_count += 1;
}
/* Helper to read a register name from input stream. */
static int
seh_x64_read_reg (const char *tok, int kind, int *regno)
{
@ -357,14 +367,26 @@ seh_x64_read_reg (const char *tok, int kind, int *regno)
return i != 16;
}
/* Read an numeric value from input stream. */
static int
seh_read_offset (const char *tok, bfd_vma *off)
{
bfd_vma r, v = 0, base = 10;
int had_one = 0;
int neg = 0;
while (*input_line_pointer == ' ' || *input_line_pointer == '\t')
input_line_pointer++;
if (*input_line_pointer == '$')
++input_line_pointer;
if (*input_line_pointer == '-')
{
neg = 1;
++input_line_pointer;
}
else if (*input_line_pointer == '+')
{
++input_line_pointer;
}
if (*input_line_pointer == '0')
{
++input_line_pointer;
@ -404,6 +426,9 @@ seh_read_offset (const char *tok, bfd_vma *off)
v += r;
had_one = 1;
}
if (neg)
v = (bfd_vma) (v ^ ((bfd_vma) -1LL)) + (bfd_vma) 1ULL;
*off = v;
if (had_one == 0)
{
@ -419,6 +444,7 @@ seh_read_offset (const char *tok, bfd_vma *off)
return had_one != 0;
}
/* Mark current context to use 32-bit instruction (arm). */
static void
obj_coff_seh_32 (int what)
{
@ -434,6 +460,7 @@ obj_coff_seh_32 (int what)
demand_empty_rest_of_line ();
}
/* Set for current context the handler and optional data (arm). */
static void
obj_coff_seh_eh (int what ATTRIBUTE_UNUSED)
{
@ -452,6 +479,7 @@ obj_coff_seh_eh (int what ATTRIBUTE_UNUSED)
demand_empty_rest_of_line ();
}
/* Set for current context the default handler (x64). */
static void
obj_coff_seh_handler (int what ATTRIBUTE_UNUSED)
{
@ -506,6 +534,7 @@ obj_coff_seh_handler (int what ATTRIBUTE_UNUSED)
demand_empty_rest_of_line ();
}
/* Add a scope-element for exception region (x64). */
static void
obj_coff_seh_scope (int what ATTRIBUTE_UNUSED)
{
@ -595,6 +624,7 @@ obj_coff_seh_scope (int what ATTRIBUTE_UNUSED)
demand_empty_rest_of_line ();
}
/* Mark begin of new context. */
static void
obj_coff_seh_proc (int what ATTRIBUTE_UNUSED)
{
@ -637,6 +667,7 @@ obj_coff_seh_proc (int what ATTRIBUTE_UNUSED)
demand_empty_rest_of_line ();
}
/* Mark end of current context. */
static void
obj_coff_seh_endproc (int what ATTRIBUTE_UNUSED)
{
@ -653,11 +684,14 @@ obj_coff_seh_endproc (int what ATTRIBUTE_UNUSED)
demand_empty_rest_of_line ();
}
/* Add a push-unwind-information to current context.
what:0 push volatile reg, 1: push machine frame, 2: set fp register. */
static void
obj_coff_seh_push (int what)
{
int reg = 0;
int kind = -1;
bfd_vma off = 0;
if (seh_ctx_cur == NULL)
{
@ -669,7 +703,7 @@ obj_coff_seh_push (int what)
switch (what)
{
case 0:
if (seh_x64_read_reg (".seh_push", 1, &reg))
if (seh_x64_read_reg (".seh_pushreg", 1, &reg))
kind = UWOP_PUSH_NONVOL;
else
as_warn (_(".seh_pushreg expects register argument."));
@ -680,13 +714,15 @@ obj_coff_seh_push (int what)
default:
abort ();
}
if (seh_get_target_kind () != seh_kind_x64)
as_warn (_(".seh_save... is ignored for this target.\n"));
else if (kind != -1)
seh_x64_make_prologue_element (kind, reg, 0);
seh_x64_make_prologue_element (kind, reg, off);
demand_empty_rest_of_line ();
}
/* Add a register save-unwind-information to current context. */
static void
obj_coff_seh_save (int what)
{
@ -727,6 +763,7 @@ obj_coff_seh_save (int what)
demand_empty_rest_of_line ();
}
/* Mark end of prologue for current context. */
static void
obj_coff_seh_endprologue (int what ATTRIBUTE_UNUSED)
{
@ -742,6 +779,7 @@ obj_coff_seh_endprologue (int what ATTRIBUTE_UNUSED)
seh_ctx_cur->endprologue_symbol = make_seh_text_label (seh_ctx_cur, &seh_ctx_cur->endprologue_addr);
}
/* Add a stack-allocation-unwind-information for current context. */
static void
obj_coff_seh_stack_alloc (int what ATTRIBUTE_UNUSED)
{
@ -762,9 +800,11 @@ obj_coff_seh_stack_alloc (int what ATTRIBUTE_UNUSED)
}
}
/* Add frame-pointer-unwind-information to current context. */
static void
obj_coff_seh_setframe (int what ATTRIBUTE_UNUSED)
{
int kind = -1;
int reg;
int ok = 1;
bfd_vma off;
@ -781,9 +821,12 @@ obj_coff_seh_setframe (int what ATTRIBUTE_UNUSED)
{
seh_ctx_cur->framereg = reg;
seh_ctx_cur->frameoff = off;
kind = UWOP_SET_FPREG;
}
if (seh_get_target_kind () != seh_kind_x64)
as_warn (_(".seh_setframe is ignored for this target.\n"));
else if (kind != -1)
seh_x64_make_prologue_element (kind, reg, off);
demand_empty_rest_of_line ();
}
@ -1053,10 +1096,108 @@ seh_needed_unwind_info (seh_context *c)
return count;
}
static size_t
seh_getelm_data_size (const seh_context *c, int elm_start, int elm_end)
static void
seh_store_elm_data (const seh_context *c, int elm_start,int elm_end, unsigned char *puwop, valueT base)
{
size_t ret = PEX64_UWI_SIZEOF_UWCODE_ARRAY (elm_end - elm_start);
int i = elm_end;
valueT off;
/* We have to store in reverse order. */
while (i > elm_start)
{
--i;
/* First comes byte offset in code. */
off = resolve_symbol_value (c->elems[i].pc_addr) - base;
*puwop++ = (unsigned char) off;
switch (c->elems[i].kind)
{
case UWOP_PUSH_NONVOL:
*puwop = UWOP_PUSH_NONVOL | (c->elems[i].reg << 4);
puwop++;
break;
case UWOP_SET_FPREG:
*puwop++ = UWOP_SET_FPREG;
break;
case UWOP_PUSH_MACHFRAME:
*puwop = UWOP_PUSH_MACHFRAME | (c->elems[i].reg << 4);
puwop++;
break;
case UWOP_SAVE_NONVOL:
if ((c->elems[i].offset & 7) != 0 ||
((c->elems[i].offset / 8) > 0xffff))
{
*puwop++ = UWOP_SAVE_NONVOL_FAR | (c->elems[i].reg << 4);
bfd_putl32 ((bfd_vma) c->elems[i].offset, puwop);
puwop += 4;
}
else
{
*puwop++ = UWOP_SAVE_NONVOL | (c->elems[i].reg << 4);
bfd_putl16 ((bfd_vma) (c->elems[i].offset / 8), puwop);
puwop += 2;
}
break;
case UWOP_SAVE_XMM:
if ((c->elems[i].offset & 7) != 0 ||
((c->elems[i].offset / 8) > 0xffff))
{
*puwop++ = UWOP_SAVE_XMM_FAR | (c->elems[i].reg << 4);
bfd_putl32 ((bfd_vma) c->elems[i].offset, puwop);
puwop += 4;
}
else
{
*puwop++ = UWOP_SAVE_XMM | (c->elems[i].reg << 4);
bfd_putl16 ((bfd_vma) (c->elems[i].offset / 8), puwop);
puwop += 2;
}
break;
case UWOP_SAVE_XMM128:
if ((c->elems[i].offset & 7) != 0 ||
((c->elems[i].offset / 8) > 0xffff))
{
*puwop++ = UWOP_SAVE_XMM128_FAR | (c->elems[i].reg << 4);
bfd_putl32 ((bfd_vma) c->elems[i].offset, puwop);
puwop += 4;
}
else
{
*puwop++ = UWOP_SAVE_XMM128 | (c->elems[i].reg << 4);
bfd_putl16 ((bfd_vma) (c->elems[i].offset / 8), puwop);
puwop += 2;
}
break;
case UWOP_ALLOC_LARGE:
if ((c->elems[i].offset & 7) != 0 ||
((c->elems[i].offset / 8) > 0xffff))
{
*puwop++ = UWOP_ALLOC_LARGE | (1 << 4);
bfd_putl32 ((bfd_vma) c->elems[i].offset, puwop);
puwop += 4;
}
else if ((c->elems[i].offset / 8) <= 0x10)
{
*puwop++ = UWOP_ALLOC_SMALL | (((c->elems[i].offset / 8) - 1) << 4);
}
else
{
*puwop++ = UWOP_ALLOC_LARGE;
bfd_putl16 ((bfd_vma) (c->elems[i].offset / 8), puwop);
puwop += 2;
}
break;
default:
puwop++;
abort ();
break;
}
}
}
static size_t
seh_getelm_data_size (const seh_context *c, int elm_start, int elm_end, size_t *unaligned_uwcodes)
{
size_t ret = 0;
while (elm_start < elm_end)
{
@ -1076,20 +1217,33 @@ seh_getelm_data_size (const seh_context *c, int elm_start, int elm_end)
ret += 4;
break;
case UWOP_ALLOC_LARGE:
ret += 4;
if ((c->elems[elm_start].offset & 7) != 0 ||
((c->elems[elm_start].offset / 8) > 0xffff))
ret += 6;
else if ((c->elems[elm_start].offset / 8) <= 0x10)
ret += 2;
else
ret += 4;
break;
case UWOP_SET_FPREG:
ret += 2;
break;
default:
ret += 2;
break;
}
elm_start++;
}
if (unaligned_uwcodes)
*unaligned_uwcodes = ret;
ret = PEX64_UWI_SIZEOF_UWCODE_ARRAY ((ret / 2));
return ret;
}
static size_t
seh_getsize_of_unwind_entry (seh_context *c, int elm_start, int elm_end, int bechain)
{
size_t ret = seh_getelm_data_size(c, elm_start, elm_end);
size_t ret = seh_getelm_data_size(c, elm_start, elm_end, NULL);
c->count_syms += 1;
if (bechain)
@ -1129,7 +1283,8 @@ seh_make_unwind_entry (const seh_context *c, char *name, int elm_start, int elm_
size_t it;
valueT start_off = resolve_symbol_value (c->start_addr);
valueT end_prologue;
size_t uwcodes = seh_getelm_data_size(c, elm_start, elm_end);
size_t unaligned_uwcodes = 0;
size_t uwcodes = seh_getelm_data_size(c, elm_start, elm_end, &unaligned_uwcodes);
unsigned int flag = UNW_FLAG_NHANDLER;
int idx;
@ -1154,9 +1309,10 @@ seh_make_unwind_entry (const seh_context *c, char *name, int elm_start, int elm_
if (end_prologue > 255)
end_prologue = 255;
data[off++] = (unsigned char) end_prologue;
data[off++] = (unsigned char) (uwcodes / 2);
data[off++] = (unsigned char) (unaligned_uwcodes / 2);
data[off] = (unsigned char) c->framereg;
data[off++] |= (unsigned char) ((c->frameoff / 16) << 4);
seh_store_elm_data (c, elm_start, elm_end, &data[off], start_off);
off += uwcodes;
if (bechain)
{