目次

ニュース

日記カテゴリ

書庫

アセンブラ言語は、コンピュータの命令を直接(と言っても機械語でもありませんが、ほぼ1対1で対応するってことで)記述する言語です。

ですが、この言語を使ってプログラミングを行うと、メモリの値を直接のデータアドレスで指定しないといけません。

もともとアセンブラには変数っていう概念はないのでアドレスを計算してあげなければいけないんですけど。

そこで、Visual C++のインラインアセンブラを使うと、C++コードの途中にアセンブラ言語を混ぜることができます。

こうすることで、必要最低限の作業量でMMXやSSEなど、通常のコンパイラが吐いてくれないアセンブラ命令を使うことができたり、CPUIDなどの特殊命令も実行することができます。

インラインアセンブラは次のような記述で使えます。

001 __asm {
002     // インラインアセンブラコードをここに記述
003 }
004 
こんな感じ。

まずは、C++で変数を定義して、そこにアセンブラでデータを突っ込んでみましょう。

データのロードにはmov命令を使います。たぶんアセンブラで最も使う命令と思われます。

001 #include <iostream>
002 void main()
003 {
004     int a;
005     __asm {
006         mov a, 256;
007     }
008     std::cout << "a = " << a << std::endl;    // a = 256 と出力される
009 }

 

MOV命令は

mov dest, src

dest レジスタ,メモリ

src レジスタ,メモリ,即値

となっています。ですので、

001 {
002     int a,b;
003     b = 256;
004     __asm {
005         mov a, b;
006     }
007 }
008 

というのは動きません。

次に、足し算命令を使ってみましょう。

足し算命令はaddを使います。

add dest, src

flag OF, SF, ZF, AF, CF, PF

dest レジスタ,メモリ

src レジスタ,メモリ,即値

これをインラインアセンブラで記述してみます。

001#include <iostream>
002void main()
003{
004    int a;
005    __asm {
006        mov a, 256;
007        add a, 128;
008    }
009    std::cout << "a = " << a << std::endl;    // a = 384 と出力される
010}

このときに、MOV命令と違って演算を行うとフラグが立ちます。これは、算術演算を行った時の結果に対して出てくるものです。

CF(キャリーフラグ)

算術命令を行った際に、最上位ビットが繰り上げもしくは繰り下げを行ったときにセットされます。

PF(パリティーフラグ)

演算結果のパリティビット。二進数で1の数が偶数のときに1になる。使ったことがないw

AF(補助フラグ)

あまり使わない…かも。調べて分かったら書く。

ZF(ゼロフラグ)

演算結果が0になった場合に1になる。とても使う。

SF(サインフラグ)

演算結果がマイナスになったときに1になる。signedコードなので基本的には最上位ビットと同じ。

OF(オーバーフローフラグ)

ビットが越えたときに1になる。たとえば、

mov AX, 65530;
add AX, 100;

とすると、AXレジスタは16ビットなのでオーバーフローとなり、ビットが立ちます。

符号付き演算で、符号が変化したときに1になります。

この値をチェックすることもあります。たとえば、INT 21Hなんかは異常時にCFが1になってくるので、関数の戻り値みたいに使う人もいたり。

 

といことで、次回はCPUID命令で。

投稿日時 : 2008年3月25日 18:18
Feedback
  • # re: インラインアセンブラ使ってみようぜ 書き方編
    さかもと画伯
    Posted @ 2008/03/25 18:23

    これはLiveWriterで?


    と、本題がよく分らないのでそのあたりをば。
  • # re: インラインアセンブラ使ってみようぜ 書き方編
    ながせ
    Posted @ 2008/03/25 18:25
    Live Writerで。

    本題はインラインアセンブラを使ってみようというお話です。
  • # re: インラインアセンブラ使ってみようぜ 書き方編
    2リットル
    Posted @ 2008/03/25 18:53
    すごい見やすい。
  • # re: インラインアセンブラ使ってみようぜ 書き方編
    myugaru
    Posted @ 2008/03/25 18:58
    LSI-C86"永遠の"試食版というやつで10年くらい昔は毎日のようにasm命令で遊び倒していたmyugaruが通ります。
  • # re: インラインアセンブラ使ってみようぜ 書き方編
    ながせ
    Posted @ 2008/03/25 19:08
    >2リットルさん
    whiteのほうが全体のイメージはよさそうですね。

    >myugaruさん
    試食版キタコレ!SSE命令もやってみたいですね。
  • # re: インラインアセンブラ使ってみようぜ 書き方編
    ちゃっぴ
    Posted @ 2008/03/25 19:19
    個人的に大期待です。wktk
  • # re: インラインアセンブラ使ってみようぜ 書き方編
    ながせ
    Posted @ 2008/03/25 19:33
    SSE命令使ったことないですけどねww
    たぶん近々画像処理で使うから勉強も兼ねておきまつ。
  • # re: インラインアセンブラ使ってみようぜ 書き方編
    とっちゃん
    Posted @ 2008/03/25 20:34
    ちょっと前?に、Pentium-MMXかをチェックするコードを書いた人が通りますよ~

    たしかVC2とか4とかだったような...w<おい!

    インラインアセンブラで書いたやつを、アセンブラで吐き出して、最終的には最適化(手動でw)して、asm に落とし込んだんですけどねw
    #いらない push/pop が山のように...w

    ついこの間のような気がするけど...
    10年以上昔の話なんだよなぁ...www
  • # re: インラインアセンブラ使ってみようぜ 書き方編
    ながせ
    Posted @ 2008/03/25 21:30
    そこまでする必要あるんですかwwww
    MMX命令が通じるかをチェックして命令コード体系変えるって?
    本物のアセンブラは地獄ぽ。インラインじゃないやつはもう触りたくもないww
  • # re: インラインアセンブラ使ってみようぜ 書き方編
    774RR
    Posted @ 2008/03/25 22:38
    えー VC++ 固有かつ x86 固有ぢゃん
    そんなの邪道
    俺ちゃんは SH2 も H8 も x86 も ARM も PIC もみな手書きしたよ
    RISC でパイプライン考えながら命令配置するのはもういやー
  • # re: インラインアセンブラ使ってみようぜ 書き方編
    ながせ
    Posted @ 2008/03/25 22:44
    いいじゃん。個別CPUとかめんどくせーし。

    >RISC でパイプライン考えながら命令配置するのはもういやー
    業務でやるなら必要なんだからしかたねーっすよ。
    耐えてくださいww
  • # re: インラインアセンブラ使ってみようぜ 書き方編
    やまだ
    Posted @ 2008/03/25 23:22
    > 本物のアセンブラは地獄ぽ。
    なので、擬似アセンブラが動くエミュレータ作るところから始めようかと思ってるやまだが通りますよー。

    でも、アセンブラ仕様が決まらない……。
    というわけでお勉強させてくだせー。

    で、何のためにエミュレータ作るかというと、その上で VM っぽいものを作りたいがためだったり。

    > 試食版キタコレ!
    つーか、あれ試食版でないの使っていた人いたのだろうか?

    > アセンブラには変数っていう概念はないのでアドレスを計算して
    えー、アセンブラで変数に相当するのはレジスタじゃないのー?
    #ローカル変数と引数、返値はスタックだし。
  • # re: インラインアセンブラ使ってみようぜ 書き方編
    myugaru
    Posted @ 2008/03/25 23:37
    試食だけでおなかいっぱいなのは今も同(ry
  • # re: インラインアセンブラ使ってみようぜ 書き方編
    ながせ
    Posted @ 2008/03/26 9:03
    >やまださん
    アセンブラ仕様…。CASLじゃぁだめなんでしょうか^-^;
    変数=アドレスという感じですかね。インラインアセンブラの場合は、勝手にローカル変数のアドレスに変換してくれてます。
    レジスタは完全にCPUの内部FlipFlopかと思いますよ。

    >myugaruさん
    製品版とどう違うのかわからないww
  • # re: インラインアセンブラ使ってみようぜ 書き方編
    スーパーあんどちん
    Posted @ 2008/03/26 11:08
    ところでC/C++にはregisterキーワードがありますよね。
    register宣言された変数の場合
    レジスタ=変数
    でもいいんじゃない?と思いますけど。

    実際にその変数のためにレジスタを割り当てるかどうかはコンパイラ次第でしょうが。

    何でもかんでもregister宣言したらコンパイラが無理に少ないレジスタに変数を割り当てようとして、挙句push/popが一杯生成されて「速くなってねーよ」ってな経験があります。
  • # re: インラインアセンブラ使ってみようぜ 書き方編
    とっちゃん
    Posted @ 2008/03/26 11:09
    >そこまでする必要あるんですかwwww
    EXE起動時(当たり前だけど、CPU途中で変わらんのでw)の処理なので、ごく僅かでもスピードあげたいところだったんでw

    ぶっちゃけ、インラインアセンブラよりも、圧倒的に早いですからw
    たかが数十クロックされど数十クロックですよw

    でも、そのコード結局MMX対応見送っちゃったのでお蔵入り...orz
    何時間もかけて作り上げたのにさぁ...
    ま、時間がかかったのは、調べるほうだったりするんだがwww
  • # re: インラインアセンブラ使ってみようぜ 書き方編
    774RR
    Posted @ 2008/03/26 11:33
    ところで CPUID 命令はレジスタを軒並み変更するんだけど、
    ABI の解説とか、その辺に wktk
  • # re: インラインアセンブラ使ってみようぜ 書き方編
    ながせ
    Posted @ 2008/03/26 11:38
    >スーパーあんどちん
    たしかに、コンパイラ次第なのかも。
    個人的には変数=メモリ領域っていうのがあるのかも。

    …registerって速くなるんでしょうかねぇ。
    あまり感じないのですが^-^;

    >とっちゃん
    数十クロック飛びます?
    10年前でも、60MHzくらいありましたよねぇ。
    画像/音声処理ライブラリ系かな…。

    >774RRさん
    インラインなのでコンパイラにpush/popしてもらいます。
  • # re: インラインアセンブラ使ってみようぜ 書き方編
    とっちゃん
    Posted @ 2008/03/26 11:48
    >数十クロック飛びます?

    なにせ、当時の動作環境が386互換CPUまであったんで...
    それじゃなくてもあちこちにボトルネックあったし...orz

    当時は重いと評判だったから、カリカリにチューニングするための検証も兼ねてたんですよw
    結局、骨までしゃぶる実装は見送られてしまったんですがね...<ついてこれねーという結論もあって...w

    今なら、数十クロック稼ぐとかはやらねーです。
    CPUのバリエーション多いからあんまり効果でないしw
  • # re: インラインアセンブラ使ってみようぜ 書き方編
    スーパーあんどちん
    Posted @ 2008/03/26 11:55
    ん?インラインアセンブラ使うときのレジスタ退避ってプログラマの責任だと思うんですけど、VCって違うんですか?
  • # re: インラインアセンブラ使ってみようぜ 書き方編
    ながせ
    Posted @ 2008/03/26 12:00
    至れり尽くせりなコンパイラですからね。
  • # re: インラインアセンブラ使ってみようぜ 書き方編
    ながせ
    Posted @ 2008/03/26 12:02
    >当時は重いと評判だった
    そうなのか…。
    正直使ったことがないのでわかりませんでした。
    今はマネージコードが多いくらいですから、そんなにパフォーマンスを問われなくなってきているんでしょうかね。
  • # re: インラインアセンブラ使ってみようぜ 書き方編
    とっちゃん
    Posted @ 2008/03/26 14:17
    >評判

    うちのソフトも...なんですけどね...orz

    仕組み上ここは...とか避けられないボトルネックはともかく
    避けられるものはなるべく避けて...
    速くできるところはより速く...
    というのはどうしてもありますからw
  • # re: インラインアセンブラ使ってみようぜ 書き方編
    774RR
    Posted @ 2008/03/26 23:11
    おっと、見落としてたけど OF のたち方例が間違ってるよ
    っていうか OF と CY が混乱してる?
    65530=-6 なので -6+100 は OV しない (CY にはなる)
    OV になるのは符号付き数があふれるとき (32760+8 とか)
  • # re: インラインアセンブラ使ってみようぜ 書き方編
    ながせ
    Posted @ 2008/03/27 13:03
    >とっちゃん
    ある意味、必要性的な部分もあるんですが、どこまで出来るやって見たいっていう部分もあったり。

    >774RRさん
    すみませんその通りですね。
    調べて修正します。
  • # re: インラインアセンブラ使ってみようぜ 書き方編
    とっちゃん
    Posted @ 2008/03/27 14:21
    >どこまで出来るやって見たい
    これはありますねぇw

    もともと好きでやってる仕事なので、どうしたって追い求めちゃう...w

    結果「誰でもメンテナンスできるコード」が難しい...w

    ま、昔ほど突き詰めてというのはなくなったので
    今は極力「誰でもメンテナンスできるコード」を目指してますけどねw
    #それにしたって、前提条件のハードルはあるんだけど...www
  • # re: インラインアセンブラ使ってみようぜ 書き方編
    スーパーあんどちん
    Posted @ 2008/03/28 10:53
    見落としっていうならCFは加算以外でも立つのでは?
    シフトとか。
    加算と書いてありながら桁借りってのもおかしいし。

    ながせさんがここで書こうとしている事の主旨から外れた細かいこと言っても仕方ないからスルーしてたけど。

    あと、x86ではCF/CYどっちが正解?
  • # re: インラインアセンブラ使ってみようぜ 書き方編
    ながせ
    Posted @ 2008/03/28 11:15
    >加算と書いてありながら桁借りってのもおかしいし。
    広い定義に修正しました。

    >あと、x86ではCF/CYどっちが正解?
    一般的にCFで良いと思いますよ。CYとかZRとかで記述したほうがよいですか?
  • # re: インラインアセンブラ使ってみようぜ 書き方編
    スーパーあんどちん
    Posted @ 2008/03/28 12:06
    CFは最上位ビットのみではありませんよ。最下位ビットからの溢れでも立ちますから。
    それと、CFって命令でも立てれたと思います。

    故にINT21で使われていたのではないかと。
    任意に立てることの出来るフラグでステータスを表すことでDOSコールした後即判定ジャンプでエラー処理に飛ばせるから。

    他のフラグも命令で立てれたっけ?

    あと、CFの名前はどっちが正しいのか知らないから聞いただけです。CPUマニュアルに載ってる名前が正解でしょうね。
  • # re: インラインアセンブラ使ってみようぜ 書き方編
    ながせ
    Posted @ 2008/03/28 13:01
    VC++のデバッガには、どれでもフラグを立てる機能があるので、あるのかもしれません。

    pushしてフラグが立つ演算をしているのかもしれないですけれど。
タイトル  
名前  
Url
コメント   

Blog 利用状況

コミュニティ

プロファイル