[PATCH 2/2] x86: constrain and fix use of the "nojumps" .arch modifier
Jan Beulich
jbeulich@suse.com
Fri Aug 29 11:47:51 GMT 2025
As said by the paragraph of the description that isn't modified here (a
few lines up), this was only ever supposed to be used with 16-bit
architectures. Actually enforcing this allows code in
md_estimate_size_before_relax() to move to a less frequently used code
path. (For backwards compatibility, keep accepting "jumps" also with 32-
or 64-bit architectures.)
Repeat the constraint also in the 2nd paragraph of the doc on this
subject. And while there also insert a missing insn in the related
i386-Jumps section.
Furthermore checking a global variable during late processing is wrong. We
need to record the state in the fragment, and use that rather than the
state of the variable at the end of parsing all input.
Seeing that there's no testing of the functionality at all, add a testcase
as well.
---
Using output_jump() also for Jcc when "nojumps" is in effect would yield
an overall more consistent result, but would violate what's documented for
local targets.
--- a/gas/config/tc-i386.c
+++ b/gas/config/tc-i386.c
@@ -3517,7 +3517,12 @@ set_cpu_arch (int dummy ATTRIBUTE_UNUSED
string = s;
if (strcmp (string, "nojumps") == 0)
- no_cond_jump_promotion = 1;
+ {
+ if (cpu_arch_flags.bitfield.cpui386)
+ as_bad (_("`%s' only supported with 16-bit architectures"), string);
+ else
+ no_cond_jump_promotion = true;
+ }
else if (strcmp (string, "jumps") != 0)
{
as_bad (_("no such architecture modifier: `%s'"), string);
@@ -15681,6 +15686,7 @@ void i386_frag_init (fragS *fragP, size_
fragP->tc_frag_data.last_insn_normal
= (seg_info(now_seg)->tc_segment_info_data.last_insn.kind
== last_insn_other);
+ fragP->tc_frag_data.no_cond_jump_promotion = no_cond_jump_promotion;
}
/* Calculate the maximum variable size (i.e., excluding fr_fix)
@@ -16198,8 +16204,19 @@ md_estimate_size_before_relax (fragS *fr
break;
case COND_JUMP86:
- if (size == 2
- && (!no_cond_jump_promotion || fragP->fr_var != NO_RELOC))
+ if (fragP->tc_frag_data.no_cond_jump_promotion
+ && fragP->fr_var == NO_RELOC)
+ {
+ fragP->fr_fix += 1;
+ fixP = fix_new (fragP, old_fr_fix, 1,
+ fragP->fr_symbol,
+ fragP->fr_offset, 1,
+ BFD_RELOC_8_PCREL);
+ fixP->fx_signed = 1;
+ break;
+ }
+
+ if (size == 2)
{
/* Negate the condition, and branch past an
unconditional jump. */
@@ -16221,17 +16238,6 @@ md_estimate_size_before_relax (fragS *fr
/* Fall through. */
case COND_JUMP:
- if (no_cond_jump_promotion && fragP->fr_var == NO_RELOC)
- {
- fragP->fr_fix += 1;
- fixP = fix_new (fragP, old_fr_fix, 1,
- fragP->fr_symbol,
- fragP->fr_offset, 1,
- BFD_RELOC_8_PCREL);
- fixP->fx_signed = 1;
- break;
- }
-
/* This changes the byte-displacement jump 0x7N
to the (d)word-displacement jump 0x0f,0x8N. */
opcode[1] = opcode[0] + 0x10;
@@ -16409,7 +16415,7 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNU
}
else
{
- if (no_cond_jump_promotion
+ if (fragP->tc_frag_data.no_cond_jump_promotion
&& TYPE_FROM_RELAX_STATE (fragP->fr_subtype) != UNCOND_JUMP)
as_warn_where (fragP->fr_file, fragP->fr_line,
_("long jump required"));
--- a/gas/config/tc-i386.h
+++ b/gas/config/tc-i386.h
@@ -331,6 +331,7 @@ struct i386_tc_frag_data
unsigned int cpunop : 1;
unsigned int isanop : 1;
unsigned int last_insn_normal : 1;
+ bool no_cond_jump_promotion : 1;
};
/* We need to emit the right NOP pattern in .align frags. This is
--- a/gas/doc/c-i386.texi
+++ b/gas/doc/c-i386.texi
@@ -1463,10 +1463,10 @@ instruction with the @samp{data16} instr
insists upon masking @samp{%eip} to 16 bits after the word displacement
is added. (See also @pxref{i386-Arch})
-Note that the @samp{jcxz}, @samp{jecxz}, @samp{loop}, @samp{loopz},
-@samp{loope}, @samp{loopnz} and @samp{loopne} instructions only come in byte
-displacements, so that if you use these instructions (@code{@value{GCC}} does
-not use them) you may get an error message (and incorrect code). The AT&T
+Note that the @samp{jcxz}, @samp{jecxz}, @samp{jrcxz}, @samp{loop},
+@samp{loopz}, @samp{loope}, @samp{loopnz} and @samp{loopne} instructions only
+come with byte displacements, so that if you use these instructions
+(@code{@value{GCC}} does not use them) you may get an error message. The AT&T
80386 assembler tries to get around this problem by expanding @samp{jcxz foo}
to
@@ -1760,8 +1760,8 @@ suffixes will disable all insns with wid
On SVR4-derived platforms, the separator character @samp{/} can be replaced by
@samp{:}.
-Following the CPU architecture (but not a sub-architecture, which are those
-starting with a dot), you may specify @samp{jumps} or @samp{nojumps} to
+Following a 16-bit CPU architecture (but not a sub-architecture, which are
+those starting with a dot), you may specify @samp{jumps} or @samp{nojumps} to
control automatic promotion of conditional jumps. @samp{jumps} is the
default, and enables jump promotion; All external jumps will be of the long
variety, and file-local jumps will be promoted as necessary.
--- a/gas/testsuite/gas/i386/i386.exp
+++ b/gas/testsuite/gas/i386/i386.exp
@@ -850,6 +850,7 @@ if {![is_aout_format]} then {
run_list_test pr32721 ""
}
if {[is_elf_format] || [istarget "*-*-vxworks*"]} then {
+ run_dump_test nojumps
run_list_test_stdin "list-1" "-al"
run_list_test_stdin "list-2" "-al"
run_list_test_stdin "list-3" "-al"
--- /dev/null
+++ b/gas/testsuite/gas/i386/nojumps.d
@@ -0,0 +1,31 @@
+#name: ix86 nojumps
+#objdump: -drw -Mi8086
+#warning_output: nojumps.e
+
+.*: +file format .*86.*
+
+Disassembly of section \.text:
+
+0+ <early>:
+[ ]*[a-f0-9]+: 73 03 jae 5 <early\+0x5>
+[ ]*[a-f0-9]+: e9 81 00 jmp 86 <late>
+[ ]*[a-f0-9]+: 70 00 jo 7 <.*> 6: R_X86_64_PC8 undef.*
+[ ]*[a-f0-9]+: 7a 00 jp 9 <.*> 8: R_X86_64_PC8 .*
+[ ]*[a-f0-9]+: eb 7b jmp 86 <late>
+#...
+0+86 <late>:
+[ ]*[a-f0-9]+: 75 03 jne 8b <late\+0x5>
+[ ]*[a-f0-9]+: e9 75 ff jmp 0 <early>
+[ ]*[a-f0-9]+: 74 03 je 90 <late\+0xa>
+[ ]*[a-f0-9]+: e9 00 00 jmp 90 <.*> 8e: R_X86_64_PC16 .*
+[ ]*[a-f0-9]+: 75 03 jne 95 <late\+0xf>
+[ ]*[a-f0-9]+: e9 00 00 jmp 95 <.*> 93: R_X86_64_PC16 undef.*
+[ ]*[a-f0-9]+: 79 03 jns 9a <late\+0x14>
+[ ]*[a-f0-9]+: e9 66 ff jmp 0 <early>
+[ ]*[a-f0-9]+: c3 ret
+#...
+Disassembly of section \.text\.other:
+
+0+ <other>:
+[ ]*[a-f0-9]+: 78 00 js 2 <.*> 1: R_X86_64_PC8 .*
+#pass
--- /dev/null
+++ b/gas/testsuite/gas/i386/nojumps.e
@@ -0,0 +1,3 @@
+.*: Assembler messages:
+.*:11: Warning: long jump required
+.*:16: Warning: long jump required
--- /dev/null
+++ b/gas/testsuite/gas/i386/nojumps.s
@@ -0,0 +1,21 @@
+ .code16
+ .arch i8086,nojumps
+
+ .section .text.other, "ax", @progbits
+other:
+ js early
+ ret
+
+ .text
+early:
+ jc late
+ jo undef
+ jp other
+ .nops 125
+late:
+ jz early
+ .arch i8086,jumps
+ jnz other
+ jz undef
+ js early
+ ret
More information about the Binutils
mailing list