| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308 |
- /*
- BlitzPC assembler.
- This REALLY needs some work - very slow.
- */
- #include "../std.h"
- #include "../ex.h"
- #include "assem_x86.h"
- #include <iomanip>
- typedef map<string,Inst*> InstMap;
- typedef InstMap::value_type InstPair;
- typedef InstMap::const_iterator InstIter;
- static InstMap instMap;
- //#define LOG
- Assem_x86::Assem_x86( istream &in,Module *mod ):Assem(in,mod){
- //build instruction map, if not built already.
- if( !instMap.size() ){
- for( int k=0;!insts[k].name || insts[k].name[0];++k ){
- if( insts[k].name ) instMap.insert( InstPair( insts[k].name,&insts[k] ) );
- }
- }
- }
- static int findCC( const string &s ){
- if( s=="o" ) return 0;
- if( s=="no" ) return 1;
- if( s=="b"||s=="c"||s=="nae" ) return 2;
- if( s=="ae"||s=="nb"||s=="nc" ) return 3;
- if( s=="e"||s=="z" ) return 4;
- if( s=="ne"||s=="nz" ) return 5;
- if( s=="be"||s=="na" ) return 6;
- if( s=="a"||s=="nbe" ) return 7;
- if( s=="s" ) return 8;
- if( s=="ns" ) return 9;
- if( s=="p"||s=="pe" ) return 10;
- if( s=="ne"||s=="po" ) return 11;
- if( s=="l"||s=="nge" ) return 12;
- if( s=="ge"||s=="nl" ) return 13;
- if( s=="le"||s=="ng" ) return 14;
- if( s=="g"||s=="nle" ) return 15;
- return -1;
- }
- void Assem_x86::align( int n ){
- int pc=mod->getPC();
- int sz=(pc+(n-1))/n*n-pc;
- while( sz-- ) mod->emit( 0x90 );
- }
- void Assem_x86::emit( int n ){
- #ifdef LOG
- clog<<hex<<(int(n)&0xff)<<dec<<' ';
- #endif
- mod->emit( n );
- }
- void Assem_x86::emitw( int n ){
- emit( n );
- emit( (n>>8) );
- }
- void Assem_x86::emitd( int n ){
- emitw( n );
- emitw( n>>16 );
- }
- void Assem_x86::emitImm( const Operand &o,int size ){
- if( size<4 && o.immLabel.size() ) throw Ex( "immediate value cannot by a label" );
- switch( size ){
- case 1:emit( o.imm );return;
- case 2:emitw( o.imm );return;
- case 4:a_reloc( o.immLabel );emitd( o.imm );return;
- }
- }
- void Assem_x86::emitImm( const string &s,int size ){
- Operand op(s);op.parse();
- if( !(op.mode&IMM) ) throw Ex( "operand must be immediate" );
- emitImm( op,size );
- }
- void Assem_x86::r_reloc( const string &s ){
- if( !s.size() ) return;
- mod->addReloc( s.c_str(),mod->getPC(),true );
- }
- void Assem_x86::a_reloc( const string &s ){
- if( !s.size() ) return;
- mod->addReloc( s.c_str(),mod->getPC(),false );
- }
- void Assem_x86::assemInst( const string &name,const string &lhs,const string &rhs ){
- //parse operands
- Operand lop( lhs ),rop( rhs );
- lop.parse();rop.parse();
- //find instruction
- int cc=-1;
- Inst *inst=0;
- //kludge for condition code instructions...
- if( name[0]=='j' ){
- if( (cc=findCC(name.substr(1)))>=0 ){
- static Inst jCC={ "jCC",IMM,NONE,RW_RD|PLUSCC,"\x2\x0F\x80" };
- inst=&jCC;
- }
- }else if( name[0]=='s' && name.substr( 0,3 )=="set" ){
- if( (cc=findCC(name.substr(3)))>=0 ){
- static Inst setCC={ "setne",R_M8,NONE,_2|PLUSCC,"\x2\x0F\x90" };
- inst=&setCC;
- }
- }
- if( inst ){
- if( !(lop.mode&inst->lmode) || !(rop.mode&inst->rmode) ) throw Ex( "illegal addressing mode" );
- }else{
- InstIter it=instMap.find( name );
- if( it==instMap.end() ) throw Ex( "unrecognized instruction" );
- inst=it->second;
- for(;;){
- if( (lop.mode&inst->lmode) && (rop.mode&inst->rmode) ) break;
- if( (++inst)->name ) throw Ex( "illegal addressing mode" );
- }
- }
- //16/32 bit modifier - NOP for now
- if( inst->flags & (O16|O32) ){}
- int k,n=inst->bytes[0];
- for( k=1;k<n;++k ) emit( inst->bytes[k] );
- if( inst->flags&PLUSREG ) emit( inst->bytes[k]+lop.reg );
- else if( inst->flags&PLUSCC ) emit( inst->bytes[k]+cc );
- else emit( inst->bytes[k] );
- if( inst->flags&(_0|_1|_2|_3|_4|_5|_6|_7|_R ) ){
- //find the memop;
- const Operand &mop=
- (inst->rmode&(MEM|MEM8|MEM16|MEM32|R_M|R_M8|R_M16|R_M32))?rop:lop;
- //find the spare field value.
- int rm=0;
- switch( inst->flags&(_0|_1|_2|_3|_4|_5|_6|_7|_R ) ){
- case _0:rm=0;break;case _1:rm=1;break;case _2:rm=2;break;case _3:rm=3;break;
- case _4:rm=4;break;case _5:rm=5;break;case _6:rm=6;break;case _7:rm=7;break;
- case _R:rm=(inst->rmode&(REG8|REG16|REG32))?rop.reg:lop.reg;break;
- }
- rm<<=3;
- if( mop.mode & REG ){ //reg
- emit( 0xc0|rm|mop.reg );
- }else if( mop.baseReg>=0 ){ //base, index?
- int mod=mop.offset ? 0x40 : 0x00;
- if( mop.baseLabel.size() || mop.offset<-128 || mop.offset>127 ) mod=0x80;
- if( mop.baseReg==5 && !mod ) mod=0x40;
- if( mop.indexReg>=0 ){ //base, index!
- emit( mod|rm|4 );
- emit( (mop.shift<<6)|(mop.indexReg<<3)|mop.baseReg );
- }else{ //base, no index!
- if( mop.baseReg!=4 ) emit( mod|rm|mop.baseReg);
- else{
- emit( mod|rm|4 );emit( (4<<3)|mop.baseReg );
- }
- }
- if( (mod&0xc0)==0x40 ) emit( mop.offset );
- else if( (mod&0xc0)==0x80 ){
- //reloc
- a_reloc( mop.baseLabel );emitd( mop.offset );
- }
- }else if( mop.indexReg>=0 ){ //index, no base!
- emit( rm|4 );
- emit( (mop.shift<<6)|(mop.indexReg<<3)|5 );
- //reloc
- a_reloc( mop.baseLabel );emitd( mop.offset );
- }else{ //[disp]
- emit( rm|5 );
- //reloc
- a_reloc( mop.baseLabel );emitd( mop.offset );
- }
- }
- if( inst->flags&RW_RD ){
- r_reloc( lop.immLabel );emitd( lop.imm-4 );
- }
- if( inst->flags&IB ){
- if( lop.mode&IMM ) emitImm( lop,1 );else emitImm( rop,1 );
- }else if( inst->flags&IW ){
- if( lop.mode&IMM ) emitImm( lop,2 );else emitImm( rop,2 );
- }else if( inst->flags&ID ){
- if( lop.mode&IMM ) emitImm( lop,4 );else emitImm( rop,4 );
- }
- }
- void Assem_x86::assemDir( const string &name,const string &op ){
- if( !op.size() ) throw Ex( "operand error" );
- if( name==".db" ){
- if( op[0]!='\"' ) emitImm( op,1 );
- else{
- if( op.size()<2 || op[op.size()-1]!='\"' ) throw Ex( "operand error" );
- for( int k=1;k<op.size()-1;++k ) emit( op[k] );
- }
- }else if( name==".dw" ){
- emitImm( op,2 );
- }else if( name==".dd" ){
- emitImm( op,4 );
- }else if( name==".align" ){
- Operand o( op );o.parse();
- if( !(o.mode&IMM) ) throw Ex( "operand must be immediate" );
- align( o.imm );
- }else{
- throw Ex( "unrecognized assembler directive" );
- }
- }
- void Assem_x86::assemLine( const string &line ){
- int i=0;
- string name;
- vector<string> ops;
- //label?
- if( !isspace( line[i] ) ){
- while( !isspace( line[i] ) ) ++i;
- string lab=line.substr( 0,i );
- if( !mod->addSymbol( lab.c_str(),mod->getPC() ) ) throw Ex( "duplicate label" );
- }
- //skip space
- while( isspace( line[i] ) && line[i]!='\n' ) ++i;
- if( line[i]=='\n' || line[i]==';' ) return;
- //fetch instruction name
- int from=i;for( ++i;!isspace( line[i] );++i ){}
- name=line.substr( from,i-from );
- for(;;){
- //skip space
- while( isspace( line[i] ) && line[i]!='\n' ) ++i;
- if( line[i]=='\n' || line[i]==';' ) break;
- int from=i;
- if( line[i]=='\"' ){
- for( ++i;line[i]!='\"' && line[i]!='\n';++i ){}
- if( line[i++]!='\"' ) throw Ex( "missing close quote" );
- }else{
- for( ++i;line[i]!=',' && line[i]!=';' && line[i]!='\n';++i ){}
- }
- //back-up over space
- while( i && isspace( line[i-1] ) ) --i;
- ops.push_back( line.substr( from,i-from ) );
- //skip space
- while( isspace( line[i] ) && line[i]!='\n' ) ++i;
- if( line[i]=='\n' || line[i]==';' ) break;
- if( line[i++]!=',' ) throw Ex( "expecting ','" );
- }
- //pseudo op?
- if( name[0]=='.' ){
- for( int k=0;k<ops.size();++k ) assemDir( name,ops[k] );
- return;
- }
- //normal instruction!
- if( ops.size()>2 ) throw Ex( "Too many operands" );
- ops.push_back( "" );ops.push_back( "" );
- assemInst( name,ops[0],ops[1] );
- }
- void Assem_x86::assemble(){
- string line;
- while( !in.eof() ){
- try{
- getline( in,line );
- line+='\n';
- #ifdef LOG
- clog<<line;
- #endif
- assemLine( line );
- #ifdef LOG
- clog<<endl;
- #endif
- }catch( Ex &x ){
- throw Ex( line+x.ex );
- }
- }
- }
|