x86用gccの拡張インラインアセンブラ構文で、オペランドにレジスタまたはメモリ参照のみを許可し即値は禁止するようにしたい
gccでのインラインアセンブラの書き方の勉強をしているのですが、以下のような場合の書き方がわからずに困っています。やり方をご存知の方は教えていただけませんでしょうか。
【実現したいこと】
x86用gccの拡張インラインアセンブラ構文で、オペランドにレジスタまたはメモリ参照のみを許可し即値は禁止するようにしたい。
【経緯】
インラインアセンブラの実験のために以下のようなコード(ファイル名:test.c)を書いてみました。
// test.c :
// gccを使用したインラインアセンブラの勉強のためのテストプログラム
#include <stdio.h>
// 被乗数(32bit)と乗数(32bit)から積(64bit)を求める。
// u: 被乗数
// v: 乗数
// w_high: 積の上位32bitが格納される領域へのポインタ
// return: 積の下位32bit
__inline unsigned __int32 multiply(unsigned __int32 u, unsigned __int32 v, unsigned __int32 *w_high)
{
unsigned __int32 ret;
__asm__("mull %3" : "=a"(ret), "=d"(*w_high) : "0"(u), "g"(v));
return (ret);
}
// メイン関数
int main()
{
// 定数の設定
unsigned __int32 u = 50000;
unsigned __int32 v = 2000;
unsigned __int64 desired_w = (unsigned __int64)u * v;
unsigned __int32 desired_w_high = (unsigned __int32)(desired_w >> 32);
unsigned __int32 desired_w_low = (unsigned __int32)(desired_w);
// 計算結果の変数の定義
unsigned __int32 w_high;
unsigned __int32 w_low;
// 計算
w_low = multiply(u, v, &w_high);
// 計算結果の検査
if (w_low == desired_w_low && w_high == desired_w_high)
printf("OK.");
else
printf("NG.");
}
このソースを以下のようにコンパイルすると、以下のエラーメッセージが表示され、アセンブルに失敗しました。
gcc -m32 -S test.c -O2
gcc -m32 -c -o test.o test.s
test.s: Assembler messages:
test.s:26: Error: operand type mismatch for `mul'
test.sの26行目付近は以下のようになっていました。
movl $50000, %eax
/APP
# 13 "test.c" 1
mull $2000 # <=== ERROR!
# 0 "" 2
/NO_APP
testl %edx, %edx
jne L2
cmpl $100000000, %eax
je L12
エラーメッセージが表示された理由は、MUL命令のオペランドに指定してはいけないはずの即値が指定されていることによるもののようです。
様々な資料を調べてみたところ、gccがこのようなコードを生成した理由は(わかってみれば当然のことですが)乗数にあたるオペランド制約文字がレジスタまたはメモリ参照だけではなく即値も許可する"g"
であったことが原因でした。
確認のため、"g"
の代わりのオペランド制約文字として"r"
または"m"
を使用すれば正常にアセンブルできました。
この問題の対処方法として、"g"
の代わりのオペランド制約文字として"r"
または"m"
を使用する、あるいはそもそも最適化を行わない、といった方法も検討中ではあるのですが、まずは、拡張インラインアセンブラ構文のオペランド制約で「レジスタまたはメモリ参照のみ」を許可する方法はないか、という方向で解決できないかを調べたいと思っています。
しかし、そういった需要は特殊なものではないと思っているのですが、今のところ望む答えが見つかっていません。
いい方法をご存知の方がおられましたら是非教えてください。
よろしくお願いします。
【使用した環境】
- CPU: Intel Core i7 7700K
- OS: Windows10 Pro 64bit
- GCC: version 7.1.0 (i686-win32-dwarf-rev0, Built by MinGW-W64 project)