dword ACTUALMNEMDESC; // Указатель на описание текущей мнемоники byte ACTUALMNEMONIC; // Код текущей мнемоники byte OPERANDSIZE; // Размер операнда(B,W,D,BW,WB,DW) byte OPDESC[3]; // Типы операндов (R,E,D,CC,SR,TR,DR,CR) byte OPDATA[3]; // Информация по операнду (RG,CO,EA) dword OPCONST[3]; // Значение константы в операнде byte OPCONSTFLAG[3]; // Наличие константы в операнде byte OPCONSTSIZE[3]; // Размерность константы в операнде byte OPPOST[3]; dword OPPOSTREF[3]; byte PFLAG; // Значение P-флага (номер класса). byte RANDFLAG; // TRUE: RAND: требуется префикс 0x66 byte ADDRFLAG; // TRUE: ADDR: требуется префикс 0x67 byte WBIT; // Бит WORD в OPCODE byte DBIT; // Бит DIRECTION в OPCODE byte OPLENGTH; // Количество операндов в текущей инструкции byte EA_M; // Байт XRM byte EA_X; byte EA_R; // R NIBBLE IN XRM BYTE. byte EA_S; //SEGMENT REGISTER byte EA_R2; //BASE REGISTER byte EA_I; //INDEX REGISTER byte EADESC[2]; //CONTAINS INFORMATION ABOUT AN PARSED EFFECTIVE ADRESS. byte EALENGTH; // Количество регистров в EA byte EA_SIBFLAG; // Флаг наличия Sib в 32-битном EA byte EA_SCALING; // Индекс в Sib dword EA_SCALE; // Значение для Scale в Sib dword EADescInd; // Индекс в EADESC byte SEGREGISTER; // SEGMENT OVERRIDE PREFIX NEEDED OR 0. byte SYSRNUM; // CONTROL/DEBUG/TASKREG INDEX byte SYSRTYPE; // SYSTEM REGISTER TYPE (CR,CR4,DR,TR) byte SYSRCODE; // ENCODED REGISTER TYPE byte OVERRIDE; //SEGMENT OVERRIDE PREFIX NEEDED OR 0. dword opDescInd; dword prevTok; // ----- Ассемблирование строки Asm(dword str) byte holdcha; byte source[256],s[STRLEN],s2[STRLEN]; { lstrcpyA(#source,str); IF(list){ fprint(mapfile,"\t//\t"); fprint(mapfile,str); fprint(mapfile,"\n"); } holdcha=cha2; //запомнить позицию разбора $PUSH linenum2,inptr2,number,tok2,tok,input,inptr,currmod,linenumber, endoffile,displaytokerrors,type; lstrcpyA(#s,#string); lstrcpyA(#s2,#string2); input=#source; //разбираем новую строку inptr = input; inptr2=input; endoffile=0; // На начале файла NextChar(); cha2 = cha; inptr2=inptr; linenum2 = 1; for(;;){ NextTok(); IF(tok==tk_mnemonics)DoMnemonics(); ELSE IF(tok==tk_eof)BREAK; ELSE IF(tok==tk_locallabel)DoLocalPost(); ELSE IF(tok!=tk_semicolon)preerror("ASM: Bad input format\n"); } lstrcpyA(#string,#s); //востановить lstrcpyA(#string2,#s2); $POP type,displaytokerrors,endoffile,linenumber,currmod,inptr,input, tok,tok2,number,inptr2,linenum2; cha2=holdcha; } DoLocalPost() dword i; { tok = tk_number; number = outptr-output+OptImageBase+OptBaseOfCode; ESI=localptr; DSDWORD[ESI+localtok] = tok; DSDWORD[ESI+localnumber] = number; i=0; WHILE(i= MAXPOSTS)maxwordpostserror(); EBX=posts<<2+postloc; DSDWORD[EBX] = outptr; EBX=posts<<2+postnum; DSDWORD[EBX] = ref; EBX=posts<<2+posttype; DSDWORD[EBX] = ptype; posts++; } // ---- Пропуск до следующей записи в шаблоне инструкции SCDEND() { $LODSB IF(AL!=0){ $CMP AL,_END $JNE SCDEND illegaloperand(); $POP EAX; // Выход из MapOperands } } GETSCALING() { NextTok(); // Получим значение масштабного коэффициента IF(tok==tk_number){ DoScale: EA_SCALE=number; // Scale EA_SIBFLAG=1; // Отметим наличие Sib в 32-битном EA } ELSE preerror("ASM: Illegal scaling value\n"); } // ---- Поиск в шаблоне подходящей к операнду записи (для однооперандной инструкции) GETOL1() { if(DSBYTE[ESI]!=0){ // Инструкция JMP - не проверяем совпадение размеров G4: $LODSB AH=AL&NOLBITS; // Исключим число операндов if(NOTZEROFLAG){// Это все-таки JMP... DL=AL&OPBITS; // Маска для типа операнда IF(DL!=SOO){ // В поле размера операнда содержится информация о типе операнда? AL&=OLBITS; // Выделим количество операндов IF(AL!=OL1){ // Шаблон для инструкции с одним операндом? G3: do{ $LODSB // Просмотрим следующую запись шаблона IF(AL==0)GOTO G4; // Конец записи? }while(AL!=_END); // Это конец шаблона? illegaloperand(); // Нет подходящей записи для такой мнемоники $POP EAX; $RET // Выход из MapOperands } // Обработка записи шаблона G2: AL=AH&TRANSBITS; // Выделим размер операнда $CMP AL,_D $JBE G5 // Операнд м.б. размера: byte, word, dword $CMP AL,_OW $JNE J0 OPERANDSIZE=_W; GOTO G40; J0: $CMP AL,_OD; $JNE J1 OPERANDSIZE=_D; GOTO G40; J1: $CMP AL,NB $JB G90 // Операнд м.б. размера WB,DW OR BW. AL-=NB; // Пересчитаем для фиксированных размеров: NB->B,OW->W, AF->D G90: $CMP AL,OPERANDSIZE // Размер операнда и размер из шаблона совпали? $JNE G3 // Нет - смотрим следующую запись в шаблоне GOTO G40; // Размеры совпали - продолжим G5: $CMP AL,OPERANDSIZE // Размер операнда и размер из шаблона совпали? $JA G3 // Нет - смотрим следующую запись в шаблоне EBX=0; // WBIT/RANDFLAG=0 DL=AL; AL=OPERANDSIZE; IF(DL==_B)&&(AL!=_B)BL++; // $CMP DL,_B // В шаблоне byte? // $JNE G20 // $CMP AL,_B // Операнд byte? // $JE G20 // BL++; // W-бит=TRUE //G20: $CMP AL,_W // В шаблоне word? $JNE G30 $JA G30 BH++; // Операнд обязательно д.б. word - требуется префикс RAND G30: WBIT=BL; RANDFLAG=BH; // Запомним информацию о префиксе и W-бите G40: AH&=NTRANSBITS; // Оставим SOO биты } } } AL=AH; // Возвратим SOO поле } // ---- Разборка шаблона для двухоперандной инструкции GETOL2() { G7: $LODSB // Получим байт из шаблона AH=AL; AL&=OLBITS; // Выделим число операндов $CMP AL,OL2 // Число операндов = 2? $JE G8 // Да - начнем проверку G9: $LODSB // Поиск следующей записи в шаблоне $OR AL,AL // Конец записи? $JZ G7 // Да - проверим новую запись $CMP AL,_END // Конец шаблона? $JNE G9 // Смотри дальше иначе - ошибка toomuchoperands(); $POP EAX; $RET // Выход из MapOperands G8: AH&=NOLBITS; // Исключим число операндов AL=AH; AL&=TRANSBITS; // Выделим размер операнда $CMP AL,_D $JBE G100 // Операнд м.б. размера: byte, word, dword G94: $CMP AL,NB $JB J0 //G95 // Операнд м.б. размера WB,DW OR BW. AL-=NB; // Пересчитаем для фиксированных размеров: NB->B,OW->W, AF->D G95: $CMP AL,OPERANDSIZE // Размер операнда и размер из шаблона совпали? $JNE G9 // Размеры не совпали - ищем следующую запись $JMP G11 // Размеры совпали - продолжим J0: $CMP OPDESC[0],CO $JNE J1 $CMP AL,WB; $JNE J1 OPCONSTSIZE[0]=_W; OPCONSTSIZE[1]=_B; GOTO G11; J1: $CMP AL,_DW; $JNE J2; RANDFLAG=0; OPCONSTSIZE[0]=_D;// OPCONSTSIZE[1]=_W; GOTO G11; J2: $CMP AL,BW; $JNE G95 OPCONSTSIZE[0]=_B; OPCONSTSIZE[1]=_W; GOTO G11; G100: $CMP OPERANDSIZE,_D $JA NEAR G9 // Размер операнда > dword - на следующую запись $CMP OPERANDSIZE,AL $JB NEAR G9 // Размеры не совпали - ищем следующую запись EBX=0; DL=AL; AL=OPERANDSIZE; $CMP DL,_B // Размер в шаблоне = byte? $JNE G50 $CMP AL,_B // Размер операнда = byte? $JE G50 BL++; // W-бит=TRUE G50: $CMP AL,_W // В шаблоне word? $JNE G60 $JA G60 BH++; // Операнд обязательно д.б. word - требуется префикс RAND G60: WBIT=BL; RANDFLAG=BH; G11: AH&=NTRANSBITS; AL=AH; // Возвратим SOO поле } // ---- Разборка шаблона для трехоперандной инструкции GETOL3() { G12: $LODSB AH=AL; AL&=OLBITS; $CMP AL,OL3 $JE G13 G14: $LODSB //TRY NEXT ENTRY. $OR AL,AL $JZ G12 $CMP AL,_END $JNE G14 toomuchoperands(); $POP EAX; $RET // Выход из MapOperands G13: AH&=NOLBITS; $CMP OPERANDSIZE,_D //DWORD ? $JE G15 $CMP OPERANDSIZE,_W //WORD ? $JE G16 preerror("ASM: This instruction required a WORD/DWORD operand\n"); $RET G16: RANDFLAG=1; G15: AL=AH&0xE0; } // ---- CREATE_EA() { EA_M=AL&7; EA_X=3; } // ---- CREATE_R() { EA_R=AL&7; } // ---- Генеррация ModRM и Sib GETMODRMBYTE() { DL=EALENGTH; // Количество регистров в EA $OR DL,DL // Нет регистров в EA? $JE NEAR C11 // Да $TEST EADESC,_W+_D*8 $JE NEAR E1 // 8-битные регистры нельзя применать в адресе $TEST EADESC,_W*8 // 16-битный регистр? $JNE NEAR E4 // 16-битная адресация не разрешена GETEADISPX(); $CMP DH,2 $JNZ X00 EAX=opDescInd; OPCONSTSIZE[EAX]=_D; // Обязательно 32-битный disp X00: DL--; // 1 регистр? $JNE N1 // нет... AL=EADESC&7; $CMP EA_SIBFLAG,1 // Флаг наличия Sib в 32-битном EA $JNE L2 // Нет Sib EA_R2=5; // Фиксируем базовый регистр EA_M=4; EA_I=AL; EDX=opDescInd; $CMP OPCONSTFLAG[EDX],1 // Используем disp? $JE L1 EAX=0; OPCONSTFLAG[EDX]=1; EDX<<=2; OPCONST[EDX]=EAX; // disp=0 в EA L1: EDX=opDescInd; OPCONSTSIZE[EDX]=_D; EA_X=0; //EA_X=AL; $RET L2: EA_M=AL; $RET N1: EA_M=4; //2 REGISTERS USED. EA_SIBFLAG=1; AL=EADESC[1]>>3; $CMP AL,_W $JE E5 //ERROR: INDEX REGISTER ISN'T OF SIZE DWORD AL=EADESC; AH=EADESC[1]; EAX&=0x707; $CMP AH,5 //CAN'T USE BP AS INDEX. $JE E6 EA_R2=AL; EA_I=AH; $RET E1: preerror("ASM: You can't use byte registers in addresses\n"); $RET E4: preerror("ASM: 16-bit addressing mode not allowed\n"); $RET E5: preerror("ASM: You must use a 32-bit registers for scaling\n"); $RET E6: preerror("ASM: You can't use EBP as an index\n"); $RET C11: EA_X=0; EA_M=5; ECX=opDescInd; AL=OPCONSTSIZE[ECX]; IF(AL==_B)OPCONSTSIZE[ECX]=_D; ELSE IF(AL==_W)ADDRFLAG=1; } // ---- GETEADISPX() { //CREATE X NIBBLE OF DISPLACEMENT SIZE. DH=0; $PUSH ECX ECX=opDescInd; IF(OPCONSTFLAG[ECX]==1){ AL=OPCONSTSIZE[ECX]; DH=2; //(D)WORD DISPLACEMENT IF(AL==_B)DH--; //SBYTE DISPLACEMENT } EA_X=DH; $POP ECX } // ---- Инициализация буфера ассемблера INIT_LINE() { ECX=#opDescInd-#OPERANDSIZE; AL=0; EDI=#OPERANDSIZE; $REP $STOSB; AL=255; OPERANDSIZE=AL; SEGREGISTER=AL; } // ---- Запись переопределения сегмента WRITEOVERRIDE() { EBX=OVERRIDE; IF(BL!=0){ AL=OVERRIDETAB[EBX]-rES; OP(); } } // ---- Запись префикса размерности операнда WRITERAND() { $PUSH EAX IF(RANDFLAG==1){ AL=0x66; OP(); } $POP EAX } // ---- Запись константы: CL=TYPE; EDI указатель на значение WRITECONST() { IF(CL==_B)CL=1; ELSE IF(CL==_W)CL=2; ELSE IF(CL==_D)CL=4; ELSE CL++; loop(ECX){ AL=DSBYTE[EDI]; EDI++; OP(); } } // ---- Обработка Override GETOVERRIDE() { IF(tok==tk_seg)&&(tok2==tk_colon){ IF(OVERRIDE==0){ OVERRIDE=number; $STC // ∙ сегментного регистра } ELSE preerror("ASM: Double segment override"); NextTok(); NextTok(); // Пропускаем : } } // ---- Вычисление размера операнда: _B,_W,_D,WB,_DW & RAND-FLAG. AL=SIZE DEF_OPSIZE() { AH=OPERANDSIZE; IF(AH==255){ OPERANDSIZE=AL; // Один операнд return; } IF(AH==AL)return; // Размеры совпадают IF(AX==0X100){ // RW,RB ? RANDFLAG=1;// OPERANDSIZE=WB; return; } IF(AX==0X200){ // RD,RB ? IF(ACTUALMNEMDESC==#PCOMMANDS3_){ // OPERANDSIZE=_D; return; } OPERANDSIZE=WB; return; } IF(AX==0X201){ //RD,RW RANDFLAG=1; OPERANDSIZE=_DW; } } // ---- Запись префикса адресации WRITEADDR() { $PUSH EAX IF(ADDRFLAG==1){ AL=0x67; OP(); } $POP EAX } // ---- Определение размерности константы DefConstSize() { // Определим размерность константы EBX=opDescInd; DL=_D; IF(OPPOST[EBX]==0){ EBX=opDescInd<<2; EAX=OPCONST[EBX]; DL=_B; // byte IF(long EAX>=-128){ // -128 $CMP EAX,0XFF // 255 $JNG W2 } DL++; // _W - word IF(long EAX>=-32768){ $CMP EAX,0XFFFF // 65535 $JNG W2 } DL++; // _D - dword } W2: EBX=opDescInd; OPCONSTSIZE[EBX]=DL; OPCONSTFLAG[EBX]=1; } // ---- Обработка мнемоники ассемблера DoMnemonics() { opDescInd=0; EADescInd=0; INIT_LINE(); // Очистка буферов IF(number<24){ IF(number<8)EBX=#PCOMMANDS1; ELSE IF(number<12){ number-=8; EBX=#PCOMMANDS2; } ELSE IF(number<20){ number-=12; EBX=#PCOMMANDS3; } ELSE{ number-=20; EBX=#PCOMMANDS4; } number+=DSBYTE[EBX]; PFLAG=number; EBX++; } ELSE{ number-=24; EBX=number<<2; EBX=TAB_MNEMONICS[EBX]; IF(EBX>=#T_DAA)&&(EBX<#T_NOT){ // Проверим на наличие инструкции без операндов ACTUALMNEMDESC=EBX; IF(tok2==tk_semicolon)NextTok(); ESI=ACTUALMNEMDESC; $JMP CreateCode;// Генерация кода для инструкции без операндов } } ACTUALMNEMDESC=EBX; // Запомним указатель на текущий шаблон мнемоники for(;;){ // Цикл анализа операндов prevTok=tok; NextTok(); // Следующий операнд FastSearch(#string,#St_Sizes);// Это размер операнда? IF(CARRYFLAG){ // Да: byte,word или dword OPERANDSIZE=AL; // Запомним _B,_W,_D continue; } GETOVERRIDE(); // Обработка конструкции SEG: ContLine: // Точка для продолжения обработки текущего IF(tok==tk_eof)||(tok==tk_semicolon){ EBX=opDescInd; IF(OPDESC[EBX]==E){ // Обработка в EA? DefConstSize(); GETMODRMBYTE(); // EOL - GENERATE MODRM OPCODE BYTE. } IF(prevTok!=tk_mnemonics){ // Были операнды OPLENGTH++; IF(OPERANDSIZE==255){ OPERANDSIZE=_D; // Принудительно установим dword } } $JMP MapOperands } else IF(tok==tk_comma){ IF(opDescInd==3){ toomuchoperands(); break; } EBX=opDescInd; IF(OPDESC[EBX]==E){ // Обработка в EA? DefConstSize(); GETMODRMBYTE(); // EOL - GENERATE MODRM OPCODE BYTE. } opDescInd++; OPLENGTH++; } else IF(tok==tk_openblock){ EBX=opDescInd; OPDESC[EBX]=E; // Отметим, что работаем с EA операндом } else IF(tok==tk_closeblock){ // ] DefConstSize(); GETMODRMBYTE(); // EOL - GENERATE MODRM OPCODE BYTE. } else IF(tok==tk_minus){ IF(tok2 == tk_number){ NextTok(); number = -number; $JMP ContLine; // Продолжим docase без выборки след.token } } else IF(tok==tk_plus) continue; else IF(tok==tk_mult){ // * GETSCALING(); // Указан масшаб в Sib } else if(tok==tk_reg){ // Обработка регистра G0: EBX=opDescInd; IF(OPDESC[EBX]==E){ // Обработка в EA? IF(type==tk_byte){ preerror("ASM: No byte register in address\n"); return; } IF(EALENGTH<2){ // Количество регистров в EA < 2 ? EALENGTH++; // Отметим, что есть еще один регистр в EA EBX=EADescInd; EADESC[EBX]=number; // Запомним ∙ регистра EADescInd++; } ELSE{ // Слишком много регистров в EA preerror("ASM: too much registers in combination\n"); return; } } ELSE{ OPDATA[EBX]=number; // ∙ регистра OPDESC[EBX]=R; AH=number&7; EA_R=AH; IF(opDescInd!=2){ AL>>=3; DEF_OPSIZE(); } } } else IF(tok==tk_number) { // Обработка константы IF(tok2==tk_mult){ DoScale(); NextTok(); continue; } NUM: EBX=opDescInd<<2; OPCONST[EBX]+=number; // Запомним константу DefConstSize(); // Определим размерность константы IF(OPDESC[EBX]!=E) // Константа в EA? OPDESC[EBX]=CO; } else IF(tok==tk_postnumber){ EBX=opDescInd; OPPOST[EBX]=POST_DATA; EBX<<=2; OPPOSTREF[EBX]=treeptr; ESI=treeptr; DSDWORD[ESI+recpost]++; GOTO NUM; } else IF(tok==tk_proc){ IF(post){ EBX=opDescInd; OPPOST[EBX]=POST_CALL; EBX<<=2; OPPOSTREF[EBX]=treeptr; ESI=treeptr; DSDWORD[ESI+recpost]++; } $JMP NUM } else IF(tok==tk_locallabel){ EBX=opDescInd<<2; OPPOSTREF[EBX]=localptr; I2: EBX=opDescInd; $CMP ACTUALMNEMDESC,#T_JCXZ; $JB I1 $CMP ACTUALMNEMDESC,#T_CALLFAR; $JA I1 OPPOST[EBX]=POST_CALL; $JMP NUM I1: OPPOST[EBX]=POST_DATA; AL=_D; DEF_OPSIZE(); $JMP PARSE_EA1 } else IF(tok==tk_undefproc){ I0: EBX=opDescInd<<2; OPPOSTREF[EBX]=treeptr; GOTO I2; } else IF(tok==tk_id){ tok = tk_undefproc; post = 1; number=0; AddToTree(#string); GOTO I0; } else IF(tok==tk_var){ // Инициализация EA с константой: EA+disp AL=type-tk_byte>>1; // AL=размер адресуемого операнда (_B,_W,_D) DEF_OPSIZE(); EBX=opDescInd; IF(post){ EBX<<=2; OPPOSTREF[EBX]=treeptr; EBX=opDescInd; OPPOST[EBX]=POST_DATA; ESI=treeptr; DSDWORD[ESI+recpost]++; } PARSE_EA1: OPDESC[EBX]=E; OPCONSTFLAG[EBX]=1; // Отметим, что работаем с EA операндом EBX<<=2; OPCONST[EBX]+=number; // Запомним адрес } else IF(tok==tk_seg){ EBX=opDescInd; OPDATA[EBX]=number-rES; // ∙ сегментного регистра SEGREGISTER=AL; AL<<=3; // Создать код для XSM поля EA_S=AL; OPDESC[EBX]=_SR; AL=_W; DEF_OPSIZE(); } else IF(tok==tk_param)||(tok==tk_local){ PARSE_PAR: AL=type-tk_byte>>1; DEF_OPSIZE(); EBX=opDescInd; OPDESC[EBX]=E; EBX<<=2; // Отметим, что работаем с EA операндом OPCONST[EBX]+=number; // Запомним адрес OPCONSTFLAG[EBX]=1; number=rEBP; $JMP G0; } else IF(tok==tk_controlreg){ EBX=opDescInd; OPDESC[EBX]=SYSR; SYSRNUM=number; IF(AL==4)SYSRTYPE=_CR4; ELSE{ SYSRTYPE=_CR; SYSRCODE=0; } } ELSE IF(tok==tk_debugreg){ EBX=opDescInd; OPDESC[EBX]=SYSR; SYSRNUM=number; SYSRTYPE=_DR; SYSRCODE=1; } ELSE IF(tok==tk_testreg){ EBX=opDescInd; OPDESC[EBX]=SYSR; SYSRNUM=number; SYSRTYPE=_TR; SYSRCODE=4; } ELSE preerror("ASM: Syntax error\n"); } } CreateScale() { IF(ADDRFLAG)return; if(EA_SIBFLAG){ // Флаг наличия Sib в 32-битном EA IF(EA_SCALE==0){ // Отсутствует EA_SCALING=0; } else IF(EA_SCALE==1)EA_SCALING=0; else IF(EA_SCALE==2)EA_SCALING=0x40; ELSE IF(EA_SCALE==4)EA_SCALING=0x80; ELSE IF(EA_SCALE==8)EA_SCALING=0xC0; ELSE{ EA_SCALING=0; IF(EA_SCALE>255)OP(byte 0x69); ELSE OP(byte 0x6B); AL=EA_I<<3|EA_I|0xC0; OP(byte AL); IF(EA_SCALE>255)OUTDWORD(EA_SCALE); ELSE OP(byte EA_SCALE); } } } // ---- Генерация кода. ESI=ptr на запись о описание мнемоники (запись типа T_...) CreateCode() { WRITEOVERRIDE(); CreateScale(); IF(ADDRFLAG==1){ //ADDR: PREFIX ? OP(byte 0x67); } IF(RANDFLAG==1){ //RAND: PREFIX ? OP(byte 0x66); } EDI=ESI; IF(ACTUALMNEMDESC==#T_TEST)DBIT=0; //DON'T ADD ANYTHING IF TESTING $SHL DBIT,1 //SHIFT D-BIT TO THE RIGHT POSITION. NEXT_DESC_BYTE: // Обработка байта из дескриптора мнемоники EBX=0; BL=DSBYTE[EDI]; EDI++; NB3: $CMP BL,X7M $JA NC3 $CMP BL,X0M $JB N24 AH=BL-X0M; AL=EA_X<<3|AH<<3|EA_M; OP(); GOTO NEXT_DESC_BYTE; N24: EBX<<=2; EBX+=#Dsc_Jump; $JMP NEAR DSDWORD[EBX] NC3: $CMP BL,_END $JNE E42 $JMP CreateConstants // Конец шаблона для мнемоники E42: preerror("Descriptor damaged\n"); return; // OpCode - 1 байт Dsc_O: AL=DSBYTE[EDI]+WBIT+DBIT; EDI++; OP(); GOTO NEXT_DESC_BYTE; // OpCode - 1 слово Dsc_OW: AL=DSBYTE[EDI]; EDI++; OP(); AL=DSBYTE[EDI]+WBIT+DBIT; EDI++; OP(); $JMP NEXT_DESC_BYTE // OpCode - 1 байт и следующий байт, заданный 8-ричной строкой Dsc_OS: AL=DSBYTE[EDI]; EDI++; OP(); // OpCode - 8-ричная строка с кодом Dsc_S: S01: CL=3; EAX=0; loop(CL){ AL=DSBYTE[EDI]; EDI++; IF(AL=='X'){ //X CHAR AL=EA_X; } ELSE IF(AL=='R')AL=EA_R; ELSE IF(AL=='M')AL=EA_M; ELSE IF(AL=='S')AL=SEGREGISTER; ELSE IF(AL=='N')AL=SYSRNUM; ELSE IF(AL=='P')AL=PFLAG; ELSE AL-='0'; AH=AH<<3|AL; } AL=AH+DBIT+WBIT; N15: OP(); $JMP NEXT_DESC_BYTE // OpCode - ModRM байт Dsc_XRM: AL=EA_X<<3|EA_R<<3|EA_M; // Получить регистр из описания мнемоники GOTO N15; // OpCode - ModRM с P-флагом (арифметические инструкции) Dsc_XPM: AL=EA_X<<3|PFLAG<<3|EA_M; GOTO N15; // OpCode - ModRM с сегментным регистром Dsc_XSM: AL=EA_X<<3|SEGREGISTER<<3|EA_M; GOTO N15; // JMP NEXT_DESC_BYTE } // ---- Разбор закончен -> на генерацию кода по шаблону MapOperands() { // AL=0; WBIT=AL; DBIT=AL; opDescInd=0; ESI=ACTUALMNEMDESC; // Указатель на информацию по генерации AL=OPLENGTH; // Количество операндов ECX=#OPDESC; // Указатель на информацию об операндах ECX=DSDWORD[ECX]; IF(ESI!=#T_MOV){ // Инструкция MOV? IF(AL!=0){ $CMP AL,1 $JE NEAR ONEOP // Инструкция с одним операндом $CMP AL,2 $JE NEAR TWOOPS // Инструкция с двумя операндами $CMP AL,3 $JE NEAR THREEOPS // Инструкция с тремя операндами toomuchoperands(); return; } // ---- Инструкция без операндов do{ $LODSB IF(AL==0)goto CreateCode; // Генерация кода }while(AL!=_END); preerror("ASM: Operand required\n"); return; // ---- Генерация MOV инструкции } $PUSH EAX,ECX WRITEOVERRIDE(); CreateScale(); $POP ECX,EAX IF(AL!=2){ // 2 OPERANDS IN INSTRUCTION? preerror("ASM: Two operands required\n"); return; L2: preerror("ASM: Not same size\n"); return; } L1: BL=0; AL=OPERANDSIZE; IF(AL!=_D){ $CMP AL,_W $JA L2 $JNE N4 RANDFLAG=1; } BL=1; N4: WBIT=BL; //STORE W-BIT DL=0; //CLEAR D-BIT WRITEADDR(); EBX=0; BL=CL; EBX=EBX<<2+#Jmp_Mov; $JMP NEAR DSDWORD[EBX] Mov_ERR: preerror("ASM: a constant can't be used as a destination\n"); return; Mov_R: EBX=0; BL=CH; EBX=EBX<<2+#Jmp_Mov_R; $JMP NEAR DSDWORD[EBX] Mov_E: EBX=0; BL=CH; EBX=EBX<<2+#Jmp_Mov_E; $JMP NEAR DSDWORD[EBX] Mov_R2R: WRITERAND(); AL=OPDATA[1]; AH=OPDATA[0]; DL=DBIT; $PUSH EAX AL=0o210+WBIT; $SHL DL,1 AL+=DL; //D-BIT OP(); $POP EAX AL=AL&7<<3; AH&=7; AL=AL|AH|0o300; OP(); $JMP CreateConstants Mov_R2E: AL=OPDATA&7; //AL/AX/EAX ? $OR AL,AL $JNE N1 $CMP EA_M,6 //AR,[DW] POSSIBLE? $JNE N1 //NO, ONLY AR,[EA] $CMP ADDRFLAG,0 //32BIT-EA ? $JE N1 //NO, TRY ANOTHER... WRITERAND(); AL=0o240+WBIT; //INSTRUCTION FOUND. OP(); $JMP CreateConstants Mov_E2R: D1: AL=OPDATA[1]&7; //[DW],AR POSSIBLE? $OR AL,AL $JNE Y1 $CMP ADDRFLAG,0 //32BIT EA ? $JNE Y1 //YES, RAVE ON... $CMP EA_M,6 $JNE Y1 WRITERAND(); AL=0o242+WBIT; //INSTRUCTION FOUND. OP(); $JMP CreateConstants N1: DL=2; //SET D-BIT Y1: DL+=0o210; WRITERAND(); AL=DL; DL=0; AL+=WBIT; OP(); AL=EA_X<<3|EA_R<<3|EA_M; OP(); $JMP CreateConstants E1: preerror("ASM: Not same size\n"); return; //EA,CONSTANT ? Mov_E2C: OPCONSTSIZE[1]=OPERANDSIZE; $CMP AL,_D $JA E1 $JE X1 $CMP AL,_W $JNE X1 AL=0x66; OP(); X1: AL=0o306+WBIT; OP(); AL=EA_X<<6|EA_M; OP(); $JMP CreateConstants Mov_R2C: OPCONSTSIZE[1]=OPERANDSIZE; $CMP OPERANDSIZE,_B $JNE N2 AL=OPDATA&7|0o260; OP(); $JMP CreateConstants N2: $CMP OPERANDSIZE,_D //BYTE, WORD OR DWORD? $JA NEAR E1 // Not same size IF(OPERANDSIZE==_W){ AL=0x66; OP(); } AL=OPDATA&7|0o270; OP(); $JMP CreateConstants E21: preerror("ASM: Word required\n"); return; //SEGMENT REGISTER IS ALWAYS WORD. Mov_S: AL=0; $CMP CX,_SR*256+E // mov EA,segreg $JE O1 $CMP CX,_SR*256+R // mov segreg,reg $JE O2 $CMP CX,R*256+_SR // mov reg,segreg $JE O3 $CMP CX,E*256+_SR // mov segreg,EA $JNE NEAR N12 AL=2; //SET D-BIT O1: $CMP OPERANDSIZE,_W $JNE E21 AL+=0o214; OP(); AL=EA_X<<6|EA_S|EA_M; OP(); $JMP CreateConstants O2: $CMP OPERANDSIZE,_W $JNE E21 AL=0o214; OP(); AL=EA_S|0o300|EA_R; //CREATE XSM BYTE OP(); $STC $RET O3: $CMP OPERANDSIZE,_W $JNE NEAR E21 AL=0o216; OP(); AL=EA_S|0o300|EA_R; OP(); $STC $RET E31: preerror("ASM: CR1 only readable\n"); $RET E32: preerror("ASM: SysR must be dword\n"); $RET Mov_SYSR: N12: AH=0o40; $CMP CX,SYSR*256+R $JE O11 $CMP CX,R*256+SYSR $JNE N22 //ERROR: ILLEGAL OPERANDS AH=0o42; $CMP SYSRTYPE,_CR //CR1 REGISTER USED? $JNE O11 $CMP SYSRNUM,1 $JE E31 //YES, ONLY READ FROM IT. O11: AH+=SYSRCODE; $CMP OPERANDSIZE,_D //SYSTEM REGISTERS ARE ALWAYS DWORD. $JNE E32 AL=0o17; OP(); $CMP SYSRTYPE,_CR4 //EXCEPTION: CR4 $JE N22 AL=AH; OP(); AL=SYSRNUM<<3|0o300|EA_R; //CREATE 3NR OPCODE OP(); $STC $RET N22: $CMP CX,SYSR*256+R $JNE N32 AL=0x22; OP(); GOTO L11; N32: AL=0x20; OP(); L11: AL=0o340|EA_R; OP(); $STC $RET // ---- Инструкция с одним операндом ONEOP: EBX=CL<<2+#Jmp_Op1; $JMP NEAR DSDWORD[EBX] Op1ERR: preerror("ASM: only use system registers within MOV instruction\n"); $RET // RX L31: SCDEND(); Op1R: GETOL1(); //GET FIRST GENERATION INFO. $CMP AL,SOR //SINGLE OPERAND/REGISTER ? $JNE X23 $JMP CreateCode X23: $CMP AL,SOE //CONVERT REGISTER INTO EFFECTIVE ADDRESS? $JNE L31 C2: EA_X=3; AL=EA_R; EA_M=AL; $JMP CreateCode // EA L41: SCDEND(); Op1E: GETOL1(); $CMP AL,SOE //SINGLE OPERAND/EFFECTIVE ADDRESS ? $JNE X24; $JMP CreateCode X24: $CMP AL,SOM //SINGLE OPERAND/MEMORY POINTER ? $JNE L41 $CMP EA_X,0 $JNE L41 $CMP EA_M,6 //[WORD CONSTANT]? $JNE L41 C11: $JMP CreateCode // CO L51: SCDEND(); Op1C: GETOL1(); $OR AL,AL //JUMP INSTRUCTION? $JNE NEAR N13 // Здесь обработка call&jmp ECX=OPCONST[0]-OptImageBase-OptBaseOfCode-outptr+output; // Расчет относительного смещения $LODSB // Получим short или near $CMP AL,_JB // short? $JNE N14 ECX-=2; $CMP ECX,0xFFFFFF80 $JL L10 $CMP ECX,0x7F $JG L10 OPCONSTSIZE[0]=_B; H1: OPCONST[0]=ECX; $JMP CreateCode N14: EAX=0; $LODSB // Поправка на размер call или jmp ECX-=EAX; OPCONSTSIZE[0]=_D; GOTO H1; L10: $CMP ACTUALMNEMDESC,#T_JCXZ $JB L51 $CMP ACTUALMNEMDESC,#T_LOOP $JA NEAR L51 preerror("ASM: Jump range too long\n"); $RET N13: $CMP AL,SO3 //CONSTANT VALUE 3 ? $JNE N23 $CMP OPCONST[0],3 $JNE NEAR L51 OPCONSTFLAG[0]=0; //YES, AVOID CONSTANT GENERATION. $JMP CreateCode N23: $CMP AL,SOC //SINGLE OPERAND/CONSTANT? $JNE X25 OPCONSTSIZE[0]=OPERANDSIZE; $JMP CreateCode X25: $CMP AL,SOO_CC //SINGLE OPERAND/SIGNED BYTE ? $JNE NEAR L51 IF(OPPOST[0])$JMP L51 $CMP OPCONST[0],0x7F $JG NEAR L51 $CMP OPCONST[0],0xFFFFFF80 $JL NEAR L51 OPCONSTSIZE[0]=_B; $JMP CreateCode // SR L61: SCDEND(); Op1S: GETOL1(); $CMP AL,SOS //SINGLE OPERAND/SEGMENT REGISTER? $JNE L61 $JMP CreateCode // AF L71: SCDEND(); Op1AF: GETOL1(); $CMP AL,SOO_AF $JNE L71 $JMP CreateCode // ---- Инструкция с двумя операндами TWOOPS: EBX=CL<<2+#Jmp_Op2; $JMP NEAR DSDWORD[EBX] // Переход по типу первого операнда //Op2ERRC: // preerror("ASM: A constant can't be used as a destination\n"); // return; Op2ERRS: preerror("ASM: segment register can only be used within a MOV or PUSH\n"); return; Op2ERRSYS: preerror("ASM: only use system registers within MOV instruction\n"); return; Op2ERRAF: preerror("Absolute FAR addresses can only be used for jumps\n"); return; // Первый операнд в 2-операндной инструкции - регистр Op2R: EBX=0; BL=CH; EBX=EBX<<2+#Jmp_Op2R; $JMP NEAR DSDWORD[EBX] // Переход по типу второго операнда // Первый операнд в 2-операндной инструкции - EA Op2E: EBX=0; BL=CH; EBX=EBX<<2+#Jmp_Op2E; $JMP NEAR DSDWORD[EBX] // Переход по типу второго операнда // mnem EA,RX L81: SCDEND(); OpE2R: GETOL2(); // Обработка записи из шаблона $CMP AL,DER //EA & R + D-BIT ? $JE C21 X26: $CMP AL,ERO //'ERO' ORDER ? $JE C21 $CMP AL,EAO //EA, ? $JNE L81 // На пропуск записи в шаблоне $CMP OPDATA[1],rCL //CL REGISTER USED?? $JNE L81 // На пропуск записи в шаблоне $CMP DSBYTE[ESI+1],rCL //CL IN GENERATION INFO? $JNE L81 // На пропуск записи в шаблоне // CMP OPERANDSIZE,_B //YES, CHECK SIZE. // JNE L81 // На пропуск записи в шаблоне ESI++; ESI++; C21: $JMP CreateCode L91: SCDEND(); OpR2E: GETOL2(); $CMP AL,DER //DER ? $JNE N43 DBIT=1; //(DIRECTION BIT) $JMP CreateCode N43: $CMP AL,REO //REO ? $JNE L91; $JMP CreateCode //RX,RX ? W2: ESI++; GOTO W1; LA1: SCDEND(); OpR2R: $CMP DSBYTE[ESI],_B+OL2+EAO // байт+2оп+EAold? $JE W2 //EAO FOUND, R+R COMBINATION NOT PERMITTED. GETOL2(); // Обработка записи шаблона $CMP AL,DER // EA,reg или reg,EA с D/W-битом? $JNE N53 LB2: AL=OPDATA[0]; // Преобразуем регистр в EA CREATE_EA(); AL=OPDATA[1]; // Второй операнд CREATE_R(); $JMP CreateCode N53: $CMP AL,ERO $JE LB2 $CMP AL,REO $JNE N63 AL=OPDATA[1]; //RX,EP CREATE_EA(); AL=OPDATA[0]; CREATE_R(); $JMP CreateCode N63: $CMP AL,EAO $JNE LA1 // На пропуск записи в шаблоне W1: ECX=2; //COMPARE 2 OPERANDS. opDescInd=0; LX2: $LODSB // поле из записи шаблона $CMP AL,255 //1ST OPERAND OK. $JE L022 $CMP AL,AR //AL/AX/EAX? $JE OL2X_AR $CMP AL,rDX //DX? $JE OL2X_DX $CMP AL,rCL $JE OL2X_CL GOTO LA1; // На пропуск записи в шаблоне OL2X_AR: EBX=opDescInd; AH=OPDATA[EBX]&7; // Операнд из мнемоники $JNZ NEAR LA1 // На пропуск записи в шаблоне L022: opDescInd++; $LOOP LX2 GOTO L23; OL2X_DX: EBX=opDescInd; $CMP OPDATA[EBX],0o12 $JNE NEAR LA1 // На пропуск записи в шаблоне opDescInd++; $LOOP LX2 GOTO L23; OL2X_CL: EBX=opDescInd; $CMP OPDATA[EBX],rCL //CL $JNE NEAR LC1 opDescInd++; $LOOP LX2 $TEST OPDATA[0],8+16 //1ST REGISTER WORD/DWORD? $JZ L23 WBIT=1; //YES, SET W-BIT. L23: AL=OPDATA[0]; CREATE_EA(); $JMP CreateCode //EA,CONSTANT ? //EA,CONST? LB1: SCDEND(); OpE2C: GETOL2(); opDescInd=1; $CMP AL,ECO $JNE N73 OPCONSTSIZE[1]=OPERANDSIZE; $JMP CreateCode N73: $CMP AL,EAO $JNE N83 $CMP OPERANDSIZE,_B $JNE N83 $CMP DSBYTE[ESI],_1 $JNE N83 $CMP OPCONST[4],1 $JNE N83 OPCONSTFLAG[1]=0; ESI++; $JMP CreateCode N83: $CMP AL,ECCO //EA/SIGNED BYTE ? $JNE LB1 $CMP OPCONST[4],0xFFFFFF80 $JL LB1 $CMP OPCONST[4],0x7F $JG NEAR LB1 OPERANDSIZE=_B; //OMIT A SINGLE BYTE ON GENERATION. $JMP CreateCode // mnem reg,const LC1: SCDEND(); OpR2C: GETOL2(); opDescInd=1; $CMP AL,RCO; $JNE Q1 A0: OPCONSTSIZE[1]=OPERANDSIZE; $JMP CreateCode // reg,const Q1: $CMP AL,ECO; $JNE L110 A1: AL=EA_R; CREATE_EA(); GOTO A0; L110: $CMP AL,EAO; $JE N93 $CMP AL,ECCO; $JNE LC1 //SIGNED BYTE CONST ? $CMP OPCONST[4],0xFFFFFF80; $JL LC1 $CMP OPCONST[4],0x7F; $JG LC1 OPERANDSIZE=_B; OPCONSTSIZE[1]=_B; GOTO A1; //CONVERT REGISTER TO EFFECTIVE ADDRESS AND GENERATE OPCODE. N93: ECX=2; //COMPARE 2 OPERAND. B2: $LODSB; $CMP AL,255; $JE L122 $CMP AL,AR; $JE OL2_AR //AL/AX/EAX? $CMP AL,CO; $JE OL2_CO //CONSTANT? $CMP AL,rDX; $JE OL2_DX //DX? $CMP AL,_1; $JE OL2_1 //CONSTANT VALUE 1? $JMP LC1 OL2_AR: AH=OPDATA[0]&7; $JNZ NEAR LC1 L122: $LOOP B2; $JMP CreateCode OL2_CO: $CMP OPDESC[1],CO; $JNE NEAR LC1 OPCONSTSIZE[1]=OPERANDSIZE; GOTO L122; OL2_DX: $CMP OPDATA[0],0o12; $JE L122; $JMP LC1 OL2_1: $CMP OPCONSTSIZE[1],_B; $JNE NEAR LC1 $CMP OPCONST[4],1; $JNE NEAR LC1 OPCONSTFLAG[1]=0; $JMP A1 LD1: SCDEND(); // Первый операнд в 2-операндной инструкции - константа Op2C: GETOL2(); $CMP AL,EAO $JNE LD1 ECX=2; //COMPARE 2 OPERANDS. opDescInd=0; B12: $LODSB $CMP AL,255 $JE L222 $CMP AL,AR //AL/AX/EAX $JE XOL2_AR $CMP AL,CO $JE XOL2_CO $CMP AL,rDX //DX $JE XOL2_DX $CMP AL,_1 $JE XOL2_1 GOTO LD1; XOL2_AR: EBX=opDescInd; AH=OPDATA[EBX]&7; $JNZ N21 L222: opDescInd++; $LOOP B12 $JMP CreateCode N21: GOTO LD1; XOL2_CO: EBX=opDescInd; $CMP OPDESC[EBX],CO $JNE LD1 opDescInd++; $LOOP B12 $JMP CreateCode XOL2_DX: EBX=opDescInd; $CMP OPDATA[EBX],0o12 $JNE NEAR LD1 opDescInd++; $LOOP B12 $JMP CreateCode XOL2_1: EDX=opDescInd; $CMP OPCONSTSIZE[EDX],_B $JNE NEAR LD1 EDX<<=2; $CMP OPCONST[EDX],1 $JNE NEAR LD1 EDX=opDescInd; OPCONSTFLAG[EDX]=0; AL=EA_R; CREATE_EA(); $JMP CreateCode // Трехоперандная инструкция LE1: SCDEND(); THREEOPS: D11: GETOL3(); $CMP AL,ERO $JNE N42 $CMP CX,R*256+E $JE O21 $CMP CX,R*256+R $JNE LE1 AL=OPDATA[0]; CREATE_EA(); AL=OPDATA[1]; CREATE_R(); GOTO O21; N42: $CMP AL,REO $JNE N52 //ERROR: INVALID OPERANDS. $CMP CX,E*256+R $JE O21 $CMP CX,R*256+R $JNE LE1 AL=OPDATA[1]; CREATE_EA(); AL=OPDATA[0]; CREATE_R(); O21: BL=AH&TRANSBITS; $CMP OPCONSTFLAG[2],1 $JNE NEAR NA3 $CMP BL,CC3 $JNE N52 $CMP OPCONST[8],0xFFFFFF80 $JL NEAR LE1 $CMP OPCONST[8],0x7F $JG NEAR LE1 OPCONSTSIZE[2]=_B; $JMP CreateCode N52: $CMP BL,CB3 $JNE N62 $CMP OPCONST[8],0xFF $JA NEAR LE1 OPCONSTSIZE[2]=_B; $JMP CreateCode N62: $CMP BL,CW3 $JNE NA3 $CMP OPCONST[8],0xFFFFFFFF $JA NEAR LE1 $CMP RANDFLAG,1 $JNE NA2 OPCONSTSIZE[2]=_W; $JMP CreateCode NA2: OPCONSTSIZE[2]=_D; NA_2: $JMP CreateCode NA3: $CMP BL,CL3 $JNE NEAR LE1 $CMP OPDESC[2],R $JNE NEAR LE1 $CMP OPDATA[2],rCL $JE NA_2 illegaloperand(); } CreateConstants() { $CMP EA_SIBFLAG,1 // Флаг наличия Sib в 32-битном EA $JNE L3 // Sib отсутствует $CMP ADDRFLAG,1 $JE L3 //NO, NORMAL XRM // Запись SIB - байта AL=EA_I<<3|EA_R2|EA_SCALING; OP(); L3: $CMP OPCONSTFLAG[0],1 $JNE NEAR N1 IF(OPPOST[0])SetPost(OPPOSTREF[0],OPPOST[0]); ECX=OPCONSTSIZE[0]; EDI=#OPCONST; // Значение disp в EA WRITECONST(); N1: $CMP OPCONSTFLAG[1],1 $JNE NEAR N41 ECX=OPCONSTSIZE[1]; $CMP CL,AF //ABSOLUTE FAR ? $JNE D21 EDI=#OPCONST+4; //YES, CREATE ADDRESS. CL=_W; //(32 BIT) $CMP ADDRFLAG,1 $JNE D2 ECX=_D; //(48 BIT) D2: WRITECONST(); EDX+=output; EBX=EDX>>4; $AND EDX,15 $PUSH EBX,EDX $POP EDX //??? EAX=opDescInd; DSDWORD[EAX]=EDX; ECX=_W; /* AFSEG нигде не определен, надо будет разбираться EDI=#AFSEG; //(SEGMENT/SELECTOR) */ WRITECONST(); $STC $RET D21: IF(OPPOST[1])SetPost(OPPOSTREF[4],OPPOST[1]); EDI=#OPCONST+4; WRITECONST(); N41: IF(OPCONSTFLAG[2]==1){ ECX=OPCONSTSIZE[2]; EDI=#OPCONST+8; WRITECONST(); } } // ---- illegaloperand() { preerror("ASM: Illegal operand\n"); } // ---- toomuchoperands() { preerror("ASM: Illegal number of operands\n"); } // JUMP TABLES dword Jmp_Mov={#Mov_R,#Mov_E,#Mov_ERR,#Mov_S, #Mov_SYSR,#Mov_SYSR,#Mov_SYSR,#Mov_SYSR,#Mov_SYSR,#Mov_SYSR}; dword Jmp_Mov_R={#Mov_R2R,#Mov_R2E,#Mov_R2C,#Mov_S, #Mov_SYSR,#Mov_SYSR,#Mov_SYSR,#Mov_SYSR,#Mov_SYSR,#Mov_SYSR}; dword Jmp_Mov_E={#Mov_E2R,#Mov_ERR,#Mov_E2C,#Mov_S, #Mov_ERR,#Mov_ERR,#Mov_ERR,#Mov_ERR,#Mov_ERR,#Mov_ERR}; dword Jmp_Op1={#Op1R,#Op1E,#Op1C,#Op1S, #Op1ERR,#Op1ERR,#Op1ERR,#Op1ERR,#Op1ERR,#Op1AF}; dword Jmp_Op2={#Op2R,#Op2E,#Op2C,#Op2ERRS, #Op2ERRSYS,#Op2ERRSYS,#Op2ERRSYS,#Op2ERRSYS,#Op2ERRSYS,#Op2ERRAF}; dword Jmp_Op2R={#OpR2R,#OpR2E,#OpR2C,#Op2ERRS, #Op2ERRSYS,#Op2ERRSYS,#Op2ERRSYS,#Op2ERRSYS,#Op2ERRSYS,#Op2ERRAF}; dword Jmp_Op2E={#OpE2R,0,#OpE2C,#Op2ERRS, #Op2ERRSYS,#Op2ERRSYS,#Op2ERRSYS,#Op2ERRSYS,#Op2ERRSYS,#Op2ERRAF}; //dword TC_JMP={#T_JMPSHORT,#T_JMPNEAR,#T_JMPFAR}; //dword TC_CALL={0,#T_CALL,#T_CALLFAR}; //dword TC_J={#T_J,#T_JN,1}; dword Dsc_Jump={#CreateConstants,#Dsc_O,#Dsc_OW,#Dsc_OS,#Dsc_S,#Dsc_XRM,#Dsc_XPM,#Dsc_XSM};