assem_x86.cpp 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308
  1. /*
  2. BlitzPC assembler.
  3. This REALLY needs some work - very slow.
  4. */
  5. #include "../std.h"
  6. #include "../ex.h"
  7. #include "assem_x86.h"
  8. #include <iomanip>
  9. typedef map<string,Inst*> InstMap;
  10. typedef InstMap::value_type InstPair;
  11. typedef InstMap::const_iterator InstIter;
  12. static InstMap instMap;
  13. //#define LOG
  14. Assem_x86::Assem_x86( istream &in,Module *mod ):Assem(in,mod){
  15. //build instruction map, if not built already.
  16. if( !instMap.size() ){
  17. for( int k=0;!insts[k].name || insts[k].name[0];++k ){
  18. if( insts[k].name ) instMap.insert( InstPair( insts[k].name,&insts[k] ) );
  19. }
  20. }
  21. }
  22. static int findCC( const string &s ){
  23. if( s=="o" ) return 0;
  24. if( s=="no" ) return 1;
  25. if( s=="b"||s=="c"||s=="nae" ) return 2;
  26. if( s=="ae"||s=="nb"||s=="nc" ) return 3;
  27. if( s=="e"||s=="z" ) return 4;
  28. if( s=="ne"||s=="nz" ) return 5;
  29. if( s=="be"||s=="na" ) return 6;
  30. if( s=="a"||s=="nbe" ) return 7;
  31. if( s=="s" ) return 8;
  32. if( s=="ns" ) return 9;
  33. if( s=="p"||s=="pe" ) return 10;
  34. if( s=="ne"||s=="po" ) return 11;
  35. if( s=="l"||s=="nge" ) return 12;
  36. if( s=="ge"||s=="nl" ) return 13;
  37. if( s=="le"||s=="ng" ) return 14;
  38. if( s=="g"||s=="nle" ) return 15;
  39. return -1;
  40. }
  41. void Assem_x86::align( int n ){
  42. int pc=mod->getPC();
  43. int sz=(pc+(n-1))/n*n-pc;
  44. while( sz-- ) mod->emit( 0x90 );
  45. }
  46. void Assem_x86::emit( int n ){
  47. #ifdef LOG
  48. clog<<hex<<(int(n)&0xff)<<dec<<' ';
  49. #endif
  50. mod->emit( n );
  51. }
  52. void Assem_x86::emitw( int n ){
  53. emit( n );
  54. emit( (n>>8) );
  55. }
  56. void Assem_x86::emitd( int n ){
  57. emitw( n );
  58. emitw( n>>16 );
  59. }
  60. void Assem_x86::emitImm( const Operand &o,int size ){
  61. if( size<4 && o.immLabel.size() ) throw Ex( "immediate value cannot by a label" );
  62. switch( size ){
  63. case 1:emit( o.imm );return;
  64. case 2:emitw( o.imm );return;
  65. case 4:a_reloc( o.immLabel );emitd( o.imm );return;
  66. }
  67. }
  68. void Assem_x86::emitImm( const string &s,int size ){
  69. Operand op(s);op.parse();
  70. if( !(op.mode&IMM) ) throw Ex( "operand must be immediate" );
  71. emitImm( op,size );
  72. }
  73. void Assem_x86::r_reloc( const string &s ){
  74. if( !s.size() ) return;
  75. mod->addReloc( s.c_str(),mod->getPC(),true );
  76. }
  77. void Assem_x86::a_reloc( const string &s ){
  78. if( !s.size() ) return;
  79. mod->addReloc( s.c_str(),mod->getPC(),false );
  80. }
  81. void Assem_x86::assemInst( const string &name,const string &lhs,const string &rhs ){
  82. //parse operands
  83. Operand lop( lhs ),rop( rhs );
  84. lop.parse();rop.parse();
  85. //find instruction
  86. int cc=-1;
  87. Inst *inst=0;
  88. //kludge for condition code instructions...
  89. if( name[0]=='j' ){
  90. if( (cc=findCC(name.substr(1)))>=0 ){
  91. static Inst jCC={ "jCC",IMM,NONE,RW_RD|PLUSCC,"\x2\x0F\x80" };
  92. inst=&jCC;
  93. }
  94. }else if( name[0]=='s' && name.substr( 0,3 )=="set" ){
  95. if( (cc=findCC(name.substr(3)))>=0 ){
  96. static Inst setCC={ "setne",R_M8,NONE,_2|PLUSCC,"\x2\x0F\x90" };
  97. inst=&setCC;
  98. }
  99. }
  100. if( inst ){
  101. if( !(lop.mode&inst->lmode) || !(rop.mode&inst->rmode) ) throw Ex( "illegal addressing mode" );
  102. }else{
  103. InstIter it=instMap.find( name );
  104. if( it==instMap.end() ) throw Ex( "unrecognized instruction" );
  105. inst=it->second;
  106. for(;;){
  107. if( (lop.mode&inst->lmode) && (rop.mode&inst->rmode) ) break;
  108. if( (++inst)->name ) throw Ex( "illegal addressing mode" );
  109. }
  110. }
  111. //16/32 bit modifier - NOP for now
  112. if( inst->flags & (O16|O32) ){}
  113. int k,n=inst->bytes[0];
  114. for( k=1;k<n;++k ) emit( inst->bytes[k] );
  115. if( inst->flags&PLUSREG ) emit( inst->bytes[k]+lop.reg );
  116. else if( inst->flags&PLUSCC ) emit( inst->bytes[k]+cc );
  117. else emit( inst->bytes[k] );
  118. if( inst->flags&(_0|_1|_2|_3|_4|_5|_6|_7|_R ) ){
  119. //find the memop;
  120. const Operand &mop=
  121. (inst->rmode&(MEM|MEM8|MEM16|MEM32|R_M|R_M8|R_M16|R_M32))?rop:lop;
  122. //find the spare field value.
  123. int rm=0;
  124. switch( inst->flags&(_0|_1|_2|_3|_4|_5|_6|_7|_R ) ){
  125. case _0:rm=0;break;case _1:rm=1;break;case _2:rm=2;break;case _3:rm=3;break;
  126. case _4:rm=4;break;case _5:rm=5;break;case _6:rm=6;break;case _7:rm=7;break;
  127. case _R:rm=(inst->rmode&(REG8|REG16|REG32))?rop.reg:lop.reg;break;
  128. }
  129. rm<<=3;
  130. if( mop.mode & REG ){ //reg
  131. emit( 0xc0|rm|mop.reg );
  132. }else if( mop.baseReg>=0 ){ //base, index?
  133. int mod=mop.offset ? 0x40 : 0x00;
  134. if( mop.baseLabel.size() || mop.offset<-128 || mop.offset>127 ) mod=0x80;
  135. if( mop.baseReg==5 && !mod ) mod=0x40;
  136. if( mop.indexReg>=0 ){ //base, index!
  137. emit( mod|rm|4 );
  138. emit( (mop.shift<<6)|(mop.indexReg<<3)|mop.baseReg );
  139. }else{ //base, no index!
  140. if( mop.baseReg!=4 ) emit( mod|rm|mop.baseReg);
  141. else{
  142. emit( mod|rm|4 );emit( (4<<3)|mop.baseReg );
  143. }
  144. }
  145. if( (mod&0xc0)==0x40 ) emit( mop.offset );
  146. else if( (mod&0xc0)==0x80 ){
  147. //reloc
  148. a_reloc( mop.baseLabel );emitd( mop.offset );
  149. }
  150. }else if( mop.indexReg>=0 ){ //index, no base!
  151. emit( rm|4 );
  152. emit( (mop.shift<<6)|(mop.indexReg<<3)|5 );
  153. //reloc
  154. a_reloc( mop.baseLabel );emitd( mop.offset );
  155. }else{ //[disp]
  156. emit( rm|5 );
  157. //reloc
  158. a_reloc( mop.baseLabel );emitd( mop.offset );
  159. }
  160. }
  161. if( inst->flags&RW_RD ){
  162. r_reloc( lop.immLabel );emitd( lop.imm-4 );
  163. }
  164. if( inst->flags&IB ){
  165. if( lop.mode&IMM ) emitImm( lop,1 );else emitImm( rop,1 );
  166. }else if( inst->flags&IW ){
  167. if( lop.mode&IMM ) emitImm( lop,2 );else emitImm( rop,2 );
  168. }else if( inst->flags&ID ){
  169. if( lop.mode&IMM ) emitImm( lop,4 );else emitImm( rop,4 );
  170. }
  171. }
  172. void Assem_x86::assemDir( const string &name,const string &op ){
  173. if( !op.size() ) throw Ex( "operand error" );
  174. if( name==".db" ){
  175. if( op[0]!='\"' ) emitImm( op,1 );
  176. else{
  177. if( op.size()<2 || op[op.size()-1]!='\"' ) throw Ex( "operand error" );
  178. for( int k=1;k<op.size()-1;++k ) emit( op[k] );
  179. }
  180. }else if( name==".dw" ){
  181. emitImm( op,2 );
  182. }else if( name==".dd" ){
  183. emitImm( op,4 );
  184. }else if( name==".align" ){
  185. Operand o( op );o.parse();
  186. if( !(o.mode&IMM) ) throw Ex( "operand must be immediate" );
  187. align( o.imm );
  188. }else{
  189. throw Ex( "unrecognized assembler directive" );
  190. }
  191. }
  192. void Assem_x86::assemLine( const string &line ){
  193. int i=0;
  194. string name;
  195. vector<string> ops;
  196. //label?
  197. if( !isspace( line[i] ) ){
  198. while( !isspace( line[i] ) ) ++i;
  199. string lab=line.substr( 0,i );
  200. if( !mod->addSymbol( lab.c_str(),mod->getPC() ) ) throw Ex( "duplicate label" );
  201. }
  202. //skip space
  203. while( isspace( line[i] ) && line[i]!='\n' ) ++i;
  204. if( line[i]=='\n' || line[i]==';' ) return;
  205. //fetch instruction name
  206. int from=i;for( ++i;!isspace( line[i] );++i ){}
  207. name=line.substr( from,i-from );
  208. for(;;){
  209. //skip space
  210. while( isspace( line[i] ) && line[i]!='\n' ) ++i;
  211. if( line[i]=='\n' || line[i]==';' ) break;
  212. int from=i;
  213. if( line[i]=='\"' ){
  214. for( ++i;line[i]!='\"' && line[i]!='\n';++i ){}
  215. if( line[i++]!='\"' ) throw Ex( "missing close quote" );
  216. }else{
  217. for( ++i;line[i]!=',' && line[i]!=';' && line[i]!='\n';++i ){}
  218. }
  219. //back-up over space
  220. while( i && isspace( line[i-1] ) ) --i;
  221. ops.push_back( line.substr( from,i-from ) );
  222. //skip space
  223. while( isspace( line[i] ) && line[i]!='\n' ) ++i;
  224. if( line[i]=='\n' || line[i]==';' ) break;
  225. if( line[i++]!=',' ) throw Ex( "expecting ','" );
  226. }
  227. //pseudo op?
  228. if( name[0]=='.' ){
  229. for( int k=0;k<ops.size();++k ) assemDir( name,ops[k] );
  230. return;
  231. }
  232. //normal instruction!
  233. if( ops.size()>2 ) throw Ex( "Too many operands" );
  234. ops.push_back( "" );ops.push_back( "" );
  235. assemInst( name,ops[0],ops[1] );
  236. }
  237. void Assem_x86::assemble(){
  238. string line;
  239. while( !in.eof() ){
  240. try{
  241. getline( in,line );
  242. line+='\n';
  243. #ifdef LOG
  244. clog<<line;
  245. #endif
  246. assemLine( line );
  247. #ifdef LOG
  248. clog<<endl;
  249. #endif
  250. }catch( Ex &x ){
  251. throw Ex( line+x.ex );
  252. }
  253. }
  254. }