Skip to main content

Himpunan sebaris

Himpunan sebaris Wave ditulis dengan blok asm { ... }. Ia digunakan untuk kod aras rendah seperti kernel, pemuat but UEFI, panggilan sistem, port I/O dan kawalan CPU.

Sasaran semasa ialah Linux x86_64/aarch64, Darwin x86_64/aarch64, Windows GNU x86_64, dan freestanding x86_64/aarch64/riscv64. Sasaran 32-bit belum disokong.

Bentuk asas

asm {
"instruction"
in("constraint_or_reg") value
out("constraint_or_reg") target
clobber("item")
}

Baris rentetan ialah arahan assembly. in(...) mengisytiharkan input, out(...) output, dan clobber(...) keadaan yang diubah oleh asm.

asm sebagai pernyataan

asm sebagai pernyataan digunakan apabila nilai ekspresi tidak diperlukan. Ia boleh mempunyai beberapa output.

let mut ret: i64 = 0;
asm {
"mov rax, 39"
"syscall"
out("rax") ret
clobber("memory")
clobber("flags")
}

asm sebagai ekspresi

asm sebagai ekspresi menghasilkan nilai dan buat masa ini memerlukan tepat satu out(...). clobber("noreturn") dilarang dalam asm ekspresi.

let mut value: i64 = 0;
value = asm {
"mov rax, 123"
out("rax") value
};

Operand dan kekangan

Operand boleh menggunakan daftar khusus atau kelas kekangan. x86_64 menggunakan rax, rbx, rcx, rdx, r8 ... r15; AArch64 menggunakan x0 ... x30 dan w0 ... w30; RISC-V menggunakan a0, a1, t0, s0, ra, sp, xN. Kelas umum ialah r, m, rm, i, ri, im, irm. Satu daftar fizikal tidak boleh menjadi operand dan clobber serentak.

Kontrak clobber

clobber("memory") bermaksud asm boleh membaca atau menulis memori. clobber("flags") dan clobber("cc") bermaksud flag keadaan diubah. clobber("stack") diperlukan apabila stack atau arahan call/return digunakan. clobber("nostack") menjanjikan stack tidak disentuh. clobber("noreturn") bermaksud kawalan tidak kembali ke blok semasa. stack dan nostack tidak boleh digabungkan.

Disiplin stack

asm biasa tidak patut mengubah stack. call, push, pop, ret, penggunaan terus rsp/esp atau sp, dan arahan seumpamanya memerlukan clobber("stack"). Walaupun begitu, stack pointer mesti dipulihkan sebelum kembali.

asm {
"sub rsp, 8"
"add rsp, 8"
clobber("stack")
}

asm tanpa kembali

Lompatan tidak langsung seperti jmp rax, jmp r11, br x0, atau jr ra memerlukan clobber("noreturn"). asm pernyataan dengan clobber ini menamatkan blok IR dengan unreachable.

fun jump_to_kernel(entry: u64, boot_info: ptr<u8>, stack_top: u64) {
asm {
"mov rsp, rdx"
"and rsp, -16"
"mov rdi, rcx"
"jmp rbx"
in("rbx") entry
in("rcx") boot_info
in("rdx") stack_top
clobber("stack")
clobber("noreturn")
}
}

Label tempatan

Lompatan ke label tempatan kekal dalam laluan asm/control-flow yang sama dan tidak memerlukan noreturn.

asm {
"jmp 1f"
"1:"
}

Sasaran output

Sasaran output stabil ialah pemboleh ubah dan deref pemboleh ubah penunjuk. Untuk field atau array, tulis ke pemboleh ubah sementara dahulu.

out("rax") value
out("rax") deref ptr

Had

inline asm sentiasa dianggap mempunyai side effect. Manipulasi stack yang kompleks masih boleh ditolak. Function pointer dan jenis calling convention eksplisit belum stabil, jadi panggilan perkhidmatan UEFI masih boleh menggunakan asm wrapper buat masa ini.