[PATCH v3] gas: support for .previous, .pushsection and .popsection pseudo ops for coff

Johannes Khoshnazar-Thoma <[email protected]>
Newsgroups gmane.comp.gnu.binutils
Message-ID <[email protected]>
This patch adds support for the .previous, .pushsection and
.popsection pseudo-ops for COFF targets. The semantics are
the same as their ELF counterparts.

This patch is one building block for compiling the Linux kernel
as a Windows/ReactOS driver.

Signed-off-by: Johannes Khoshnazar-Thoma <[email protected]>
---
 gas/NEWS                               |   6 ++
 gas/config/obj-coff.c                  | 100 ++++++++++++++++++++++++-
 gas/config/obj-coff.h                  |   2 +
 gas/config/tc-ppc.c                    |   4 +
 gas/config/tc-tic4x.c                  |   3 +
 gas/doc/as.texi                        |  11 ++-
 gas/read.c                             |   3 +
 gas/testsuite/gas/coff/coff.exp        |   3 +
 gas/testsuite/gas/coff/previous.d      |   9 +++
 gas/testsuite/gas/coff/previous.s      |   8 ++
 gas/testsuite/gas/coff/pushpop.d       |   9 +++
 gas/testsuite/gas/coff/pushpop.s       |   6 ++
 gas/testsuite/gas/ppc/aix.exp          |   2 +
 gas/testsuite/gas/ppc/xcoff-previous.d |   9 +++
 gas/testsuite/gas/ppc/xcoff-previous.s |  10 +++
 15 files changed, 179 insertions(+), 6 deletions(-)
 create mode 100644 gas/testsuite/gas/coff/previous.d
 create mode 100644 gas/testsuite/gas/coff/previous.s
 create mode 100644 gas/testsuite/gas/coff/pushpop.d
 create mode 100644 gas/testsuite/gas/coff/pushpop.s
 create mode 100644 gas/testsuite/gas/ppc/xcoff-previous.d
 create mode 100644 gas/testsuite/gas/ppc/xcoff-previous.s

diff --git a/gas/NEWS b/gas/NEWS
index 165e23361bb..9d59a989f9f 100644
--- a/gas/NEWS
+++ b/gas/NEWS
@@ -1,5 +1,11 @@
 -*- text -*-
 
+Changes in 2.48:
+
+* Support for .previous, .pushsection and .popsection for COFF targets.
+  The semantics are the same as for ELF targets. This allows one to
+  compile the Linux kernel as a Windows/ReactOS driver.
+
 Changes in 2.47:
 
 * New command line option --reloc-section-sym=[all|internal|none]
diff --git a/gas/config/obj-coff.c b/gas/config/obj-coff.c
index 7732c0af911..21e2f6c2bf8 100644
--- a/gas/config/obj-coff.c
+++ b/gas/config/obj-coff.c
@@ -160,7 +160,10 @@ static void
 obj_coff_bss (int ignore ATTRIBUTE_UNUSED)
 {
   if (*input_line_pointer == '\n')
-    subseg_new (".bss", get_absolute_expression ());
+    {
+      obj_coff_section_change_hook ();
+      subseg_new (".bss", get_absolute_expression ());
+    }
   else
     s_lcomm (0);
 }
@@ -1536,6 +1539,69 @@ obj_coff_finalize_section_relocs (asection *sec, arelent **relocs,
   return true;
 }
 
+static segT previous_section;
+static subsegT previous_subsection;
+
+/* This can be called from the processor backends if they change
+   sections.  */
+
+void
+obj_coff_section_change_hook (void)
+{
+  previous_section = now_seg;
+  previous_subsection = now_subseg;
+}
+
+void
+obj_coff_previous (int ignore ATTRIBUTE_UNUSED)
+{
+  segT new_section;
+  subsegT new_subsection;
+
+  if (previous_section == 0)
+    {
+      as_warn (_(".previous without corresponding .section; ignored"));
+      return;
+    }
+
+#ifdef md_flush_pending_output
+  md_flush_pending_output ();
+#endif
+
+  new_section = previous_section;
+  new_subsection = previous_subsection;
+  obj_coff_section_change_hook ();
+
+  subseg_set (new_section, new_subsection);
+}
+
+struct section_stack
+{
+  struct section_stack *next;
+  segT seg, prev_seg;
+  subsegT subseg, prev_subseg;
+};
+
+static struct section_stack *section_stack;
+
+static void
+obj_coff_popsection (int ignore ATTRIBUTE_UNUSED)
+{
+  struct section_stack *top = section_stack;
+
+  if (top == NULL)
+    {
+      as_warn (_(".popsection without corresponding .pushsection; ignored"));
+      return;
+    }
+
+  section_stack = top->next;
+  previous_section = top->prev_seg;
+  previous_subsection = top->prev_subseg;
+  subseg_set (top->seg, top->subseg);
+  free (top);
+}
+
 /* Implement the .section pseudo op:
   	.section name {, "flags"}
                   ^         ^
@@ -1559,7 +1625,7 @@ obj_coff_finalize_section_relocs (asection *sec, arelent **relocs,
    .section directive to be parsed in both ELF and COFF formats.  */
 
 void
-obj_coff_section (int ignore ATTRIBUTE_UNUSED)
+obj_coff_section (int push)
 {
   /* Strip out the section name.  */
   char *section_name;
@@ -1691,6 +1757,18 @@ obj_coff_section (int ignore ATTRIBUTE_UNUSED)
 	}
     }
 
+  if (push)
+    {
+      struct section_stack *elt = XNEW (struct section_stack);
+      elt->next = section_stack;
+      elt->seg = now_seg;
+      elt->prev_seg = previous_section;
+      elt->subseg = now_subseg;
+      elt->prev_subseg = previous_subsection;
+      section_stack = elt;
+    }
+
+  obj_coff_section_change_hook ();
   sec = subseg_new (name, exp);
 
   if (is_bss)
@@ -1898,6 +1976,9 @@ static const pseudo_typeS coff_pseudo_table[] =
   {"ident", obj_coff_ident, 0},
   {"line", obj_coff_line, 0},
   {"ln", obj_coff_ln, 0},
+  {"popsection", obj_coff_popsection, 0},
+  {"previous", obj_coff_previous, 0},
+  {"pushsection", obj_coff_section, 1},
   {"scl", obj_coff_scl, 0},
   {"sect", obj_coff_section, 0},
   {"sect.s", obj_coff_section, 0},
@@ -1937,13 +2018,26 @@ coff_separate_stab_sections (void)
   return 1;
 }
 
+void
+coff_end (void)
+{
+  if (!ENABLE_LEAK_CHECK)
+    return;
+  while (section_stack)
+    {
+      struct section_stack *top = section_stack;
+      section_stack = top->next;
+      free (top);
+    }
+}
+
 const struct format_ops coff_format_ops =
 {
   bfd_target_coff_flavour,
   0,	/* dfl_leading_underscore */
   1,	/* emit_section_symbols */
   0,    /* begin */
-  0,	/* end.  */
+  coff_end,	/* end.  */
   c_dot_file_symbol,
   coff_assign_symbol,
   coff_frob_symbol,
diff --git a/gas/config/obj-coff.h b/gas/config/obj-coff.h
index 0b933f467b2..052c580ffe1 100644
--- a/gas/config/obj-coff.h
+++ b/gas/config/obj-coff.h
@@ -318,7 +318,9 @@ extern void coff_obj_read_begin_hook     (void);
 extern void pecoff_obj_set_weak_hook     (symbolS *);
 extern void pecoff_obj_clear_weak_hook   (symbolS *);
 #endif
+extern void obj_coff_section_change_hook (void);
 extern void obj_coff_section             (int);
+extern void obj_coff_previous            (int);
 extern segT obj_coff_add_segment         (const char *);
 extern void obj_coff_def                 (int);
 extern segT s_get_segment                (symbolS *);
diff --git a/gas/config/tc-ppc.c b/gas/config/tc-ppc.c
index b82ba2eaebd..c0382635cf4 100644
--- a/gas/config/tc-ppc.c
+++ b/gas/config/tc-ppc.c
@@ -4529,6 +4529,8 @@ ppc_csect (int ignore ATTRIBUTE_UNUSED)
 static void
 ppc_change_csect (symbolS *sym, offsetT align)
 {
+  obj_coff_section_change_hook ();
+
   if (S_IS_DEFINED (sym))
     subseg_set (S_GET_SEGMENT (sym), symbol_get_tc (sym)->subseg);
   else
@@ -4652,6 +4654,7 @@ ppc_change_debug_section (unsigned int idx, subsegT subseg)
   flagword oldflags;
   const struct xcoff_dwsect_name *dw = &xcoff_dwsect_names[idx];
 
+  obj_coff_section_change_hook ();
   sec = subseg_new (dw->xcoff_name, subseg);
   oldflags = bfd_section_flags (sec);
   if (oldflags == SEC_NO_FLAGS)
@@ -5650,6 +5653,7 @@ ppc_ec (int ignore ATTRIBUTE_UNUSED)
 static void
 ppc_toc (int ignore ATTRIBUTE_UNUSED)
 {
+  obj_coff_section_change_hook ();
   if (ppc_toc_csect != NULL)
     subseg_set (data_section, symbol_get_tc (ppc_toc_csect)->subseg);
   else
diff --git a/gas/config/tc-tic4x.c b/gas/config/tc-tic4x.c
index a6f8d7a203b..7a27c06dc93 100644
--- a/gas/config/tc-tic4x.c
+++ b/gas/config/tc-tic4x.c
@@ -988,6 +988,9 @@ tic4x_sect (int x ATTRIBUTE_UNUSED)
   else
     num = 0;
 
+#ifdef OBJ_COFF
+  obj_coff_section_change_hook ();
+#endif
   seg = subseg_new (name, num);
   if (line_label != NULL)
     {
diff --git a/gas/doc/as.texi b/gas/doc/as.texi
index 5d7772d62d3..6beb30a0171 100644
--- a/gas/doc/as.texi
+++ b/gas/doc/as.texi
@@ -6700,7 +6700,7 @@ undefined.
 This is one of the ELF section stack manipulation directives.  The others are
 @code{.section} (@pxref{Section}), @code{.subsection} (@pxref{SubSection}),
 @code{.pushsection} (@pxref{PushSection}), and @code{.previous}
-(@pxref{Previous}).
+(@pxref{Previous}). It is also implemented on COFF targets.
 
 This directive replaces the current section (and subsection) with the top
 section (and subsection) on the section stack.  This section is popped off the
@@ -6716,7 +6716,7 @@ stack.
 This is one of the ELF section stack manipulation directives.  The others are
 @code{.section} (@pxref{Section}), @code{.subsection} (@pxref{SubSection}),
 @code{.pushsection} (@pxref{PushSection}), and @code{.popsection}
-(@pxref{PopSection}).
+(@pxref{PopSection}). It is also implemented on COFF targets.
 
 This directive swaps the current section (and subsection) with most recently
 referenced section/subsection pair prior to this one.  Multiple
@@ -6820,7 +6820,7 @@ expanded.  @xref{Macro}.
 This is one of the ELF section stack manipulation directives.  The others are
 @code{.section} (@pxref{Section}), @code{.subsection} (@pxref{SubSection}),
 @code{.popsection} (@pxref{PopSection}), and @code{.previous}
-(@pxref{Previous}).
+(@pxref{Previous}). It is also implemented on COFF targets.
 
 This directive pushes the current section (and subsection) onto the
 top of the section stack, and then replaces the current section and
@@ -6996,6 +6996,11 @@ will be as if no flags had been specified at all.
 
 If the optional argument to the @code{.section} directive is not quoted, it is
 taken as a subsection number (@pxref{Sub-Sections}).
+
+For COFF targets, the @code{.pushsection} (@pxref{PushSection}),
+@code{.popsection} (@pxref{PopSection}), and @code{.previous}
+(@pxref{Previous}) directives are also implemented.
+
 @end ifset
 
 @ifset ELF
diff --git a/gas/read.c b/gas/read.c
index ae481007c32..76c8fa84d53 100644
--- a/gas/read.c
+++ b/gas/read.c
@@ -3952,6 +3952,9 @@ s_struct (int ignore ATTRIBUTE_UNUSED)
      that .previous works correctly. */
   if (IS_ELF)
     obj_elf_section_change_hook ();
+#endif
+#if defined (OBJ_COFF)
+  obj_coff_section_change_hook ();
 #endif
   subseg_set (absolute_section, 0);
   demand_empty_rest_of_line ();
diff --git a/gas/testsuite/gas/coff/coff.exp b/gas/testsuite/gas/coff/coff.exp
index 3732a226e3b..323c59c21ce 100644
--- a/gas/testsuite/gas/coff/coff.exp
+++ b/gas/testsuite/gas/coff/coff.exp
@@ -38,3 +38,6 @@ if { ![istarget *c4x*-*-*] && ![istarget *c54x*-*-*] } {
     run_dump_test func3
     run_dump_test func4
 }
+
+run_dump_test pushpop
+run_dump_test previous
diff --git a/gas/testsuite/gas/coff/previous.d b/gas/testsuite/gas/coff/previous.d
new file mode 100644
index 00000000000..495fb245cab
--- /dev/null
+++ b/gas/testsuite/gas/coff/previous.d
@@ -0,0 +1,9 @@
+#objdump: -s
+#name: .previous support
+
+.*:     file format .*
+
+Contents of section a:
+ 0000.*01[0 ]*03.*
+Contents of section b:
+ 0000.*02[0 ]*04.*
diff --git a/gas/testsuite/gas/coff/previous.s b/gas/testsuite/gas/coff/previous.s
new file mode 100644
index 00000000000..aea07428368
--- /dev/null
+++ b/gas/testsuite/gas/coff/previous.s
@@ -0,0 +1,8 @@
+	.section a
+	.byte 1
+	.section b
+	.byte 2
+	.previous
+	.byte 3
+	.previous
+	.byte 4 
diff --git a/gas/testsuite/gas/coff/pushpop.d b/gas/testsuite/gas/coff/pushpop.d
new file mode 100644
index 00000000000..7d3ce21a273
--- /dev/null
+++ b/gas/testsuite/gas/coff/pushpop.d
@@ -0,0 +1,9 @@
+#objdump: -s
+#name: .pushsection and .popsection support
+
+.*:     file format .*
+
+Contents of section a:
+ 0000.*01[0 ]*03.*
+Contents of section b:
+ 0000.*02.*
diff --git a/gas/testsuite/gas/coff/pushpop.s b/gas/testsuite/gas/coff/pushpop.s
new file mode 100644
index 00000000000..ec05bade0dc
--- /dev/null
+++ b/gas/testsuite/gas/coff/pushpop.s
@@ -0,0 +1,6 @@
+	.section a
+	.byte 1
+	.pushsection b
+	.byte 2
+	.popsection
+	.byte 3
diff --git a/gas/testsuite/gas/ppc/aix.exp b/gas/testsuite/gas/ppc/aix.exp
index 613c71b81ff..6f195289220 100644
--- a/gas/testsuite/gas/ppc/aix.exp
+++ b/gas/testsuite/gas/ppc/aix.exp
@@ -79,6 +79,8 @@ if { [istarget "powerpc*-*-aix*"] || [istarget "rs6000-*-aix*"] } then {
     run_dump_test "xcoff-function-1-32"
     run_dump_test "xcoff-function-1-64"
 
+    run_dump_test "xcoff-previous"
+
     run_dump_test "xcoff-tls-32"
     run_dump_test "xcoff-tls-64"
 
diff --git a/gas/testsuite/gas/ppc/xcoff-previous.d b/gas/testsuite/gas/ppc/xcoff-previous.d
new file mode 100644
index 00000000000..838475b0b8a
--- /dev/null
+++ b/gas/testsuite/gas/ppc/xcoff-previous.d
@@ -0,0 +1,9 @@
+#objdump: -s
+#name: .previous support for xcoff
+
+.*:     file format .*
+
+Contents of section .text:
+ 0000.*01[0 ]*03.*
+Contents of section .data:
+ 0008.*02[0 ]*04.*
diff --git a/gas/testsuite/gas/ppc/xcoff-previous.s b/gas/testsuite/gas/ppc/xcoff-previous.s
new file mode 100644
index 00000000000..f57ded56e84
--- /dev/null
+++ b/gas/testsuite/gas/ppc/xcoff-previous.s
@@ -0,0 +1,10 @@
+	.globl .a
+	.globl .b
+	.section .text
+	.byte 1 
+	.section .data
+	.byte 2 
+	.previous
+	.byte 3
+	.previous
+	.byte 4
-- 
2.55.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.