size_t DisCliValueString( void *d, dis_dec_ins *ins, unsigned op_num, char *buff, size_t buff_len ) { struct pass2 *pd = d; size_t len; dis_operand *op; ref_flags rf; buff_len = buff_len; buff[0] = '\0'; rf = RFLAG_DEFAULT; op = &ins->op[op_num]; switch( op->type & DO_MASK ) { case DO_RELATIVE: case DO_MEMORY_REL: case DO_ABSOLUTE: case DO_MEMORY_ABS: if( pd->r_entry != NULL ) { /* if there is an override we must avoid the frame */ if( ( ins->flags.u.x86 & DIS_X86_SEG_OR ) && IsIntelx86() ) { rf |= RFLAG_NO_FRAME; } len = HandleAReference( op->value, ins->size, rf, pd->loop + op->op_position, pd->size, &pd->r_entry, buff ); if( len != 0 ) { return( len ); } } switch( op->type & DO_MASK ) { case DO_RELATIVE: case DO_MEMORY_REL: op->value += pd->loop; break; } if( op->base == DR_NONE && op->index == DR_NONE ) { FmtSizedHexNum( buff, ins, op_num ); } else if( op->value > 0 ) { FmtHexNum( buff, 0, op->value, FALSE ); } else if( op->value < 0 ) { buff[0] = '-'; FmtHexNum( &buff[1], 0, -op->value, FALSE ); } break; case DO_IMMED: if( pd->r_entry != NULL ) { rf |= RFLAG_IS_IMMED; len = HandleAReference( op->value, ins->size, rf, pd->loop + op->op_position, pd->size, &pd->r_entry, buff ); if( len != 0 ) { return( len ); } } FmtSizedHexNum( buff, ins, op_num ); break; } return( strlen( buff ) ); }
ref_entry DoPass1Relocs( unsigned_8 *contents, ref_entry r_entry, orl_sec_offset start, orl_sec_offset end ) { long value; unnamed_label_return_struct rs; if( !IsIntelx86() ) return( r_entry ); while( r_entry && ( r_entry->offset < start ) ) { r_entry = r_entry->next; } while( r_entry && ( r_entry->offset < end ) ) { if( r_entry->label->shnd && ( r_entry->label->type == LTYP_SECTION ) ) { if( r_entry->addend ) { value = HandleAddend( r_entry ); } else { switch( RelocSize( r_entry ) ) { case( 6 ): case( 4 ): value = *((long *)&(contents[ r_entry->offset ])); break; case( 2 ): value = *((short *)&(contents[ r_entry->offset ])); break; case( 1 ): value = *((signed char *)&(contents[ r_entry->offset ])); break; default: value = 0; } } CreateUnnamedLabel( r_entry->label->shnd, value, &rs ); if( rs.error == RC_OKAY ) { r_entry->label = rs.entry; r_entry->no_val = 1; } } r_entry = r_entry->next; } return( r_entry ); }
return_val Init( void ) { return_val error; const char * const *list; const char *name; hash_entry_data key_entry; error = RC_OKAY; OutputDest = STDOUT_FILENO; ChangePrintDest( OutputDest ); relocSections.first = NULL; relocSections.last = NULL; if( !MsgInit() ) { // MsgInit does its own error message printing return( RC_ERROR ); } MemOpen(); error = HandleArgs(); if( error != RC_OKAY ) { return( error ); } openFiles(); initGlobals(); error = initHashTables(); if( error != RC_OKAY ) { PrintErrorMsg( error, WHERE_INIT_HASH_TABLES ); return( error ); } error = initServicesUsed(); if( error != RC_OKAY ) { // initServicesUsed does its own error message printing return( error ); } error = initSectionTables(); if( error != RC_OKAY ) { PrintErrorMsg( error, WHERE_CREATE_SEC_TABLES ); return( error ); } if( Options & PRINT_PUBLICS ) { CreatePublicsArray(); } if( IsMasmOutput() ) { CommentString = MASM_COMMENT_STRING; } if( IsIntelx86() ) { SkipRefTable = HashTableCreate( RECOGNITION_TABLE_SIZE, HASH_STRING_IGNORECASE ); if( SkipRefTable != NULL ) { for( list = intelSkipRefList; (name = *list) != NULL; ++list ) { key_entry.key.u.string = name; key_entry.data.u.string = *list; error = HashTableInsert( SkipRefTable, &key_entry ); if( error != RC_OKAY ) { break; } } } } if( LabelChar == 0 ) { if( IsMasmOutput() ) { LabelChar = 'L'; } else { LabelChar = 'X'; } } return( error ); }
void Init( void ) { char cmd_line[ CMD_LINE_LEN ]; return_val error; char **list; OutputDest = STDOUT_FILENO; ChangePrintDest( OutputDest ); relocSections.first = NULL; relocSections.last = NULL; if( !MsgInit() ) { // MsgInit does its own error message printing exit( -1 ); } MemOpen(); getcmd( cmd_line ); HandleArgs( cmd_line ); openFiles(); initGlobals(); error = initHashTables(); if( error == OKAY ) { error = initServicesUsed(); if( error == OKAY ) { error = initSectionTables(); if( error != OKAY ) { // free hash tables and services MemClose(); LeaveProgram( error, WHERE_CREATE_SEC_TABLES ); } } else { // free hash tables CloseFiles(); FreeHashTables(); // initServicesUsed does its own error message printing exit( error ); } } else { CloseFiles(); MemClose(); LeaveProgram( error, WHERE_INIT_HASH_TABLES ); } if( Options & PRINT_PUBLICS ) { CreatePublicsArray(); } if( IsMasmOutput() ) { CommentString = MASM_COMMENT_STRING; } if( IsIntelx86() ) { SkipRefTable = HashTableCreate( RECOGNITION_TABLE_SIZE, HASH_STRING, (hash_table_comparison_func) stricmp ); if( SkipRefTable ) { list = intelSkipRefList; while( *list ) { error = HashTableInsert( SkipRefTable, (hash_value) *list, (hash_data) *list ); if( error != OKAY ) break; list++; } } } if( !LabelChar ) { if( IsMasmOutput() ) { LabelChar = 'L'; } else { LabelChar = 'X'; } } }
return_val DoPass1( orl_sec_handle shnd, unsigned_8 *contents, orl_sec_size size, ref_list sec_ref_list, scantab_ptr stl ) // perform pass 1 on one section { orl_sec_offset loop; dis_dec_ins decoded; dis_value value; dis_return dr; unnamed_label_return_struct rs; return_val error; unsigned i; ref_entry r_entry; dis_inst_flags flags; orl_sec_offset op_pos; int is_intel; int adjusted; sa_disasm_struct sds; sds.data = contents; sds.last = size - 1; if( sec_ref_list != NULL ) { r_entry = sec_ref_list->first; } else { r_entry = NULL; } flags.u.all = DIF_NONE; if( GetMachineType() == ORL_MACHINE_TYPE_I386 ) { if( ( GetFormat() != ORL_OMF ) || ( ORLSecGetFlags( shnd ) & ORL_SEC_FLAG_USE_32 ) ) { flags.u.x86 = DIF_X86_USE32_FLAGS; } is_intel = 1; } else { is_intel = IsIntelx86(); } for( loop = 0; loop < size; loop += decoded.size ) { // skip data in code segment while( stl && ( loop > stl->end ) ) { stl = stl->next; } if( stl && ( loop >= stl->start ) ) { decoded.size = 0; if( is_intel ) { r_entry = DoPass1Relocs( contents, r_entry, loop, stl->end ); } loop = stl->end; stl = stl->next; continue; } // data may not be listed in scan table, but a fixup at this offset will // give it away while( r_entry && ( ( r_entry->offset < loop ) || SkipRef(r_entry) ) ) { r_entry = r_entry->next; } if( r_entry && ( r_entry->offset == loop ) ) { if( is_intel || IsDataReloc( r_entry ) ) { // we just skip the data op_pos = loop; decoded.size = 0; loop += RelocSize( r_entry ); r_entry = DoPass1Relocs( contents, r_entry, op_pos, loop ); continue; } } DisDecodeInit( &DHnd, &decoded ); decoded.flags.u.all |= flags.u.all; sds.offs = loop; dr = DisDecode( &DHnd, &sds, &decoded ); // if an invalid instruction was found, there is nothing we can do. if( dr != DR_OK ) return( RC_ERROR ); for( i = 0; i < decoded.num_ops; ++i ) { adjusted = 0; op_pos = loop + decoded.op[i].op_position; switch( decoded.op[i].type & DO_MASK ) { case DO_IMMED: if( !is_intel ) break; /* fall through */ case DO_RELATIVE: case DO_MEMORY_REL: if( ( decoded.op[i].type & DO_MASK ) != DO_IMMED ) { decoded.op[i].value += loop; adjusted = 1; } /* fall through */ case DO_ABSOLUTE: case DO_MEMORY_ABS: // Check for reloc at this location while( r_entry && r_entry->offset < op_pos ) { r_entry = r_entry->next; } if( r_entry && ( r_entry->offset == op_pos ) ) { if( is_intel && r_entry->label->shnd && ( r_entry->type != ORL_RELOC_TYPE_SEGMENT ) && ( r_entry->label->type == LTYP_SECTION ) ) { /* For section offsets under intel we MUST generate a * local label because the offset might change when the * code is re-assembled */ if( r_entry->addend ) { r_entry->no_val = 0; CreateUnnamedLabel( r_entry->label->shnd, HandleAddend( r_entry ), &rs ); } else { r_entry->no_val = 1; if( adjusted && isSelfReloc( r_entry ) && ( r_entry->label->type == LTYP_SECTION ) ) { /* This is a kludgy reloc done under OMF */ decoded.op[i].value -= loop; decoded.op[i].value -= decoded.size; switch( RelocSize( r_entry ) ) { case( 2 ): decoded.op[i].value = (uint_16)(decoded.op[i].value); case( 1 ): decoded.op[i].value = (uint_8)(decoded.op[i].value); } } value = decoded.op[i].value; if( value < 0 || value > ORLSecGetSize( r_entry->label->shnd ) ) { // can't fold it into the label position - BBB Oct 28, 1996 value = 0; r_entry->no_val = 0; } CreateUnnamedLabel( r_entry->label->shnd, value, &rs ); } if( rs.error != RC_OKAY ) return( rs.error ); r_entry->label = rs.entry; } else { // fixme: got to handle other types of relocs here } } else if( ( decoded.op[i].type & DO_MASK ) != DO_IMMED ) { if( decoded.op[i].base == DR_NONE && decoded.op[i].index == DR_NONE ) { switch( decoded.op[i].type & DO_MASK ) { case DO_MEMORY_REL: case DO_MEMORY_ABS: // use decoded instruction size for absolute memory on amd64. // the cpu will reference rip _after_ the instruction is // completely fetched and decoded. // relocations in pass2 are not applied because they break // relative memory references if no relocation is present! if( GetMachineType() == ORL_MACHINE_TYPE_AMD64 ) { decoded.op[i].value += decoded.size; // I don't know if this is neccessary, but it will generate // labels for memory references if no symbol is present // (ex: executable file) CreateUnnamedLabel( shnd, decoded.op[i].value, &rs ); if( rs.error != RC_OKAY ) return( rs.error ); error = CreateUnnamedLabelRef( shnd, rs.entry, op_pos ); } else { // create an LTYP_ABSOLUTE label CreateAbsoluteLabel( shnd, decoded.op[i].value, &rs ); if( rs.error != RC_OKAY ) return( rs.error ); error = CreateAbsoluteLabelRef( shnd, rs.entry, op_pos ); } break; default: // create an LTYP_UNNAMED label CreateUnnamedLabel( shnd, decoded.op[i].value, &rs ); if( rs.error != RC_OKAY ) return( rs.error ); error = CreateUnnamedLabelRef( shnd, rs.entry, op_pos ); break; } if( error != RC_OKAY ) { return( error ); } } } break; } } } return( RC_OKAY ); }
num_errors DoPass2( section_ptr sec, unsigned_8 *contents, orl_sec_size size, label_list sec_label_list, ref_list sec_ref_list ) // perform pass 2 on one section { struct pass2 data; label_entry l_entry; dis_dec_ins decoded; char name[ MAX_INS_NAME ]; char ops[ MAX_OBJ_NAME + 24 ]; // at most 1 label/relocation per instruction, plus room for registers, brackets and other crap dis_inst_flags flags; scantab_ptr st; int is_intel; sa_disasm_struct sds; char *FPU_fixup; int pos_tabs; bool is32bit; routineBase = 0; st = sec->scan; data.size = size; sds.data = contents; sds.last = size - 1; l_entry = NULL; if( sec_label_list != NULL ) { l_entry = sec_label_list->first; } if( sec_ref_list != NULL ) { data.r_entry = sec_ref_list->first; } else { data.r_entry = NULL; } data.disassembly_errors = 0; if( source_mix ) { GetSourceFile( sec ); } PrintHeader( sec ); if( size && sec_label_list ) PrintAssumeHeader( sec ); flags.u.all = DIF_NONE; if( GetMachineType() == ORL_MACHINE_TYPE_I386 ) { if( ( GetFormat() != ORL_OMF ) || ( ORLSecGetFlags( sec->shnd ) & ORL_SEC_FLAG_USE_32 ) ) { flags.u.x86 = DIF_X86_USE32_FLAGS; } is_intel = 1; } else { is_intel = IsIntelx86(); } is32bit = ( size >= 0x10000 ); for( data.loop = 0; data.loop < size; data.loop += decoded.size ) { // process data in code segment while( st && ( data.loop > st->end ) ) { st = st->next; } if( st && ( data.loop >= st->start ) ) { decoded.size = 0; processDataInCode( sec, contents, &data, st->end - data.loop, &l_entry ); st = st->next; continue; } // data may not be listed in scan table, but a fixup at this offset will // give it away while( data.r_entry && ( data.r_entry->offset < data.loop ) ) { data.r_entry = data.r_entry->next; } FPU_fixup = processFpuEmulatorFixup( &data.r_entry, data.loop ); if( data.r_entry && ( data.r_entry->offset == data.loop ) ) { if( is_intel || IsDataReloc( data.r_entry ) ) { // we just skip the data decoded.size = 0; processDataInCode( sec, contents, &data, RelocSize( data.r_entry ), &l_entry ); continue; } } if( source_mix ) { MixSource( data.loop ); } DisDecodeInit( &DHnd, &decoded ); decoded.flags.u.all |= flags.u.all; sds.offs = data.loop; DisDecode( &DHnd, &sds, &decoded ); if( sec_label_list ) { l_entry = handleLabels( sec->name, data.loop, data.loop + decoded.size, l_entry, size ); if( ( l_entry != NULL ) && ( l_entry->offset > data.loop ) && ( l_entry->offset < data.loop + decoded.size ) ) { /* If we have a label planted in the middle of this instruction (see inline memchr for example), put out a couple of data bytes, and then restart decode and label process from offset of actual label. */ decoded.size = 0; processDataInCode( sec, contents, &data, l_entry->offset - data.loop, &l_entry ); continue; } } DisFormat( &DHnd, &data, &decoded, DFormat, name, sizeof( name ), ops, sizeof( ops ) ); if( FPU_fixup != NULL ) { if( !(DFormat & DFF_ASM) ) { BufferAlignToTab( PREFIX_SIZE_TABS ); } BufferStore( "\t%sFPU fixup %s\n", CommentString, FPU_fixup ); } if( !(DFormat & DFF_ASM) ) { unsigned_64 *tmp_64; unsigned_32 *tmp_32; unsigned_16 *tmp_16; tmp_64 = (unsigned_64 *)(contents + data.loop); tmp_32 = (unsigned_32 *)(contents + data.loop); tmp_16 = (unsigned_16 *)(contents + data.loop); if( DHnd.need_bswap ) { switch( DisInsSizeInc( &DHnd ) ) { //case 8: SWAP_64( *tmp_64 ); // break; case 4: SWAP_32( *tmp_32 ); break; case 2: SWAP_16( *tmp_16 ); break; default: break; } } PrintLinePrefixAddress( data.loop, is32bit ); PrintLinePrefixData( contents, data.loop, size, DisInsSizeInc( &DHnd ), decoded.size ); BufferAlignToTab( PREFIX_SIZE_TABS ); } BufferStore( "\t%s", name ); if( *ops != '\0' ) { pos_tabs = ( DisInsNameMax( &DHnd ) + TAB_WIDTH ) / TAB_WIDTH + 1; if( !(DFormat & DFF_ASM) ) { pos_tabs += PREFIX_SIZE_TABS; } BufferAlignToTab( pos_tabs ); BufferConcat( ops ); } BufferConcatNL(); BufferPrint(); } if( sec_label_list ) { l_entry = handleLabels( sec->name, size, (orl_sec_offset)-1, l_entry, size ); } if( !(DFormat & DFF_ASM) ) { routineSize = data.loop - routineBase; BufferConcatNL(); BufferMsg( ROUTINE_SIZE ); BufferStore(" %d ", routineSize ); BufferMsg( BYTES ); BufferConcat(", "); BufferMsg( ROUTINE_BASE ); BufferStore(" %s + %04X\n\n", sec->name, routineBase ); BufferPrint(); } if( source_mix ) { EndSourceMix(); } PrintTail( sec ); return( data.disassembly_errors ); }
size_t HandleAReference( dis_value value, int ins_size, ref_flags flags, orl_sec_offset offset, orl_sec_size sec_size, ref_entry * r_entry, char *buff ) // handle any references at this offset { return_val error; dis_value nvalue; char *p; buff[0] = '\0'; for( ; *r_entry && (*r_entry)->offset == offset; *r_entry = (*r_entry)->next ) { if( (*r_entry)->no_val == 0 ) { nvalue = value; } else if( (*r_entry)->addend ) { nvalue = HandleAddend( *r_entry ); } else { nvalue = 0; } switch( (*r_entry)->type ) { case ORL_RELOC_TYPE_MAX + 1: case ORL_RELOC_TYPE_JUMP: case ORL_RELOC_TYPE_REL_21_SH: case ORL_RELOC_TYPE_WORD_26: error = referenceString( *r_entry, sec_size, "j^", "", "", buff, flags ); if( error != RC_OKAY ) { // label is defined to be beyond the boundaries of the section! if( !(DFormat & DFF_ASM) ){ BufferStore("\t %04X", offset ); BufferAlignToTab( COMMENT_TAB_POS ); } else { BufferConcat("\t" ); } BufferConcat( CommentString ); BufferMsg( LABEL_BEYOND_SECTION ); BufferConcatNL(); BufferPrint(); *r_entry = (*r_entry)->next; return( 0 ); } continue; // Don't print addend break; case ORL_RELOC_TYPE_SEC_REL: referenceString( *r_entry, sec_size, "s^", "s^", "@s", buff, flags ); break; case ORL_RELOC_TYPE_HALF_HI: referenceString( *r_entry, sec_size, "h^", "h^", "@h", buff, flags ); break; case ORL_RELOC_TYPE_HALF_HA: referenceString( *r_entry, sec_size, "ha^", "ha^", "@ha", buff, flags ); break; case ORL_RELOC_TYPE_HALF_LO: referenceString( *r_entry, sec_size, "l^", "l^", "@l", buff, flags ); break; case ORL_RELOC_TYPE_REL_14: case ORL_RELOC_TYPE_REL_24: case ORL_RELOC_TYPE_WORD_14: case ORL_RELOC_TYPE_WORD_24: nvalue &= ~0x3; case ORL_RELOC_TYPE_WORD_16: case ORL_RELOC_TYPE_WORD_32: case ORL_RELOC_TYPE_WORD_64: if( ( (*r_entry)->label->type != LTYP_GROUP ) && ( flags & RFLAG_IS_IMMED ) && IsMasmOutput() ) { referenceString( *r_entry, sec_size, "offset ", "offset ", "", buff, flags ); } else { referenceString( *r_entry, sec_size, "", "", "", buff, flags ); } break; case ORL_RELOC_TYPE_REL_16: if( IsIntelx86() && !(*r_entry)->no_val ) { nvalue -= ins_size; } if( ( (*r_entry)->label->type != LTYP_GROUP ) && ( flags & RFLAG_IS_IMMED ) && IsMasmOutput() ) { referenceString( *r_entry, sec_size, "offset ", "offset ", "", buff, flags ); } else { referenceString( *r_entry, sec_size, "", "", "", buff, flags ); } break; case ORL_RELOC_TYPE_WORD_8: case ORL_RELOC_TYPE_WORD_16_SEG: case ORL_RELOC_TYPE_WORD_HI_8: case ORL_RELOC_TYPE_WORD_32_SEG: // Keep these seperate because they are OMF specific referenceString( *r_entry, sec_size, "", "", "", buff, flags ); break; case ORL_RELOC_TYPE_SEGMENT: if( ( (*r_entry)->label->type != LTYP_GROUP ) && ( (*r_entry)->label->type != LTYP_SECTION ) && ( flags & RFLAG_IS_IMMED ) && IsMasmOutput() ) { referenceString( *r_entry, sec_size, "seg ", "seg ", "", buff, flags ); } else { referenceString( *r_entry, sec_size, "", "", "", buff, flags ); } break; case ORL_RELOC_TYPE_REL_32_NOADJ: // this is a little kluge because Brian's ELF files seem to have // -4 in the implicit addend for calls and such BBB May 09, 1997 nvalue += 4; // fall through case ORL_RELOC_TYPE_REL_8: case ORL_RELOC_TYPE_REL_16_SEG: case ORL_RELOC_TYPE_REL_HI_8: case ORL_RELOC_TYPE_REL_32_SEG: case ORL_RELOC_TYPE_REL_32: case ORL_RELOC_TYPE_REL_32_ADJ5: case ORL_RELOC_TYPE_REL_32_ADJ4: case ORL_RELOC_TYPE_REL_32_ADJ3: case ORL_RELOC_TYPE_REL_32_ADJ2: case ORL_RELOC_TYPE_REL_32_ADJ1: // For some reason we add the instruction size to the value // of the displacement in a relative call and get a bad // offset, due to CORE implementation // // Main reason : // instruction size with displacement and with addend is correct for // relative addresses without relocate // // in amd64 code the instruction size will be added in pass1.c! if( (*r_entry)->no_val == 0 && !( GetMachineType() == ORL_MACHINE_TYPE_AMD64 ) ) { nvalue -= ins_size; } referenceString( *r_entry, sec_size, "", "", "", buff, flags ); break; case ORL_RELOC_TYPE_TOCREL_14: nvalue &= ~0x3; case ORL_RELOC_TYPE_TOCREL_16: referenceString( *r_entry, sec_size, "[toc]", "[toc]", "@toc", buff, flags ); break; case ORL_RELOC_TYPE_TOCVREL_14: nvalue &= ~0x3; case ORL_RELOC_TYPE_TOCVREL_16: referenceString( *r_entry, sec_size, "[tocv]", "[tocv]", "@tocv", buff, flags ); break; case ORL_RELOC_TYPE_GOT_16: referenceString( *r_entry, sec_size, "", "", "@got", buff, flags ); break; case ORL_RELOC_TYPE_GOT_16_HI: referenceString( *r_entry, sec_size, "", "", "@got@h", buff, flags ); break; case ORL_RELOC_TYPE_GOT_16_HA: referenceString( *r_entry, sec_size, "", "", "@got@ha", buff, flags ); break; case ORL_RELOC_TYPE_GOT_16_LO: referenceString( *r_entry, sec_size, "", "", "@got@l", buff, flags ); break; case ORL_RELOC_TYPE_PLTREL_24: case ORL_RELOC_TYPE_PLTREL_32: case ORL_RELOC_TYPE_PLT_32: referenceString( *r_entry, sec_size, "", "", "@plt", buff, flags ); break; case ORL_RELOC_TYPE_PLT_16_HI: referenceString( *r_entry, sec_size, "", "", "@plt@h", buff, flags ); break; case ORL_RELOC_TYPE_PLT_16_HA: referenceString( *r_entry, sec_size, "", "", "@plt@ha", buff, flags ); break; case ORL_RELOC_TYPE_PLT_16_LO: referenceString( *r_entry, sec_size, "", "", "@plt@l", buff, flags ); break; default: continue; } // LTYP_UNNAMED labels are always at the correct location // if( nvalue != 0 && (*r_entry)->label->type != LTYP_UNNAMED ) { // not so - BBB Oct 28, 1996 if(( (*r_entry)->no_val == 0 ) && ( nvalue != 0 )) { p = &buff[strlen(buff)]; if( nvalue < 0 ) { *p++ = '-'; nvalue = -nvalue; } else { *p++ = '+'; } FmtHexNum( p, 0, nvalue, FALSE ); } } return( strlen( buff ) ); }