● アセンブラからの呼び出し
- fixedX.dll の関数は、使用する汎用レジスタの内容を保存しますので、呼び出し側で退避/復元を行う必要はありません。ただし、eax レジスタについては、戻り値が void 以外の場合は保存しません。
フラグレジスタは、ディレクションフラグ以外の内容は保障されません。
- ユーティリティー関数については、通常のCの関数と同じ条件でコールしてください。
- fixedX.dll、ユーティリティー関数の呼び出し規約は __stdcall です(引数を後ろから順に push し、呼び出された側がスタッククリアする)。
例1.「加減算」 の例1 をインラインアセンブラで作る
#include <stdio.h>
#include "fixedX.h"
#define FIXED_BIT 128
#define FIXED_SIZE (FIXED_BIT / 8)
void main(void )
{
FIXEDVAL a[FIXED_SIZE],b[FIXED_SIZE];
char *pszA = "1156262128751139";
char *pszB = "6643456757654475";
char *pformat = "%s\n";
char buf[39+1];
_asm{
lea edi,a
lea esi,b
;; a に値をセット
push dword ptr pszA ; 変換対象の文字列
push dword ptr FIXED_SIZE ; 変数 a の数値幅
push edi ; 変数 a のアドレス
call dword ptr fixed_atoui ; __stdcall fixed_atoui
;; b に値をセット
push dword ptr pszB ; 変換対象の文字列
push dword ptr FIXED_SIZE ; 変数 b の数値幅
push esi ; 変数 b のアドレス
call dword ptr fixed_atoui ; __stdcall fixed_atoui
;; 加算
push dword ptr FIXED_SIZE ; 変数の数値幅
push esi ; 加数 b
push edi ; 被加数 a
call dword ptr fixed_add ; __stdcall fixed_add
;; 結果を文字列に変換
lea eax,buf
push eax ; 文字列を受け取るバッファのアドレス
push dword ptr FIXED_SIZE ; 変数 a の数値幅
push edi ; 変数 a のアドレス
call dword ptr fixed_num2str10 ; __stdcall fixed_num2str10
; void : この時点で eax の内容は変わらず
;; 結果表示
push eax ; 文字列を格納しているバッファのアドレス
push dword ptr pformat ; 表示フォーマット
call printf ; printf
add esp,8 ; __cdecl
}
}
例2.「double値の変換」にある「FIXEDVAL型 → double型」の例1 を MASM で作る
MASM の場合はインラインアセンブラより呼び出し手続きが簡単ですが、
当然の事ながら、対象関数を全てアセンブラで作る必要があります。
.486
.model flat,stdcall
option casemap : none
fixed_neg proto stdcall :dword,:dword
fixed_bsr proto stdcall :dword,:dword
fixed_rshift proto stdcall :dword,:dword,:dword
.code
BIT_SIGN equ 80000000h ; 符号ビット
MANTCNT equ 52 ; 仮数部ビットサイズ
;; double __stdcall to_double(PFIXEDVAL pval,int len);
to_double proc public uses eax ecx edx esi pval:dword,len:dword
mov esi,pval ; esi ... pval
mov ecx,len
mov edx,[esi+ecx-4]
and edx,BIT_SIGN ; 符号チェック
jz @f
invoke fixed_neg,esi,ecx ; 負なら絶対値に変換
@@:
invoke fixed_bsr,esi,ecx ; 最上位ビットの検索
test eax,eax
jge @f
fldz ; 値自体がゼロなら 0.0 で終了
ret
@@:
sub eax,MANTCNT-1 ; 数値の幅 > 52bit ?
jg @f
xor eax,eax ; 52bit以下なら全部入る
jmp next_step
@@:
invoke fixed_rshift,esi,eax,ecx ; 上位を残し、下位側を切り捨てる
next_step:
;; ここでは標準ライブラリの ldexp を使用しません。
push eax
fild dword ptr [esp]
lea esp,[esp+4]
fild qword ptr [esi]
fscale ; [esi] * 2^eax → st(0)
fstp st(1)
test edx,edx
jz @f
fchs ; 負にする
@@:
ret
to_double endp
end