a21_txt02_12b
をテンプレートにして作成
[
トップ
] [
新規
|
一覧
|
単語検索
|
最終更新
|
ヘルプ
]
開始行:
* 「10日くらいでできる!プログラミング言語自作入門」の続...
-(by [[K]], 2021.06.09)
** (1) HL-22b
-HL-22aまでで、JITコンパイラの作り方の説明は一通りできた...
-普通のコンパイラなら、JITコンパイルした機械語を出力すれ...
----
-さてアセンブラを出力するといっても、アセンブラごとに多少...
--https://www.nasm.us/ まずここへいきます(ちなみに私は、...
--私は、画面上部のDOWNLOADを選んで、 https://www.nasm.us/...
--(それぞれ自分の環境に合わせてダウンロードしてください...
--zipの中にはnasm.exeがあるので、それを適当なところにコピ...
----
-次に考えたのは開発方針です。普通に考えれば、putIcX64()を...
-普通のコンパイラの世界では、コンパイラがアセンブラのソー...
--まあ結局、こんな変わった作り方をする人は少ないと思うの...
--この変な作り方のおかげで、HL-22bは普通のコンパイラとし...
----
-ということで、「codedump 2」にしたらアセンブラ用のソース...
prompt>hl22b mandel.c -asm
とするだけでいきなりソースコードが出てくるようになるので...
----
-[1]関数compile()を以下のように改造
int aryInitList[100], ailp; // この行追加.
char varOpt[MAX_TC + 1]; // この行追加.
int compile(String s)
{
int pc, pc1, i, j;
unsigned char *icq1, *icp;
pc1 = lexer(s, tc);
tc[pc1++] = TcSemi; // 末尾に「;」を付け忘れることが...
tc[pc1] = tc[pc1 + 1] = tc[pc1 + 2] = tc[pc1 + 3] = ...
icq = icq0 = ic;
! jp = ailp = 0;
icq1 = icqSet = 0;
putIcX64("41_57; 41_56; 41_55; 41_54; 41_53; 41_52;"...
putIcX64("41_51; 41_50; 57; 56; 55; 54; 53; 52; 51; ...
putIcX64("%R_81_ec_f8_01_00_00; %R_bd_%0q;", var, 0,...
regVarSaveLoad(RvLoad);
dump0 = icq;
for (i = 0; i < 10; i++) {
tmp_flag[i] = 0;
}
tmpLabelNo = 0;
for (i = 0; i < MAX_TC + 1; i++) {
vc[i] = 0;
! varOpt[i] = 0;
}
bd = lbd = 0;
toExit = tmpLabelAlloc();
for (pc = 0; pc < pc1; ) { // コンパイル開始.
(中略)
} else if (phrCmp( 0, "!!*0:", pc)) { // ラベル...
defLabel(tc[wpc[0]]); // ラベルに対応するicq...
+ varOpt[tc[wpc[0]]] |= 1;
} else if (phrCmp( 5, "goto !!*0;", pc)) { // go...
(中略)
} else if (phrCmp(22, "int !!*0[!!**2] = {", pc)...
e2 = expr(2);
#if (ABI_MSW64 != 0)
putIcX64("%R_8b_%1m1; %R_ff_%2m2; %R_89_...
#elif (ABI_SYSV64 != 0)
putIcX64("%R_8b_%1m7; %R_ff_%2m2; %R_89_...
#endif
j = 0;
for (i = ppc1; i < pc1; i++) { // コンマ以外...
if (tc[i] == TcCrBrCls) break;
if (tc[i] != TcComma) {
j++;
}
}
if (i >= pc1) goto err;
AInt *ip = malloc(j * sizeof (AInt));
j = 0;
for (i = ppc1; tc[i] != TcCrBrCls; i++) {
if (tc[i] == TcCrBrCls) break;
if (tc[i] != TcComma) {
ip[j] = var[tc[i]];
j++;
}
}
+ aryInitList[ailp] = icq - ic; // sub_aryInit...
+ ailp++;
#if (ABI_MSW64 != 0)
putIcX64("%R_8b_%0m1; %R_ba_%1q; 41_b8_%...
#elif (ABI_SYSV64 != 0)
! putIcX64("%R_8b_%0m7; %R_be_%1q; 40_ba_%...
#endif
ppc1 = i + 2; // } と ; の分.
} else if (phrCmpPutIcX86(23, "aSetPix0(!!***8, ...
(中略)
}
(中略)
for (i = 0; i < jp; i++) { // ジャンプ命令の最適化.
(中略)
}
+ if (codedump != 2) {
for (i = 0; i < jp; i++) { // ジャンプ先の設定(...
icq = jmps[i] + ic;
j = var[get32(icq)]; // ラベル番号を取得.
icp = j + ic; // icp=飛び先の命令列の先頭.
put32(icq, icp - (icq + 4));
}
+ }
return icq1 - ic;
(中略)
}
-[2]関数run()の直前に以下の関数群を追加
int rexB, rexX, rexR, rexW;
String regNamX64[2][16] = {
"EAX", "ECX", "EDX", "EBX", "ESP", "EBP", "ESI", "ED...
"RAX", "RCX", "RDX", "RBX", "RSP", "RBP", "RSI", "RD...
};
int modRmX64(unsigned char *p, char *s)
{
int c0 = *p;
if ((c0 & 0xc0) == 0xc0) {
strcpy(s, regNamX64[rexW][(c0 & 7) + rexB * 8]);
return 1;
}
if ((c0 & 0xc7) == 0x85 && rexB == 0) {
sprintf(s, "QWORD [RBP+.%s-.data0]", ts[get32(p ...
return 5;
}
if ((c0 & 0xc7) == 0x04 && p[1] == 0xca && rexB == 0...
sprintf(s, "QWORD [RDX+RCX*8]");
return 2;
}
if ((c0 & 0xc7) == 0x44 && p[1] == 0x24 && rexB == 0...
sprintf(s, "QWORD [RSP+%d]", p[2]);
return 3;
}
printf("modRmX64: error: %02x\n", c0);
exit(1);
}
String asmX64_sub1(int q, String p0, String s, String p1...
// (q) 1:modRmの直前の1バイトの下位3bitがレジスタを指定,...
// 4:8bit即値, 5:32bit即値, 6:64bit即値, 7:CL, 8:sub...
{
if (q == 1) { return regNamX64[rexW][(p0[-1] & 7) + ...
if (q == 2) { return regNamX64[rexW][((p0[0] >> 3) &...
if (q == 3) { return s; }
if (q == 4) { sprintf(t, "%d", *((signed char *) p1)...
if (q == 5) { sprintf(t, "%d", get32(p1)); return t; }
if (q == 7) { return "CL"; }
if (q == 8) { return ts[get32(p0 + 1) / 8]; }
if (q == 9) { sprintf(t, ".%s", ts[get32(p1)]); retu...
if (q == 6) {
int i = get32(p1), j = get32(p1 + 4);
sprintf(t, "0x%08x%08x", j, i);
for (j = 0; j < tcs; j++) {
if (var[j] == i && ts[j][0] == 34) {
sprintf(t, ".str%d", i);
varOpt[j] |= 2;
}
}
return t;
}
return "?";
}
int asmX64_sub0(unsigned char *p, String op)
// modRm: mod r/m があるかないか.
{
char s[100], t[100];
int len = 0, q0 = op[1] - '0', q1 = op[2] - '0', q2 ...
p++;
String p0 = p;
if (op[0] == 'm') {
len = modRmX64(p, s);
p += len;
}
printf(" %-8s", op + 4);
if (q0 > 0) { printf( "%s", asmX64_sub1(q0, p0, s, p...
if (q1 > 0) { printf(",%s", asmX64_sub1(q1, p0, s, p...
if (q2 > 0) { printf(",%s", asmX64_sub1(q2, p0, s, p...
printf("\n");
return len + 1;
}
char asmX64_jcc[16][4] = { "O", "NO", "B", "AE", "E", "N...
char asmX64_table0[][16] = {
"0039m230ADD", "02b9m230SUB", "0319m320XOR", "03b...
"0810m350ADD", "0814m350AND", "0815m350SUB", "081...
"0830m340ADD", "0834m340AND", "0835m340SUB", "083...
"0859m320TEST", "0899m320MOV", "08b9m230MOV", "099...
"0c39_000RET", "0c79m350MOV", "0e99_900JMP",
"0c14m340SHL", "0c15m340SHR", "0c17m340SAR", "0d34...
"0f73m300NEG", "0f75m300IMUL", "0f77m300IDIV", "0ff...
"1af9m230IMUL", "x"
};
void asmX64()
{
int i, j, k = 0;
if (dump0 == dump1) return;
printf("BITS 64\n");
printf("SECTION .text\n");
printf("GLOBAL aMain\n");
printf(" ALIGNB 16\n");
printf("aMain:\n");
for (i = 0; i < jp; i++) {
icq = jmps[i] + ic;
j = get32(icq);
varOpt[j] |= 1; // 利用したラベルをマークする.
}
for (i = TcSubPrint; i <= TcSubAryInit; i++) {
vc[i] = 0;
}
for (i = 0;;) {
for (j = 0; j < tcs; j++) {
if (var[j] == (AInt) i && (varOpt[j] & 1) !=...
printf(".%s:\n", ts[j]); // ラベル定義出...
}
}
rexW = rexR = rexX = rexB = 0;
int c0 = ic[i], c1;
if (0x40 <= c0 && c0 <= 0x4f) {
rexB = c0 & 1;
rexX = (c0 >> 1) & 1;
rexR = (c0 >> 2) & 1;
rexW = (c0 >> 3) & 1;
i++;
c0 = ic[i];
}
if (c0 == 0x0f) {
i++;
c0 = ic[i] + 0x100;
}
if (c0 == 0xbd && rexB == 0 && rexW != 0) {
printf(" MOV RBP,.data0\n");
i += 9;
continue;
}
if (k < ailp && aryInitList[k] + 8 == i) {
printf(" MOV %s,.ary%d\n", regNam...
i += 9;
k++;
continue;
}
String op = 0;
char t[16];
c1 = c0 & ~0xf;
if (c1 == 0x180) {
sprintf(t, "_900J%s", asmX64_jcc[c0 & 0xf]);
op = t;
goto skip;
}
if (c1 == 0x190) {
printf(" SET%-5sAL\n", asmX64_jcc[c0 ...
printf(" MOVZX EAX,AL\n");
i += 5;
continue;
}
c1 = c0 & ~0x7;
if (c1 == 0x050) { rexW = 1; op = "_100PUSH";...
if (c1 == 0x058) { rexW = 1; op = "_100POP"; ...
if (c1 == 0x0b8 && rexW == 0) { op = "_150MOV"; ...
if (c1 == 0x0b8 && rexW != 0) { op = "_160MOV"; ...
c1 = (ic[i + 1] >> 3) & 7;
for (j = 0; asmX64_table0[j][0] != 'x'; j++) {
op = &asmX64_table0[j][4];
if (c0 != getHex(op[-4]) * 256 + getHex(op[-...
if (op[-1] != '9' && c1 != op[-1] - '0') con...
goto skip;
}
printf("asmX64: error: %02x-%02x\n", c0, c1);
exit(1);
skip:
i += asmX64_sub0(&ic[i], op);
if (c0 == 0x0c3) break;
}
printf("EXTERN sub_print, sub_time, sub_aRgb8,...
printf("EXTERN sub_aGetPix, sub_f16Sin, sub_f16Cos...
printf("EXTERN sub_prints, sub_aSetPix0, sub_aFilRc...
printf("EXTERN sub_gprDec, sub_OpnWin, sub_aWait,...
printf("EXTERN sub_aryNew, sub_aryInit\n");
printf("SECTION .data\n");
printf(" ALIGNB 16\n");
printf(".data0:\n");
for (j = 0; j < tcs; j++) { // 普通の変数の出力.
if (vc[j] > 0) {
printf(".%-6s DQ %d\n", ts[j], var[j]);
}
}
for (k = 0; k < ailp; k++) { // 配列の初期値の出力.
AInt j1 = get32(&ic[aryInitList[k] + 19]), *ip =...
printf(".ary%d:\n", (int) ((AInt) ip & 0xfffffff...
for (j = 0; j < j1; j++) {
printf(" DQ %d\n", ip[j]);
}
}
for (j = 0; j < tcs; j++) { // 文字列リテラルの出力.
if ((varOpt[j] & 2) != 0) {
printf(".str%d DQ %s,0\n", var[j], ts[j]);
}
}
}
-[3]関数run()を以下のように改造
int run(String s)
{
if (compile(s) < 0)
return 1;
if (codedump == 0) {
void (*func)() = (void (*)()) ic;
t0 = clock();
func();
if (win != 0) {
aFlushAll(win);
}
! } else if (codedump == 1) {
int i, i1 = dump1 - dump0;
for (i = 0; i < i1; i++) {
printf("%02x ", dump0[i]);
}
printf("\n(len=%d)\n", i1);
for (i = 0; i < MAX_TC + 1; i++) {
if (vc[i] != 0) {
printf("#%04d(%08x): %06d: %s\n", i, (in...
}
}
+ } else if (codedump == 2) {
+ asmX86();
}
return 0;
}
-[4]関数aMain()を以下のように改造
void aMain()
{
(中略)
if (aArgc >= 2) {
int wait = 0;
if (aArgc >= 3) {
if (strcmp(aArgv[2], "-asm") == 0) { codedum...
if (strcmp(aArgv[2], "-wait") == 0) { wait =...
}
if (loadText((String) aArgv[1], txt, 10000) == 0...
run(txt);
if (win != 0) { aWait(wait); }
}
exit(0);
}
(中略)
}
----
-以上すべての改造を終えると、プログラムは1440行になります...
-''(以下編集中)''
-それでは早速動かしてみます。
>codedump 2
>run maze.c
BITS 32
SECTION .text
GLOBAL _aMain
ALIGNB 16
_aMain:
PUSHAD
SUB ESP,124
MOV EAX,752
MOV DWORD [ESP+0],EAX
MOV EAX,496
MOV DWORD [ESP+4],EAX
MOV EAX,.str36703696
MOV DWORD [ESP+8],EAX
CALL _sub_OpnWin
(中略)
.d DD 0
.dd DD 0
.23 DD 23
.15 DD 15
.str36703696 DD "maze",0
-この出力部分(「BITS 32」以降の部分)をコピー&ペースト...
--もしくは「 prompt>hl16b maze.c -asm > maze_asm.nas 」で...
-これを
prompt>nasm -f win32 -o maze_asm.obj maze_asm.nas
としてアセンブルします。-fはelf32とかにすることもできます...
-さらに実行ファイルを作りたいわけですが、そのためには前も...
#include <acl.c>
AWindow *win;
void sub_print(int i) { printf("%d\n", ...
void sub_time() { printf("time: %...
int sub_aRgb8(int r, int g, int b) { return aRgb8(r,...
int sub_XorShift() { return aXorShif...
int sub_aGetPix(int x, int y) { return aGetPix(...
int sub_f16Sin(int x) { return (int) (s...
int sub_f16Cos(int x) { return (int) (c...
int sub_aInkey(int opt) { return aInkey(w...
void sub_prints(char *s) { printf("%s\n", ...
void sub_aSetPix0(int x, int y, int c) { aSetPix0(win, x...
void sub_aFilRct0(int xsz, int ysz, int x0, int y0, int ...
void sub_aDrwStr0(int x, int y, int c, int b, char *s) ...
void sub_gprDec(int x, int y, int w, int c, int b, int i...
int sub_OpnWin(int xsz, int ysz, char *s)
{
win = aOpenWin(xsz, ysz, s, 0);
return 0;
}
int sub_aWait(int msec)
{
aWait(msec);
return 0;
}
void sub_bitblt(int xsz, int ysz, int x0, int y0, int *a)
{
AInt32 *p32 = &win->buf[x0 + y0 * win->xsiz];
int i, j;
for (j = 0; j < ysz; j++) {
for (i = 0; i < xsz; i++) {
p32[i] = a[i];
}
a += xsz;
p32 += win->xsiz;
}
}
AInt *sub_aryNew(int n)
{
int *p = malloc(n * sizeof (AInt));
memset((char *) p, 0, n * sizeof (AInt));
return p;
}
void sub_aryInit(AInt *a, AInt *ip, int n)
{
memcpy((char *) a, (char *) ip, n * sizeof (AInt));
}
-これを以下の手順でコンパイルして、sub32.objを作っておき...
prompt>gcc -m32 -Wno-unused-function -O3 -I (acl-winへの...
-sub32.objとmaze_asm.objから、maze_asm.exeを生成できます。
prompt>gcc -Wl,-s -o maze_asm.exe maze_asm.obj sub32.obj...
本当はldコマンドでリンクすべきなのですが、指定しなければ...
-こちらで試したところ、15.0KBのmaze_asm.exeが生成されまし...
** (2) プログラムの説明
-まず全体的な改造の構成を説明したいと思います。
--基本的には、compile()が生成した機械語を逆アセンブルして...
--[1]文字列リテラルの値は、文字列へのポインタが定数として...
それで、あとで文字列リテラルの内容を.dataセクション内に展...
--[2]初期値付きの配列宣言の場合、初期値テーブルを.dataセ...
--[3]初期値付きの配列宣言のところで、putIcX86()の内容を少...
旧: putIcX86("8b_%0m0; 89_44_24_00; b8_%1i; 89_44_24_04;...
新: putIcX86( "89_44_24_00; b8_%0i; 89_44_24_04;...
これは最初の8b命令が、直前の89命令の関係でoptimizerX86()...
--[4]アセンブラで出力することを考えると、JMP命令やJcc命令...
--[5]asmX86()関数では、ラベル宣言に関して、プログラム内で...
-それ以外の部分はこんな感じです。
--regNamX86[] : レジスタ番号をレジスタ名に変換するための...
--modRmX86(p, s) : pに mod r/m の機械語のアドレスを渡すと...
--asmX86_sub1(q, p0, s, p1, t) : qで指定された情報を返し...
---q=1: modRmの直前の1バイトの下位3bitによるレジスタ指定(...
---q=2: modRm内の中間3bitによるレジスタ指定
---q=3: modRmを解釈した結果
---q=4: 8bit即値
---q=5: 32bit即値
---q=6: CL
---q=7: sub関数呼び出し
---q=8: JMP/Jccの分岐先ラベル
--asmX86_sub0(p, op) : 1命令を指定された形式で逆アセンブ...
--asmX86_jcc[] : Jcc命令の表です。
--asmX86_table0[][] : アセンブラの命令の表です。
---(例)"0039m230ADD"
---最初の"0"は、頭に0x0fが付かないことを表します。
---次の"03"は機械語命令が0x03であることを表します。
---次の"9"はmod r/m の中の3ビットで命令が変化しないことを...
---次の"m"は、この命令はmod r/mフィールドを有するという意...
---次の"230"はasmX86_sub1()のためのqの値です。
---最後の"ADD"が命令名です。
--asmX86() : アセンブラ出力のメインルーチンです。
** 次回に続く
*こめんと欄
#comment
終了行:
* 「10日くらいでできる!プログラミング言語自作入門」の続...
-(by [[K]], 2021.06.09)
** (1) HL-22b
-HL-22aまでで、JITコンパイラの作り方の説明は一通りできた...
-普通のコンパイラなら、JITコンパイルした機械語を出力すれ...
----
-さてアセンブラを出力するといっても、アセンブラごとに多少...
--https://www.nasm.us/ まずここへいきます(ちなみに私は、...
--私は、画面上部のDOWNLOADを選んで、 https://www.nasm.us/...
--(それぞれ自分の環境に合わせてダウンロードしてください...
--zipの中にはnasm.exeがあるので、それを適当なところにコピ...
----
-次に考えたのは開発方針です。普通に考えれば、putIcX64()を...
-普通のコンパイラの世界では、コンパイラがアセンブラのソー...
--まあ結局、こんな変わった作り方をする人は少ないと思うの...
--この変な作り方のおかげで、HL-22bは普通のコンパイラとし...
----
-ということで、「codedump 2」にしたらアセンブラ用のソース...
prompt>hl22b mandel.c -asm
とするだけでいきなりソースコードが出てくるようになるので...
----
-[1]関数compile()を以下のように改造
int aryInitList[100], ailp; // この行追加.
char varOpt[MAX_TC + 1]; // この行追加.
int compile(String s)
{
int pc, pc1, i, j;
unsigned char *icq1, *icp;
pc1 = lexer(s, tc);
tc[pc1++] = TcSemi; // 末尾に「;」を付け忘れることが...
tc[pc1] = tc[pc1 + 1] = tc[pc1 + 2] = tc[pc1 + 3] = ...
icq = icq0 = ic;
! jp = ailp = 0;
icq1 = icqSet = 0;
putIcX64("41_57; 41_56; 41_55; 41_54; 41_53; 41_52;"...
putIcX64("41_51; 41_50; 57; 56; 55; 54; 53; 52; 51; ...
putIcX64("%R_81_ec_f8_01_00_00; %R_bd_%0q;", var, 0,...
regVarSaveLoad(RvLoad);
dump0 = icq;
for (i = 0; i < 10; i++) {
tmp_flag[i] = 0;
}
tmpLabelNo = 0;
for (i = 0; i < MAX_TC + 1; i++) {
vc[i] = 0;
! varOpt[i] = 0;
}
bd = lbd = 0;
toExit = tmpLabelAlloc();
for (pc = 0; pc < pc1; ) { // コンパイル開始.
(中略)
} else if (phrCmp( 0, "!!*0:", pc)) { // ラベル...
defLabel(tc[wpc[0]]); // ラベルに対応するicq...
+ varOpt[tc[wpc[0]]] |= 1;
} else if (phrCmp( 5, "goto !!*0;", pc)) { // go...
(中略)
} else if (phrCmp(22, "int !!*0[!!**2] = {", pc)...
e2 = expr(2);
#if (ABI_MSW64 != 0)
putIcX64("%R_8b_%1m1; %R_ff_%2m2; %R_89_...
#elif (ABI_SYSV64 != 0)
putIcX64("%R_8b_%1m7; %R_ff_%2m2; %R_89_...
#endif
j = 0;
for (i = ppc1; i < pc1; i++) { // コンマ以外...
if (tc[i] == TcCrBrCls) break;
if (tc[i] != TcComma) {
j++;
}
}
if (i >= pc1) goto err;
AInt *ip = malloc(j * sizeof (AInt));
j = 0;
for (i = ppc1; tc[i] != TcCrBrCls; i++) {
if (tc[i] == TcCrBrCls) break;
if (tc[i] != TcComma) {
ip[j] = var[tc[i]];
j++;
}
}
+ aryInitList[ailp] = icq - ic; // sub_aryInit...
+ ailp++;
#if (ABI_MSW64 != 0)
putIcX64("%R_8b_%0m1; %R_ba_%1q; 41_b8_%...
#elif (ABI_SYSV64 != 0)
! putIcX64("%R_8b_%0m7; %R_be_%1q; 40_ba_%...
#endif
ppc1 = i + 2; // } と ; の分.
} else if (phrCmpPutIcX86(23, "aSetPix0(!!***8, ...
(中略)
}
(中略)
for (i = 0; i < jp; i++) { // ジャンプ命令の最適化.
(中略)
}
+ if (codedump != 2) {
for (i = 0; i < jp; i++) { // ジャンプ先の設定(...
icq = jmps[i] + ic;
j = var[get32(icq)]; // ラベル番号を取得.
icp = j + ic; // icp=飛び先の命令列の先頭.
put32(icq, icp - (icq + 4));
}
+ }
return icq1 - ic;
(中略)
}
-[2]関数run()の直前に以下の関数群を追加
int rexB, rexX, rexR, rexW;
String regNamX64[2][16] = {
"EAX", "ECX", "EDX", "EBX", "ESP", "EBP", "ESI", "ED...
"RAX", "RCX", "RDX", "RBX", "RSP", "RBP", "RSI", "RD...
};
int modRmX64(unsigned char *p, char *s)
{
int c0 = *p;
if ((c0 & 0xc0) == 0xc0) {
strcpy(s, regNamX64[rexW][(c0 & 7) + rexB * 8]);
return 1;
}
if ((c0 & 0xc7) == 0x85 && rexB == 0) {
sprintf(s, "QWORD [RBP+.%s-.data0]", ts[get32(p ...
return 5;
}
if ((c0 & 0xc7) == 0x04 && p[1] == 0xca && rexB == 0...
sprintf(s, "QWORD [RDX+RCX*8]");
return 2;
}
if ((c0 & 0xc7) == 0x44 && p[1] == 0x24 && rexB == 0...
sprintf(s, "QWORD [RSP+%d]", p[2]);
return 3;
}
printf("modRmX64: error: %02x\n", c0);
exit(1);
}
String asmX64_sub1(int q, String p0, String s, String p1...
// (q) 1:modRmの直前の1バイトの下位3bitがレジスタを指定,...
// 4:8bit即値, 5:32bit即値, 6:64bit即値, 7:CL, 8:sub...
{
if (q == 1) { return regNamX64[rexW][(p0[-1] & 7) + ...
if (q == 2) { return regNamX64[rexW][((p0[0] >> 3) &...
if (q == 3) { return s; }
if (q == 4) { sprintf(t, "%d", *((signed char *) p1)...
if (q == 5) { sprintf(t, "%d", get32(p1)); return t; }
if (q == 7) { return "CL"; }
if (q == 8) { return ts[get32(p0 + 1) / 8]; }
if (q == 9) { sprintf(t, ".%s", ts[get32(p1)]); retu...
if (q == 6) {
int i = get32(p1), j = get32(p1 + 4);
sprintf(t, "0x%08x%08x", j, i);
for (j = 0; j < tcs; j++) {
if (var[j] == i && ts[j][0] == 34) {
sprintf(t, ".str%d", i);
varOpt[j] |= 2;
}
}
return t;
}
return "?";
}
int asmX64_sub0(unsigned char *p, String op)
// modRm: mod r/m があるかないか.
{
char s[100], t[100];
int len = 0, q0 = op[1] - '0', q1 = op[2] - '0', q2 ...
p++;
String p0 = p;
if (op[0] == 'm') {
len = modRmX64(p, s);
p += len;
}
printf(" %-8s", op + 4);
if (q0 > 0) { printf( "%s", asmX64_sub1(q0, p0, s, p...
if (q1 > 0) { printf(",%s", asmX64_sub1(q1, p0, s, p...
if (q2 > 0) { printf(",%s", asmX64_sub1(q2, p0, s, p...
printf("\n");
return len + 1;
}
char asmX64_jcc[16][4] = { "O", "NO", "B", "AE", "E", "N...
char asmX64_table0[][16] = {
"0039m230ADD", "02b9m230SUB", "0319m320XOR", "03b...
"0810m350ADD", "0814m350AND", "0815m350SUB", "081...
"0830m340ADD", "0834m340AND", "0835m340SUB", "083...
"0859m320TEST", "0899m320MOV", "08b9m230MOV", "099...
"0c39_000RET", "0c79m350MOV", "0e99_900JMP",
"0c14m340SHL", "0c15m340SHR", "0c17m340SAR", "0d34...
"0f73m300NEG", "0f75m300IMUL", "0f77m300IDIV", "0ff...
"1af9m230IMUL", "x"
};
void asmX64()
{
int i, j, k = 0;
if (dump0 == dump1) return;
printf("BITS 64\n");
printf("SECTION .text\n");
printf("GLOBAL aMain\n");
printf(" ALIGNB 16\n");
printf("aMain:\n");
for (i = 0; i < jp; i++) {
icq = jmps[i] + ic;
j = get32(icq);
varOpt[j] |= 1; // 利用したラベルをマークする.
}
for (i = TcSubPrint; i <= TcSubAryInit; i++) {
vc[i] = 0;
}
for (i = 0;;) {
for (j = 0; j < tcs; j++) {
if (var[j] == (AInt) i && (varOpt[j] & 1) !=...
printf(".%s:\n", ts[j]); // ラベル定義出...
}
}
rexW = rexR = rexX = rexB = 0;
int c0 = ic[i], c1;
if (0x40 <= c0 && c0 <= 0x4f) {
rexB = c0 & 1;
rexX = (c0 >> 1) & 1;
rexR = (c0 >> 2) & 1;
rexW = (c0 >> 3) & 1;
i++;
c0 = ic[i];
}
if (c0 == 0x0f) {
i++;
c0 = ic[i] + 0x100;
}
if (c0 == 0xbd && rexB == 0 && rexW != 0) {
printf(" MOV RBP,.data0\n");
i += 9;
continue;
}
if (k < ailp && aryInitList[k] + 8 == i) {
printf(" MOV %s,.ary%d\n", regNam...
i += 9;
k++;
continue;
}
String op = 0;
char t[16];
c1 = c0 & ~0xf;
if (c1 == 0x180) {
sprintf(t, "_900J%s", asmX64_jcc[c0 & 0xf]);
op = t;
goto skip;
}
if (c1 == 0x190) {
printf(" SET%-5sAL\n", asmX64_jcc[c0 ...
printf(" MOVZX EAX,AL\n");
i += 5;
continue;
}
c1 = c0 & ~0x7;
if (c1 == 0x050) { rexW = 1; op = "_100PUSH";...
if (c1 == 0x058) { rexW = 1; op = "_100POP"; ...
if (c1 == 0x0b8 && rexW == 0) { op = "_150MOV"; ...
if (c1 == 0x0b8 && rexW != 0) { op = "_160MOV"; ...
c1 = (ic[i + 1] >> 3) & 7;
for (j = 0; asmX64_table0[j][0] != 'x'; j++) {
op = &asmX64_table0[j][4];
if (c0 != getHex(op[-4]) * 256 + getHex(op[-...
if (op[-1] != '9' && c1 != op[-1] - '0') con...
goto skip;
}
printf("asmX64: error: %02x-%02x\n", c0, c1);
exit(1);
skip:
i += asmX64_sub0(&ic[i], op);
if (c0 == 0x0c3) break;
}
printf("EXTERN sub_print, sub_time, sub_aRgb8,...
printf("EXTERN sub_aGetPix, sub_f16Sin, sub_f16Cos...
printf("EXTERN sub_prints, sub_aSetPix0, sub_aFilRc...
printf("EXTERN sub_gprDec, sub_OpnWin, sub_aWait,...
printf("EXTERN sub_aryNew, sub_aryInit\n");
printf("SECTION .data\n");
printf(" ALIGNB 16\n");
printf(".data0:\n");
for (j = 0; j < tcs; j++) { // 普通の変数の出力.
if (vc[j] > 0) {
printf(".%-6s DQ %d\n", ts[j], var[j]);
}
}
for (k = 0; k < ailp; k++) { // 配列の初期値の出力.
AInt j1 = get32(&ic[aryInitList[k] + 19]), *ip =...
printf(".ary%d:\n", (int) ((AInt) ip & 0xfffffff...
for (j = 0; j < j1; j++) {
printf(" DQ %d\n", ip[j]);
}
}
for (j = 0; j < tcs; j++) { // 文字列リテラルの出力.
if ((varOpt[j] & 2) != 0) {
printf(".str%d DQ %s,0\n", var[j], ts[j]);
}
}
}
-[3]関数run()を以下のように改造
int run(String s)
{
if (compile(s) < 0)
return 1;
if (codedump == 0) {
void (*func)() = (void (*)()) ic;
t0 = clock();
func();
if (win != 0) {
aFlushAll(win);
}
! } else if (codedump == 1) {
int i, i1 = dump1 - dump0;
for (i = 0; i < i1; i++) {
printf("%02x ", dump0[i]);
}
printf("\n(len=%d)\n", i1);
for (i = 0; i < MAX_TC + 1; i++) {
if (vc[i] != 0) {
printf("#%04d(%08x): %06d: %s\n", i, (in...
}
}
+ } else if (codedump == 2) {
+ asmX86();
}
return 0;
}
-[4]関数aMain()を以下のように改造
void aMain()
{
(中略)
if (aArgc >= 2) {
int wait = 0;
if (aArgc >= 3) {
if (strcmp(aArgv[2], "-asm") == 0) { codedum...
if (strcmp(aArgv[2], "-wait") == 0) { wait =...
}
if (loadText((String) aArgv[1], txt, 10000) == 0...
run(txt);
if (win != 0) { aWait(wait); }
}
exit(0);
}
(中略)
}
----
-以上すべての改造を終えると、プログラムは1440行になります...
-''(以下編集中)''
-それでは早速動かしてみます。
>codedump 2
>run maze.c
BITS 32
SECTION .text
GLOBAL _aMain
ALIGNB 16
_aMain:
PUSHAD
SUB ESP,124
MOV EAX,752
MOV DWORD [ESP+0],EAX
MOV EAX,496
MOV DWORD [ESP+4],EAX
MOV EAX,.str36703696
MOV DWORD [ESP+8],EAX
CALL _sub_OpnWin
(中略)
.d DD 0
.dd DD 0
.23 DD 23
.15 DD 15
.str36703696 DD "maze",0
-この出力部分(「BITS 32」以降の部分)をコピー&ペースト...
--もしくは「 prompt>hl16b maze.c -asm > maze_asm.nas 」で...
-これを
prompt>nasm -f win32 -o maze_asm.obj maze_asm.nas
としてアセンブルします。-fはelf32とかにすることもできます...
-さらに実行ファイルを作りたいわけですが、そのためには前も...
#include <acl.c>
AWindow *win;
void sub_print(int i) { printf("%d\n", ...
void sub_time() { printf("time: %...
int sub_aRgb8(int r, int g, int b) { return aRgb8(r,...
int sub_XorShift() { return aXorShif...
int sub_aGetPix(int x, int y) { return aGetPix(...
int sub_f16Sin(int x) { return (int) (s...
int sub_f16Cos(int x) { return (int) (c...
int sub_aInkey(int opt) { return aInkey(w...
void sub_prints(char *s) { printf("%s\n", ...
void sub_aSetPix0(int x, int y, int c) { aSetPix0(win, x...
void sub_aFilRct0(int xsz, int ysz, int x0, int y0, int ...
void sub_aDrwStr0(int x, int y, int c, int b, char *s) ...
void sub_gprDec(int x, int y, int w, int c, int b, int i...
int sub_OpnWin(int xsz, int ysz, char *s)
{
win = aOpenWin(xsz, ysz, s, 0);
return 0;
}
int sub_aWait(int msec)
{
aWait(msec);
return 0;
}
void sub_bitblt(int xsz, int ysz, int x0, int y0, int *a)
{
AInt32 *p32 = &win->buf[x0 + y0 * win->xsiz];
int i, j;
for (j = 0; j < ysz; j++) {
for (i = 0; i < xsz; i++) {
p32[i] = a[i];
}
a += xsz;
p32 += win->xsiz;
}
}
AInt *sub_aryNew(int n)
{
int *p = malloc(n * sizeof (AInt));
memset((char *) p, 0, n * sizeof (AInt));
return p;
}
void sub_aryInit(AInt *a, AInt *ip, int n)
{
memcpy((char *) a, (char *) ip, n * sizeof (AInt));
}
-これを以下の手順でコンパイルして、sub32.objを作っておき...
prompt>gcc -m32 -Wno-unused-function -O3 -I (acl-winへの...
-sub32.objとmaze_asm.objから、maze_asm.exeを生成できます。
prompt>gcc -Wl,-s -o maze_asm.exe maze_asm.obj sub32.obj...
本当はldコマンドでリンクすべきなのですが、指定しなければ...
-こちらで試したところ、15.0KBのmaze_asm.exeが生成されまし...
** (2) プログラムの説明
-まず全体的な改造の構成を説明したいと思います。
--基本的には、compile()が生成した機械語を逆アセンブルして...
--[1]文字列リテラルの値は、文字列へのポインタが定数として...
それで、あとで文字列リテラルの内容を.dataセクション内に展...
--[2]初期値付きの配列宣言の場合、初期値テーブルを.dataセ...
--[3]初期値付きの配列宣言のところで、putIcX86()の内容を少...
旧: putIcX86("8b_%0m0; 89_44_24_00; b8_%1i; 89_44_24_04;...
新: putIcX86( "89_44_24_00; b8_%0i; 89_44_24_04;...
これは最初の8b命令が、直前の89命令の関係でoptimizerX86()...
--[4]アセンブラで出力することを考えると、JMP命令やJcc命令...
--[5]asmX86()関数では、ラベル宣言に関して、プログラム内で...
-それ以外の部分はこんな感じです。
--regNamX86[] : レジスタ番号をレジスタ名に変換するための...
--modRmX86(p, s) : pに mod r/m の機械語のアドレスを渡すと...
--asmX86_sub1(q, p0, s, p1, t) : qで指定された情報を返し...
---q=1: modRmの直前の1バイトの下位3bitによるレジスタ指定(...
---q=2: modRm内の中間3bitによるレジスタ指定
---q=3: modRmを解釈した結果
---q=4: 8bit即値
---q=5: 32bit即値
---q=6: CL
---q=7: sub関数呼び出し
---q=8: JMP/Jccの分岐先ラベル
--asmX86_sub0(p, op) : 1命令を指定された形式で逆アセンブ...
--asmX86_jcc[] : Jcc命令の表です。
--asmX86_table0[][] : アセンブラの命令の表です。
---(例)"0039m230ADD"
---最初の"0"は、頭に0x0fが付かないことを表します。
---次の"03"は機械語命令が0x03であることを表します。
---次の"9"はmod r/m の中の3ビットで命令が変化しないことを...
---次の"m"は、この命令はmod r/mフィールドを有するという意...
---次の"230"はasmX86_sub1()のためのqの値です。
---最後の"ADD"が命令名です。
--asmX86() : アセンブラ出力のメインルーチンです。
** 次回に続く
*こめんと欄
#comment
ページ名: