[binutils-gdb] gas/coff: support for .previous and .{push, pop}section pseudo ops
Jan Beulich
jbeulich@sourceware.org
Fri Sep 11 11:48:24 GMT 2026
https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=636a636c473a55d3420ac4bffd1dd4c223b96408
commit 636a636c473a55d3420ac4bffd1dd4c223b96408
Author: Johannes Khoshnazar-Thoma <johannes@johannesthoma.com>
Date: Fri Sep 11 13:44:56 2026 +0200
gas/coff: support for .previous and .{push,pop}section pseudo ops
Add 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 <johannes@johannesthoma.com>
Diff:
---
gas/NEWS | 4 ++
gas/config/obj-coff.c | 104 ++++++++++++++++++++++++++++++++-
gas/config/obj-coff.h | 1 +
gas/config/tc-ppc.c | 4 ++
gas/config/tc-tic4x.c | 3 +
gas/doc/as.texi | 11 +++-
gas/read.c | 7 ++-
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, 182 insertions(+), 8 deletions(-)
diff --git a/gas/NEWS b/gas/NEWS
index 8b07d86daa3..64674e6e490 100644
--- a/gas/NEWS
+++ b/gas/NEWS
@@ -1,5 +1,9 @@
-*- text -*-
+* 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.
+
* Add support for the x86 AVX10_V2_AUX instructions.
* The avr target supports .gnu_attribute 4 (Tag_GNU_AVR_VTABLE_AS).
diff --git a/gas/config/obj-coff.c b/gas/config/obj-coff.c
index b08295019d8..e9cbe16029a 100644
--- a/gas/config/obj-coff.c
+++ b/gas/config/obj-coff.c
@@ -164,7 +164,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);
}
@@ -1540,6 +1543,73 @@ 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;
+}
+
+static void
+obj_coff_previous (int ignore ATTRIBUTE_UNUSED)
+{
+ segT new_section;
+ subsegT new_subsection;
+
+ if (previous_section == NULL)
+ {
+ 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;
+ }
+
+#ifdef md_flush_pending_output
+ md_flush_pending_output ();
+#endif
+
+ 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"}
^ ^
@@ -1563,7 +1633,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;
@@ -1695,6 +1765,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)
@@ -1902,6 +1984,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},
@@ -1941,13 +2026,26 @@ coff_separate_stab_sections (void)
return 1;
}
+static 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,
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..7a01401ea0e 100644
--- a/gas/config/obj-coff.h
+++ b/gas/config/obj-coff.h
@@ -318,6 +318,7 @@ 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 segT obj_coff_add_segment (const char *);
extern void obj_coff_def (int);
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 2cf4bdfe610..070ead47246 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..99405ef6834 100644
--- a/gas/read.c
+++ b/gas/read.c
@@ -3947,11 +3947,14 @@ s_struct (int ignore ATTRIBUTE_UNUSED)
if (flag_mri)
stop = mri_comment_field (&stopc);
abs_section_offset = get_absolute_expression ();
-#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
- /* The ELF backend needs to know that we are changing sections, so
+ /* The ELF and COFF backends need to know that we are changing sections, so
that .previous works correctly. */
+#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
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..c47ff8ab5af
--- /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..0a5d86b0063
--- /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
More information about the Binutils-cvs
mailing list