una simplificar semirrecta reducir numeros mixtas grandes fracciones fraccion facil ejercicios cómo con como c++ windows visual-c++ assembly x86

c++ - semirrecta - simplificar fracciones ejercicios



¿Cómo puedo simplificar la generación de código en tiempo de ejecución? (4)

Echa un vistazo a asmjit . Es una biblioteca de C ++ para la generación de código en tiempo de ejecución. Admite x64 y probablemente la mayoría de las extensiones existentes (FPU, MMX, 3dNow, SSE, SSE2, SSE3, SSE4). Su interfaz se parece a la sintaxis del ensamblaje y codifica las instrucciones correctamente para usted.

Estoy trabajando en un software que genera código de ensamblador en tiempo de ejecución. Por ejemplo, aquí hay una función muy simple que genera un código de ensamblador para llamar a la función GetCurrentProcess (para Win64 ABI):

void genGetCurrentProcess( char *codePtr, FARPROC addressForGetCurrentProcessFunction ) { #ifdef _WIN64 // mov rax, addressForGetCurrentProcessFunction *codePtr++ = 0x48 *codePtr++ = 0xB8; *((FARPROC *)codePtr)++ = addressForGetCurrentProcessFunction; // call rax *codePtr++ = 0xFF; *codePtr++ = 0xD0; #else // mov eax, addressForGetCurrentProcessfunction *codePtr++ = 0xB8; *((FARPROC *)codePtr)++ = addressForGetCurrentProcessFunction; // call eax *codePtr++ = 0xFF; *codePtr++ = 0xD0; #endif }

Usualmente uso un ensamblador en línea, pero por desgracia, esto ya no parece ser posible con los compiladores MSVC de 64 bits. Mientras estoy en ello, este código debería funcionar con MSVC6 hasta MSVC10 y también con MinGW. Hay muchas más funciones como genGetCurrentProcess , todas emiten código de ensamblador y muchas de ellas hacen que los punteros a funciones se llamen pasados ​​como argumentos.

Lo molesto de esto es que la modificación de este código es propensa a errores y tenemos que encargarnos de las cosas específicas de ABI de forma manual (por ejemplo, reservar un espacio de pila de 32 bytes antes de llamar a las funciones para el registro de derrames).

Entonces, mi pregunta es: ¿puedo simplificar este código para generar código de ensamblador en tiempo de ejecución? Mi esperanza era que de alguna manera pudiera escribir el código del ensamblador directamente (posiblemente en un archivo externo que luego se ensambla usando ml / ml64 ) pero no tengo claro cómo funcionaría esto si algunos de los bytes en el código ensamblado solo se conocen en runtime (por ejemplo, el valor de addressForGetcurrentProcessFunction en el ejemplo anterior). ¿Quizás es posible ensamblar algo de código pero asignar "etiquetas" a ciertas ubicaciones en el código para que pueda modificar fácilmente el código en tiempo de ejecución y luego copiarlo en mi búfer?


Lo obvio es crear un conjunto de abstracciones que representen la generación de los elementos de las instrucciones de la máquina de interés y luego redactar llamadas para obtener las instrucciones / modos de direccionamiento que desee. Si genera una gran variedad de códigos, puede terminar codificando todo el conjunto de instrucciones de esta manera.

Luego, para generar una instrucción MOV, puedes escribir un código que se vea así:

ObjectCodeEmitMovRegister32ScaledRegister32OffsetRegister32(EAX,EDX,4,-LowerBound*4,ESP);

Se puede decir que me gustan los nombres largos. (Al menos nunca olvido lo que hacen.)

Aquí hay algunos bits de un generador de código que soporta esto que implementé en C hace mucho tiempo. Esto cubre el tipo de la parte más difícil, que es la generación de bytes MOD y SIB. Siguiendo este estilo, uno puede implementar la mayor cantidad de instrucciones que desee. Este ejemplo es solo para x32, por lo que OP deberá extenderse y modificarse en consecuencia. La definición del generador de instrucciones MOV está abajo al final.

#define Register32T enum Register32Type enum Register32Type {EAX=0,ECX=1,EDX=2,EBX=3,ESP=4,EBP=5,ESI=6,EDI=7}; inline byte ObjectCodeEmitModRM32Register32(Register32T Register32,Register32T BaseRegister32) // Send ModRM32Bytes for register-register mode to object file { byte ModRM32Byte=0xC0+Register32*0x8+BaseRegister32; ObjectCodeEmitByte(ModRM32Byte); return ModRM32Byte; } inline byte ObjectCodeEmitModRM32Direct(Register32T Register32) // Send ModRM32Bytes for direct address mode to object file { byte ModRM32Byte=Register32*0x8+0x05; ObjectCodeEmitByte(ModRM32Byte); return ModRM32Byte; } inline void ObjectCodeEmitSIB(Register32T ScaledRegister32, natural Scale, Register32T BaseRegister32) // send SIB byte to object file // Note: Use ESP for ScaledRegister32 to disable scaling; only useful when using ESP for BASE. { if (ScaledRegister32==ESP && BaseRegister32!=ESP) CompilerFault(31); if (Scale==1) ObjectCodeEmitByte((byte)(0x00+ScaledRegister32*0x8+BaseRegister32)); else if (Scale==2) ObjectCodeEmitByte((byte)(0x40+ScaledRegister32*0x8+BaseRegister32)); else if (Scale==4) ObjectCodeEmitByte((byte)(0x80+ScaledRegister32*0x8+BaseRegister32)); else if (Scale==8) ObjectCodeEmitByte((byte)(0xC0+ScaledRegister32*0x8+BaseRegister32)); else CompilerFault(32); } inline byte ObjectCodeEmitModRM32OffsetRegister32(Register32T Register32, integer Offset, Register32T BaseRegister32) // Send ModRM32Bytes for indexed address mode to object file // Returns 1st byte of ModRM32 for possible use in EmittedPushRM32 peephole optimization { byte ModRM32Byte; if (Offset==0 && BaseRegister32!=EBP) { ModRM32Byte=0x00+Register32*0x8+BaseRegister32; ObjectCodeEmitByte(ModRM32Byte); if (BaseRegister32==ESP) ObjectCodeEmitSIB(ESP,1,ESP); } else if (Offset>=-128 && Offset<=127) { ModRM32Byte=0x40+Register32*0x8+BaseRegister32; ObjectCodeEmitByte(ModRM32Byte); if (BaseRegister32==ESP) ObjectCodeEmitSIB(ESP,1,ESP); ObjectCodeEmitByte((byte)Offset); } else { // large offset ModRM32Byte=0x80+Register32*0x8+BaseRegister32; ObjectCodeEmitByte(ModRM32Byte); if (BaseRegister32==ESP) ObjectCodeEmitSIB(ESP,1,ESP); ObjectCodeEmitDword(Offset); } return ModRM32Byte; } inline byte ObjectCodeEmitModRM32OffsetScaledRegister32(Register32T Register32, integer Offset, Register32T ScaledRegister32, natural Scale) // Send ModRM32Bytes for indexing by a scaled register with no base register to object file // Returns 1st byte of ModRM32 for possible use in EmittedPushRM32 peephole optimization { byte ModRM32Byte=0x00+Register32*0x8+ESP; ObjectCodeEmitByte(ModRM32Byte); // MOD=00 --> SIB does disp32[index] ObjectCodeEmitSIB(ScaledRegister32,Scale,EBP); ObjectCodeEmitDword(Offset); return ModRM32Byte; } inline byte ObjectCodeEmitModRM32ScaledRegister32OffsetRegister32(Register32T Register32, Register32T ScaledRegister32, natural Scale, integer Offset, Register32T BaseRegister32) // Send ModRM32Bytes for indexed address mode to object file // Returns 1st byte of ModRM32 for possible use in EmittedPushRM32 peephole optimization // If Scale==0, leave scale and scaled register out of the computation { byte ModRM32Byte; if (Scale==0) ObjectCodeEmitModRM32OffsetRegister32(Register32,Offset,BaseRegister32); else if (Offset==0 && BaseRegister32!=EBP) { ModRM32Byte=0x00+Register32*0x8+ESP; ObjectCodeEmitByte(ModRM32Byte); ObjectCodeEmitSIB(ScaledRegister32,Scale,BaseRegister32); } else if (Offset>=-128 && Offset<=127) { ModRM32Byte=0x40+Register32*0x8+ESP; ObjectCodeEmitByte(ModRM32Byte); ObjectCodeEmitSIB(ScaledRegister32,Scale,BaseRegister32); ObjectCodeEmitByte((byte)Offset); } else { // large offset ModRM32Byte=0x80+Register32*0x8+ESP; ObjectCodeEmitByte(ModRM32Byte); ObjectCodeEmitSIB(ScaledRegister32,Scale,BaseRegister32); ObjectCodeEmitDword(Offset); } return ModRM32Byte; } inline void ObjectCodeEmitLeaRegister32OffsetRegister32ScaledPlusBase32( Register32T Register32Destination, integer Offset, Register32T Register32Source, natural Scale, // 1,2,4 or 8 Register32T Base) // send "LEA Register32,offset[Register32*Scale+Base]" to object file { ObjectCodeEmitLeaOpcode(); ObjectCodeEmitModRM32ScaledRegister32OffsetRegister32( Register32Destination,Register32Source,Scale,Offset,Base); } inline void ObjectCodeEmitMovRegister32ScaledRegister32OffsetRegister32(Register32T DestinationRegister32, Register32T ScaledRegister32, natural Scale, integer Offset, Register32T BaseRegister32) // Emit Mov R32 using scaled index addressing { ObjectCodeEmitMovRegister32Opcode(); ObjectCodeEmitModRM32ScaledRegister32OffsetRegister32(DestinationRegister32, ScaledRegister32, Scale, Offset, BaseRegister32); }


Podría confiar en un ensamblador real para que haga el trabajo por usted; obviamente, uno que genere una salida binaria es el mejor. Considere mirar yasm o fasm (hay algunas publicaciones en los foros de fasm sobre cómo hacer una versión DLL, por lo que no tiene que escribir un archivo de ensamblaje temporal, iniciar un proceso externo y volver a leer el archivo de salida, pero no sé si se ha actualizado para versiones posteriores).

Sin embargo, esto podría ser excesivo si sus necesidades son relativamente simples. Consideraría hacer una clase de ensamblador de C ++ que admita solo los mnemotécnicos que necesita, junto con algunas funciones de ayuda como GeneratePrologue , GenerateEpilogue , InstructionPointerRelativeAddress y demás. Esto le permitiría escribir un pseudoensamblaje y hacer que las funciones de ayuda se ocupen de los problemas de 32/64 bits.


Puede abstraer algunas instrucciones de codificación, convención de llamada y detalles relacionados con el modo de CPU escribiendo algunas funciones de ayuda y macros.

Incluso puede crear un pequeño ensamblador que ensamblaría un pseudo-asm-código codificado numéricamente y contenido en una matriz en un código ejecutable, por ejemplo, comenzando con una entrada como esta:

UINT32 blah[] = { mov_, ebx_, dwordPtr_, edi_, plus_, eax_, times8_, plus_, const_, 0xFEDCBA98, call_, dwordPtr_, ebx_, };

Pero es mucho trabajo hacer esto correctamente. Para algo más simple, simplemente cree funciones de ayuda / macros, esencialmente haciendo lo que ya ha hecho, pero ocultando algunos detalles desagradables al usuario.