Index: src/gas/config/obj-coff-seh.c =================================================================== --- src.orig/gas/config/obj-coff-seh.c 2010-09-08 14:14:48.000000000 +0200 +++ src/gas/config/obj-coff-seh.c 2010-09-10 21:48:06.054923800 +0200 @@ -22,42 +22,101 @@ #include "obj-coff-seh.h" +/* Private segment collection list. */ +struct seh_seg_list { + struct seh_seg_list *next; + segT seg; + int subseg; +}; + /* Local data. */ static seh_context *seh_ctx_cur = NULL; -static segT xdata_seg; -static segT pdata_seg; -static int xdata_subseg; +static struct seh_seg_list *x_seg = NULL; +static struct seh_seg_list *p_seg = NULL; + +static struct seh_seg_list *x_segcur = NULL; +static struct seh_seg_list *p_segcur = NULL; + +static struct seh_seg_list * +find_sehseg (const char *postfix, struct seh_seg_list *in) +{ + if (!in) + return NULL; + do + { + const char *name = bfd_get_section_name (stdoutput, in->seg); + name = strchr (name, '$'); + if (!name && (!postfix || postfix[0] == 0)) + return in; + else if (name && postfix && !strcmp (name, postfix)) + return in; + + in = in->next; + } while (in != NULL); + return NULL; +} + +static struct seh_seg_list * +add_sehseg (struct seh_seg_list **inp, segT seg, const char *base_name) +{ + const char *name = bfd_get_section_name (stdoutput, seg); + struct seh_seg_list *in; + flagword flags; + char sname[1024]; + segT save_seg = now_seg; + int save_subseg = now_subseg; + + name = strchr (name, '$'); + in = find_sehseg (name, *inp); + if (in) + return in; + + /* Check if code segment is marked as linked once. */ + flags = bfd_get_section_flags (stdoutput, seg); + flags &= SEC_LINK_ONCE | SEC_LINK_DUPLICATES_DISCARD | SEC_LINK_DUPLICATES_ONE_ONLY + | SEC_LINK_DUPLICATES_SAME_SIZE | SEC_LINK_DUPLICATES_SAME_CONTENTS; + + in = XCNEW (struct seh_seg_list); + + /* Create segment. */ + sprintf (sname, "%s%s", base_name, (!name ? "" : name)); + in->seg = subseg_new (xstrdup (sname), 0); + in->subseg = 0; + + /* Chain new element into segment list. */ + in->next = *inp; + *inp = in; + + /* Apply possibly lined once flags to new generated segment, too. */ + flags |= bfd_get_section_flags (stdoutput, in->seg); + if (!bfd_set_section_flags (stdoutput, in->seg, flags)) + as_bad (_("bfd_set_section_flags: %s"), + bfd_errmsg (bfd_get_error ())); + + /* Restore to previous segment. */ + subseg_set (save_seg, save_subseg); + return in; +} static void write_function_xdata (seh_context *); static void write_function_pdata (seh_context *); static void -switch_xdata (int subseg) +switch_xdata (int subseg, segT code_seg) { - if (xdata_seg == NULL) - { - xdata_seg = subseg_new (".xdata", 0); - bfd_set_section_flags (stdoutput, xdata_seg, - ((SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_DATA) - & bfd_applicable_section_flags (stdoutput))); - } - subseg_set (xdata_seg, subseg); + x_segcur = add_sehseg (&x_seg, code_seg, ".xdata"); + + subseg_set (x_segcur->seg, subseg); } static void -switch_pdata (void) +switch_pdata (segT code_seg) { - if (pdata_seg == NULL) - { - pdata_seg = subseg_new (".pdata", 0); - bfd_set_section_flags (stdoutput, pdata_seg, - ((SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_DATA) - & bfd_applicable_section_flags (stdoutput))); - } - else - subseg_set (pdata_seg, 0); + p_segcur = add_sehseg (&p_seg, code_seg, ".pdata"); + + subseg_set (p_segcur->seg, p_segcur->subseg); } /* Parsing routines. */ @@ -260,7 +319,7 @@ obj_coff_seh_handlerdata (int what ATTRI return; demand_empty_rest_of_line (); - switch_xdata (seh_ctx_cur->subsection + 1); + switch_xdata (seh_ctx_cur->subsection + 1, seh_ctx_cur->code_seg); } /* Mark end of current context. */ @@ -311,10 +370,13 @@ obj_coff_seh_proc (int what ATTRIBUTE_UN seh_ctx_cur = XCNEW (seh_context); + seh_ctx_cur->code_seg = now_seg; + if (seh_get_target_kind () == seh_kind_x64) { - seh_ctx_cur->subsection = xdata_subseg; - xdata_subseg += 2; + x_segcur = add_sehseg (&x_seg, seh_ctx_cur->code_seg, ".xdata"); + seh_ctx_cur->subsection = x_segcur->subseg; + x_segcur->subseg += 2; } SKIP_WHITESPACE (); @@ -766,7 +828,7 @@ write_function_xdata (seh_context *c) if (seh_get_target_kind () != seh_kind_x64) return; - switch_xdata (c->subsection); + switch_xdata (c->subsection, c->code_seg); seh_x64_write_function_xdata (c); @@ -833,7 +895,7 @@ write_function_pdata (seh_context *c) segT save_seg = now_seg; int save_subseg = now_subseg; memset (&exp, 0, sizeof (expressionS)); - switch_pdata (); + switch_pdata (c->code_seg); switch (seh_get_target_kind ()) { Index: src/gas/config/obj-coff-seh.h =================================================================== --- src.orig/gas/config/obj-coff-seh.h 2010-09-03 19:21:20.000000000 +0200 +++ src/gas/config/obj-coff-seh.h 2010-09-10 21:40:12.529839700 +0200 @@ -90,6 +90,8 @@ typedef struct seh_context { struct seh_context *next; + /* Initial code-segment. */ + segT code_seg; /* Function name. */ char *func_name; /* BeginAddress. */ Index: src/ld/scripttempl/pep.sc =================================================================== --- src.orig/ld/scripttempl/pep.sc 2010-07-25 08:31:36.000000000 +0200 +++ src/ld/scripttempl/pep.sc 2010-09-10 17:34:54.412011600 +0200 @@ -118,7 +118,12 @@ SECTIONS .pdata ${RELOCATING+BLOCK(__section_alignment__)} : { - *(.pdata) + *(.pdata*) + } + + .xdata ${RELOCATING+BLOCK(__section_alignment__)} : + { + *(.xdata*) } .bss ${RELOCATING+BLOCK(__section_alignment__)} :