From 5edb575ba0cca082b8dbfeef511f265e506b8fb6 Mon Sep 17 00:00:00 2001 From: kdnakt Date: Sat, 2 Sep 2023 23:54:02 +0900 Subject: [PATCH 01/35] Translate asm.md --- src/SUMMARY.md | 2 +- src/unsafe/asm.md | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/SUMMARY.md b/src/SUMMARY.md index 013f49dc..d2f2330c 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -443,7 +443,7 @@ - [Inline assembly](unsafe/asm.md) --> - [安全でない操作](unsafe.md) - - [Inline assembly](unsafe/asm.md) + - [インラインアセンブリ](unsafe/asm.md) +# インラインアセンブリ Rust provides support for inline assembly via the `asm!` macro. It can be used to embed handwritten assembly in the assembly output generated by the compiler. From 6a70b0c69f5ba4afc9708e144ea433254d98a6ac Mon Sep 17 00:00:00 2001 From: kdnakt Date: Sun, 3 Sep 2023 16:10:19 +0900 Subject: [PATCH 02/35] Translate untranslated lines in asm.md --- src/unsafe/asm.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/unsafe/asm.md b/src/unsafe/asm.md index 3c72234a..ec23a6f5 100644 --- a/src/unsafe/asm.md +++ b/src/unsafe/asm.md @@ -3,18 +3,34 @@ --> # インラインアセンブリ + +Rustは`asm!`マクロによってインラインアセンブリをサポートしています。 +コンパイラによって生成されるアセンブリに、手書きのアセンブリを埋め込むことができます。 +一般的には必要ありませんが、要求されるパフォーマンスやタイミングを達成するために必要な場合があります。 +カーネルコードのような、低レベルなハードウェアの基本要素にアクセスする場合にも、この機能が必要でしょう。 + +> **注意**: 以下の例はx86/x86-64アセンブリで書かれていますが、他のアーキテクチャもサポートされています。 + +インラインアセンブリは現在以下のアーキテクチャでサポートされています。 +- x86とx86-64 +- ARM +- AArch64 +- RISC-V ## Basic usage From 7d01a9bccd9c72ec6b9773d28a7f49d89073eac4 Mon Sep 17 00:00:00 2001 From: kdnakt Date: Mon, 4 Sep 2023 22:39:07 +0900 Subject: [PATCH 03/35] Translate untranslated lines in asm.md --- src/unsafe/asm.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/unsafe/asm.md b/src/unsafe/asm.md index ec23a6f5..9b7d8da4 100644 --- a/src/unsafe/asm.md +++ b/src/unsafe/asm.md @@ -32,9 +32,15 @@ Inline assembly is currently supported on the following architectures: - AArch64 - RISC-V + +## 基本的な使い方 + +最も単純な例から始めましょう: ```rust # #[cfg(target_arch = "x86_64")] { From 606c8e2a4a6c2811c902cc212afd09bcd4846a1d Mon Sep 17 00:00:00 2001 From: kdnakt Date: Tue, 5 Sep 2023 09:59:54 +0900 Subject: [PATCH 04/35] Translate untranslated lines in asm.md --- src/unsafe/asm.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/unsafe/asm.md b/src/unsafe/asm.md index 9b7d8da4..7453a0de 100644 --- a/src/unsafe/asm.md +++ b/src/unsafe/asm.md @@ -52,10 +52,16 @@ unsafe { # } ``` + +これにより、コンパイラが生成したアセンブリに、NOP (no operation) 命令が挿入されます。 +すべての`asm!`呼び出しは、`unsafe`ブロックの中になければいけません。 +というのも、インラインアセンブリは任意の命令を挿入でき、本来不変のものを変更できてしまうからです。 +挿入される命令は、`asm!`マクロの引数として文字列リテラルとして列挙されます。 ## Inputs and outputs From 72550744661694e9a45d495ac97ade6a2d9db032 Mon Sep 17 00:00:00 2001 From: kdnakt Date: Wed, 6 Sep 2023 00:07:23 +0900 Subject: [PATCH 05/35] Translate untranslated lines in asm.md --- src/unsafe/asm.md | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/unsafe/asm.md b/src/unsafe/asm.md index 7453a0de..e2270750 100644 --- a/src/unsafe/asm.md +++ b/src/unsafe/asm.md @@ -63,10 +63,17 @@ in the first argument of the `asm!` macro as a string literal. というのも、インラインアセンブリは任意の命令を挿入でき、本来不変のものを変更できてしまうからです。 挿入される命令は、`asm!`マクロの引数として文字列リテラルとして列挙されます。 + +## 入力と出力 + +何もしない命令を挿入しても面白くないですよね。 +実際にデータを操作してみましょう: ```rust # #[cfg(target_arch = "x86_64")] { @@ -80,6 +87,7 @@ assert_eq!(x, 5); # } ``` + +`u64`型の変数`x`に`5`の値を書き込んでいます。 +命令を指定するために利用している文字列リテラルが、実はテンプレート文字列になっています。 +これはRustの[フォーマット文字列][format-syntax]と同じルールに従います。 +ですが、テンプレートに挿入される引数が、みなさんがよく知っているものとは少し違っています。 +まず、変数がインラインアセンブリの入力なのか出力なのかを指定する必要があります。 +上記の例では出力となっています。 +`out`と書くことでそれを宣言しています。 +また、アセンブリが変数をどの種類のレジスタに格納するかも指定する必要があります。 +上の例では、`reg`を指定することで任意の汎用レジスタに格納しています。 +コンパイラはテンプレートに挿入すべき適切なレジスタを選び、インラインアセンブリの実行終了後、そのレジスタから変数を読みこみます。 [format-syntax]: https://doc.rust-lang.org/std/fmt/#syntax From 7dd030921aea2de310f466d99be34940c13cd5f2 Mon Sep 17 00:00:00 2001 From: kdnakt Date: Thu, 7 Sep 2023 09:13:29 +0900 Subject: [PATCH 06/35] Translate untranslated lines in asm.md --- src/unsafe/asm.md | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/unsafe/asm.md b/src/unsafe/asm.md index e2270750..168b8368 100644 --- a/src/unsafe/asm.md +++ b/src/unsafe/asm.md @@ -112,7 +112,10 @@ the template and will read the variable from there after the inline assembly fin [format-syntax]: https://doc.rust-lang.org/std/fmt/#syntax + +入力を利用する別の例を見てみましょう: ```rust # #[cfg(target_arch = "x86_64")] { @@ -132,23 +135,44 @@ assert_eq!(o, 8); # } ``` + +この例では、変数`i`の入力に`5`を加え、その結果を変数`o`に書き込んでいます。 +このアセンブリ特有のやり方として、はじめに`i`の値を出力にコピーし、それから`5`を加えています。 + +この例はいくつかのことを示します: + +まず、`asm!`では複数のテンプレート文字列を引数として利用できます。 +それぞれの文字列は、あたかも改行を挟んで結合されたかのように、独立したアセンブリコードとして扱われます。 +このおかげで、アセンブリコードを容易にフォーマットできます。 + +つぎに、入力は`out`ではなく`in`と書くことで宣言されています。 + +そして、他のフォーマット文字列と同じように引数の番号や名前で指定できます。 +インラインアセンブリのテンプレートでは、引数が2回以上利用されることが多いため、これは特に有用です。 +より複雑なインラインアセンブリを書く場合、この機能を使うのが推奨されます。 +可読性が向上し、引数の順序を変えることなく命令を並べ替えることができるからです。 We can further refine the above example to avoid the `mov` instruction: From 6b93194ec3fad0498ff5696db1cfb70af13d929b Mon Sep 17 00:00:00 2001 From: kdnakt Date: Thu, 7 Sep 2023 09:16:49 +0900 Subject: [PATCH 07/35] Translate untranslated lines in asm.md --- src/unsafe/asm.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/unsafe/asm.md b/src/unsafe/asm.md index 168b8368..158c21c8 100644 --- a/src/unsafe/asm.md +++ b/src/unsafe/asm.md @@ -174,7 +174,10 @@ readability, and allows reordering instructions without changing the argument or より複雑なインラインアセンブリを書く場合、この機能を使うのが推奨されます。 可読性が向上し、引数の順序を変えることなく命令を並べ替えることができるからです。 + +上記の例をさらに改善して、`mov`命令を避けることもできます: ```rust # #[cfg(target_arch = "x86_64")] { @@ -188,10 +191,17 @@ assert_eq!(x, 8); # } ``` + +`inout`で入力でもあり出力でもある引数を指定しています。 +こうすることで、入力と出力を個別に指定する場合と違って、入出力が同じレジスタに割り当てられることが保証されます。 + +`inout`の被演算子として、入力と出力それぞれに異なる変数を指定することも可能です: ```rust # #[cfg(target_arch = "x86_64")] { From fc3052fe6291cd09b2fad3575c0d59de55a79653 Mon Sep 17 00:00:00 2001 From: kdnakt Date: Fri, 8 Sep 2023 17:50:21 +0900 Subject: [PATCH 08/35] Translate untranslated lines in asm.md --- src/unsafe/asm.md | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/unsafe/asm.md b/src/unsafe/asm.md index 158c21c8..19676f16 100644 --- a/src/unsafe/asm.md +++ b/src/unsafe/asm.md @@ -201,7 +201,7 @@ This is different from specifying an input and output separately in that it is g -`inout`の被演算子として、入力と出力それぞれに異なる変数を指定することも可能です: +`inout`のオペランドとして、入力と出力それぞれに異なる変数を指定することも可能です: ```rust # #[cfg(target_arch = "x86_64")] { @@ -216,8 +216,12 @@ assert_eq!(y, 8); # } ``` + +## 遅延出力オペランド + +Rustコンパイラはオペランドの割り当てに保守的です。 +`out`はいつでも書き込めるので、他の引数とは場所を共有できません。 +しかし、最適なパフォーマンスを保証するためには、できるだけ少ないレジスタを使うことが重要です。 +そうすることで、インラインアセンブリブロックの前後でレジスタを保存したり再読み込みしたりする必要がありません。 +これを達成するために、Rustは`lateout`指定子を提供します。 +全ての入力が消費された後でのみ書き込まれる出力に利用できます。 +この指定子には`inlateout`という変化形もあります。 Here is an example where `inlateout` *cannot* be used in `release` mode or other optimized cases: From cf53178ee9ba0cd6ae84efbfd2a08ed1d7c24db7 Mon Sep 17 00:00:00 2001 From: kdnakt Date: Sat, 9 Sep 2023 13:36:27 +0900 Subject: [PATCH 09/35] Translate untranslated lines in asm.md --- src/unsafe/asm.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/unsafe/asm.md b/src/unsafe/asm.md index 19676f16..26f83fe5 100644 --- a/src/unsafe/asm.md +++ b/src/unsafe/asm.md @@ -238,7 +238,10 @@ Rustコンパイラはオペランドの割り当てに保守的です。 全ての入力が消費された後でのみ書き込まれる出力に利用できます。 この指定子には`inlateout`という変化形もあります。 + +以下は、`release`モードやその他の最適化された場合に、`inout`を利用 *できない* 例です: ```rust # #[cfg(target_arch = "x86_64")] { @@ -259,9 +262,20 @@ unsafe { assert_eq!(a, 12); # } ``` + +上記は`Debug`モードなど最適化されていない場合にはうまく動作します。 +しかし、`release`モードなど最適化されたパフォーマンスが必要な場合、動作しない可能性があります。 + +というのも、最適化されている場合、コンパイラは`b`と`c`が同じ値だと知っているので、 +`b`と`c`の入力に同じレジスタを割り当てる場合があるのです。 +しかし、`a`については`inlateout`ではなく`inout`を使っているので、独立したレジスタを割り当てる必要があります。 +もし`inlateout`が使われていたら、`a`と`c`に同じレジスタが割り当てられたかもしれません。 +そうすると、最初の命令によって`c`の値が上書きされ、アセンブリコードが間違った結果を引き起こします。 However the following example can use `inlateout` since the output is only modified after all input registers have been read: From 4a5a2d05579f657fc6438276a7494d007f86452c Mon Sep 17 00:00:00 2001 From: kdnakt Date: Sun, 10 Sep 2023 01:30:45 +0900 Subject: [PATCH 10/35] Translate untranslated lines in asm.md --- src/unsafe/asm.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/unsafe/asm.md b/src/unsafe/asm.md index 26f83fe5..1ff5848c 100644 --- a/src/unsafe/asm.md +++ b/src/unsafe/asm.md @@ -277,7 +277,10 @@ That is because in optimized cases, the compiler is free to allocate the same re もし`inlateout`が使われていたら、`a`と`c`に同じレジスタが割り当てられたかもしれません。 そうすると、最初の命令によって`c`の値が上書きされ、アセンブリコードが間違った結果を引き起こします。 + +しかし、次の例では、全ての入力レジスタが読み込まれた後でのみ出力が変更されるので、`inlateout`を利用できます。 ```rust # #[cfg(target_arch = "x86_64")] { @@ -292,7 +295,10 @@ assert_eq!(a, 8); # } ``` + +このアセンブリコードは、`a`と`b`が同じレジスタに割り当てられても、正しく動作します。 ## Explicit register operands From 14b4a2301207b85b8769e6c0abc16244faa7d3ca Mon Sep 17 00:00:00 2001 From: kdnakt Date: Sun, 10 Sep 2023 14:30:06 +0900 Subject: [PATCH 11/35] Translate untranslated lines in asm.md --- src/unsafe/asm.md | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/unsafe/asm.md b/src/unsafe/asm.md index 1ff5848c..56463614 100644 --- a/src/unsafe/asm.md +++ b/src/unsafe/asm.md @@ -300,11 +300,20 @@ As you can see, this assembly fragment will still work correctly if `a` and `b` --> このアセンブリコードは、`a`と`b`が同じレジスタに割り当てられても、正しく動作します。 + +## 明示的なレジスタオペランド + +いくつかの命令では、オペランドが特定のレジスタにある必要があります。 +したがって、Rustのインラインアセンブリでは、より具体的な制約指定子を提供しています。 +`reg`は一般的にどのアーキテクチャでも利用可能ですが、明示的レジスタはアーキテクチャに強く依存しています。 +たとえば、x86の汎用レジスタである`eax`、`ebx`、`ecx`、`edx`、`ebp`、`esi`、`edi`などは、その名前で指定できます。 ```rust,no_run # #[cfg(target_arch = "x86_64")] { @@ -317,9 +326,19 @@ unsafe { # } ``` + +この例では、`out`命令を呼び出して、`cmd`変数の中身を`0x64`ポートに出力しています。 +`out`命令は`eax`とそのサブレジスタのみをオペランドとして受け取るため、 +`eax`の制約指定子を使わなければなりません。 + +> **注意**: 他のオペランドタイプと異なり、明示的なレジスタオペランドはテンプレート文字列中で利用できません。 +`{}`を使えないので、レジスタの名前を直接書く必要があります。 +また、オペランドのリストの中で他のオペランドタイプの一番最後に置かれなくてはなりません。 Consider this example which uses the x86 `mul` instruction: From 3eb695137a0677e0afdda70a866c406fe7d081cd Mon Sep 17 00:00:00 2001 From: kdnakt Date: Tue, 12 Sep 2023 01:10:59 +0900 Subject: [PATCH 12/35] Translate untranslated lines in asm.md --- src/unsafe/asm.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/unsafe/asm.md b/src/unsafe/asm.md index 56463614..17b2ecd5 100644 --- a/src/unsafe/asm.md +++ b/src/unsafe/asm.md @@ -340,7 +340,10 @@ In this example we call the `out` instruction to output the content of the `cmd` `{}`を使えないので、レジスタの名前を直接書く必要があります。 また、オペランドのリストの中で他のオペランドタイプの一番最後に置かれなくてはなりません。 + +x86の`mul`命令を使った次の例を考えてみましょう: ```rust # #[cfg(target_arch = "x86_64")] { @@ -354,6 +357,8 @@ fn mul(a: u64, b: u64) -> u128 { asm!( // The x86 mul instruction takes rax as an implicit input and writes // the 128-bit result of the multiplication to rax:rdx. + // x86のmul命令はraxを暗黙的な入力に取り、 + // 128ビットの乗算結果をrax:rdxに書き込む。 "mul {}", in(reg) a, inlateout("rax") b => lo, @@ -366,11 +371,18 @@ fn mul(a: u64, b: u64) -> u128 { # } ``` + +`mul`命令を使って2つの64ビットの入力を128ビットの結果に出力する。 +唯一の明示的なオペランドはレジスタで、変数`a`から入力します。 +2つ目のオペランドは暗黙的であり、`rax`レジスタである必要があります。変数`b`から入力します。 +計算結果の下位64ビットは`rax`レジスタに保存され、そこから変数`lo`に出力されます。 +上位64ビットは`rdx`レジスタに保存され、そこから変数`hi`に出力されます。 ## Clobbered registers From 30d11287512a071451f5672e7ba3152ecd61c041 Mon Sep 17 00:00:00 2001 From: kdnakt Date: Thu, 14 Sep 2023 23:33:19 +0900 Subject: [PATCH 13/35] Translate untranslated lines in asm.md --- src/unsafe/asm.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/unsafe/asm.md b/src/unsafe/asm.md index 17b2ecd5..3a6ad123 100644 --- a/src/unsafe/asm.md +++ b/src/unsafe/asm.md @@ -384,12 +384,24 @@ The higher 64 bits are stored in `rdx` from which we fill the variable `hi`. 計算結果の下位64ビットは`rax`レジスタに保存され、そこから変数`lo`に出力されます。 上位64ビットは`rdx`レジスタに保存され、そこから変数`hi`に出力されます。 + +## 上書きされたレジスタ + +多くの場合、インラインレジスタは出力として必要のない状態を変更することがあります。 +これは普通、アセンブリでスクラッチレジスタを利用する必要があったり、 +私たちがこれ以上必要としていない状態を命令が変更したりするためです。 +これを一般的に「上書き」された状態と呼びます。 +私たちはコンパイラにこのことを伝える必要があります。 +なぜならコンパイラは、インラインアセンブリブロックの前後で、 +この状態を保存して復元しなくてはならない可能性があるからです。 ```rust use std::arch::asm; From 726775d49fed197a38823af9a50fc3016eff7c46 Mon Sep 17 00:00:00 2001 From: kdnakt Date: Sat, 16 Sep 2023 23:49:58 +0900 Subject: [PATCH 14/35] Translate untranslated lines in asm.md --- src/unsafe/asm.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/unsafe/asm.md b/src/unsafe/asm.md index 3a6ad123..7ad22350 100644 --- a/src/unsafe/asm.md +++ b/src/unsafe/asm.md @@ -409,11 +409,16 @@ use std::arch::asm; # #[cfg(target_arch = "x86_64")] fn main() { // three entries of four bytes each + // 4バイトのエントリー3つ let mut name_buf = [0_u8; 12]; // String is stored as ascii in ebx, edx, ecx in order // Because ebx is reserved, the asm needs to preserve the value of it. // So we push and pop it around the main asm. // (in 64 bit mode for 64 bit processors, 32 bit processors would use ebx) + // 文字列はasciiとしてebx, edx, ecxの順に保存されている。 + // ebxは予約されているので、アセンブリはebxの値を維持する必要がある。 + // 従ってメインのアセンブリの前後でプッシュおよびポップを行う。 + // (以下は64ビットプロセッサの64ビットモードの場合。32ビットプロセッサはebxを利用する。) unsafe { asm!( @@ -428,10 +433,17 @@ fn main() { // This is more explicit with how the asm works however, as opposed // to explicit register outputs such as `out("ecx") val` // The *pointer itself* is only an input even though it's written behind + // いくつかのアセンブリ命令を追加してRustのコードを単純化するために + // 値を格納する配列へのポインタを利用する。 + // しかし、`out("ecx") val`のような明示的なレジスタの出力とは違い、 + // アセンブリの動作をより明示的にする。 + // *ポインタそのもの* は後ろに書かれていても入力にすぎない。 in("rdi") name_buf.as_mut_ptr(), // select cpuid 0, also specify eax as clobbered + // cpuid 0を選択し、eaxを上書きする inout("eax") 0 => _, // cpuid clobbers these registers too + // cpuidは以下のレジスタも上書きする out("ecx") _, out("edx") _, ); From 5ecd55076e828aead468ea49f7cacff6d36ea25e Mon Sep 17 00:00:00 2001 From: kdnakt Date: Sun, 17 Sep 2023 00:44:45 +0900 Subject: [PATCH 15/35] Translate untranslated lines in asm.md --- src/unsafe/asm.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/unsafe/asm.md b/src/unsafe/asm.md index 7ad22350..d170c813 100644 --- a/src/unsafe/asm.md +++ b/src/unsafe/asm.md @@ -457,10 +457,21 @@ fn main() { # fn main() {} ``` + +上の例では、`cpuid`命令を使い、CPUベンタIDを読み込んでいます。 +この命令は`eax`にサポートされている最大の`cpuid`引数を書き込み、 +`ebx`、`edx`、`ecx`の順にCPUベンダIDをASCIIコードとして書き込みます。 + +`eax`は読み込まれることはありません。 +しかし、コンパイラがアセンブリ以前にこれらのレジスタにあった値を保存できるように、 +レジスタが変更されたことをコンパイラに伝える必要があります。 +そのために、変数名の代わりに`_`を用いて出力を宣言し、出力の値が破棄されるということを示しています。 This code also works around the limitation that `ebx` is a reserved register by LLVM. That means that LLVM assumes that it has full control over the register and it must be restored to its original state before exiting the asm block, so it cannot be used as an input or output **except** if the compiler uses it to fulfill a general register class (e.g. `in(reg)`). This makes `reg` operands dangerous when using reserved registers as we could unknowingly corrupt our input or output because they share the same register. From c7665ddac878ece3c7af7e621eed04e1b5ad20d0 Mon Sep 17 00:00:00 2001 From: kdnakt Date: Mon, 18 Sep 2023 10:04:56 +0900 Subject: [PATCH 16/35] Translate untranslated lines in asm.md --- src/unsafe/asm.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/unsafe/asm.md b/src/unsafe/asm.md index d170c813..18f58802 100644 --- a/src/unsafe/asm.md +++ b/src/unsafe/asm.md @@ -473,9 +473,20 @@ Even though `eax` is never read we still need to tell the compiler that the regi レジスタが変更されたことをコンパイラに伝える必要があります。 そのために、変数名の代わりに`_`を用いて出力を宣言し、出力の値が破棄されるということを示しています。 + +このコードは`ebx`がLLVMによって予約されたレジスタであるという制約を回避しています。 +LLVMは、自身がレジスタを完全にコントロールし、 +アセンブリブロックを抜ける前に元の状態を復元しなくてはならないと考えています。 +そのため、コンパイラが`in(reg)`のような汎用レジスタクラスを満たすために使用する場合 **を除いて** `ebx`を入力や出力として利用できません。 + +これを回避するために、`rdi`を用いて出力の配列へのポインタを保管し、`push`で`ebx`を保存し、アセンブリブロック内で`ebx`から読み込んで配列に書き込み、`pop`で`ebx`を元の状態に戻しています。 +`push`と`pop`は完全な64ビットの`rbx`レジスタを使って、レジスタ全体を確実に保存しています。 +32ビットの場合、`push`と`pop`において`ebx`がかわりに利用されるでしょう。 This can also be used with a general register class to obtain a scratch register for use inside the asm code: From aae9da03df7a193d89d8afae5dfe344092281153 Mon Sep 17 00:00:00 2001 From: kdnakt Date: Tue, 19 Sep 2023 08:35:12 +0900 Subject: [PATCH 17/35] Translate untranslated lines in asm.md --- src/unsafe/asm.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/unsafe/asm.md b/src/unsafe/asm.md index 18f58802..ccf8e611 100644 --- a/src/unsafe/asm.md +++ b/src/unsafe/asm.md @@ -488,13 +488,18 @@ To work around this we use `rdi` to store the pointer to the output array, save `push`と`pop`は完全な64ビットの`rbx`レジスタを使って、レジスタ全体を確実に保存しています。 32ビットの場合、`push`と`pop`において`ebx`がかわりに利用されるでしょう。 + +アセンブリコード内部で利用するスクラッチレジスタを獲得するために、 +汎用レジスタクラスとともに使用することもできます: ```rust # #[cfg(target_arch = "x86_64")] { use std::arch::asm; // Multiply x by 6 using shifts and adds +// シフト演算と加算を利用してxに6をかける let mut x: u64 = 4; unsafe { asm!( From ba44d8ecf5c6a1ff56a3fab6894272094cfbcc40 Mon Sep 17 00:00:00 2001 From: kdnakt Date: Fri, 22 Sep 2023 02:26:08 +0900 Subject: [PATCH 18/35] Translate untranslated lines in asm.md --- src/unsafe/asm.md | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/src/unsafe/asm.md b/src/unsafe/asm.md index ccf8e611..93bd882e 100644 --- a/src/unsafe/asm.md +++ b/src/unsafe/asm.md @@ -387,7 +387,7 @@ The higher 64 bits are stored in `rdx` from which we fill the variable `hi`. -## 上書きされたレジスタ +## クロバーレジスタ +## シンボル・オペランドとABIクロバー + +デフォルトでは、`asm!`は、出力として指定されていないレジスタはアセンブリコードによって保存される、と考えます。 +`asm!`に渡される[`clobber_abi`]引数は、与えられた呼び出し規約のABIに従って、 +必要なクロバーオペランドを自動的に挿入するようコンパイラに伝えます。 +そのABIで完全に保存されていないレジスタは、クロバーとして扱われます。 +複数の `clobber_abi` 引数を指定すると、指定されたすべてのABIのクロバーが挿入されます。 [`clobber_abi`]: ../../reference/inline-assembly.html#abi-clobbers @@ -536,13 +546,17 @@ fn call_foo(arg: i32) -> i32 { asm!( "call {}", // Function pointer to call + // 呼び出す関数ポインタ in(reg) foo, // 1st argument in rdi + // 最初の引数はrdiにある in("rdi") arg, // Return value in rax + // 戻り値はraxにある out("rax") result, // Mark all registers which are not preserved by the "C" calling // convention as clobbered. + // "C"の呼び出し規約で保存されていないすべてのレジスタをクロバーに指定 clobber_abi("C"), ); result From 49800633efae31046d8eaf48e923ae3485b5bc45 Mon Sep 17 00:00:00 2001 From: kdnakt Date: Sat, 23 Sep 2023 08:50:12 +0900 Subject: [PATCH 19/35] Translate untranslated lines in asm.md --- src/unsafe/asm.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/unsafe/asm.md b/src/unsafe/asm.md index 93bd882e..24d7b52e 100644 --- a/src/unsafe/asm.md +++ b/src/unsafe/asm.md @@ -565,13 +565,27 @@ fn call_foo(arg: i32) -> i32 { # } ``` + +レジスタテンプレート修飾子 + +テンプレート文字列に挿入されるレジスタの名前のフォーマット方法について、細かい制御が必要な場合があります。 +アーキテクチャのアセンブリ言語が、同じレジスタに別名を持っている場合です。 +典型的な例としては、レジスタの部分集合に対する"ビュー"があります(例:64ビットレジスタの下位32ビット)。 + +デフォルトでは、コンパイラは常に完全なレジスタサイズの名前を選択します(例:x86-64では`rax`、x86では`eax`、など)。 + +この挙動は、フォーマット文字列と同じように、テンプレート文字列のオペランドに修飾子を利用することで上書きできます。 ```rust # #[cfg(target_arch = "x86_64")] { From abe45f678eb1fdf9bae8c5383d2723139f5e851c Mon Sep 17 00:00:00 2001 From: kdnakt Date: Sun, 24 Sep 2023 14:22:40 +0900 Subject: [PATCH 20/35] Translate untranslated lines in asm.md --- src/unsafe/asm.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/unsafe/asm.md b/src/unsafe/asm.md index 24d7b52e..e0525ad6 100644 --- a/src/unsafe/asm.md +++ b/src/unsafe/asm.md @@ -601,12 +601,24 @@ assert_eq!(x, 0xabab); # } ``` + +この例では、`reg_abcd`レジスタクラスを用いて、レジスタアロケータを4つのレガシーなx86レジスタ (`ax`, `bx`, `cx`, `dx`) に制限しています。このうち最初の2バイトは独立して指定できます。 + +レジスタアロケータが`x`を`ax`レジスタに割り当てることにしたと仮定しましょう。 +`h`修飾子はそのレジスタの上位バイトのレジスタ名を出力し、`l`修飾子は下位バイトのレジスタ名を出力します。 +したがって、このアセンブリコードは`mov ah, al`に展開され、値の下位バイトを上位バイトにコピーします。 + +より小さなデータ型(例:`u16`)をオペランドに利用し、テンプレート修飾子を使い忘れた場合、 +コンパイラは警告を出力し、正しい修飾子を提案してくれます。 ## Memory address operands From 53790a3e24414933b19f24fd7201545f01cb57e8 Mon Sep 17 00:00:00 2001 From: kdnakt Date: Mon, 25 Sep 2023 13:32:10 +0900 Subject: [PATCH 21/35] Translate untranslated lines in asm.md --- src/unsafe/asm.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/unsafe/asm.md b/src/unsafe/asm.md index e0525ad6..bc3d7e42 100644 --- a/src/unsafe/asm.md +++ b/src/unsafe/asm.md @@ -620,11 +620,19 @@ If you use a smaller data type (e.g. `u16`) with an operand and forget to use te より小さなデータ型(例:`u16`)をオペランドに利用し、テンプレート修飾子を使い忘れた場合、 コンパイラは警告を出力し、正しい修飾子を提案してくれます。 + +## メモリアドレスオペランド + +アセンブリ命令はオペランドがメモリアドレスやメモリロケーション経由で渡される必要なこともあります。 +そのときは手動で、ターゲットのアーキテクチャによって指定されたメモリアドレスのシンタックスを利用しなくてはなりません。 +例えば、Intelのアセンブリシンタックスを使うx86/x86_64の場合、入出力を`[]`で囲んで、メモリオペランドであることを示さなくてはなりません。 ```rust # #[cfg(target_arch = "x86_64")] { From 799d22ffc305057862bec2dae57e201a540aaaa9 Mon Sep 17 00:00:00 2001 From: kdnakt Date: Tue, 26 Sep 2023 08:23:12 +0900 Subject: [PATCH 22/35] Translate untranslated lines in asm.md --- src/unsafe/asm.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/unsafe/asm.md b/src/unsafe/asm.md index bc3d7e42..795281fd 100644 --- a/src/unsafe/asm.md +++ b/src/unsafe/asm.md @@ -646,13 +646,25 @@ fn load_fpu_control_word(control: u16) { # } ``` + +## ラベル + +名前つきラベルの再利用は、ローカルかそうでないかに関わらず、アセンブラやリンカのエラーを引き起こしたり、変な挙動の原因となります。 +名前つきラベルの再利用は以下のようなケースがあります: + +- 明示的再利用: 同じラベルを1つの`asm!`ブロック中で、または複数のブロック中で2回以上利用する場合です。 +- インライン化による暗黙の再利用: コンパイラは`asm!`ブロックの複数のコピーをインスタンス化する場合があります。例えば、`asm!`ブロックを含む関数が複数箇所でインライン化される場合です。 +- LTO(訳注: Link Time Optimizationの略)による暗黙の再利用: LTOは *他のクレート* のコードを同じコード生成単位に配置するため、同じ名前のラベルを持ち込む場合があります。 As a consequence, you should only use GNU assembler **numeric** [local labels] inside inline assembly code. Defining symbols in assembly code may lead to assembler and/or linker errors due to duplicate symbol definitions. From 942d8bbd816c9d73bb9fc2d641e174b9cd706dfc Mon Sep 17 00:00:00 2001 From: kdnakt Date: Wed, 27 Sep 2023 09:54:53 +0900 Subject: [PATCH 23/35] Translate untranslated lines in asm.md --- src/unsafe/asm.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/unsafe/asm.md b/src/unsafe/asm.md index 795281fd..55309894 100644 --- a/src/unsafe/asm.md +++ b/src/unsafe/asm.md @@ -666,9 +666,20 @@ Any reuse of a named label, local or otherwise, can result in an assembler or li - インライン化による暗黙の再利用: コンパイラは`asm!`ブロックの複数のコピーをインスタンス化する場合があります。例えば、`asm!`ブロックを含む関数が複数箇所でインライン化される場合です。 - LTO(訳注: Link Time Optimizationの略)による暗黙の再利用: LTOは *他のクレート* のコードを同じコード生成単位に配置するため、同じ名前のラベルを持ち込む場合があります。 + +そのため、インラインアセンブリコードの中では、GNUアセンブラの **数値型** [ローカルラベル][local labels]のみ使用してください。 +アセンブリコード内でシンボルを定義すると、シンボル定義の重複により、アセンブラやリンカのエラーが発生する可能性があります。 + +さらに、x86でデフォルトのIntel構文を使用する場合、[LLVMのバグ][an LLVM bug]によって、 +`0`、`11`、`101010`といった`0`と`1`だけで構成されたラベルは、 +バイナリ値として解釈されてしまうため、使用してはいけません。 +`options(att_syntax)`を使うと曖昧さを避けられますが、`asm!`ブロック _全体_ の構文に影響します。 +(`options`については、後述の[オプション](#options)を参照してください。) ```rust # #[cfg(target_arch = "x86_64")] { From 9de6d3465b2788cd21083cab1ff2efd185e83daf Mon Sep 17 00:00:00 2001 From: kdnakt Date: Sat, 30 Sep 2023 00:18:32 +0900 Subject: [PATCH 24/35] Translate untranslated lines in asm.md --- src/unsafe/asm.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/unsafe/asm.md b/src/unsafe/asm.md index 55309894..ef67a901 100644 --- a/src/unsafe/asm.md +++ b/src/unsafe/asm.md @@ -703,12 +703,22 @@ assert_eq!(a, 5); # } ``` + +このコードは、`{0}`のレジスタの値を10から3にデクリメントし、2を加え、`a`にその値を保存します。 + +この例は、以下のことを示しています: + +- まず、ラベルとして同じ数字を複数回、同じインラインブロックで利用できます。 +- つぎに、数字のラベルが参照として(例えば、命令のオペランドに)利用された場合、"b"("後方")や"f"("前方")の接尾辞が数字のラベルに追加されなくてはなりません。そうすることで、この数字の指定された方向の最も近いラベルを参照できます。 [local labels]: https://sourceware.org/binutils/docs/as/Symbol-Names.html#Local-Labels [an LLVM bug]: https://bugs.llvm.org/show_bug.cgi?id=36144 From 2d853071d44633dd931965165cd5c7393d3907e4 Mon Sep 17 00:00:00 2001 From: kdnakt Date: Sat, 30 Sep 2023 09:35:24 +0900 Subject: [PATCH 25/35] Translate untranslated lines in asm.md --- src/unsafe/asm.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/unsafe/asm.md b/src/unsafe/asm.md index ef67a901..9654673c 100644 --- a/src/unsafe/asm.md +++ b/src/unsafe/asm.md @@ -723,11 +723,21 @@ This example shows a few things: [local labels]: https://sourceware.org/binutils/docs/as/Symbol-Names.html#Local-Labels [an LLVM bug]: https://bugs.llvm.org/show_bug.cgi?id=36144 + +## オプション + +デフォルトでは、インラインアセンブリブロックは、カスタム呼び出し規約をもつ外部のFFI関数呼び出しと同じように扱われます: メモリを読み込んだり書き込んだり、観測可能な副作用を持っていたりするかもしれません。 +しかし、多くの場合、アセンブリコードが実際に何をするかという情報を多く与えて、より最適化できる方が望ましいでしょう。 + +先ほどの`add`命令の例を見てみましょう: ```rust # #[cfg(target_arch = "x86_64")] { From bc55f948b19904336194fd82456b8175a7c13069 Mon Sep 17 00:00:00 2001 From: kdnakt Date: Sat, 30 Sep 2023 10:21:21 +0900 Subject: [PATCH 26/35] Translate untranslated lines in asm.md --- src/unsafe/asm.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/unsafe/asm.md b/src/unsafe/asm.md index 9654673c..9d884ff7 100644 --- a/src/unsafe/asm.md +++ b/src/unsafe/asm.md @@ -756,11 +756,24 @@ assert_eq!(a, 8); # } ``` + +オプションは`asm!`マクロの最後の任意引数として渡されます。 +ここでは3つのオプションを利用しました: +- `pure`は、アセンブリコードが観測可能な副作用を持っておらず、出力は入力のみに依存することを意味します。これにより、コンパイラオプティマイザはインラインアセンブリの呼び出し回数を減らしたり、インラインアセンブリを完全に削除したりできます。 +- `nomem`は、アセンブリコードがメモリの読み書きをしないことを意味します。デフォルトでは、インラインアセンブリはアクセス可能なメモリアドレス(例えばオペランドとして渡されたポインタや、グローバルなど)の読み書きを行うとコンパイラは仮定しています。 +- `nostack`は、アセンブリコードがスタックにデータをプッシュしないことを意味します。これにより、コンパイラはx86-64のスタックレッドゾーンなどの最適化を利用し、スタックポインタの調整を避けることができます。 + +これにより、コンパイラは、出力が全く必要とされていない純粋な`asm!`ブロックを削除するなどして、`asm!`を使ったコードをより最適化できます。 + +利用可能なオプションとその効果の一覧は[リファレンス](https://doc.rust-lang.org/stable/reference/inline-assembly.html)を参照してください。 From b1a030bbcd4b132427c187cc77a7ac4968ee6970 Mon Sep 17 00:00:00 2001 From: kdnakt Date: Tue, 3 Oct 2023 10:22:19 +0900 Subject: [PATCH 27/35] fix markdown --- src/unsafe/asm.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/unsafe/asm.md b/src/unsafe/asm.md index 9d884ff7..189bf7fc 100644 --- a/src/unsafe/asm.md +++ b/src/unsafe/asm.md @@ -568,7 +568,7 @@ fn call_foo(arg: i32) -> i32 { -レジスタテンプレート修飾子 +## レジスタテンプレート修飾子 -最も単純な例から始めましょう: +最も単純な例から始めましょう。 ```rust # #[cfg(target_arch = "x86_64")] { @@ -72,8 +72,8 @@ in the first argument of the `asm!` macro as a string literal. Now inserting an instruction that does nothing is rather boring. Let us do something that actually acts on data: --> -何もしない命令を挿入しても面白くないですよね。 -実際にデータを操作してみましょう: +何もしない命令を挿入しても面白くありません。 +実際にデータを操作してみましょう。 ```rust # #[cfg(target_arch = "x86_64")] { @@ -115,7 +115,7 @@ the template and will read the variable from there after the inline assembly fin -入力を利用する別の例を見てみましょう: +入力を利用する別の例を見てみましょう。 ```rust # #[cfg(target_arch = "x86_64")] { @@ -146,7 +146,7 @@ and then adding `5` to it. -この例はいくつかのことを示します: +この例はいくつかのことを示します。 -上記の例をさらに改善して、`mov`命令を避けることもできます: +上記の例をさらに改善して、`mov`命令を避けることもできます。 ```rust # #[cfg(target_arch = "x86_64")] { @@ -201,7 +201,7 @@ This is different from specifying an input and output separately in that it is g -`inout`のオペランドとして、入力と出力それぞれに異なる変数を指定することも可能です: +`inout`のオペランドとして、入力と出力それぞれに異なる変数を指定することも可能です。 ```rust # #[cfg(target_arch = "x86_64")] { @@ -241,7 +241,7 @@ Rustコンパイラはオペランドの割り当てに保守的です。 -以下は、`release`モードやその他の最適化された場合に、`inout`を利用 *できない* 例です: +以下は、`release`モードやその他の最適化された場合に、`inout`を利用 *できない* 例です。 ```rust # #[cfg(target_arch = "x86_64")] { @@ -343,7 +343,7 @@ In this example we call the `out` instruction to output the content of the `cmd` -x86の`mul`命令を使った次の例を考えてみましょう: +x86の`mul`命令を使った次の例を考えてみましょう。 ```rust # #[cfg(target_arch = "x86_64")] { @@ -492,7 +492,7 @@ To work around this we use `rdi` to store the pointer to the output array, save This can also be used with a general register class to obtain a scratch register for use inside the asm code: --> アセンブリコード内部で利用するスクラッチレジスタを獲得するために、 -汎用レジスタクラスとともに使用することもできます: +汎用レジスタクラスとともに使用することもできます。 ```rust # #[cfg(target_arch = "x86_64")] { @@ -655,7 +655,7 @@ fn load_fpu_control_word(control: u16) { Any reuse of a named label, local or otherwise, can result in an assembler or linker error or may cause other strange behavior. Reuse of a named label can happen in a variety of ways including: --> 名前つきラベルの再利用は、ローカルかそうでないかに関わらず、アセンブラやリンカのエラーを引き起こしたり、変な挙動の原因となります。 -名前つきラベルの再利用は以下のようなケースがあります: +名前つきラベルの再利用は以下のようなケースがあります。 -この例は、以下のことを示しています: +この例は、以下のことを示しています。 -先ほどの`add`命令の例を見てみましょう: +先ほどの`add`命令の例を見てみましょう。 ```rust # #[cfg(target_arch = "x86_64")] { From 0c7214258610294a15b7e31228a3bdb51c4aa239 Mon Sep 17 00:00:00 2001 From: kdnakt Date: Sat, 7 Oct 2023 13:36:33 +0900 Subject: [PATCH 29/35] fix translation --- src/unsafe/asm.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/unsafe/asm.md b/src/unsafe/asm.md index 1d2bb5cb..d0d006e2 100644 --- a/src/unsafe/asm.md +++ b/src/unsafe/asm.md @@ -10,7 +10,7 @@ Generally this should not be necessary, but might be where the required performa cannot be otherwise achieved. Accessing low level hardware primitives, e.g. in kernel code, may also demand this functionality. --> Rustは`asm!`マクロによってインラインアセンブリをサポートしています。 -コンパイラによって生成されるアセンブリに、手書きのアセンブリを埋め込むことができます。 +コンパイラが生成するアセンブリに、手書きのアセンブリを埋め込むことができます。 一般的には必要ありませんが、要求されるパフォーマンスやタイミングを達成するために必要な場合があります。 カーネルコードのような、低レベルなハードウェアの基本要素にアクセスする場合にも、この機能が必要でしょう。 @@ -58,10 +58,10 @@ Note that all `asm!` invocations have to be inside an `unsafe` block, as they co arbitrary instructions and break various invariants. The instructions to be inserted are listed in the first argument of the `asm!` macro as a string literal. --> -これにより、コンパイラが生成したアセンブリに、NOP (no operation) 命令が挿入されます。 +これは、コンパイラが生成したアセンブリに、NOP (no operation) 命令を挿入します。 すべての`asm!`呼び出しは、`unsafe`ブロックの中になければいけません。 -というのも、インラインアセンブリは任意の命令を挿入でき、本来不変のものを変更できてしまうからです。 -挿入される命令は、`asm!`マクロの引数として文字列リテラルとして列挙されます。 +インラインアセンブリは任意の命令を挿入でき、本来不変のものを変更できてしまうからです。 +挿入される命令は、文字列リテラルとして`asm!`マクロの第一引数に列挙されます。 -`u64`型の変数`x`に`5`の値を書き込んでいます。 +これは`u64`型の変数`x`に`5`の値を書き込んでいます。 命令を指定するために利用している文字列リテラルが、実はテンプレート文字列になっています。 これはRustの[フォーマット文字列][format-syntax]と同じルールに従います。 ですが、テンプレートに挿入される引数が、みなさんがよく知っているものとは少し違っています。 まず、変数がインラインアセンブリの入力なのか出力なのかを指定する必要があります。 上記の例では出力となっています。 -`out`と書くことでそれを宣言しています。 +`out`と書くことで出力であると宣言しています。 また、アセンブリが変数をどの種類のレジスタに格納するかも指定する必要があります。 -上の例では、`reg`を指定することで任意の汎用レジスタに格納しています。 -コンパイラはテンプレートに挿入すべき適切なレジスタを選び、インラインアセンブリの実行終了後、そのレジスタから変数を読みこみます。 +上の例では、`reg`を指定して任意の汎用レジスタに格納しています。 +コンパイラはテンプレートに挿入する適切なレジスタを選び、インラインアセンブリの実行終了後、そのレジスタから変数を読みこみます。 [format-syntax]: https://doc.rust-lang.org/std/fmt/#syntax @@ -155,7 +155,7 @@ together with newlines between them. This makes it easy to format assembly code. --> まず、`asm!`では複数のテンプレート文字列を引数として利用できます。 -それぞれの文字列は、あたかも改行を挟んで結合されたかのように、独立したアセンブリコードとして扱われます。 +それぞれの文字列は、改行を挟んで結合されたのと同じように、独立したアセンブリコードとして扱われます。 このおかげで、アセンブリコードを容易にフォーマットできます。 -そして、他のフォーマット文字列と同じように引数の番号や名前で指定できます。 -インラインアセンブリのテンプレートでは、引数が2回以上利用されることが多いため、これは特に有用です。 +そして、他のフォーマット文字列と同じように引数を番号や名前で指定できます。 +インラインアセンブリのテンプレートでは、引数が2回以上利用されることが多いため、これは特に便利です。 より複雑なインラインアセンブリを書く場合、この機能を使うのが推奨されます。 可読性が向上し、引数の順序を変えることなく命令を並べ替えることができるからです。 -上記の例をさらに改善して、`mov`命令を避けることもできます。 +上記の例をさらに改善して、`mov`命令をやめることもできます。 ```rust # #[cfg(target_arch = "x86_64")] { @@ -272,7 +272,7 @@ The above could work well in unoptimized cases (`Debug` mode), but if you want o That is because in optimized cases, the compiler is free to allocate the same register for inputs `b` and `c` since it knows they have the same value. However it must allocate a separate register for `a` since it uses `inout` and not `inlateout`. If `inlateout` was used, then `a` and `c` could be allocated to the same register, in which case the first instruction to overwrite the value of `c` and cause the assembly code to produce the wrong result. --> というのも、最適化されている場合、コンパイラは`b`と`c`が同じ値だと知っているので、 -`b`と`c`の入力に同じレジスタを割り当てる場合があるのです。 +`b`と`c`の入力に同じレジスタを割り当てる場合があります。 しかし、`a`については`inlateout`ではなく`inout`を使っているので、独立したレジスタを割り当てる必要があります。 もし`inlateout`が使われていたら、`a`と`c`に同じレジスタが割り当てられたかもしれません。 そうすると、最初の命令によって`c`の値が上書きされ、アセンブリコードが間違った結果を引き起こします。 From 77d57a6da5ded35e4f5d34d3f55810ecf9f9cc55 Mon Sep 17 00:00:00 2001 From: kdnakt Date: Tue, 10 Oct 2023 09:52:56 +0900 Subject: [PATCH 31/35] fix translation --- src/unsafe/asm.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/unsafe/asm.md b/src/unsafe/asm.md index 88856e3a..1bf46ba0 100644 --- a/src/unsafe/asm.md +++ b/src/unsafe/asm.md @@ -378,9 +378,9 @@ The second operand is implicit, and must be the `rax` register, which we fill fr The lower 64 bits of the result are stored in `rax` from which we fill the variable `lo`. The higher 64 bits are stored in `rdx` from which we fill the variable `hi`. --> -`mul`命令を使って2つの64ビットの入力を128ビットの結果に出力する。 +`mul`命令を使って2つの64ビットの入力を128ビットの結果に出力しています。 唯一の明示的なオペランドはレジスタで、変数`a`から入力します。 -2つ目のオペランドは暗黙的であり、`rax`レジスタである必要があります。変数`b`から入力します。 +2つ目のオペランドは暗黙的であり、`rax`レジスタである必要があります。変数`b`から`rax`レジスタに入力します。 計算結果の下位64ビットは`rax`レジスタに保存され、そこから変数`lo`に出力されます。 上位64ビットは`rdx`レジスタに保存され、そこから変数`hi`に出力されます。 From df160f05cfee1983001b6f12398f9c913595edef Mon Sep 17 00:00:00 2001 From: kdnakt Date: Fri, 13 Oct 2023 10:30:36 +0900 Subject: [PATCH 32/35] fix translation --- src/unsafe/asm.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/unsafe/asm.md b/src/unsafe/asm.md index 1bf46ba0..a949b3de 100644 --- a/src/unsafe/asm.md +++ b/src/unsafe/asm.md @@ -102,11 +102,11 @@ the template and will read the variable from there after the inline assembly fin これは`u64`型の変数`x`に`5`の値を書き込んでいます。 命令を指定するために利用している文字列リテラルが、実はテンプレート文字列になっています。 これはRustの[フォーマット文字列][format-syntax]と同じルールに従います。 -ですが、テンプレートに挿入される引数が、みなさんがよく知っているものとは少し違っています。 +ですが、テンプレートに挿入される引数は、みなさんがよく知っているものとは少し違っています。 まず、変数がインラインアセンブリの入力なのか出力なのかを指定する必要があります。 上記の例では出力となっています。 `out`と書くことで出力であると宣言しています。 -また、アセンブリが変数をどの種類のレジスタに格納するかも指定する必要があります。 +また、アセンブリが変数をどの種類のレジスタに格納するかについても指定する必要があります。 上の例では、`reg`を指定して任意の汎用レジスタに格納しています。 コンパイラはテンプレートに挿入する適切なレジスタを選び、インラインアセンブリの実行終了後、そのレジスタから変数を読みこみます。 From 6a13ac5e304671311fb490e62eab3e041b74cd86 Mon Sep 17 00:00:00 2001 From: KIDANI Akito Date: Sat, 2 Dec 2023 21:40:27 +0900 Subject: [PATCH 33/35] Update src/unsafe/asm.md Co-authored-by: dalance --- src/unsafe/asm.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/unsafe/asm.md b/src/unsafe/asm.md index a949b3de..c34f7110 100644 --- a/src/unsafe/asm.md +++ b/src/unsafe/asm.md @@ -395,7 +395,7 @@ Usually this is either because we have to use a scratch register in the assembly This state is generally referred to as being "clobbered". We need to tell the compiler about this since it may need to save and restore this state around the inline assembly block. --> -多くの場合、インラインレジスタは出力として必要のない状態を変更することがあります。 +多くの場合、インラインアセンブリは出力として必要のない状態を変更することがあります。 これは普通、アセンブリでスクラッチレジスタを利用する必要があったり、 私たちがこれ以上必要としていない状態を命令が変更したりするためです。 この状態を一般的に"クロバー"(訳注:上書き)と呼びます。 From ac12ab6339bbb16fc5e2d5907342a2bbbd9712f7 Mon Sep 17 00:00:00 2001 From: KIDANI Akito Date: Sat, 2 Dec 2023 21:40:41 +0900 Subject: [PATCH 34/35] Update src/unsafe/asm.md Co-authored-by: dalance --- src/unsafe/asm.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/unsafe/asm.md b/src/unsafe/asm.md index c34f7110..4053cb5d 100644 --- a/src/unsafe/asm.md +++ b/src/unsafe/asm.md @@ -241,7 +241,7 @@ Rustコンパイラはオペランドの割り当てに保守的です。 -以下は、`release`モードやその他の最適化された場合に、`inout`を利用 *できない* 例です。 +以下は、`release`モードやその他の最適化された場合に、`inlateout`を利用 *できない* 例です。 ```rust # #[cfg(target_arch = "x86_64")] { From 67444476b1aaa1e586b835ff436d519314c90d72 Mon Sep 17 00:00:00 2001 From: kdnakt Date: Sat, 2 Dec 2023 21:52:42 +0900 Subject: [PATCH 35/35] Update translation of asm.md --- src/unsafe/asm.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/unsafe/asm.md b/src/unsafe/asm.md index 4053cb5d..1439665c 100644 --- a/src/unsafe/asm.md +++ b/src/unsafe/asm.md @@ -60,7 +60,7 @@ in the first argument of the `asm!` macro as a string literal. --> これは、コンパイラが生成したアセンブリに、NOP (no operation) 命令を挿入します。 すべての`asm!`呼び出しは、`unsafe`ブロックの中になければいけません。 -インラインアセンブリは任意の命令を挿入でき、本来不変のものを変更できてしまうからです。 +インラインアセンブリは任意の命令を挿入でき、不変条件を壊してしまうからです。 挿入される命令は、文字列リテラルとして`asm!`マクロの第一引数に列挙されます。 -デフォルトでは、`asm!`は、出力として指定されていないレジスタはアセンブリコードによって保存される、と考えます。 +デフォルトでは、`asm!`は、出力として指定されていないレジスタはアセンブリコードによって中身が維持される、と考えます。 `asm!`に渡される[`clobber_abi`]引数は、与えられた呼び出し規約のABIに従って、 必要なクロバーオペランドを自動的に挿入するようコンパイラに伝えます。 そのABIで完全に保存されていないレジスタは、クロバーとして扱われます。 pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy