機械語、または他の実行Programを呼び出すときの引数の受け渡しの説明。
関数[USR] での引数の扱いは異なります。
命令での引数は定数は使用出来ません。
機械語のProgramには変数のMemoryのアドレス(Pointer)を渡します。
このため、引数の記述欄には変数名を記入します。引数はコンマ(,)で区切って記入します。
内部では4Byteのアドレス(Pointer)として記述順に渡されます。
BASICの整数変数、単精度実数、倍精度実数は2Byte,4Byte,8Byte変数として渡されますが、
文字変数はchar型の[256]要素配列として先頭要素[0]のアドレスをPointerとして渡します。
これらは、
16Byte時代の旧来のStringsDescripterではなく、0で終了する単純なchar型の配列です。
Cの場合、
char CS1[256]=”1234”;
とするとき、cs1[0]='1' ,,, cs1[3]='4' , cs1[4]=0 です。
Assemblerの場合は、Pointer以降をByte単位で操作してください。
終端Byteを0として下さい。
機械語内部で文字列を操作する場合、
最大255文字と0要素で終了することに注意してください。
0に出会わない限り255文字まで扱います。
CALL P%(A%,B%,C%[0]) では、Argumentの記述順にそのAddressPointerが渡されます。
A%,B%は整数変数で、C%は整数の配列変数でたとえばDIM C%[20]
などと宣言済みとします。
配列の場合は先頭C%[0]のPointerを渡します。
後続の要素はC%[0]のPointerOffsetを加えてアクセスします。整数変数
の場合、Offset 2を加えてC%[1]を、Offset 10を加えてC%[5]をアクセス出来ます。
Cで作成の場合、引数Pointerの取り出しは規定どうりにargv[0]、argv[1]、、、
で取り出せます。
[SAMPLE40]実行ProgramのLoad 参照。
VisualStudioのCompilerでAssembler Programを組む場合、
ArgumentのPointer取り出しには注意をしてください。
_ASM{ }の内部での、特殊Register EBPを使用の場合、およびESI,EDI,EBXを壊した場合、SPの
Pointが変わります。VisualStudioのCompilerが感知して、
_ASM{}に入る前にこれらRegisterをPUSHし、出たあとに、POPしているためです。
例えば、EBX,ESI,EDIを壊さずに、かつEBPを使用しない場合、
Assembler(VisualStudioを使用の場合は_ASM{ }の内部)では
MOV ECX, 4[ESP] でArgumentのPointerの格納場所を取り出せます。
MOV EDX,WORD PTR [ECX]で1stのArgumentのPointer,
MOV EDX,WORD PTR 4[ECX]で2ndのArgumentのPointerを取り出せます。
Stackを 4Byte戻すのは、_ASM{ } に入る前に、帰り番地をPUSHしているためです。
例えば、ESIをして壊して使用する場合、
AssemblerではMOV EBX,DWORD PTR 8[ESP] でArgument
のPointerの格納場所を取り出せます。
例えば、EBPを使用し,かつESI,EDIを壊して使用した場合、
AssemblerではMOV EBX,DWORD PTR
16[ESP] でArgumentのPointerの格納場所を取り出せます。
尚、_ASM{ }を出たあとは、Cの終了と同じです。
_ASM[ ]で作成の場合のために、
念のために引数の格納Pointer取り出しのSampleコードを書いておきます。
/************************** Start of MAIN.H **************************/
#ifndef _[#ifndef _
#define _[#define _
#ifdef __STDC__
#else /* __STDC__ */
#endif /* __STDC__ */
#endif /* _[#endif /* _ */
/*************************** End of MAIN.H ***************************/
/************************* Start of MAIN-C.C *************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "main.h"
#ifdef __STDC__
#else
#endif
void main( )
{
//////////////////////////
//ASM assemble inner C, SP is incremented 4 according break numbers these register BX,SI,DI or
use BP。
//In case of not using 4[ESP],
// when break edi,esi,ebx or use ebp,increment 4 of SP
//For example, break EBX only,4+4-->8,in asm_program argument pointer SP is 8[ESP],
//if break EBX,ESI,EDI ,4+4*3-->16,argument pointer is 16[ESP]
//EAX,ECX,EDX may be break or use.
//////////////////////////
_asm {
/*case1 don't increase
MOV ECX,DWORD PTR 4[ESP];
MOV ECX,DWORD PTR [ECX];//This is 1st argument pointer.
MOV WORD PTR [ECX],31;
MOV EAX,EBX;
MOV EAX,EDI;
MOV EAX,ESI;
//case1
*/
/*
//case2 use EBP , increase 4
MOV ECX,DWORD PTR 8[ESP];
MOV ECX,DWORD PTR [ECX]; //This is 1st argument pointer.
MOV WORD PTR [ECX],31;
MOV EAX,EBP;
MOV EAX,EDI;
MOV EAX,ESI;
MOV EAX,EBX;
//case2
*/
/*
//case3 use EBP and break EBX , increase 8
MOV ECX,DWORD PTR 12[ESP];
MOV ECX,DWORD PTR [ECX]; //This is 1st argument pointer.
MOV WORD PTR [ECX],31;
MOV EAX,EBP;
MOV EAX,EDI;
MOV EBX,ESI;
//case3
*/
/*
//case4 use EBP and break EBX,EDI , increase 12
MOV ECX,DWORD PTR 16[ESP];
MOV ECX,DWORD PTR [ECX]; //This is 1st argument pointer.
MOV WORD PTR [ECX],31;
MOV EAX,EBP;
MOV EAX,EDI;
MOV EBX,ESI;
MOV EDI,5
//case4
*/
/*
//case5 break ESI , increase 4
MOV ECX,DWORD PTR 8[ESP];
MOV ECX,DWORD PTR [ECX]; //This is 1st argument pointer.
MOV WORD PTR [ECX],31;
//MOV EAX,EBP;
MOV EAX,EDI;
MOV EAX,EBX;
MOV EAX,ESI;
MOV ESI,EAX
//case5
*/
/*
//case6 all stars , increase 16
MOV ECX,DWORD PTR 20[ESP];
MOV ECX,DWORD PTR [ECX]; //This is 1st argument pointer.
MOV WORD PTR [ECX],31;
MOV EAX,EBP;
MOV EAX,EDI;
MOV EAX,EBX;
MOV EAX,ESI;
MOV ESI,EAX
MOV EDI,EAX
MOV EBX,EAX
//case6
*/
/////////////////This is active example///////////
//case7 all stars ,duplicate is OK, increase 16
MOV ESI,EAX
MOV EDI,EAX
MOV EBX,EAX
MOV EBP,EDX;
MOV ESI,EAX
MOV EDI,EAX
MOV EBX,EAX
MOV EBP,EDX;
MOV ESI,EAX
MOV EDI,EAX
MOV EBX,EAX
MOV EBP,EDX;
MOV ECX,DWORD PTR 20[ESP];
MOV ECX,DWORD PTR [ECX]; //This is 1st argument pointer.
MOV WORD PTR [ECX],31;
MOV EAX,EBP;
MOV EAX,EDI;
MOV EAX,EBX;
MOV EAX,ESI;
MOV ESI,EAX
MOV EDI,EAX
MOV EBX,EAX
//case7
} //_ASM{
return ;
}
/************************** End of MAIN-C.C **************************/
Visual Studioで、CやCで_ASM{......}によりAssemblerを組む場合、
新規作成--->プロジェクト
--->Win32 コンソールアプリケーション--->空のプロジェクトとします。
Visual Studioで、CやCで_ASM{......}によりAssemblerを組む場合、
実行Module(EXEファイル)の開始番地は0x1000です。
および、後続部にもWindows処理が入っており、_ASM{.....}の処理部
分はかなり小さくなります。
CALL文に使う場合、0x1000からHexを調べて、最後は、C3,90,90,90,,,,とな
る部分までです。これはC言語でEXEファイルを作成する場合も同じです。
[CALL][CALL] 、[POKE] 、[BLOAD] 命令、
[MACHINEWORD] 参照。
CALL P%(A%,B%,C%[0] では、引数の取り出しは、C言語の場合は次のとうりです。
arg[0]は1stのArgumentのPointer、arg[1]は
2ndのArgumentのPointer、、、です。
void main( argv
char *argv[];
{
short i,j,k;
short *ii,*jj,*kk;
ii=( short*)(argv[0]);
i=*ii; //This is A%
jj=(short*)(argv[1]);
j=*jj; //This is B%
kk=(short*)(argv[2]);
k=*kk; //This is C%
........
}
CALL P%(A%,B%,C%[0] では、引数の取り出しは、Assemblerの場合は次のとうりです。
void main( argv)
char *argv[];
{
_ASM{
MOV ECX, DWORD PTR 4[ESP];//In case of not use ESI,EDI,EBP.
MOV ECX, DWORD PTR [ECX];
MOV EDX,DWORD PTR [ECX}; //This is A%
MOV EAX,DWORD PTR 4[ECX}; //This is B%
MOV ECX,DWORD PTR 8[ECX}; //This is C%
、、、、、、
}//_ASM CLOSE
}
CALL P%(A%,B%,C%[0] では、Assemblerの場合は引数の取り出しは、次の方法が簡単です。
ESI,EDI,EBPの使用を考慮しなくても良いからです。
_ASM{
に入る前にCで取り出しをします。
void main( argv
char *argv[];
{
short *ii1,*ii2,*ii3;
ii1=(short*)(argv[0]); //This is A%
ii2=(short*)(argv[1]); //This is B%
ii3=(short*)(argv[2]); //This is C%
_asm {
MOV EBX,DWORD PTR ii1;
MOV ECX,DWORD PTR ii2;
MOV EDI,DWORD PTR ii3;
MOV AX,WORD PTR [EBX];
ADD AX,WORD PTR [ECX];
MOV WORD PTR [EDI],AX;
}//_ASM CLOSE
}
これはA%+B%をC%として書き換えをしています。