diff --git a/tools/post_compile/post_compile.cpp b/tools/post_compile/post_compile.cpp index 492d95fdf816..60a605695863 100644 --- a/tools/post_compile/post_compile.cpp +++ b/tools/post_compile/post_compile.cpp @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -39,11 +40,17 @@ #include #include #include -#include +//#include //---------------------------------------------------------------------- bool gDebug=false; +bool gCompact=false; +bool gOptimize=false; + +#define bswap_32(x) \ + ((((x) & 0xff000000) >> 24) | (((x) & 0x00ff0000) >> 8) | \ + (((x) & 0x0000ff00) << 8) | (((x) & 0x000000ff) << 24)) //---------------------------------------------------------------------- @@ -222,6 +229,9 @@ char reg_name[14][4] = { "eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi", char instr_name[][8] = { "unknown", "push", "add", "sub", "cmp", "mov", "j", "lea", "inc", "pop", "xor", "nop", "ret" }; +char cond_name[][4] = { "o", "no", "b", "nb", "z", "nz", "be", "nbe", + "s", "ns", "pe", "po", "l", "ge", "le", "g", "mp", "cxz" }; + enum eRegister { kNoReg = -1, @@ -234,6 +244,12 @@ enum eInstruction { kinc, kpop, kxor, knop, kret, }; +enum eCond { + kjo, kjno, kjb, kjnb, kjz, kjnz, kjbe, kjnbe, + kjs, kjns, kjpe, kjpo, kjl, kjge, kjle, kjg, kjt, kjcxz +}; + + const int kBaseFormatMask = (1<<5) -1; enum eFormat { kfNone, kfreg, kfrm32, kfrm32_r32, kfr32_rm32, @@ -241,6 +257,7 @@ enum eFormat { kfmImm32 = 1 << 6, // set on if imm32 kfmSize8 = 1 << 7, // set on if 8 bit kfmSize16 = 1 << 8, // set on if 16 bit + kfmDeref = 1 << 9, }; typedef unsigned char uchar; @@ -272,7 +289,17 @@ struct CInstruction { int am_rm32( uchar *pCode, eFormat *format ); int am_rm32_reg( uchar *pCode, eFormat *format ); - int am_encode( uchar *buffer, eRegister reg1, eFormat format ); + int am_encode( uchar *buffer, eRegister reg1 ); +}; + + +struct CFunction { + CFunction( string funcName ){fName = funcName;} + string fName; + list fInstructions; + + void get_instructions( uchar *pCode, long codeSize ); + void remove_nops(); }; @@ -388,6 +415,7 @@ struct CAdd:CInstruction { fFormat = format; } + virtual void optimize( void ); virtual int generate_opcode( uchar *buffer ); }; @@ -418,14 +446,18 @@ struct CXor:CInstruction { struct CJmp:CInstruction { - CJmp( uchar imm8 ) + eCond fCond; + + CJmp( eCond cond, uchar imm8 ) { fInstr = kjmp; fImm32 = imm8; + fCond = cond; fSize = 2; } virtual void output_text( void ); + virtual int generate_opcode( uchar *buffer ); }; @@ -458,6 +490,8 @@ struct CLea:CInstruction { fSize += am_rm32_reg( pCode, &format ); fFormat = format; } + + virtual int generate_opcode( uchar *buffer ); }; @@ -478,6 +512,11 @@ int CInstruction::am_rm32( uchar *pCode, eFormat *format ) if ( ((reg & 0x07) == 0x04) && // check for SIB ((reg & 0xC0) != 0xC0) ) { + fFormat = (eFormat)(fFormat | kfmDeref); + fReg2 = (eRegister)(*pCode & 0x07); + fReg3 = (eRegister)((*pCode & 0x38) >> 3); + if ((int)fReg3 = 0x04) fReg3 = kNoReg; + fScale = 1 << ((*pCode & 0xC0) >> 6); pCode++; isize++; } @@ -485,20 +524,20 @@ int CInstruction::am_rm32( uchar *pCode, eFormat *format ) if ((reg & 0xC0) == 0x80) // disp32 { fDisp32 = bswap_32( *(long*)pCode ); + fFormat = (eFormat)(fFormat | kfmDeref); pCode += 4; isize += 4; } else if ((reg & 0xC0) == 0x40) // disp8 { fDisp32 = *(char*)pCode; // need it as a signed value + fFormat = (eFormat)(fFormat | kfmDeref); pCode++; isize++; } else if ((reg & 0xC0) == 0x00) // no disp { - } - else // direct register - { + fFormat = (eFormat)(fFormat | kfmDeref); } if (*format & kfmImm8) @@ -526,27 +565,66 @@ int CInstruction::am_rm32_reg( uchar *pCode, eFormat *format ) } -int CInstruction::am_encode( uchar *buffer, eRegister reg1, eFormat format ) +int CInstruction::am_encode( uchar *buffer, eRegister reg1 ) { - int isize = 0; + int isize = 1; + uchar sib=0; + bool use_sib=false; + eFormat format=fFormat; + + if ((fScale != 1) || + (fReg3 != kNoReg) || + ( (fReg2 == kesp) && (format & kfmDeref) )) + { + uchar scale=1; + switch (fScale) + { + case 1: + scale = 0x00; + break; + case 2: + scale = 0x40; + break; + case 4: + scale = 0x80; + break; + case 8: + scale = 0xC0; + break; + } + if (fReg3 == kNoReg) + sib = scale | (0x04 << 3) | fReg2; + else + sib = scale | (fReg3 << 3) | fReg2; + use_sib = true; +*buffer = 0xff; + buffer++; + isize++; + } if (fDisp32 == 0) { - *buffer = 0xC0 | (reg1 << 3) | fReg2; - isize = 1; + if (format & kfmDeref) + { + *buffer = 0x00 | (reg1 << 3) | fReg2; + } + else + { + *buffer = 0xC0 | (reg1 << 3) | fReg2; + } } else if ( (fDisp32 >= -128) && (fDisp32 <= 127) ) { *buffer = 0x40 | (reg1 << 3) | fReg2; *(buffer+1) = (uchar)fDisp32; - isize = 2; + isize++; } else { *buffer = 0x40 | (reg1 << 3) | fReg2; long bsDisp32 = bswap_32( fDisp32 ); memcpy( buffer+1, &bsDisp32, 4 ); - isize = 5; + isize += 4; } if (format & kfmImm8) @@ -585,6 +663,8 @@ int CPop::generate_opcode( uchar *buffer ) buffer[0] = 0x58 | fReg1; return 1; } + + return 0; } @@ -595,6 +675,8 @@ int CPush::generate_opcode( uchar *buffer ) buffer[0] = 0x50 | fReg1; return 1; } + + return 0; } @@ -605,6 +687,15 @@ int CRet::generate_opcode( uchar *buffer ) buffer[0] = 0xC3; return 1; } + + return 0; +} + + +int CLea::generate_opcode( uchar *buffer ) +{ + buffer[0] = 0x8D; + return 1+am_encode( &buffer[1], fReg1 ); } @@ -635,7 +726,7 @@ int CMov::generate_opcode( uchar *buffer ) buffer[0] = 0x8B; } - isize += am_encode( &buffer[1], fReg1, fFormat ); + isize += am_encode( &buffer[1], fReg1 ); return isize; } @@ -656,17 +747,17 @@ int CInc::generate_opcode( uchar *buffer ) if (kfmSize8 & fFormat) { buffer[0] = 0xFE; - isize += am_encode( &buffer[1], (eRegister)0, fFormat ); + isize += am_encode( &buffer[1], (eRegister)0 ); } else if (kfmSize16 & fFormat) { buffer[0] = 0xFF; - isize += am_encode( &buffer[1], (eRegister)0, fFormat ); + isize += am_encode( &buffer[1], (eRegister)0 ); } else { buffer[0] = 0xFF; - isize += am_encode( &buffer[1], (eRegister)6, fFormat ); + isize += am_encode( &buffer[1], (eRegister)6 ); } return isize; } @@ -689,7 +780,7 @@ int CCmp::generate_opcode( uchar *buffer ) else buffer[0] = 0x81; - isize += am_encode( &buffer[1], (eRegister)7, fFormat ); + isize += am_encode( &buffer[1], (eRegister)7 ); return isize; } else if (format == kfrm32_r32) @@ -707,7 +798,7 @@ int CCmp::generate_opcode( uchar *buffer ) buffer[0] = 0x3B; } - isize += am_encode( &buffer[1], fReg1, fFormat ); + isize += am_encode( &buffer[1], fReg1 ); return isize; } @@ -726,7 +817,7 @@ int CXor::generate_opcode( uchar *buffer ) else buffer[0] = 0x81; - isize += am_encode( &buffer[1], (eRegister)6, fFormat ); + isize += am_encode( &buffer[1], (eRegister)6 ); return isize; } else if (format == kfrm32_r32) @@ -744,11 +835,37 @@ int CXor::generate_opcode( uchar *buffer ) buffer[0] = 0x33; } - isize += am_encode( &buffer[1], fReg1, fFormat ); + isize += am_encode( &buffer[1], fReg1 ); return isize; } +void CAdd::optimize() +{ + eFormat format = (eFormat)(kBaseFormatMask & (int)fFormat); + eFormat isize = (eFormat)((int)fFormat & (kfmSize8 | kfmSize16 )); + + if (format == kfrm32) + { + if (kfmSize8 & isize) + { + fFormat = (eFormat)(format | kfmImm8 | kfmSize8); + } + else + { + if ( (fImm32 >= -128) && (fImm32 <= 127) ) + { + fFormat =(eFormat)(format | kfmImm8 | isize); + } + else + { + fFormat =(eFormat)(format | kfmImm32 | isize); + } + } + } +} + + int CAdd::generate_opcode( uchar *buffer ) { int isize = 1; @@ -756,11 +873,32 @@ int CAdd::generate_opcode( uchar *buffer ) if (format == kfrm32) { - buffer[0] = 0x01; - isize += am_encode( &buffer[1], (eRegister)0, fFormat ); + if (fFormat & kfmSize8) + buffer[0] = 0x80; + else if (fFormat & kfmImm8) + buffer[0] = 0x83; + else + buffer[0] = 0x81; + + isize += am_encode( &buffer[1], (eRegister)0 ); return isize; } + else if (format == kfrm32_r32) + { + if (fFormat & kfmSize8) + buffer[0] = 0x00; + else + buffer[0] = 0x01; + } + else if (format == kfr32_rm32) + { + if (fFormat & kfmSize8) + buffer[0] = 0x02; + else + buffer[0] = 0x03; + } + isize += am_encode( &buffer[1], fReg1 ); return isize; } @@ -801,7 +939,7 @@ int CSub::generate_opcode( uchar *buffer ) if (kfmSize8 & fFormat) { buffer[0] = 0x80; - isize += am_encode( &buffer[1], (eRegister)5, fFormat ); + isize += am_encode( &buffer[1], (eRegister)5 ); return isize; } else @@ -810,7 +948,7 @@ int CSub::generate_opcode( uchar *buffer ) buffer[0] = 0x83; else buffer[0] = 0x81; - isize += am_encode( &buffer[1], (eRegister)5, fFormat ); + isize += am_encode( &buffer[1], (eRegister)5 ); return isize; } } @@ -819,11 +957,39 @@ int CSub::generate_opcode( uchar *buffer ) } +int CJmp::generate_opcode( uchar *buffer ) +{ + int isize = 1; + + if (fCond == kjt) + { + buffer[0] = 0xEB; + } + else if (fCond == kjcxz) + { + buffer[0] = 0xE3; + } + else + { + buffer[0] = fCond | 0x70; + } + + buffer[1] = fImm32; + isize++; + + return isize; +} + + + //*********************************** Mneumonic Outputers ********************* void CInstruction::output_text( void ) { + if (fInstr == kunknown) return; + + cout << instr_name[fInstr] << "\t"; eFormat format = (eFormat)(kBaseFormatMask & (int)fFormat); @@ -854,20 +1020,28 @@ void CInstruction::output_text( void ) void CJmp::output_text( void ) { - cout << "j\t"; - cout.form( ".+0x%02X\n", fImm32 ); + cout << "j" << cond_name[fCond]; + cout.form( "\t.+0x%02X\n", fImm32 ); } -void hexdump( CInstruction *instr ) +//********************* the rest of the code ******************************** + + +int hexdump( CInstruction *instr ) { uchar buffer[16]; int instrSize = instr->generate_opcode( buffer ); - for (int i=0; ioutput_text(); - delete instr; + fInstructions.push_back( instr ); } +} - return 0; +void CFunction::remove_nops( void ) +{ + for( list::iterator p = fInstructions.begin(); + p != fInstructions.end(); ++p ) + { + if ( (*p)->fInstr == knop ) + { + list::iterator s = p; + --p; + fInstructions.erase(s); + } + } } @@ -1055,21 +1287,47 @@ process_mapping(char* mapping, size_t size) // look for code in the .text section elf_text_map textmap; - long bytesSaved = 0; + long newSize = 0, oldSize = 0; + long numUnknowns=0; for (int i = 0; i < nentries; ++i) { const Elf32_Sym* sym = symtab + i; if ( sym->st_shndx == textndx && sym->st_size) { - basic_string funcname(sym->st_name + strtab, sym->st_size); +// basic_string funcname(sym->st_name + strtab, sym->st_size); + string funcname(sym->st_name + strtab, sym->st_size); basic_string functext(text + sym->st_value - textaddr, sym->st_size); + CFunction *func = new CFunction( funcname ); + if (gDebug) cout << funcname << "\n\n"; - if (gDebug) hexdump(cout,functext.data(),sym->st_size); - bytesSaved += process_function( (unsigned char *)functext.data(), sym->st_size ); + if (gDebug) (void)hexdump(cout,functext.data(),sym->st_size); + oldSize += sym->st_size; + func->get_instructions( (unsigned char *)functext.data(), sym->st_size ); + + if (gCompact) func->remove_nops(); + + for( list::iterator p = func->fInstructions.begin(); + p != func->fInstructions.end(); ++p ) + { + //if ( (*p)->fInstr == kunknown) numUnknowns++; + if (gOptimize) (*p)->optimize(); + uchar buffer[16]; + int instrSize = (*p)->generate_opcode( buffer ); + if (instrSize == 0) numUnknowns++; + newSize += instrSize; + + (void)hexdump( *p ); + (*p)->output_text(); + + delete *p; + } + delete func; } } - cout << "Code size reduction of " << bytesSaved << "\n"; + cout << "Code size reduction of " << oldSize-newSize -numUnknowns << " bytes out of " + << oldSize << " bytes.\n"; + if (numUnknowns) cout << "*** Unknowns found: " << numUnknowns << "\n"; } void @@ -1109,15 +1367,23 @@ int main(int argc, char* argv[]) { while(1) { - char c = getopt( argc, argv, "d" ); + char c = getopt( argc, argv, "dco" ); if (c == -1) break; switch (c) { + case 'c': + gCompact = true; + cout << "Compacting Dead Code ON\n"; + break; case 'd': gDebug = true; cout << "Debugging Info ON\n"; break; + case 'o': + gOptimize = true; + cout << "Instrustion Optimization ON\n"; + break; } }