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