# How does inline assembly and the physical machine fit into the abstract machine model, or exist outside of it?

**URL:** <https://internals.rust-lang.org/t/how-does-inline-assembly-and-the-physical-machine-fit-into-the-abstract-machine-model-or-exist-outside-of-it/22545>\
**Category:** language design\
**Created:** [March 6, 2025, 5:51pm UTC](https://internals.rust-lang.org/t/how-does-inline-assembly-and-the-physical-machine-fit-into-the-abstract-machine-model-or-exist-outside-of-it/22545 "2025-03-06T17:51:00Z")\
**Posts on this page:** 1\
**Showing post:** 27

<div class="post-metadata">

**Author:** ![RalfJung](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/ralfjung/32/2415_2.png) [@RalfJung](https://internals.rust-lang.org/u/RalfJung)\
**Post date:** [March 19, 2025, 3:16pm UTC](https://internals.rust-lang.org/t/how-does-inline-assembly-and-the-physical-machine-fit-into-the-abstract-machine-model-or-exist-outside-of-it/22545/27 "2025-03-19T15:16:53Z")

</div>

> [@Vorpal](#):
>
> I follow on the write, but why can't it read?

That's literally what @CAD97's example shows. Here's another one:

```rust
fn my_fun(x: &mut i32, f: impl FnOnce()) {
  *x = 0;
  *x = 1;
  f();
  *x = 2;
}

```

When building with `panic=abort`, the compiler is allowed to remove the `*x = 1`. (SB would also let it remove the `*x = 0` but TB might not permit that... let's not have that discussion here okay? 😉 )

But if an inline asm block inside `f` were allowed to even just read from the part of the AM state that `x` points to, then obviously such an optimization would be unsound.

So, to ensure that inline assembly is compatible with optimizations on the rest of the code, and to ensure that code which does not want to use inline asm can be optimized as much as it could if inline asm did not exist, it is crucial that the AM state transition implemented by the inline asm block cannot even _observe_ parts of the AM state that Rust code could not observe here.

To be clear, since that may explain some of the confusion above: It is totally legal to write an inline asm block that stores a `MaybeUninit<i32>` in some register, loads it again, and returns the result as `i32`. However, to justify the legailty of this, you have to declare that the semantics of your block is that it returns some arbitrary non-deterministically-chosen number, and then the rest of the code has to be correct under those semantics. That is obviously not the same semantics as `freeze`, and that is the entire point.

But you cannot at the same time say "this behaves like `freeze`" and "this is allowed to always return garbage". Those two statements just cannot be true at the same time.

> [@newpavlov](#):
>
> Again, my point is that the mistake is not reading the garbage, the mistake is incorrectly assigning some meaning to it.

Exactly. And by saying that this behaves like `freeze`, you are assigning meaning to it, since `freeze` is defined to preserve the original contents if they were already initialized (i.e., it does not always return garbage).

> [@newpavlov](#):
>
> Yes, I know that we currently consider that this function contains UB

As I just sketched, it is possible to consider this function well-defined with the semantics of "reset `*page` to contain arbitrarily non-deterministically-chosen contents (without provenance)". But it is not possible to consider this function well-defined with `freeze` semantics, where existing contents are preserved if they have been already initialized.

> [@newpavlov](#):
>
> provide a concrete example of how it could break in practice

We provided concrete examples of how other inline asm blocks that observe machine state which Rust code cannot observe can break in practice. I think that validates my approach in principle, so now the burden of proof is on whoever wants to introduce exceptions from this principle for particular cases.

I already acknowledged upthread that _specifically for `freeze`_, it is _possible_ that all optimizations remain sound, due to specifically how that state works. But our correctness standards are generally higher than "there exists the possibility of a correctness argument for this code, but nobody has actually been able to come up with a solid argument".

> [@newpavlov](#):
>
> But we deal _only_ with machine state while writing `asm!`.

This is wrong, and that's what we are trying to tell you. 🙂 As long as you are writing Rust code, you are dealing with Rust AM states. If you use `asm!`, you _additionally_ deal with concrete machine states, but never ever can you ignore the AM state when writing anything that passes through the Rust compiler.

The urban myth than inline assembly lets you go down to the concrete machine level and entirely ignore the Abstract Machine is just that, an urban myth. It is fundamentally incompatible with how optimizing compilers work. You can curse the fact that we have optimizing compilers, you can demand a language that is less optimized and thus makes writing inline assembly much easier -- but you cannot have both powerful optimizations and easy inline assembly, that's just a logical impossibility.

---

_[View the full topic](https://internals.rust-lang.org/t/how-does-inline-assembly-and-the-physical-machine-fit-into-the-abstract-machine-model-or-exist-outside-of-it/22545)._
