Skip to content

Latest commit

 

History

History
115 lines (80 loc) · 4.71 KB

File metadata and controls

115 lines (80 loc) · 4.71 KB

列挙型

Rustにおける列挙型は、いくつかの異なる要素の型の中から一つを選択する場面で利用される。特に、Rustの列挙型は各要素に異なる型を柔軟に指定できる点が特徴的である。

本調査では、Rustの列挙型の中でも特に広く利用されているOption型について調査を行った。Option型は、値が存在する場合にはその値を返すSome、存在しない場合にはNoneを返す列挙型である。このOption型がアセンブリレベルでどのように実装されているかを調査した。また、Option型に関連して使用可能な、expect()unwrap()などのパニックを引き起こす関数のアセンブリについても調査した。

調査結果

  • Option型では、SomeまたはNoneを示す判別値がeaxレジスタで返される。eaxが1の場合はSome、0の場合はNoneを示す。
    • Someの場合、その値はedxレジスタで返される。

なお、32ビットバイナリにおいても、引数の受け渡し方法やアドレスサイズを除いて実装は同様であることが確認できた。

詳細

調査に使用したサンプルプログラムは、後半に記載している。

Option型

リリースビルド、最小化バイナリでサンプルプログラムをビルドした場合、最適化によって無駄な処理が削除されるため、最適化の影響を受けないデバッグビルドのバイナリで調査した。

RustのOption型において、SomeNoneかはeaxレジスタで返され、1がSome、0がNoneを示す。 Option型の関連する処理である戻り値をサンプルプログラムで確認すると、eaxレジスタへ1が、edxレジスタへ2が格納されている。 edxレジスタに格納された2はサンプルプログラムで定義した配列の最初の偶数である。 eaxレジスタの値が0か否かをチェックし、1の場合(Some)は、edxレジスタの値を出力し、0の場合(None)は文字列No even number foundを出力する。

enum

expect()

リリースビルド、最小化バイナリでサンプルプログラムをビルドした場合、最適化によって無駄な処理やexpect()が削除されるため、最適化の影響を受けないデバッグビルドのバイナリで調査した。

expect()は、第一引数にSomeNoneかを示す値、第二引数にOption型の値、第三引数にpanicメッセージ、第四引数にパニックメッセージの文字数、第五引数にcore::panic::Location構造体を受け取る。

enum

以下は、expect()の内部処理であるが、内部ではSomeNoneかのチェックを行い、Someの場合は第二引数の値をそのまま返却し、Noneの場合はパニックを発生させる。

enum

unwrap()

リリースビルド、最小化バイナリでサンプルプログラムをビルドした場合、最適化によって無駄な処理やunwrap()が削除されるため、最適化の影響を受けないデバッグビルドのバイナリで調査した。

以下は、サンプルプログラムの結果であるが、unwrap()がインライン展開されていおり、処理からはunwrap()の使用が確認出来なくなった。

enum

使用したサンプルプログラム

  • Option型
fn find_first_even_number(numbers: &[i32]) -> Option<i32> {
    for &number in numbers {
        if number % 2 == 0 {
            return Some(number);
        }
    }
    None
}

fn main(){
    let numbers = [1, 2, 3, 4, 5, 6];
    let result = find_first_even_number(&numbers);
    match result {
        Some(even_number) => println!("Even number: {}", even_number),
        None => println!("No even number found"),
    }
}
  • expect()
fn find_first_even_number(numbers: &[i32]) -> Option<i32> {
    for &number in numbers {
        if number % 2 == 0 {
            return Some(number);
        }
    }
    None
}

fn main() {
    let numbers = [1, 3, 7, 9];
    let result = find_first_even_number(&numbers);

    let even_number = result.expect("No even number found");
    
    println!("Even number: {}", even_number);
}
  • unwrap()
fn find_first_even_number(numbers: &[i32]) -> Option<i32> {
    for &number in numbers {
        if number % 2 == 0 {
            return Some(number);
        }
    }
    None
}

fn main() {
    let numbers = [1, 3, 7, 9];
    let result = find_first_even_number(&numbers);

    let even_number = result.unwrap();

    println!("Even number: {}", even_number);
}