/* -*- Mode: C++; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * The contents of this file are subject to the Mozilla Public * License Version 1.1 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr * implied. See the License for the specific language governing * rights and limitations under the License. * * The Original Code is foldelf.cpp, released November 28, 2000. * * The Initial Developer of the Original Code is Netscape * Communications Corporation. Portions created by Netscape are * Copyright (C) 2000 Netscape Communications Corporation. All * Rights Reserved. * * Contributor(s): * Edward Kandrot * Chris Waterson * * This program reads an ELF file and computes information about * redundancies. * * */ #include #include #include #include #include #include #include #include #include #include #include #include #include //#include //---------------------------------------------------------------------- bool gDebug=false; bool gCompact=false; bool gOptimize=false; bool gAssembly=false; #define bswap_32(x) \ ((((x) & 0xff000000) >> 24) | (((x) & 0x00ff0000) >> 8) | \ (((x) & 0x0000ff00) << 8) | (((x) & 0x000000ff) << 24)) //---------------------------------------------------------------------- static void hexdump(ostream& out, const char* bytes, size_t count) { hex(out); size_t off = 0; while (off < count) { out.form("%08lx: ", off); const char* p = bytes + off; int j = 0; while (j < 16) { out.form("%02x", p[j++] & 0xff); if (j + off >= count) break; out.form("%02x ", p[j++] & 0xff); if (j + off >= count) break; } // Pad for (; j < 16; ++j) out << ((j%2) ? " " : " "); for (j = 0; j < 16; ++j) { if (j + off < count) out.put(isprint(p[j]) ? p[j] : '.'); } out << endl; off += 16; } } //---------------------------------------------------------------------- int verify_elf_header(const Elf32_Ehdr* hdr) { if (hdr->e_ident[EI_MAG0] != ELFMAG0 || hdr->e_ident[EI_MAG1] != ELFMAG1 || hdr->e_ident[EI_MAG2] != ELFMAG2 || hdr->e_ident[EI_MAG3] != ELFMAG3) { cerr << "not an elf file" << endl; return -1; } if (hdr->e_ident[EI_CLASS] != ELFCLASS32) { cerr << "not a 32-bit elf file" << endl; return -1; } if (hdr->e_ident[EI_DATA] != ELFDATA2LSB) { cerr << "not a little endian elf file" << endl; return -1; } if (hdr->e_ident[EI_VERSION] != EV_CURRENT) { cerr << "incompatible version" << endl; return -1; } return 0; } //---------------------------------------------------------------------- class elf_symbol : public Elf32_Sym { public: elf_symbol(const Elf32_Sym& sym) { ::memcpy(static_cast(this), &sym, sizeof(Elf32_Sym)); } friend bool operator==(const elf_symbol& lhs, const elf_symbol& rhs) { return 0 == ::memcmp(static_cast(&lhs), static_cast(&rhs), sizeof(Elf32_Sym)); } }; //---------------------------------------------------------------------- static const char* st_bind(unsigned char info) { switch (ELF32_ST_BIND(info)) { case STB_LOCAL: return "local"; case STB_GLOBAL: return "global"; case STB_WEAK: return "weak"; default: return "unknown"; } } static const char* st_type(unsigned char info) { switch (ELF32_ST_TYPE(info)) { case STT_NOTYPE: return "none"; case STT_OBJECT: return "object"; case STT_FUNC: return "func"; case STT_SECTION: return "section"; case STT_FILE: return "file"; default: return "unknown"; } } static unsigned char st_type(const char* type) { if (strcmp(type, "none") == 0) { return STT_NOTYPE; } else if (strcmp(type, "object") == 0) { return STT_OBJECT; } else if (strcmp(type, "func") == 0) { return STT_FUNC; } else { return 0; } } //---------------------------------------------------------------------- int DIGIT_MAP[256] = { 0, 0, 0, 0, 0, 0, 0, 0, // 0x00 - 0x07 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, // 0x38 - 0x3f 0, 0, 0, 0, 0, 0, 0, 0, // 0x40 - 0x47 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, // 0x78 - 0x7f 0, 0, 0, 0, 0, 0, 0, 0, // 0x80 - 0x87 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, // 0xb8 - 0xbf 0, 0, 0, 0, 0, 0, 0, 0, // 0xc0 - 0xc7 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7}; // 0xf8 - 0xff /* * Dceclation of the Instruction types */ char reg_name[14][4] = { "eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi", "cs", "ss", "ds", "es", "fs", "gs" }; char instr_name[][8] = { "unknown", "push", "add", "sub", "cmp", "mov", "j", "lea", "inc", "pop", "xor", "nop", "ret", "call" }; 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, keax = 0, kecx, kedx, kebx, kesp, kebp, kesi, kedi, kcs, kss, kds, kes, kfs, kgs }; enum eInstruction { kunknown, kpush, kadd, ksub, kcmp, kmov, kjmp, klea, kinc, kpop, kxor, knop, kret, kcall, }; 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, kfmImm8 = 1 << 5, // set on if imm8 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; //******************************** Base OpCode Classes ********************** struct CInstruction { CInstruction(); int fSize; // size of the instruction in bytes eInstruction fInstr; eFormat fFormat; eRegister fReg1; eRegister fReg2; long fDisp32; eRegister fReg3; int fScale; long fImm32; virtual void output_text( void ); virtual void optimize( void ) {} virtual int generate_opcode( uchar *buffer ); int am_rm32( uchar *pCode ); int am_rm32_reg( uchar *pCode ); 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(); }; CInstruction::CInstruction() { fSize = 1; fInstr = kunknown; fFormat = kfNone; fReg1 = kNoReg; fReg2 = kNoReg; fDisp32 = 0; fReg3 = kNoReg; fScale = 1; fImm32 = 0; } struct CPop:CInstruction { CPop( eRegister reg ) { fInstr = kpop; fFormat = kfreg; fReg1 = reg; } CPop( char imm8 ) { } CPop( long imm32 ) { } CPop( uchar *pCode, eFormat format ) { fInstr = kpop; fFormat = format; fSize += am_rm32( pCode ); } virtual int generate_opcode( uchar *buffer ); }; struct CPush:CInstruction { CPush( eRegister reg ) { fInstr = kpush; fFormat = kfreg; fReg1 = reg; } CPush( char imm8 ) { } CPush( long imm32 ) { } CPush( uchar *pCode, eFormat format ) { fInstr = kpush; fFormat = format; fSize += am_rm32( pCode ); } virtual int generate_opcode( uchar *buffer ); }; struct CInc:CInstruction { CInc( eRegister reg ) { fInstr = kpush; fFormat = kfreg; fReg1 = reg; } CInc( uchar *pCode, eFormat format ) { fInstr = kinc; fFormat = format; fSize += am_rm32( pCode ); } virtual int generate_opcode( uchar *buffer ); }; struct CMov:CInstruction { CMov( uchar *pCode, eFormat format ) { fInstr = kmov; fFormat = format; fSize += am_rm32_reg( pCode ); } virtual int generate_opcode( uchar *buffer ); }; struct CCmp:CInstruction { CCmp( uchar *pCode, eFormat format ) { fInstr = kcmp; fFormat = format; fSize += am_rm32_reg( pCode ); } virtual int generate_opcode( uchar *buffer ); }; struct CAdd:CInstruction { CAdd( uchar *pCode, eFormat format ) { fInstr = kadd; fFormat = format; fSize += am_rm32_reg( pCode ); } virtual void optimize( void ); virtual int generate_opcode( uchar *buffer ); }; struct CSub:CInstruction { CSub( uchar *pCode, eFormat format ) { fInstr = ksub; fFormat = format; fSize += am_rm32_reg( pCode ); } virtual void optimize( void ); virtual int generate_opcode( uchar *buffer ); }; struct CXor:CInstruction { CXor( uchar *pCode, eFormat format ) { fInstr = kxor; fFormat = format; fSize += am_rm32_reg( pCode ); } virtual int generate_opcode( uchar *buffer ); }; struct CCall:CInstruction { CCall( long imm32 ) { fInstr = kcall; fImm32 = imm32; fSize = 5; } // virtual void output_text( void ); virtual int generate_opcode( uchar *buffer ); }; struct CJmp:CInstruction { 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 ); }; struct CNop:CInstruction { CNop() { fInstr = knop; fSize = 1; } virtual int generate_opcode( uchar *buffer ) { buffer[0] = 0x90; return 1; } }; struct CRet:CInstruction { CRet() { fInstr = kret; fSize = 1; } virtual int generate_opcode( uchar *buffer ); }; struct CLea:CInstruction { CLea( uchar *pCode, eFormat format ) { fInstr = klea; fFormat = format; fSize += am_rm32_reg( pCode ); } virtual void optimize( void ); virtual int generate_opcode( uchar *buffer ); }; //************************* Address Mode En/Decoding ************************ /* * am_rm32 decodes the destination reg, and assumes that the src reg is a * selector or was set outside of this function */ int CInstruction::am_rm32( uchar *pCode ) { unsigned char reg = *pCode++; int isize = 1; fReg2 = (eRegister)(reg & 0x07); 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++; } 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 { fFormat = (eFormat)(fFormat | kfmDeref); } if (fFormat & kfmImm8) { fImm32 = *(char*)pCode; // need it as a signed value pCode++; isize++; } if (fFormat & kfmImm32) { fImm32 = bswap_32( *(long*)pCode ); pCode+=4; isize+=4; } return isize; } int CInstruction::am_rm32_reg( uchar *pCode ) { fReg1 = (eRegister)((*pCode & 0x38) >> 3); return am_rm32( pCode ); } int CInstruction::am_encode( uchar *buffer, eRegister reg1 ) { 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; // ek must fix the order of the SIB output -> opcode, sib, disp, imm buffer++; isize++; } if (fDisp32 == 0) { 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++; } else { *buffer = 0x40 | (reg1 << 3) | fReg2; long bsDisp32 = bswap_32( fDisp32 ); memcpy( buffer+1, &bsDisp32, 4 ); isize += 4; } if (format & kfmImm8) { buffer[isize] = (uchar)fImm32; isize++; } else if (format & kfmImm32) { long bsImm32 = bswap_32( fImm32 ); memcpy( buffer+isize, &bsImm32, 4 ); isize += 4; } return isize; } //********************************** OpCode generators ************************ /* * returns the size of the generated opcode, which is in buffer */ int CInstruction::generate_opcode( uchar *buffer ) { buffer[0] = 0x90; // make the default NOP return 0; } int CPop::generate_opcode( uchar *buffer ) { if (fFormat == kfreg) { buffer[0] = 0x58 | fReg1; return 1; } return 0; } int CPush::generate_opcode( uchar *buffer ) { if (fFormat == kfreg) { buffer[0] = 0x50 | fReg1; return 1; } return 0; } int CCall::generate_opcode( uchar *buffer ) { if (fFormat == kfNone) { buffer[0] = 0xE8; long bsImm32 = bswap_32( fImm32 ); memcpy( buffer+1, &bsImm32, 4 ); return 5; } return 0; } int CRet::generate_opcode( uchar *buffer ) { if (fFormat == kfNone) { buffer[0] = 0xC3; return 1; } return 0; } void CLea::optimize( void ) { eFormat format = (eFormat)(kBaseFormatMask & (int)fFormat); if ( (fDisp32 == 0) && (fReg1 == fReg2) && (fReg3 == kNoReg) ) fInstr = knop; } int CLea::generate_opcode( uchar *buffer ) { buffer[0] = 0x8D; return 1+am_encode( &buffer[1], fReg1 ); } int CMov::generate_opcode( uchar *buffer ) { int isize = 1; eFormat format = (eFormat)(kBaseFormatMask & (int)fFormat); if (format == kfrm32) { if (fFormat & kfmSize8) buffer[0] = 0xC6; else buffer[0] = 0xC7; } else if (format == kfrm32_r32) { if (fFormat & kfmSize8) buffer[0] = 0x88; else buffer[0] = 0x89; } else if (format == kfr32_rm32) { if (fFormat & kfmSize8) buffer[0] = 0x8A; else buffer[0] = 0x8B; } isize += am_encode( &buffer[1], fReg1 ); return isize; } int CInc::generate_opcode( uchar *buffer ) { if (fFormat == kfreg) { buffer[0] = 0x40 | fReg1; return 1; } int isize = 1; eFormat format = (eFormat)(kBaseFormatMask & (int)fFormat); if (format == kfrm32) { if (kfmSize8 & fFormat) { buffer[0] = 0xFE; isize += am_encode( &buffer[1], (eRegister)0 ); } else if (kfmSize16 & fFormat) { buffer[0] = 0xFF; isize += am_encode( &buffer[1], (eRegister)0 ); } else { buffer[0] = 0xFF; isize += am_encode( &buffer[1], (eRegister)6 ); } return isize; } return isize; } int CCmp::generate_opcode( uchar *buffer ) { int isize = 1; eFormat format = (eFormat)(kBaseFormatMask & (int)fFormat); if (format == kfrm32) { if (fFormat & kfmSize8) buffer[0] = 0x80; else if (fFormat & kfmImm8) buffer[0] = 0x83; else buffer[0] = 0x81; isize += am_encode( &buffer[1], (eRegister)7 ); return isize; } else if (format == kfrm32_r32) { if (fFormat & kfmSize8) buffer[0] = 0x38; else buffer[0] = 0x39; } else if (format == kfr32_rm32) { if (fFormat & kfmSize8) buffer[0] = 0x3A; else buffer[0] = 0x3B; } isize += am_encode( &buffer[1], fReg1 ); return isize; } int CXor::generate_opcode( uchar *buffer ) { int isize = 1; eFormat format = (eFormat)(kBaseFormatMask & (int)fFormat); if (format == kfrm32) { if (fFormat & kfmSize8) buffer[0] = 0x80; else if (fFormat & kfmImm8) buffer[0] = 0x83; else buffer[0] = 0x81; isize += am_encode( &buffer[1], (eRegister)6 ); return isize; } else if (format == kfrm32_r32) { if (fFormat & kfmSize8) buffer[0] = 0x30; else buffer[0] = 0x31; } else if (format == kfr32_rm32) { if (fFormat & kfmSize8) buffer[0] = 0x32; else buffer[0] = 0x33; } 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; eFormat format = (eFormat)(kBaseFormatMask & (int)fFormat); if (format == kfrm32) { 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; } void CSub::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 CSub::generate_opcode( uchar *buffer ) { int isize = 1; eFormat format = (eFormat)(kBaseFormatMask & (int)fFormat); if (format == kfrm32) { if (kfmSize8 & fFormat) { buffer[0] = 0x80; isize += am_encode( &buffer[1], (eRegister)5 ); return isize; } else { if (fFormat | kfmImm8) buffer[0] = 0x83; else buffer[0] = 0x81; isize += am_encode( &buffer[1], (eRegister)5 ); return isize; } } return isize; } 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); switch (format) { case kfreg: cout << reg_name[fReg1]; break; case kfrm32: if (fDisp32) cout << fDisp32; if (fFormat & kfmDeref) cout << "("; cout << reg_name[fReg2]; if (fFormat & kfmDeref) cout << ")"; break; case kfrm32_r32: if (fDisp32) cout << fDisp32; if (fFormat & kfmDeref) cout << "("; cout << reg_name[fReg2]; if (fFormat & kfmDeref) cout << ")"; cout << ", "; cout << reg_name[fReg1]; break; case kfr32_rm32: cout << reg_name[fReg1] << ", "; if (fDisp32) cout << fDisp32; if (fFormat & kfmDeref) cout << "("; cout << reg_name[fReg2]; if (fFormat & kfmDeref) cout << ")"; break; } if (fFormat & kfmImm8) cout.form( ", #0x%02X", fImm32 ); if (fFormat & kfmImm32) cout.form( ", #0x%08X", fImm32 ); cout << "\n"; } void CJmp::output_text( void ) { cout << "j" << cond_name[fCond]; cout.form( "\t.+0x%02X\n", fImm32 ); } //********************* the rest of the code ******************************** int hexdump( CInstruction *instr ) { uchar buffer[16]; int instrSize = instr->generate_opcode( buffer ); if (instrSize) { for (int i=0; i 0) { CInstruction *instr = get_next_instruction( pCode ); int instrSize = instr->fSize; pCode += instrSize; codeSize -= instrSize; fInstructions.push_back( instr ); } } void CFunction::remove_nops( void ) { for( list::iterator p = fInstructions.begin(); p != fInstructions.end(); ++p ) { if ( (*p)->fInstr == knop ) { list::iterator s = p; --p; delete *s; fInstructions.erase(s); } } } //---------------------------------------------------------------------- typedef vector elf_symbol_table; typedef map< basic_string, elf_symbol_table > elf_text_map; void process_mapping(char* mapping, size_t size) { const Elf32_Ehdr* ehdr = reinterpret_cast(mapping); if (verify_elf_header(ehdr) < 0) return; // find the section headers const Elf32_Shdr* shdrs = reinterpret_cast(mapping + ehdr->e_shoff); // find the section header string table, .shstrtab const Elf32_Shdr* shstrtabsh = shdrs + ehdr->e_shstrndx; const char* shstrtab = mapping + shstrtabsh->sh_offset; // find the sections we care about const Elf32_Shdr *symtabsh, *strtabsh, *textsh; int textndx; for (int i = 0; i < ehdr->e_shnum; ++i) { basic_string name(shstrtab + shdrs[i].sh_name); if (gDebug) cout << "name = " << name << "\n"; if (name == ".symtab") { symtabsh = shdrs + i; } else if (name == ".text") { textsh = shdrs + i; textndx = i; } else if (name == ".strtab") { strtabsh = shdrs + i; } } // find the .strtab char* strtab = mapping + strtabsh->sh_offset; // find the .text char* text = mapping + textsh->sh_offset; int textaddr = textsh->sh_addr; // find the symbol table int nentries = symtabsh->sh_size / sizeof(Elf32_Sym); Elf32_Sym* symtab = reinterpret_cast(mapping + symtabsh->sh_offset); // look for code in the .text section elf_text_map textmap; 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); 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) (void)hexdump(cout,functext.data(),sym->st_size); oldSize += sym->st_size; func->get_instructions( (unsigned char *)functext.data(), sym->st_size ); if (gOptimize) { for( list::iterator p = func->fInstructions.begin(); p != func->fInstructions.end(); ++p ) { (*p)->optimize(); } } if (gCompact) func->remove_nops(); for( list::iterator p = func->fInstructions.begin(); p != func->fInstructions.end(); ++p ) { //if ( (*p)->fInstr == kunknown) numUnknowns++; uchar buffer[16]; int instrSize = (*p)->generate_opcode( buffer ); if (instrSize == 0) numUnknowns++; newSize += instrSize; if (gAssembly) { (void)hexdump( *p ); (*p)->output_text(); } delete *p; } delete func; } } cout << "Code size reduction of " << oldSize-newSize -numUnknowns << " bytes out of " << oldSize << " bytes.\n"; if (numUnknowns) cout << "*** Unknowns found: " << numUnknowns << "\n"; } void process_file(const char* name) { if (gDebug) cout << name << "\n"; int fd = open(name, O_RDWR); if (fd < 0) { cerr << "***Failed to Open!***"<< "\n"; } else { struct stat statbuf; if (fstat(fd, &statbuf) < 0) { cerr << "***Failed to Access File!***"<< "\n"; } else { size_t size = statbuf.st_size; void* mapping = mmap(0, size, PROT_READ, MAP_SHARED, fd, 0); if (mapping != MAP_FAILED) { process_mapping(static_cast(mapping), size); munmap(mapping, size); } } close(fd); } } int main(int argc, char* argv[]) { while(1) { char c = getopt( argc, argv, "dcoa" ); if (c == -1) break; switch (c) { case 'a': gAssembly = true; break; 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; } } for (int i = optind; i < argc; ++i) process_file(argv[i]); return 0; }