Rustのインラインアセンブリについて
Cのインラインアセンブリ
code:riscv.s
__asm__ __volatile__("ecall"
: "=r"(a0), "=r"(a1) // 出力オペランド
: "r"(a0), "r"(a1), "r"(a2), "r"(a3), "r"(a4), "r"(a5), "r"(a6), "r"(a7) // 入力オペランド
: "memory"); // メモリ領域が変更される
命令、出力オペランド、入力オペランド、破壊されるレジスタの4項目の指定ができる
"ダブルクォートでくくられている部分は「制約」で、rは汎用レジスタ、=は書き込み可能を表す
破壊されるレジスタの部分は、変更が行われる部分をコンパイラに知らせている
コンパイラは必要に応じて、レジスタなどの退避を行うらしい
ここはちゃんと理解していない
Rustのインラインアセンブリ
基本的には、Cのインラインアセンブリと対応している
code:riscv.rs
asm!(
"ecall",
inout("a0") arg0,
inout("a1") arg1,
out("a2") arg2,
out("a3") arg3,
out("a4") arg4,
out("a5") arg5,
out("a6") fid,
out("a7") eid,
);
入力、出力のオペランドについては、たぶん同じ?
inoutは、inとoutで同じレジスタが使われることが保証される。また、mutableである必要がある
outは、mutableでないとコンパイルエラーになった(ドキュメントに「最後に書き込まれる」とあるためか?)
レジスタの指定について
普通に使うレジスタは全部使えそう
ただし、アーキテクチャによって、レジスタに渡せる型に違いがある
riscvだとx10をa0のような、対応している別名(エイリアス?)として使える
破壊されるレジスタについて
nomemのところを見ると、メモリを変更しないことを保証する的なことが書いてあるため、デフォルトではメモリは変更される前提らしい
Cのインラインアセンブリと対応させるときは、ちゃんと調べる必要あり