質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
アセンブリ言語

アセンブリ言語とは、機械語を人間にわかりやすい形で記述した低水準言語です。

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

GCC

GCCはGNU Compiler Collectionの略です。LinuxのC言語コンパイラのデファクトスタンダードであり、数多くの他言語やプラットフォームサポートもします。

x86

x86はIntel 8086 CPU シリーズの命令セットアルキテクチャーです。

Q&A

解決済

1回答

3272閲覧

インラインアセンブリ 構文・ルール がよくわからないのでお願いします

kazuyakazuya

総合スコア193

アセンブリ言語

アセンブリ言語とは、機械語を人間にわかりやすい形で記述した低水準言語です。

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

GCC

GCCはGNU Compiler Collectionの略です。LinuxのC言語コンパイラのデファクトスタンダードであり、数多くの他言語やプラットフォームサポートもします。

x86

x86はIntel 8086 CPU シリーズの命令セットアルキテクチャーです。

1グッド

2クリップ

投稿2020/11/10 22:36

インラインアセンブリに関して。
基本的なことかもしれませんが私にはさっぱり理解できないのでおねがいします

リンク内容

__asm__ ( アセンブリテンプレート : 出力オペランド /* オプション */ : 入力オペランド /* オプション */ : 破壊されるレジスタのリスト /* オプション */ );

インラインアセンブリは上記の要素から構成されているようです。
また、関数と違い 何も指定しない場合レジスタの値を勝手に保存してくれないので
レジスタを破壊したまま__asm__から抜け出すとまずいようです。

int型変数sampleにEBXレジスタの値をコピーする処理を作りました。(間違ってたら教えてください)

int sample; __asm__( "MOV %%EBX,%0\n\t" :"=a" (sample) : );

出力オペランドで EAXレジスタの値を変数sampleに出力するように指定しているので

MOV %%EBX,%0

これは

MOV %%EBX,%%EAX

となり、EBXの値がコピーされたEAXの内容がsampleに出力されるのでしょうか?

また、この場合eaxレジスタが破壊されるので
: 破壊されるレジスタのリスト にeaxを追加するべきですか?

2

つぎは"マッチング制約"と呼ばれているものについて
リンク内容

int in_out=100,in2=200; __asm__ ( "addl %2,%0;" :"=a"(in_out) /* eaxの値をin_out出力 */ :"0"(in_out),"b"(in2) /* in_outの値を出力オペランドで割り当てたレジスタ(eax)に入力値としてセット */ );

"0"は 出力オペランド "=a"(in_out) (つまり、%0 ?)を指しており
eaxに入力値としてin_outの値がセットされると書かれています。

・・・どういうことなのでしょうか?

:"=a"(in_out)
:"a"(in_out)

これとは違うのですか?
また、上記で書いたプログラムで言うと
__asm__が始まった時点でeaxにin_outの値がコピーされているのでしょうか?

3

制約修飾子"&"
説明には・・・

このオペランドが早期破壊 オペランドであることを意味する。早期破壊オペランドとは、 命令が入力オペランドを使い終わる前に変更されるオペランドである。 このため、このオペランドは、入力オペランドや任意のメモリアドレスの一部 として使われるレジスタには置かれない。

入力オペランドを使い終わる前に変更されるとは 例えばどういうことでしょうか?

4

:"i" ((short) (0x8000+(dpl<<13)+(type<<8)))

これはset_idtの一部ですが

制約文字 "i"の説明では・・・
整数の即値オペランド(定数値のもの)が許される。これには、値がアセンブル時にならないとわからないシンボリックな定数も含まれる。

とのことです。

上記の例で言えば 定数が0x8000。
では
シンボリックな定数とはどういうことですか?

Bearded-Ockham👍を押しています

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

まず前提として「GCC のインラインアセンブリは最適化の対象になる」ということを知っておいてください。 前後の文脈から無意味だと判断されたら除去されたり変形されたりすることがあります。 ですから、実際に必要なものは何なのかということを制約づけてプログラマの意図に反する変形がされないようにするのが GCC の拡張アセンブリ構文なのです。

絶対に書いた通りにして欲しいというときは volatile 指定をつけてください。

問1 について

EBX の値がコピーされた EAX の内容が sample に出力されるのでしょうか?

はい。 概念的にはその通りです。

しかし冒頭に述べたように最適化される可能性がありますからその時点での EBX の内容が自明な定数の場合に sample に直接に定数を入れるというようなコードが生成されることもあり得ますし、 sample を使っていないならインラインアセンブリの部分全体が除去されるということもあります。

破壊されるレジスタのリストにeaxを追加するべきですか?

不要です。 出力に使われる以上はその内容が変更されうることは自明なので。

問2 について

:"=a"(in_out) :"a"(in_out)

これとは違うのですか?

質問の事例においては差はないです。 入出力で同じレジスタを使うことを特に強調したいということが読む人にわかるというだけです。

ですがたとえば出力オペランドに "=r" と指定して入力オペランドに "r" と指定した場合に、候補の中からそれぞれ違うレジスタが選ばれる可能性があります。 そういうときに同じであることという制約を付けたいときにマッチング制約を利用できるのです。

asmが始まった時点でeaxにin_outの値がコピーされているのでしょうか?

はい。 その通りです。

問3 について

端的に言えばマッチング制約の逆です。

出力と入力の両方に "r" を使っていた場合に同じレジスタが選択されてしまうことがありうるのですが、出力用の値をそのレジスタにセットした後に入力値を利用しようとした場合などに破綻してしまいます。

異なるレジスタが選択されるようにして破綻を防ぐのが & です。

問4 について

シンボリックな定数とはどういうことですか?

1 とか 2 とかいった直接的な定数リテラルではなく定数として解釈可能なもの (定数式) なら大丈夫という意味だと思われます。

投稿2020/11/11 06:51

SaitoAtsushi

総合スコア5684

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

kazuyakazuya

2020/11/11 10:43

回答ありがとうございます。 >不要です。 出力に使われる以上はその内容が変更されうることは自明なので。 このような場合はコンパイラがなんとかしてくれるということですか? 問2>はい。 その通りです 心配になったので一応お聞きしたいのですが・・・ マッチング制約を使ったときはasmが始まる時点でレジスタに値が設定されるが 入力オペランドを使ったときは %0,%1などで呼び出されて初めてレジスタに値がコピーされるのでしょうか? >1 とか 2 とかいった直接的な定数リテラルではなく定数として解釈可能なもの (定数式) なら大丈夫という意味だと思われます。 dpl,typeは定数ではなく値が変わる"変数"ですが 大丈夫なのですか?
SaitoAtsushi

2020/11/11 11:18

> このような場合はコンパイラがなんとか はい。 壊れることがわかっているので別途書かなくても壊れるものとして扱ってくれるということです。 破壊されるレジスタとして書いても特に害もないとは思いますが。 > 呼び出されて初めて いいえ。 入力オペランドはいずれも `asm` 内の命令群を実行するより前に値はセットされるているはずです。 `&` が必要になるのはそれ故ですから。 > dpl,typeは定数ではなく 「アセンブル時に定数であれば良い」ので、 C としての理屈上では変数であってもコンパイル時に定数に置き換わるのであればよいということになるのだと思います。 ためしに以下のような例をやってみたのですが、最適化なしだとエラーになってコンパイルできませんが、最適化ありだとコンパイルが通ります。 最適化を有効にしたときに限っては x が事実上の定数であることをコンパイラが見抜いて定数扱いにしてくれるので通るということなんでしょう。 #include <stdio.h> int main(void) { int y, x=0; __asm__("mov %1,%0\n\t" : "=r" (y) : "i" (x) ); printf("%d\n", sample); return 0; }
kazuyakazuya

2020/11/11 11:58

最後に一つ >いいえ。 入力オペランドはいずれも `asm` 内の命令群を実行するより前に値はセットされるているはずです。 4つ以上入力オペランドを使うと EAX,EBX,ECX,EDXにC変数の値がコピーされることになり 汎用レジスタを使うことができず何もできなくなってしまう気がするのですが ここはどうなっているのでしょうか?
SaitoAtsushi

2020/11/11 12:16

x86 (32ビット) だと esi や edi も汎用レジスタ扱いらしいですが、それを超えてレジスタが足りなければ「不可能な制約」としてエラーになります。
kazuyakazuya

2020/11/11 12:25

わかりました ありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問