Stream: git-wasmtime

Topic: wasmtime / PR #13975 cranelift-jit: handle far x86_64 cal...


view this post on Zulip Wasmtime GitHub notifications bot (Jul 25 2026 at 18:55):

glebpom edited PR #13975.

view this post on Zulip Wasmtime GitHub notifications bot (Jul 25 2026 at 18:55):

glebpom edited PR #13975:

Summary

Handle JIT functions and data allocated outside x86_64's signed 32-bit
PC-relative range.

This change:

Fixes #4000.

Motivation

A JITMemoryProvider may allocate generated code, data objects, and functions
independently. It does not guarantee that these allocations will be within
±2 GiB of one another.

Both relevant x86_64 relocation forms use signed 32-bit PC-relative
displacements:

If the target is outside that range, finalize_definitions previously panicked
when converting the displacement to i32.

The problem was observed in Nervix while compiling Roto UDFs. The CI run
intermittently failed with both TryFromIntError(NegOverflow) and
TryFromIntError(PosOverflow):

https://github.com/nervix-io/nervix/actions/runs/30129378927/job/89600292950?pr=57#step:17:56674

After adding call veneers, a follow-up run showed that Roto could still fail
while materializing addresses of separately allocated data:

https://github.com/nervix-io/nervix/actions/runs/30147477548/job/89651977365?pr=57

Implementation

Calls and tail jumps

Address materialization

A branch veneer cannot fix an address-producing instruction: it would produce
the address of the veneer rather than the requested symbol.

Instead, before compiling a function in cranelift-jit:

On x86_64, these far address operations use full-width Abs8 relocations and
therefore do not depend on the code and target being within ±2 GiB.

Relocation handling

Testing

The JIT integration tests use a custom memory provider that deterministically
places allocations on opposite sides of a virtual address range larger than
2 GiB.

Call and veneer coverage includes:

Address-materialization coverage includes:

Additional tests verify:

Commands run:

AI-assisted development

Claude Code assisted with the initial call-veneer implementation.

OpenAI Codex assisted with auditing the fix, recovering and evaluating stashed
work, strengthening the tests, implementing the address-materialization fix,
and porting the changes to the current main branch.

All AI-assisted code and text were reviewed by the human contributor, who
understands the changes and accepts full responsibility for the contribution.

view this post on Zulip Wasmtime GitHub notifications bot (Jul 25 2026 at 18:56):

glebpom edited PR #13975:

Summary

Handle JIT functions and data allocated outside x86_64's signed 32-bit PC-relative range.

This change:

Fixes #4000.

Motivation

A JITMemoryProvider may allocate generated code, data objects, and functions independently. It does not guarantee that these allocations will be within ±2 GiB of one another.

Both relevant x86_64 relocation forms use signed 32-bit PC-relative displacements:

If the target is outside that range, finalize_definitions previously panicked when converting the displacement to i32.

The problem was observed in Nervix while compiling Roto UDFs. The CI run intermittently failed with both TryFromIntError(NegOverflow) and TryFromIntError(PosOverflow):

https://github.com/nervix-io/nervix/actions/runs/30129378927/job/89600292950?pr=57#step:17:56674

After adding call veneers, a follow-up run showed that Roto could still fail while materializing addresses of separately allocated data:

https://github.com/nervix-io/nervix/actions/runs/30147477548/job/89651977365?pr=57

Implementation

Calls and tail jumps

Address materialization

A branch veneer cannot fix an address-producing instruction: it would produce the address of the veneer rather than the requested symbol.

Instead, before compiling a function in cranelift-jit:

On x86_64, these far address operations use full-width Abs8 relocations and therefore do not depend on the code and target being within ±2 GiB.

Relocation handling

Testing

The JIT integration tests use a custom memory provider that deterministically places allocations on opposite sides of a virtual address range larger than 2 GiB.

Call and veneer coverage includes:

Address-materialization coverage includes:

Additional tests verify:

Commands run:

AI-assisted development

Claude Code assisted with the initial call-veneer implementation.

OpenAI Codex assisted with auditing the fix, recovering and evaluating stashed work, strengthening the tests, implementing the address-materialization fix, and porting the changes to the current main branch.

All AI-assisted code and text were reviewed by the human contributor, who understands the changes and accepts full responsibility for the contribution.

view this post on Zulip Wasmtime GitHub notifications bot (Jul 25 2026 at 19:03):

glebpom edited PR #13975:

Summary

Handle JIT functions and data allocated outside x86_64's signed 32-bit PC-relative range.

This change:

Fixes #4000.

Motivation

A JITMemoryProvider may allocate generated code, data objects, and functions independently. It does not guarantee that these allocations will be within ±2 GiB of one another.

Both relevant x86_64 relocation forms use signed 32-bit PC-relative displacements:

If the target is outside that range, finalize_definitions previously panicked when converting the displacement to i32.

The problem was observed in Nervix while compiling Roto UDFs. The CI run intermittently failed with both TryFromIntError(NegOverflow) and TryFromIntError(PosOverflow):

https://github.com/nervix-io/nervix/issues/60

After adding call veneers, a follow-up run showed that Roto could still fail while materializing addresses of separately allocated data:

https://github.com/nervix-io/nervix/actions/runs/30147477548/job/89651977365?pr=57

Implementation

Calls and tail jumps

Address materialization

A branch veneer cannot fix an address-producing instruction: it would produce the address of the veneer rather than the requested symbol.

Instead, before compiling a function in cranelift-jit:

On x86_64, these far address operations use full-width Abs8 relocations and therefore do not depend on the code and target being within ±2 GiB.

Relocation handling

Testing

The JIT integration tests use a custom memory provider that deterministically places allocations on opposite sides of a virtual address range larger than 2 GiB.

Call and veneer coverage includes:

Address-materialization coverage includes:

Additional tests verify:

Commands run:

AI-assisted development

Claude Code assisted with the initial call-veneer implementation.

OpenAI Codex assisted with auditing the fix, recovering and evaluating stashed work, strengthening the tests, implementing the address-materialization fix, and porting the changes to the current main branch.

All AI-assisted code and text were reviewed by the human contributor, who understands the changes and accepts full responsibility for the contribution.

view this post on Zulip Wasmtime GitHub notifications bot (Jul 25 2026 at 19:04):

glebpom updated PR #13975.

view this post on Zulip Wasmtime GitHub notifications bot (Jul 25 2026 at 19:05):

glebpom edited PR #13975:

Summary

Handle JIT functions and data allocated outside x86_64's signed 32-bit PC-relative range.

This change:

Fixes #4000.

Motivation

A JITMemoryProvider may allocate generated code, data objects, and functions independently. It does not guarantee that these allocations will be within ±2 GiB of one another.

Both relevant x86_64 relocation forms use signed 32-bit PC-relative displacements:

If the target is outside that range, finalize_definitions previously panicked when converting the displacement to i32.

The problem was observed in Nervix while compiling Roto UDFs. The CI run intermittently failed with both TryFromIntError(NegOverflow) and TryFromIntError(PosOverflow):

https://github.com/nervix-io/nervix/issues/60

After adding call veneers, a follow-up run showed that Roto could still fail while materializing addresses of separately allocated data:

https://github.com/nervix-io/nervix/actions/runs/30147477548/job/89651977365?pr=57

Finally, after backporting 2334e132e2fcca79638d3051887153218dce054f the build succeeded https://github.com/nervix-io/nervix/actions/runs/30169535347/job/89708162970?pr=57

Implementation

Calls and tail jumps

Address materialization

A branch veneer cannot fix an address-producing instruction: it would produce the address of the veneer rather than the requested symbol.

Instead, before compiling a function in cranelift-jit:

On x86_64, these far address operations use full-width Abs8 relocations and therefore do not depend on the code and target being within ±2 GiB.

Relocation handling

Testing

The JIT integration tests use a custom memory provider that deterministically places allocations on opposite sides of a virtual address range larger than 2 GiB.

Call and veneer coverage includes:

Address-materialization coverage includes:

Additional tests verify:

Commands run:

AI-assisted development

Claude Code assisted with the initial call-veneer implementation.

OpenAI Codex assisted with auditing the fix, recovering and evaluating stashed work, strengthening the tests, implementing the address-materialization fix, and porting the changes to the current main branch.

All AI-assisted code and text were reviewed by the human contributor, who understands the changes and accepts full responsibility for the contribution.

view this post on Zulip Wasmtime GitHub notifications bot (Jul 25 2026 at 19:05):

glebpom edited PR #13975:

Summary

Handle JIT functions and data allocated outside x86_64's signed 32-bit PC-relative range.

This change:

Fixes #4000.

Motivation

A JITMemoryProvider may allocate generated code, data objects, and functions independently. It does not guarantee that these allocations will be within ±2 GiB of one another.

Both relevant x86_64 relocation forms use signed 32-bit PC-relative displacements:

If the target is outside that range, finalize_definitions previously panicked when converting the displacement to i32.

The problem was observed in Nervix while compiling Roto UDFs. The CI run intermittently failed with both TryFromIntError(NegOverflow) and TryFromIntError(PosOverflow):

https://github.com/nervix-io/nervix/issues/60

After adding call veneers, a follow-up run showed that Roto could still fail while materializing addresses of separately allocated data:

https://github.com/nervix-io/nervix/actions/runs/30147477548/job/89651977365?pr=57

Finally, after backporting 2334e132e2fcca79638d3051887153218dce054f the build succeeded:

https://github.com/nervix-io/nervix/actions/runs/30169535347/job/89708162970?pr=57

Implementation

Calls and tail jumps

Address materialization

A branch veneer cannot fix an address-producing instruction: it would produce the address of the veneer rather than the requested symbol.

Instead, before compiling a function in cranelift-jit:

On x86_64, these far address operations use full-width Abs8 relocations and therefore do not depend on the code and target being within ±2 GiB.

Relocation handling

Testing

The JIT integration tests use a custom memory provider that deterministically places allocations on opposite sides of a virtual address range larger than 2 GiB.

Call and veneer coverage includes:

Address-materialization coverage includes:

Additional tests verify:

Commands run:

AI-assisted development

Claude Code assisted with the initial call-veneer implementation.

OpenAI Codex assisted with auditing the fix, recovering and evaluating stashed work, strengthening the tests, implementing the address-materialization fix, and porting the changes to the current main branch.

All AI-assisted code and text were reviewed by the human contributor, who understands the changes and accepts full responsibility for the contribution.

view this post on Zulip Wasmtime GitHub notifications bot (Jul 25 2026 at 19:06):

glebpom edited PR #13975:

Summary

Handle JIT functions and data allocated outside x86_64's signed 32-bit PC-relative range.

This change:

Fixes #4000.

Motivation

A JITMemoryProvider may allocate generated code, data objects, and functions independently. It does not guarantee that these allocations will be within ±2 GiB of one another.

Both relevant x86_64 relocation forms use signed 32-bit PC-relative displacements:

If the target is outside that range, finalize_definitions previously panicked when converting the displacement to i32.

The problem was observed in Nervix while compiling Roto UDFs. The CI run intermittently failed with both TryFromIntError(NegOverflow) and TryFromIntError(PosOverflow):

https://github.com/nervix-io/nervix/issues/60

After adding call veneers, a follow-up run showed that Roto could still fail while materializing addresses of separately allocated data:

https://github.com/nervix-io/nervix/actions/runs/30147477548/job/89651977365?pr=57

Finally, after backporting 2334e132e2fcca79638d3051887153218dce054f the build succeeded:

https://github.com/nervix-io/nervix/actions/runs/30169535347/job/89708162970?pr=57

Implementation

Calls and tail jumps

Address materialization

A branch veneer cannot fix an address-producing instruction: it would produce the address of the veneer rather than the requested symbol.

Instead, before compiling a function in cranelift-jit:

On x86_64, these far address operations use full-width Abs8 relocations and therefore do not depend on the code and target being within ±2 GiB.

Relocation handling

Testing

The JIT integration tests use a custom memory provider that deterministically places allocations on opposite sides of a virtual address range larger than 2 GiB.

Call and veneer coverage includes:

Address-materialization coverage includes:

Additional tests verify:

Commands run:

AI-assisted development

Claude Code assisted with the initial call-veneer implementation.

OpenAI Codex assisted with auditing the fix, recovering and evaluating stashed work, strengthening the tests, implementing the address-materialization fix, and porting the changes to the current main branch.

All AI-assisted code and text were reviewed by the human contributor, who understands the changes and accepts full responsibility for the contribution.

view this post on Zulip Wasmtime GitHub notifications bot (Jul 25 2026 at 19:08):

glebpom has marked PR #13975 as ready for review.

view this post on Zulip Wasmtime GitHub notifications bot (Jul 25 2026 at 20:04):

:memo: bjorn3 submitted PR review.

view this post on Zulip Wasmtime GitHub notifications bot (Jul 25 2026 at 20:04):

:speech_balloon: bjorn3 created PR review comment:

This feels like a hack to me. cranelift-jit shouldn't modify the function. A better solution is probably to just add support for PLT relocations and then tell Cranelift to emit PLT relocations.

view this post on Zulip Wasmtime GitHub notifications bot (Jul 25 2026 at 22:14):

glebpom updated PR #13975.

view this post on Zulip Wasmtime GitHub notifications bot (Jul 25 2026 at 22:35):

glebpom edited PR #13975:

Summary

Handle JIT functions and data allocated outside x86_64's signed 32-bit PC-relative range.

This change:

Fixes #4000.

Motivation

A JITMemoryProvider may allocate generated code, data objects, and functions independently. It does not guarantee that these allocations will be within ±2 GiB of one another.

Both relevant x86_64 relocation forms use signed 32-bit PC-relative displacements:

If the target is outside that range, finalize_definitions previously panicked when converting the displacement to i32.

The problem was observed in Nervix while compiling Roto UDFs. The CI run intermittently failed with both TryFromIntError(NegOverflow) and TryFromIntError(PosOverflow):

https://github.com/nervix-io/nervix/actions/runs/30129378927/job/89600292950?pr=57#step:17:56674

After adding call veneers, a follow-up run showed that Roto could still fail while materializing addresses of separately allocated data:

https://github.com/nervix-io/nervix/actions/runs/30147477548/job/89651977365?pr=57

Implementation

The work is organized as two commits.

1. Calls and tail jumps: veneers

Redirecting through a veneer is only sound for control transfers, so X86CallPCRel4 is now reserved for call/jmp displacements and this invariant is documented on the relocation. The RIP-relative lea emitted by LoadExtName for near symbols now uses X86PCRel4 instead; LabelUse::from_reloc and the text-section builder learned to resolve it, and object files now get a PC-relative rather than a branch relocation for the lea, matching its semantics.

2. Symbol addresses: a per-blob GOT

A branch veneer cannot fix an address-producing instruction: it would produce the address of the veneer rather than the requested symbol. Instead, as suggested by @bjorn3 in review, the JIT now uses GOT-based address materialization:

Direct calls are unaffected: they keep their colocated references and use veneers when needed. GOT entries hold the symbol's real address, preserving pointer identity with the finalized definitions.

Testing

The JIT integration tests use a custom memory provider that deterministically places allocations on opposite sides of a virtual address range larger than 2 GiB.

Call and veneer coverage:

Address-materialization coverage:

The test ISA helper now enables is_pic on x86_64, resolving an old FIXME from when the JIT last supported PIC; libcall_function therefore exercises GOT resolution against real host symbols.

Commands run:

Notes

AArch64 direct calls already use veneers, and its non-colocated materialization uses an inline literal, so it works at any distance. Its colocated adrp+add sequence retains a pre-existing ±2 GiB assumption in the Aarch64AdrPrelPgHi21 handler; supporting is_pic with the AArch64 GOT relocations would be the analogous fix and is left as a follow-up.

AI-assisted development

Claude Code assisted with the call-veneer implementation and with the GOT-based address materialization following the review suggestion. OpenAI Codex assisted with auditing the fix, recovering and evaluating stashed work, strengthening the tests, and porting the changes to the current main branch.

All AI-assisted code and text were reviewed by the human contributor, who understands the changes and accepts full responsibility for the contribution.
`


Last updated: Jul 29 2026 at 05:03 UTC