Optimizing 0-displacement jumps on i386

Jan Beulich jbeulich@suse.com
Tue Aug 12 05:57:17 GMT 2025


On 11.08.2025 20:19, H. Peter Anvin wrote:
> On 2025-08-07 23:41, Jan Beulich wrote:
>> On 08.08.2025 01:26, Petr Skočík wrote:
>>> Hi. I'm new here. I noticed (1) gas isn't literal and is capable of various
>>> optimizations & (2) jumps are effectively variable-length due to how gas
>>> iteratively does jmp relaxations and I was wondering why not take (2) all
>>> the way and delete sequences like 0eb 00, i.e., jumps to the next
>>> instruction?
>>>
>>> These come up quite a lot (tailcalls to a neighboring function) & might be
>>> difficult for compilers to eliminate them.
>>> (It might be better if the assembler did it for other reasons anyway--like
>>> I'd like to a bit more efficiently tailcall to some asm without the
>>> compiler getting too nosy). It might be difficult for gas too, but since
>>> the framework for length-adjusting jumps is already there ...?
>>>
>>> Alternatively, and this seems rather easy, 0-displacement jumps could be
>>> turned into 2-byte nops, which are quite a bit faster.
>>>
>>> I tried doing it by modifying the tail of md_convert_frag like so:
>>>
>>>   if(extension==1 && 0==(valueT)(displacement_from_opcode_start -
>>> extension)){ //new
>>>       opcode[0]=0x66; //new
>>>       opcode[1]=0x90; //new
>>>   }else  //new
>>>   {
>>>   /* Now put displacement after opcode.  */
>>>       md_number_to_chars ((char *) where_to_put_displacement,
>>>                   (valueT) (displacement_from_opcode_start - extension),
>>>                   DISP_SIZE_FROM_RELAX_STATE (fragP->fr_subtype));
>>>   }
>>>   fragP->fr_fix += extension;
>>> }
>>>
>>> and it seems to do the job.
>>> Just a thought. Thanks for reading my message.
>>
>> Hmm, yes, why not? Would you mind transforming the above into a proper patch?
>>
> 
> Arguably this should be merged with subsequent alignment padding if it
> fits within one instruction.  However, in order to actually be effective
> in any meaningful way, this version of the optimization probably needs
> to be performed in the linker, or it will simply never happen if the
> code is compiled with linker garbage collection, which is pretty common
> these days.

Having the linker do it would indeed by nice, but I expect that wouldn't
fly without specialized (new) relocation types. We simply shouldn't add
more heuristics-based optimizations there, imo, and disassembling all
code (to determine where JMPs live) is imo prohibitive.

> The optimization in gas would still apply to intra-function jumps.
> 
> Note that it may very well be necessary to disable this optimization, in
> case something expects to be able to create a jump instruction and patch
> its target; such code might use a zero-displacement jump to ensure a
> two-byte as opposed to a 5/6-byte jump. It should be rare though.

Like all (newer) optimizations, this one also shouldn't be on by default,
but be controlled by -O...

Jan


More information about the Binutils mailing list