[Pre-RFC #2]: Inline assembly

Issues that I haven't seen brought up yet:

People have been talking about which registers can be used with this or that instruction, and yeah, that's a mess, but what's often even more of a mess is which immediate operand values can be used with this or that instruction. x86 is actually one of the simpler ISAs in this respect. To get a taste of how messy it can get, look at the definition of a "modified immediate operand" in 32-bit ARM machine language (ARM ARM, page F2-3924): any number that can be created by zero-extending an 8-bit constant to 32 bits and then rotating the 32-bit word right by an even number of bits. (Whether or not this is considered a signed number depends on the instruction. Some instructions take the bitwise NOT of the value before using it, and some instructions take the twos-complement negation before using it. If you're generating Thumb-2 machine instructions instead of traditional ARM instructions, the set of possibilities changes.) Something has to know which constants are allowed; if there's a separate assembler you can punt to it, but it sounds like people want to be able to generate machine code directly.

Symbolic operands are even worse, because the limitations of the linker and the object file format come into play as well:

let mut val = 1u32;
asm!("add {0}, {1}", inout(reg) val, sym GLOBAL_DATA);

Depending on the architecture and the ABI, this probably translates to some kind of fused load-register-indirect-and-add operation,

add eax, dword ptr [rip+0x0] !R_X86_64_PC32(GLOBAL_DATA)

which may or may not be representable depending on how big that immediate displacement field is, what relocation types can be used with it, etc. etc. It may not be possible to know whether the operation is representable until link time. Users probably expect that the toolchain will "fix up" the instruction and make it work regardless, which may involve rewriting the original instruction from load-reg-indirect-and-add to add-reg-reg (and finding a scratch register), inserting specially tagged no-op instructions before this one to give the linker space to rewrite in, etc. etc. etc.

In the previous thread on inline assembly, use cases involving switching between the text section and special data sections (and referring to addresses in the text section from the special data section) came up, e.g. https://github.com/cuviper/rust-libprobe/blob/431ac2999eb88e3a8ba5ee15df13557e234d9775/src/platform/systemtap.rs#L164 I don't see anything in here about that. I'd be fine with an initial implementation that doesn't support those kinds of use cases, but I'd hate to see them get forgotten about.

2 Likes