cpuasm.pas 45 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681
  1. {
  2. $Id$
  3. Copyright (c) 1998-2000 by Florian Klaempfl and Peter Vreman
  4. Contains the assembler object for the i386
  5. * This code was inspired by the NASM sources
  6. The Netwide Assembler is copyright (C) 1996 Simon Tatham and
  7. Julian Hall. All rights reserved.
  8. This program is free software; you can redistribute it and/or modify
  9. it under the terms of the GNU General Public License as published by
  10. the Free Software Foundation; either version 2 of the License, or
  11. (at your option) any later version.
  12. This program is distributed in the hope that it will be useful,
  13. but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. GNU General Public License for more details.
  16. You should have received a copy of the GNU General Public License
  17. along with this program; if not, write to the Free Software
  18. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  19. ****************************************************************************
  20. }
  21. unit cpuasm;
  22. {$i defines.inc}
  23. { Optimize addressing and skip already passed nodes }
  24. {$ifndef NASMDEBUG}
  25. {$define OPTEA}
  26. {$define PASS2FLAG}
  27. {$endif ndef NASMDEBUG}
  28. { Give warnings when an immediate is found in the reference struct }
  29. {.$define REF_IMMEDIATE_WARN}
  30. interface
  31. uses
  32. cobjects,
  33. aasm,globals,verbose,
  34. cpubase;
  35. const
  36. MaxPrefixes=4;
  37. type
  38. pairegalloc = ^tairegalloc;
  39. tairegalloc = object(tai)
  40. allocation : boolean;
  41. reg : tregister;
  42. constructor alloc(r : tregister);
  43. constructor dealloc(r : tregister);
  44. end;
  45. { alignment for operator }
  46. pai_align = ^tai_align;
  47. tai_align = object(tai_align_abstract)
  48. reg : tregister;
  49. constructor init(b:byte);
  50. constructor init_op(b: byte; _op: byte);
  51. function getfillbuf:pchar;
  52. end;
  53. paicpu = ^taicpu;
  54. taicpu = object(tai)
  55. is_jmp : boolean; { is this instruction a jump? (needed for optimizer) }
  56. opcode : tasmop;
  57. opsize : topsize;
  58. condition : TAsmCond;
  59. ops : longint;
  60. oper : array[0..2] of toper;
  61. constructor op_none(op : tasmop;_size : topsize);
  62. constructor op_reg(op : tasmop;_size : topsize;_op1 : tregister);
  63. constructor op_const(op : tasmop;_size : topsize;_op1 : longint);
  64. constructor op_ref(op : tasmop;_size : topsize;_op1 : preference);
  65. constructor op_reg_reg(op : tasmop;_size : topsize;_op1,_op2 : tregister);
  66. constructor op_reg_ref(op : tasmop;_size : topsize;_op1 : tregister;_op2 : preference);
  67. constructor op_reg_const(op:tasmop; _size: topsize; _op1: tregister; _op2: longint);
  68. constructor op_const_reg(op : tasmop;_size : topsize;_op1 : longint;_op2 : tregister);
  69. constructor op_const_const(op : tasmop;_size : topsize;_op1,_op2 : longint);
  70. constructor op_const_ref(op : tasmop;_size : topsize;_op1 : longint;_op2 : preference);
  71. constructor op_ref_reg(op : tasmop;_size : topsize;_op1 : preference;_op2 : tregister);
  72. { this is only allowed if _op1 is an int value (_op1^.isintvalue=true) }
  73. constructor op_ref_ref(op : tasmop;_size : topsize;_op1,_op2 : preference);
  74. constructor op_reg_reg_reg(op : tasmop;_size : topsize;_op1,_op2,_op3 : tregister);
  75. constructor op_const_reg_reg(op : tasmop;_size : topsize;_op1 : longint;_op2 : tregister;_op3 : tregister);
  76. constructor op_const_ref_reg(op : tasmop;_size : topsize;_op1 : longint;_op2 : preference;_op3 : tregister);
  77. constructor op_reg_reg_ref(op : tasmop;_size : topsize;_op1,_op2 : tregister; _op3 : preference);
  78. constructor op_const_reg_ref(op : tasmop;_size : topsize;_op1 : longint;_op2 : tregister;_op3 : preference);
  79. { this is for Jmp instructions }
  80. constructor op_cond_sym(op : tasmop;cond:TAsmCond;_size : topsize;_op1 : pasmsymbol);
  81. constructor op_sym(op : tasmop;_size : topsize;_op1 : pasmsymbol);
  82. constructor op_sym_ofs(op : tasmop;_size : topsize;_op1 : pasmsymbol;_op1ofs:longint);
  83. constructor op_sym_ofs_reg(op : tasmop;_size : topsize;_op1 : pasmsymbol;_op1ofs:longint;_op2 : tregister);
  84. constructor op_sym_ofs_ref(op : tasmop;_size : topsize;_op1 : pasmsymbol;_op1ofs:longint;_op2 : preference);
  85. procedure loadconst(opidx:longint;l:longint);
  86. procedure loadsymbol(opidx:longint;s:pasmsymbol;sofs:longint);
  87. procedure loadref(opidx:longint;p:preference);
  88. procedure loadreg(opidx:longint;r:tregister);
  89. procedure loadoper(opidx:longint;o:toper);
  90. procedure changeopsize(siz:topsize);
  91. procedure SetCondition(c:TAsmCond);
  92. destructor done;virtual;
  93. function getcopy:plinkedlist_item;virtual;
  94. function GetString:string;
  95. procedure SwapOperands;
  96. procedure CheckNonCommutativeOpcodes;
  97. private
  98. segprefix : tregister;
  99. procedure init(op : tasmop;_size : topsize); { this need to be called by all constructor }
  100. {$ifndef NOAG386BIN}
  101. public
  102. { the next will reset all instructions that can change in pass 2 }
  103. procedure ResetPass2;
  104. function Pass1(offset:longint):longint;virtual;
  105. procedure Pass2;virtual;
  106. private
  107. { next fields are filled in pass1, so pass2 is faster }
  108. insentry : PInsEntry;
  109. insoffset,
  110. inssize : longint;
  111. LastInsOffset : longint; { need to be public to be reset }
  112. function InsEnd:longint;
  113. procedure create_ot;
  114. function Matches(p:PInsEntry):longint;
  115. function calcsize(p:PInsEntry):longint;
  116. procedure gencode;
  117. function NeedAddrPrefix(opidx:byte):boolean;
  118. {$endif NOAG386BIN}
  119. end;
  120. implementation
  121. uses
  122. cutils,og386;
  123. {*****************************************************************************
  124. TaiRegAlloc
  125. *****************************************************************************}
  126. constructor tairegalloc.alloc(r : tregister);
  127. begin
  128. inherited init;
  129. typ:=ait_regalloc;
  130. allocation:=true;
  131. reg:=r;
  132. end;
  133. constructor tairegalloc.dealloc(r : tregister);
  134. begin
  135. inherited init;
  136. typ:=ait_regalloc;
  137. allocation:=false;
  138. reg:=r;
  139. end;
  140. {****************************************************************************
  141. TAI_ALIGN
  142. ****************************************************************************}
  143. constructor tai_align.init(b: byte);
  144. begin
  145. inherited init(b);
  146. reg := R_ECX;
  147. end;
  148. constructor tai_align.init_op(b: byte; _op: byte);
  149. begin
  150. inherited init_op(b,_op);
  151. reg := R_NO;
  152. end;
  153. function tai_align.getfillbuf:pchar;
  154. const
  155. alignarray:array[0..5] of string[8]=(
  156. #$8D#$B4#$26#$00#$00#$00#$00,
  157. #$8D#$B6#$00#$00#$00#$00,
  158. #$8D#$74#$26#$00,
  159. #$8D#$76#$00,
  160. #$89#$F6,
  161. #$90
  162. );
  163. var
  164. bufptr : pchar;
  165. j : longint;
  166. begin
  167. if not use_op then
  168. begin
  169. bufptr:=@buf;
  170. while (fillsize>0) do
  171. begin
  172. for j:=0 to 5 do
  173. if (fillsize>=length(alignarray[j])) then
  174. break;
  175. move(alignarray[j][1],bufptr^,length(alignarray[j]));
  176. inc(bufptr,length(alignarray[j]));
  177. dec(fillsize,length(alignarray[j]));
  178. end;
  179. end;
  180. getfillbuf:=pchar(@buf);
  181. end;
  182. {*****************************************************************************
  183. Taicpu Constructors
  184. *****************************************************************************}
  185. procedure taicpu.loadconst(opidx:longint;l:longint);
  186. begin
  187. if opidx>=ops then
  188. ops:=opidx+1;
  189. with oper[opidx] do
  190. begin
  191. if typ=top_ref then
  192. disposereference(ref);
  193. val:=l;
  194. typ:=top_const;
  195. end;
  196. end;
  197. procedure taicpu.loadsymbol(opidx:longint;s:pasmsymbol;sofs:longint);
  198. begin
  199. if opidx>=ops then
  200. ops:=opidx+1;
  201. with oper[opidx] do
  202. begin
  203. if typ=top_ref then
  204. disposereference(ref);
  205. sym:=s;
  206. symofs:=sofs;
  207. typ:=top_symbol;
  208. end;
  209. { Mark the symbol as used }
  210. if assigned(s) then
  211. inc(s^.refs);
  212. end;
  213. procedure taicpu.loadref(opidx:longint;p:preference);
  214. begin
  215. if opidx>=ops then
  216. ops:=opidx+1;
  217. with oper[opidx] do
  218. begin
  219. if typ=top_ref then
  220. disposereference(ref);
  221. if p^.is_immediate then
  222. begin
  223. {$ifdef REF_IMMEDIATE_WARN}
  224. Comment(V_Warning,'Reference immediate');
  225. {$endif}
  226. val:=p^.offset;
  227. disposereference(p);
  228. typ:=top_const;
  229. end
  230. else
  231. begin
  232. ref:=p;
  233. if not(ref^.segment in [R_DS,R_NO]) then
  234. segprefix:=ref^.segment;
  235. typ:=top_ref;
  236. { mark symbol as used }
  237. if assigned(ref^.symbol) then
  238. inc(ref^.symbol^.refs);
  239. end;
  240. end;
  241. end;
  242. procedure taicpu.loadreg(opidx:longint;r:tregister);
  243. begin
  244. if opidx>=ops then
  245. ops:=opidx+1;
  246. with oper[opidx] do
  247. begin
  248. if typ=top_ref then
  249. disposereference(ref);
  250. reg:=r;
  251. typ:=top_reg;
  252. end;
  253. end;
  254. procedure taicpu.loadoper(opidx:longint;o:toper);
  255. begin
  256. if opidx>=ops then
  257. ops:=opidx+1;
  258. if oper[opidx].typ=top_ref then
  259. disposereference(oper[opidx].ref);
  260. oper[opidx]:=o;
  261. { copy also the reference }
  262. if oper[opidx].typ=top_ref then
  263. oper[opidx].ref:=newreference(o.ref^);
  264. end;
  265. procedure taicpu.changeopsize(siz:topsize);
  266. begin
  267. opsize:=siz;
  268. end;
  269. procedure taicpu.init(op : tasmop;_size : topsize);
  270. begin
  271. typ:=ait_instruction;
  272. is_jmp:=false;
  273. segprefix:=R_NO;
  274. opcode:=op;
  275. opsize:=_size;
  276. ops:=0;
  277. condition:=c_none;
  278. fillchar(oper,sizeof(oper),0);
  279. {$ifndef NOAG386BIN}
  280. insentry:=nil;
  281. LastInsOffset:=-1;
  282. InsOffset:=0;
  283. InsSize:=0;
  284. {$endif}
  285. end;
  286. constructor taicpu.op_none(op : tasmop;_size : topsize);
  287. begin
  288. inherited init;
  289. init(op,_size);
  290. end;
  291. constructor taicpu.op_reg(op : tasmop;_size : topsize;_op1 : tregister);
  292. begin
  293. inherited init;
  294. init(op,_size);
  295. ops:=1;
  296. loadreg(0,_op1);
  297. end;
  298. constructor taicpu.op_const(op : tasmop;_size : topsize;_op1 : longint);
  299. begin
  300. inherited init;
  301. init(op,_size);
  302. ops:=1;
  303. loadconst(0,_op1);
  304. end;
  305. constructor taicpu.op_ref(op : tasmop;_size : topsize;_op1 : preference);
  306. begin
  307. inherited init;
  308. init(op,_size);
  309. ops:=1;
  310. loadref(0,_op1);
  311. end;
  312. constructor taicpu.op_reg_reg(op : tasmop;_size : topsize;_op1,_op2 : tregister);
  313. begin
  314. inherited init;
  315. init(op,_size);
  316. ops:=2;
  317. loadreg(0,_op1);
  318. loadreg(1,_op2);
  319. end;
  320. constructor taicpu.op_reg_const(op:tasmop; _size: topsize; _op1: tregister; _op2: longint);
  321. begin
  322. inherited init;
  323. init(op,_size);
  324. ops:=2;
  325. loadreg(0,_op1);
  326. loadconst(1,_op2);
  327. end;
  328. constructor taicpu.op_reg_ref(op : tasmop;_size : topsize;_op1 : tregister;_op2 : preference);
  329. begin
  330. inherited init;
  331. init(op,_size);
  332. ops:=2;
  333. loadreg(0,_op1);
  334. loadref(1,_op2);
  335. end;
  336. constructor taicpu.op_const_reg(op : tasmop;_size : topsize;_op1 : longint;_op2 : tregister);
  337. begin
  338. inherited init;
  339. init(op,_size);
  340. ops:=2;
  341. loadconst(0,_op1);
  342. loadreg(1,_op2);
  343. end;
  344. constructor taicpu.op_const_const(op : tasmop;_size : topsize;_op1,_op2 : longint);
  345. begin
  346. inherited init;
  347. init(op,_size);
  348. ops:=2;
  349. loadconst(0,_op1);
  350. loadconst(1,_op2);
  351. end;
  352. constructor taicpu.op_const_ref(op : tasmop;_size : topsize;_op1 : longint;_op2 : preference);
  353. begin
  354. inherited init;
  355. init(op,_size);
  356. ops:=2;
  357. loadconst(0,_op1);
  358. loadref(1,_op2);
  359. end;
  360. constructor taicpu.op_ref_reg(op : tasmop;_size : topsize;_op1 : preference;_op2 : tregister);
  361. begin
  362. inherited init;
  363. init(op,_size);
  364. ops:=2;
  365. loadref(0,_op1);
  366. loadreg(1,_op2);
  367. end;
  368. constructor taicpu.op_ref_ref(op : tasmop;_size : topsize;_op1,_op2 : preference);
  369. begin
  370. inherited init;
  371. init(op,_size);
  372. ops:=2;
  373. loadref(0,_op1);
  374. loadref(1,_op2);
  375. end;
  376. constructor taicpu.op_reg_reg_reg(op : tasmop;_size : topsize;_op1,_op2,_op3 : tregister);
  377. begin
  378. inherited init;
  379. init(op,_size);
  380. ops:=3;
  381. loadreg(0,_op1);
  382. loadreg(1,_op2);
  383. loadreg(2,_op3);
  384. end;
  385. constructor taicpu.op_const_reg_reg(op : tasmop;_size : topsize;_op1 : longint;_op2 : tregister;_op3 : tregister);
  386. begin
  387. inherited init;
  388. init(op,_size);
  389. ops:=3;
  390. loadconst(0,_op1);
  391. loadreg(1,_op2);
  392. loadreg(2,_op3);
  393. end;
  394. constructor taicpu.op_reg_reg_ref(op : tasmop;_size : topsize;_op1,_op2 : tregister;_op3 : preference);
  395. begin
  396. inherited init;
  397. init(op,_size);
  398. ops:=3;
  399. loadreg(0,_op1);
  400. loadreg(1,_op2);
  401. loadref(2,_op3);
  402. end;
  403. constructor taicpu.op_const_ref_reg(op : tasmop;_size : topsize;_op1 : longint;_op2 : preference;_op3 : tregister);
  404. begin
  405. inherited init;
  406. init(op,_size);
  407. ops:=3;
  408. loadconst(0,_op1);
  409. loadref(1,_op2);
  410. loadreg(2,_op3);
  411. end;
  412. constructor taicpu.op_const_reg_ref(op : tasmop;_size : topsize;_op1 : longint;_op2 : tregister;_op3 : preference);
  413. begin
  414. inherited init;
  415. init(op,_size);
  416. ops:=3;
  417. loadconst(0,_op1);
  418. loadreg(1,_op2);
  419. loadref(2,_op3);
  420. end;
  421. constructor taicpu.op_cond_sym(op : tasmop;cond:TAsmCond;_size : topsize;_op1 : pasmsymbol);
  422. begin
  423. inherited init;
  424. init(op,_size);
  425. condition:=cond;
  426. ops:=1;
  427. loadsymbol(0,_op1,0);
  428. end;
  429. constructor taicpu.op_sym(op : tasmop;_size : topsize;_op1 : pasmsymbol);
  430. begin
  431. inherited init;
  432. init(op,_size);
  433. ops:=1;
  434. loadsymbol(0,_op1,0);
  435. end;
  436. constructor taicpu.op_sym_ofs(op : tasmop;_size : topsize;_op1 : pasmsymbol;_op1ofs:longint);
  437. begin
  438. inherited init;
  439. init(op,_size);
  440. ops:=1;
  441. loadsymbol(0,_op1,_op1ofs);
  442. end;
  443. constructor taicpu.op_sym_ofs_reg(op : tasmop;_size : topsize;_op1 : pasmsymbol;_op1ofs:longint;_op2 : tregister);
  444. begin
  445. inherited init;
  446. init(op,_size);
  447. ops:=2;
  448. loadsymbol(0,_op1,_op1ofs);
  449. loadreg(1,_op2);
  450. end;
  451. constructor taicpu.op_sym_ofs_ref(op : tasmop;_size : topsize;_op1 : pasmsymbol;_op1ofs:longint;_op2 : preference);
  452. begin
  453. inherited init;
  454. init(op,_size);
  455. ops:=2;
  456. loadsymbol(0,_op1,_op1ofs);
  457. loadref(1,_op2);
  458. end;
  459. destructor taicpu.done;
  460. var
  461. i : longint;
  462. begin
  463. if is_jmp then
  464. dec(PasmLabel(oper[0].sym)^.refs)
  465. else
  466. for i:=1 to ops do
  467. if (oper[i-1].typ=top_ref) then
  468. dispose(oper[i-1].ref);
  469. inherited done;
  470. end;
  471. function taicpu.getcopy:plinkedlist_item;
  472. var
  473. i : longint;
  474. p : plinkedlist_item;
  475. begin
  476. p:=inherited getcopy;
  477. { make a copy of the references }
  478. for i:=1 to ops do
  479. if (paicpu(p)^.oper[i-1].typ=top_ref) then
  480. begin
  481. new(paicpu(p)^.oper[i-1].ref);
  482. paicpu(p)^.oper[i-1].ref^:=oper[i-1].ref^;
  483. end;
  484. getcopy:=p;
  485. end;
  486. procedure taicpu.SetCondition(c:TAsmCond);
  487. begin
  488. condition:=c;
  489. end;
  490. function taicpu.GetString:string;
  491. var
  492. i : longint;
  493. s : string;
  494. addsize : boolean;
  495. begin
  496. s:='['+int_op2str[opcode];
  497. for i:=1to ops do
  498. begin
  499. if i=1 then
  500. s:=s+' '
  501. else
  502. s:=s+',';
  503. { type }
  504. addsize:=false;
  505. if (oper[i-1].ot and OT_XMMREG)=OT_XMMREG then
  506. s:=s+'xmmreg'
  507. else
  508. if (oper[i-1].ot and OT_MMXREG)=OT_MMXREG then
  509. s:=s+'mmxreg'
  510. else
  511. if (oper[i-1].ot and OT_FPUREG)=OT_FPUREG then
  512. s:=s+'fpureg'
  513. else
  514. if (oper[i-1].ot and OT_REGISTER)=OT_REGISTER then
  515. begin
  516. s:=s+'reg';
  517. addsize:=true;
  518. end
  519. else
  520. if (oper[i-1].ot and OT_IMMEDIATE)=OT_IMMEDIATE then
  521. begin
  522. s:=s+'imm';
  523. addsize:=true;
  524. end
  525. else
  526. if (oper[i-1].ot and OT_MEMORY)=OT_MEMORY then
  527. begin
  528. s:=s+'mem';
  529. addsize:=true;
  530. end
  531. else
  532. s:=s+'???';
  533. { size }
  534. if addsize then
  535. begin
  536. if (oper[i-1].ot and OT_BITS8)<>0 then
  537. s:=s+'8'
  538. else
  539. if (oper[i-1].ot and OT_BITS16)<>0 then
  540. s:=s+'16'
  541. else
  542. if (oper[i-1].ot and OT_BITS32)<>0 then
  543. s:=s+'32'
  544. else
  545. s:=s+'??';
  546. { signed }
  547. if (oper[i-1].ot and OT_SIGNED)<>0 then
  548. s:=s+'s';
  549. end;
  550. end;
  551. GetString:=s+']';
  552. end;
  553. procedure taicpu.SwapOperands;
  554. var
  555. p : TOper;
  556. begin
  557. { Fix the operands which are in AT&T style and we need them in Intel style }
  558. case ops of
  559. 2 : begin
  560. { 0,1 -> 1,0 }
  561. p:=oper[0];
  562. oper[0]:=oper[1];
  563. oper[1]:=p;
  564. end;
  565. 3 : begin
  566. { 0,1,2 -> 2,1,0 }
  567. p:=oper[0];
  568. oper[0]:=oper[2];
  569. oper[2]:=p;
  570. end;
  571. end;
  572. end;
  573. { This check must be done with the operand in ATT order
  574. i.e.after swapping in the intel reader
  575. but before swapping in the NASM and TASM writers PM }
  576. procedure taicpu.CheckNonCommutativeOpcodes;
  577. begin
  578. if ((ops=2) and
  579. (oper[0].typ=top_reg) and
  580. (oper[1].typ=top_reg) and
  581. { if the first is ST and the second is also a register
  582. it is necessarily ST1 .. ST7 }
  583. (oper[0].reg=R_ST)) or
  584. ((ops=1) and
  585. (oper[0].typ=top_reg) and
  586. (oper[0].reg in [R_ST1..R_ST7])) or
  587. (ops=0) then
  588. if opcode=A_FSUBR then
  589. opcode:=A_FSUB
  590. else if opcode=A_FSUB then
  591. opcode:=A_FSUBR
  592. else if opcode=A_FDIVR then
  593. opcode:=A_FDIV
  594. else if opcode=A_FDIV then
  595. opcode:=A_FDIVR
  596. else if opcode=A_FSUBRP then
  597. opcode:=A_FSUBP
  598. else if opcode=A_FSUBP then
  599. opcode:=A_FSUBRP
  600. else if opcode=A_FDIVRP then
  601. opcode:=A_FDIVP
  602. else if opcode=A_FDIVP then
  603. opcode:=A_FDIVRP;
  604. end;
  605. {*****************************************************************************
  606. Assembler
  607. *****************************************************************************}
  608. {$ifndef NOAG386BIN}
  609. type
  610. ea=packed record
  611. sib_present : boolean;
  612. bytes : byte;
  613. size : byte;
  614. modrm : byte;
  615. sib : byte;
  616. end;
  617. procedure taicpu.create_ot;
  618. {
  619. this function will also fix some other fields which only needs to be once
  620. }
  621. var
  622. i,l,relsize : longint;
  623. begin
  624. if ops=0 then
  625. exit;
  626. { update oper[].ot field }
  627. for i:=0 to ops-1 do
  628. with oper[i] do
  629. begin
  630. case typ of
  631. top_reg :
  632. ot:=reg_2_type[reg];
  633. top_ref :
  634. begin
  635. { create ot field }
  636. ot:=OT_MEMORY or opsize_2_type[i,opsize];
  637. if (ref^.base=R_NO) and (ref^.index=R_NO) then
  638. ot:=ot or OT_MEM_OFFS;
  639. { handle also the offsetfixup }
  640. inc(ref^.offset,ref^.offsetfixup);
  641. ref^.offsetfixup:=0;
  642. { fix scalefactor }
  643. if (ref^.index=R_NO) then
  644. ref^.scalefactor:=0
  645. else
  646. if (ref^.scalefactor=0) then
  647. ref^.scalefactor:=1;
  648. end;
  649. top_const :
  650. begin
  651. if (opsize<>S_W) and (val>=-128) and (val<=127) then
  652. ot:=OT_IMM8 or OT_SIGNED
  653. else
  654. ot:=OT_IMMEDIATE or opsize_2_type[i,opsize];
  655. end;
  656. top_symbol :
  657. begin
  658. if LastInsOffset=-1 then
  659. l:=0
  660. else
  661. l:=InsOffset-LastInsOffset;
  662. inc(l,symofs);
  663. if assigned(sym) then
  664. inc(l,sym^.address);
  665. { instruction size will then always become 2 (PFV) }
  666. relsize:=(InsOffset+2)-l;
  667. if (not assigned(sym) or
  668. ((sym^.bind<>AB_EXTERNAL) and (sym^.address<>0))) and
  669. (relsize>=-128) and (relsize<=127) then
  670. ot:=OT_IMM32 or OT_SHORT
  671. else
  672. ot:=OT_IMM32 or OT_NEAR;
  673. end;
  674. end;
  675. end;
  676. end;
  677. function taicpu.InsEnd:longint;
  678. begin
  679. InsEnd:=InsOffset+InsSize;
  680. end;
  681. function taicpu.Matches(p:PInsEntry):longint;
  682. { * IF_SM stands for Size Match: any operand whose size is not
  683. * explicitly specified by the template is `really' intended to be
  684. * the same size as the first size-specified operand.
  685. * Non-specification is tolerated in the input instruction, but
  686. * _wrong_ specification is not.
  687. *
  688. * IF_SM2 invokes Size Match on only the first _two_ operands, for
  689. * three-operand instructions such as SHLD: it implies that the
  690. * first two operands must match in size, but that the third is
  691. * required to be _unspecified_.
  692. *
  693. * IF_SB invokes Size Byte: operands with unspecified size in the
  694. * template are really bytes, and so no non-byte specification in
  695. * the input instruction will be tolerated. IF_SW similarly invokes
  696. * Size Word, and IF_SD invokes Size Doubleword.
  697. *
  698. * (The default state if neither IF_SM nor IF_SM2 is specified is
  699. * that any operand with unspecified size in the template is
  700. * required to have unspecified size in the instruction too...)
  701. }
  702. var
  703. i,j,asize,oprs : longint;
  704. siz : array[0..2] of longint;
  705. begin
  706. Matches:=100;
  707. { Check the opcode and operands }
  708. if (p^.opcode<>opcode) or (p^.ops<>ops) then
  709. begin
  710. Matches:=0;
  711. exit;
  712. end;
  713. { Check that no spurious colons or TOs are present }
  714. for i:=0 to p^.ops-1 do
  715. if (oper[i].ot and (not p^.optypes[i]) and (OT_COLON or OT_TO))<>0 then
  716. begin
  717. Matches:=0;
  718. exit;
  719. end;
  720. { Check that the operand flags all match up }
  721. for i:=0 to p^.ops-1 do
  722. begin
  723. if (p^.optypes[i] and (not oper[i].ot) or
  724. ((p^.optypes[i] and OT_SIZE_MASK) and
  725. ((p^.optypes[i] xor oper[i].ot) and OT_SIZE_MASK)))<>0 then
  726. begin
  727. if ((p^.optypes[i] and (not oper[i].ot) and OT_NON_SIZE) or
  728. (oper[i].ot and OT_SIZE_MASK))<>0 then
  729. begin
  730. Matches:=0;
  731. exit;
  732. end
  733. else
  734. Matches:=1;
  735. end;
  736. end;
  737. { Check operand sizes }
  738. { as default an untyped size can get all the sizes, this is different
  739. from nasm, but else we need to do a lot checking which opcodes want
  740. size or not with the automatic size generation }
  741. asize:=$ffffffff;
  742. if (p^.flags and IF_SB)<>0 then
  743. asize:=OT_BITS8
  744. else if (p^.flags and IF_SW)<>0 then
  745. asize:=OT_BITS16
  746. else if (p^.flags and IF_SD)<>0 then
  747. asize:=OT_BITS32;
  748. if (p^.flags and IF_ARMASK)<>0 then
  749. begin
  750. siz[0]:=0;
  751. siz[1]:=0;
  752. siz[2]:=0;
  753. if (p^.flags and IF_AR0)<>0 then
  754. siz[0]:=asize
  755. else if (p^.flags and IF_AR1)<>0 then
  756. siz[1]:=asize
  757. else if (p^.flags and IF_AR2)<>0 then
  758. siz[2]:=asize;
  759. end
  760. else
  761. begin
  762. { siz[0]:=asize;
  763. siz[1]:=asize;
  764. siz[2]:=asize; }
  765. { we can leave because the size for all operands is forced to be
  766. the same }
  767. exit;
  768. end;
  769. if (p^.flags and (IF_SM or IF_SM2))<>0 then
  770. begin
  771. if (p^.flags and IF_SM2)<>0 then
  772. oprs:=2
  773. else
  774. oprs:=p^.ops;
  775. for i:=0 to oprs-1 do
  776. if ((p^.optypes[i] and OT_SIZE_MASK) <> 0) then
  777. begin
  778. for j:=0 to oprs-1 do
  779. siz[j]:=p^.optypes[i] and OT_SIZE_MASK;
  780. break;
  781. end;
  782. end
  783. else
  784. oprs:=2;
  785. { Check operand sizes }
  786. for i:=0to p^.ops-1 do
  787. begin
  788. if ((p^.optypes[i] and OT_SIZE_MASK)=0) and
  789. ((oper[i].ot and OT_SIZE_MASK and (not siz[i]))<>0) and
  790. { Immediates can always include smaller size }
  791. ((oper[i].ot and OT_IMMEDIATE)=0) and
  792. (((p^.optypes[i] and OT_SIZE_MASK) or siz[i])<(oper[i].ot and OT_SIZE_MASK)) then
  793. Matches:=2;
  794. end;
  795. end;
  796. procedure taicpu.ResetPass2;
  797. begin
  798. { we are here in a second pass, check if the instruction can be optimized }
  799. if assigned(InsEntry) and
  800. ((InsEntry^.flags and IF_PASS2)<>0) then
  801. begin
  802. InsEntry:=nil;
  803. InsSize:=0;
  804. end;
  805. LastInsOffset:=-1;
  806. end;
  807. function taicpu.Pass1(offset:longint):longint;
  808. var
  809. m,i : longint;
  810. begin
  811. Pass1:=0;
  812. { Save the old offset and set the new offset }
  813. InsOffset:=Offset;
  814. { Things which may only be done once, not when a second pass is done to
  815. optimize }
  816. if Insentry=nil then
  817. begin
  818. { Check if error last time then InsSize=-1 }
  819. if InsSize=-1 then
  820. exit;
  821. { We need intel style operands }
  822. SwapOperands;
  823. { create the .ot fields }
  824. create_ot;
  825. { set the file postion }
  826. aktfilepos:=fileinfo;
  827. end
  828. else
  829. begin
  830. {$ifdef PASS2FLAG}
  831. { we are here in a second pass, check if the instruction can be optimized }
  832. if (InsEntry^.flags and IF_PASS2)=0 then
  833. begin
  834. Pass1:=InsSize;
  835. exit;
  836. end;
  837. { update the .ot fields, some top_const can be updated }
  838. create_ot;
  839. {$endif}
  840. end;
  841. { Lookup opcode in the table }
  842. InsSize:=-1;
  843. i:=instabcache^[opcode];
  844. if i=-1 then
  845. begin
  846. Message1(asmw_e_opcode_not_in_table,att_op2str[opcode]);
  847. exit;
  848. end;
  849. insentry:=@instab[i];
  850. while (insentry^.opcode=opcode) do
  851. begin
  852. m:=matches(insentry);
  853. if m=100 then
  854. begin
  855. InsSize:=calcsize(insentry);
  856. if (segprefix<>R_NO) then
  857. inc(InsSize);
  858. Pass1:=InsSize;
  859. LastInsOffset:=InsOffset;
  860. exit;
  861. end;
  862. inc(i);
  863. insentry:=@instab[i];
  864. end;
  865. if insentry^.opcode<>opcode then
  866. Message1(asmw_e_invalid_opcode_and_operands,GetString);
  867. { No instruction found, set insentry to nil and inssize to -1 }
  868. insentry:=nil;
  869. inssize:=-1;
  870. LastInsOffset:=-1;
  871. end;
  872. procedure taicpu.Pass2;
  873. var
  874. c : longint;
  875. begin
  876. { error in pass1 ? }
  877. if insentry=nil then
  878. exit;
  879. aktfilepos:=fileinfo;
  880. { Segment override }
  881. if (segprefix<>R_NO) then
  882. begin
  883. case segprefix of
  884. R_CS : c:=$2e;
  885. R_DS : c:=$3e;
  886. R_ES : c:=$26;
  887. R_FS : c:=$64;
  888. R_GS : c:=$65;
  889. R_SS : c:=$36;
  890. end;
  891. objectoutput^.writebytes(c,1);
  892. { fix the offset for GenNode }
  893. inc(InsOffset);
  894. end;
  895. { Generate the instruction }
  896. GenCode;
  897. end;
  898. function taicpu.NeedAddrPrefix(opidx:byte):boolean;
  899. var
  900. i,b : tregister;
  901. begin
  902. if (OT_MEMORY and (not oper[opidx].ot))=0 then
  903. begin
  904. i:=oper[opidx].ref^.index;
  905. b:=oper[opidx].ref^.base;
  906. if not(i in [R_NO,R_EAX,R_EBX,R_ECX,R_EDX,R_EBP,R_ESP,R_ESI,R_EDI]) or
  907. not(b in [R_NO,R_EAX,R_EBX,R_ECX,R_EDX,R_EBP,R_ESP,R_ESI,R_EDI]) then
  908. begin
  909. NeedAddrPrefix:=true;
  910. exit;
  911. end;
  912. end;
  913. NeedAddrPrefix:=false;
  914. end;
  915. function regval(r:tregister):byte;
  916. begin
  917. case r of
  918. R_EAX,R_AX,R_AL,R_ES,R_CR0,R_DR0,R_ST,R_ST0,R_MM0 :
  919. regval:=0;
  920. R_ECX,R_CX,R_CL,R_CS,R_DR1,R_ST1,R_MM1 :
  921. regval:=1;
  922. R_EDX,R_DX,R_DL,R_SS,R_CR2,R_DR2,R_ST2,R_MM2 :
  923. regval:=2;
  924. R_EBX,R_BX,R_BL,R_DS,R_CR3,R_DR3,R_TR3,R_ST3,R_MM3 :
  925. regval:=3;
  926. R_ESP,R_SP,R_AH,R_FS,R_CR4,R_TR4,R_ST4,R_MM4 :
  927. regval:=4;
  928. R_EBP,R_BP,R_CH,R_GS,R_TR5,R_ST5,R_MM5 :
  929. regval:=5;
  930. R_ESI,R_SI,R_DH,R_DR6,R_TR6,R_ST6,R_MM6 :
  931. regval:=6;
  932. R_EDI,R_DI,R_BH,R_DR7,R_TR7,R_ST7,R_MM7 :
  933. regval:=7;
  934. else
  935. begin
  936. internalerror(777001);
  937. regval:=0;
  938. end;
  939. end;
  940. end;
  941. function process_ea(const input:toper;var output:ea;rfield:longint):boolean;
  942. const
  943. regs : array[0..31] of tregister=(
  944. R_MM0, R_EAX, R_AX, R_AL, R_MM1, R_ECX, R_CX, R_CL,
  945. R_MM2, R_EDX, R_DX, R_DL, R_MM3, R_EBX, R_BX, R_BL,
  946. R_MM4, R_ESP, R_SP, R_AH, R_MM5, R_EBP, R_BP, R_CH,
  947. R_MM6, R_ESI, R_SI, R_DH, R_MM7, R_EDI, R_DI, R_BH
  948. );
  949. var
  950. j : longint;
  951. i,b : tregister;
  952. sym : pasmsymbol;
  953. md,s : byte;
  954. base,index,scalefactor,
  955. o : longint;
  956. begin
  957. process_ea:=false;
  958. { register ? }
  959. if (input.typ=top_reg) then
  960. begin
  961. j:=0;
  962. while (j<=high(regs)) do
  963. begin
  964. if input.reg=regs[j] then
  965. break;
  966. inc(j);
  967. end;
  968. if j<=high(regs) then
  969. begin
  970. output.sib_present:=false;
  971. output.bytes:=0;
  972. output.modrm:=$c0 or (rfield shl 3) or (j shr 2);
  973. output.size:=1;
  974. process_ea:=true;
  975. end;
  976. exit;
  977. end;
  978. { memory reference }
  979. i:=input.ref^.index;
  980. b:=input.ref^.base;
  981. s:=input.ref^.scalefactor;
  982. o:=input.ref^.offset;
  983. sym:=input.ref^.symbol;
  984. { it's direct address }
  985. if (b=R_NO) and (i=R_NO) then
  986. begin
  987. { it's a pure offset }
  988. output.sib_present:=false;
  989. output.bytes:=4;
  990. output.modrm:=5 or (rfield shl 3);
  991. end
  992. else
  993. { it's an indirection }
  994. begin
  995. { 16 bit address? }
  996. if not((i in [R_NO,R_EAX,R_EBX,R_ECX,R_EDX,R_EBP,R_ESP,R_ESI,R_EDI]) and
  997. (b in [R_NO,R_EAX,R_EBX,R_ECX,R_EDX,R_EBP,R_ESP,R_ESI,R_EDI])) then
  998. Message(asmw_e_16bit_not_supported);
  999. {$ifdef OPTEA}
  1000. { make single reg base }
  1001. if (b=R_NO) and (s=1) then
  1002. begin
  1003. b:=i;
  1004. i:=R_NO;
  1005. end;
  1006. { convert [3,5,9]*EAX to EAX+[2,4,8]*EAX }
  1007. if (b=R_NO) and
  1008. (((s=2) and (i<>R_ESP)) or
  1009. (s=3) or (s=5) or (s=9)) then
  1010. begin
  1011. b:=i;
  1012. dec(s);
  1013. end;
  1014. { swap ESP into base if scalefactor is 1 }
  1015. if (s=1) and (i=R_ESP) then
  1016. begin
  1017. i:=b;
  1018. b:=R_ESP;
  1019. end;
  1020. {$endif}
  1021. { wrong, for various reasons }
  1022. if (i=R_ESP) or ((s<>1) and (s<>2) and (s<>4) and (s<>8) and (i<>R_NO)) then
  1023. exit;
  1024. { base }
  1025. case b of
  1026. R_EAX : base:=0;
  1027. R_ECX : base:=1;
  1028. R_EDX : base:=2;
  1029. R_EBX : base:=3;
  1030. R_ESP : base:=4;
  1031. R_NO,
  1032. R_EBP : base:=5;
  1033. R_ESI : base:=6;
  1034. R_EDI : base:=7;
  1035. else
  1036. exit;
  1037. end;
  1038. { index }
  1039. case i of
  1040. R_EAX : index:=0;
  1041. R_ECX : index:=1;
  1042. R_EDX : index:=2;
  1043. R_EBX : index:=3;
  1044. R_NO : index:=4;
  1045. R_EBP : index:=5;
  1046. R_ESI : index:=6;
  1047. R_EDI : index:=7;
  1048. else
  1049. exit;
  1050. end;
  1051. case s of
  1052. 0,
  1053. 1 : scalefactor:=0;
  1054. 2 : scalefactor:=1;
  1055. 4 : scalefactor:=2;
  1056. 8 : scalefactor:=3;
  1057. else
  1058. exit;
  1059. end;
  1060. if (b=R_NO) or
  1061. ((b<>R_EBP) and (o=0) and (sym=nil)) then
  1062. md:=0
  1063. else
  1064. if ((o>=-128) and (o<=127) and (sym=nil)) then
  1065. md:=1
  1066. else
  1067. md:=2;
  1068. if (b=R_NO) or (md=2) then
  1069. output.bytes:=4
  1070. else
  1071. output.bytes:=md;
  1072. { SIB needed ? }
  1073. if (i=R_NO) and (b<>R_ESP) then
  1074. begin
  1075. output.sib_present:=false;
  1076. output.modrm:=(md shl 6) or (rfield shl 3) or base;
  1077. end
  1078. else
  1079. begin
  1080. output.sib_present:=true;
  1081. output.modrm:=(md shl 6) or (rfield shl 3) or 4;
  1082. output.sib:=(scalefactor shl 6) or (index shl 3) or base;
  1083. end;
  1084. end;
  1085. if output.sib_present then
  1086. output.size:=2+output.bytes
  1087. else
  1088. output.size:=1+output.bytes;
  1089. process_ea:=true;
  1090. end;
  1091. function taicpu.calcsize(p:PInsEntry):longint;
  1092. var
  1093. codes : pchar;
  1094. c : byte;
  1095. len : longint;
  1096. ea_data : ea;
  1097. begin
  1098. len:=0;
  1099. codes:=@p^.code;
  1100. repeat
  1101. c:=ord(codes^);
  1102. inc(codes);
  1103. case c of
  1104. 0 :
  1105. break;
  1106. 1,2,3 :
  1107. begin
  1108. inc(codes,c);
  1109. inc(len,c);
  1110. end;
  1111. 8,9,10 :
  1112. begin
  1113. inc(codes);
  1114. inc(len);
  1115. end;
  1116. 4,5,6,7 :
  1117. begin
  1118. if opsize=S_W then
  1119. inc(len,2)
  1120. else
  1121. inc(len);
  1122. end;
  1123. 15,
  1124. 12,13,14,
  1125. 16,17,18,
  1126. 20,21,22,
  1127. 40,41,42 :
  1128. inc(len);
  1129. 24,25,26,
  1130. 31,
  1131. 48,49,50 :
  1132. inc(len,2);
  1133. 28,29,30, { we don't have 16 bit immediates code }
  1134. 32,33,34,
  1135. 52,53,54,
  1136. 56,57,58 :
  1137. inc(len,4);
  1138. 192,193,194 :
  1139. if NeedAddrPrefix(c-192) then
  1140. inc(len);
  1141. 208 :
  1142. inc(len);
  1143. 200,
  1144. 201,
  1145. 202,
  1146. 209,
  1147. 210,
  1148. 217,218,219 : ;
  1149. 216 :
  1150. begin
  1151. inc(codes);
  1152. inc(len);
  1153. end;
  1154. 224,225,226 :
  1155. begin
  1156. InternalError(777002);
  1157. end;
  1158. else
  1159. begin
  1160. if (c>=64) and (c<=191) then
  1161. begin
  1162. if not process_ea(oper[(c shr 3) and 7], ea_data, 0) then
  1163. Message(asmw_e_invalid_effective_address)
  1164. else
  1165. inc(len,ea_data.size);
  1166. end
  1167. else
  1168. InternalError(777003);
  1169. end;
  1170. end;
  1171. until false;
  1172. calcsize:=len;
  1173. end;
  1174. procedure taicpu.GenCode;
  1175. {
  1176. * the actual codes (C syntax, i.e. octal):
  1177. * \0 - terminates the code. (Unless it's a literal of course.)
  1178. * \1, \2, \3 - that many literal bytes follow in the code stream
  1179. * \4, \6 - the POP/PUSH (respectively) codes for CS, DS, ES, SS
  1180. * (POP is never used for CS) depending on operand 0
  1181. * \5, \7 - the second byte of POP/PUSH codes for FS, GS, depending
  1182. * on operand 0
  1183. * \10, \11, \12 - a literal byte follows in the code stream, to be added
  1184. * to the register value of operand 0, 1 or 2
  1185. * \17 - encodes the literal byte 0. (Some compilers don't take
  1186. * kindly to a zero byte in the _middle_ of a compile time
  1187. * string constant, so I had to put this hack in.)
  1188. * \14, \15, \16 - a signed byte immediate operand, from operand 0, 1 or 2
  1189. * \20, \21, \22 - a byte immediate operand, from operand 0, 1 or 2
  1190. * \24, \25, \26 - an unsigned byte immediate operand, from operand 0, 1 or 2
  1191. * \30, \31, \32 - a word immediate operand, from operand 0, 1 or 2
  1192. * \34, \35, \36 - select between \3[012] and \4[012] depending on 16/32 bit
  1193. * assembly mode or the address-size override on the operand
  1194. * \37 - a word constant, from the _segment_ part of operand 0
  1195. * \40, \41, \42 - a long immediate operand, from operand 0, 1 or 2
  1196. * \50, \51, \52 - a byte relative operand, from operand 0, 1 or 2
  1197. * \60, \61, \62 - a word relative operand, from operand 0, 1 or 2
  1198. * \64, \65, \66 - select between \6[012] and \7[012] depending on 16/32 bit
  1199. * assembly mode or the address-size override on the operand
  1200. * \70, \71, \72 - a long relative operand, from operand 0, 1 or 2
  1201. * \1ab - a ModRM, calculated on EA in operand a, with the spare
  1202. * field the register value of operand b.
  1203. * \2ab - a ModRM, calculated on EA in operand a, with the spare
  1204. * field equal to digit b.
  1205. * \30x - might be an 0x67 byte, depending on the address size of
  1206. * the memory reference in operand x.
  1207. * \310 - indicates fixed 16-bit address size, i.e. optional 0x67.
  1208. * \311 - indicates fixed 32-bit address size, i.e. optional 0x67.
  1209. * \320 - indicates fixed 16-bit operand size, i.e. optional 0x66.
  1210. * \321 - indicates fixed 32-bit operand size, i.e. optional 0x66.
  1211. * \322 - indicates that this instruction is only valid when the
  1212. * operand size is the default (instruction to disassembler,
  1213. * generates no code in the assembler)
  1214. * \330 - a literal byte follows in the code stream, to be added
  1215. * to the condition code value of the instruction.
  1216. * \340 - reserve <operand 0> bytes of uninitialised storage.
  1217. * Operand 0 had better be a segmentless constant.
  1218. }
  1219. var
  1220. currval : longint;
  1221. currsym : pasmsymbol;
  1222. procedure getvalsym(opidx:longint);
  1223. begin
  1224. case oper[opidx].typ of
  1225. top_ref :
  1226. begin
  1227. currval:=oper[opidx].ref^.offset;
  1228. currsym:=oper[opidx].ref^.symbol;
  1229. end;
  1230. top_const :
  1231. begin
  1232. currval:=oper[opidx].val;
  1233. currsym:=nil;
  1234. end;
  1235. top_symbol :
  1236. begin
  1237. currval:=oper[opidx].symofs;
  1238. currsym:=oper[opidx].sym;
  1239. end;
  1240. else
  1241. Message(asmw_e_immediate_or_reference_expected);
  1242. end;
  1243. end;
  1244. const
  1245. CondVal:array[TAsmCond] of byte=($0,
  1246. $7, $3, $2, $6, $2, $4, $F, $D, $C, $E, $6, $2,
  1247. $3, $7, $3, $5, $E, $C, $D, $F, $1, $B, $9, $5,
  1248. $0, $A, $A, $B, $8, $4);
  1249. var
  1250. c : byte;
  1251. pb,
  1252. codes : pchar;
  1253. bytes : array[0..3] of byte;
  1254. rfield,
  1255. data,s,opidx : longint;
  1256. ea_data : ea;
  1257. begin
  1258. codes:=insentry^.code;
  1259. { Force word push/pop for registers }
  1260. if (opsize=S_W) and ((codes[0]=#4) or (codes[0]=#6) or
  1261. ((codes[0]=#1) and ((codes[2]=#5) or (codes[2]=#7)))) then
  1262. begin
  1263. bytes[0]:=$66;
  1264. objectoutput^.writebytes(bytes,1);
  1265. end;
  1266. repeat
  1267. c:=ord(codes^);
  1268. inc(codes);
  1269. case c of
  1270. 0 :
  1271. break;
  1272. 1,2,3 :
  1273. begin
  1274. objectoutput^.writebytes(codes^,c);
  1275. inc(codes,c);
  1276. end;
  1277. 4,6 :
  1278. begin
  1279. case oper[0].reg of
  1280. R_CS :
  1281. begin
  1282. if c=4 then
  1283. bytes[0]:=$f
  1284. else
  1285. bytes[0]:=$e;
  1286. end;
  1287. R_NO,
  1288. R_DS :
  1289. begin
  1290. if c=4 then
  1291. bytes[0]:=$1f
  1292. else
  1293. bytes[0]:=$1e;
  1294. end;
  1295. R_ES :
  1296. begin
  1297. if c=4 then
  1298. bytes[0]:=$7
  1299. else
  1300. bytes[0]:=$6;
  1301. end;
  1302. R_SS :
  1303. begin
  1304. if c=4 then
  1305. bytes[0]:=$17
  1306. else
  1307. bytes[0]:=$16;
  1308. end;
  1309. else
  1310. InternalError(777004);
  1311. end;
  1312. objectoutput^.writebytes(bytes,1);
  1313. end;
  1314. 5,7 :
  1315. begin
  1316. case oper[0].reg of
  1317. R_FS :
  1318. begin
  1319. if c=5 then
  1320. bytes[0]:=$a1
  1321. else
  1322. bytes[0]:=$a0;
  1323. end;
  1324. R_GS :
  1325. begin
  1326. if c=5 then
  1327. bytes[0]:=$a9
  1328. else
  1329. bytes[0]:=$a8;
  1330. end;
  1331. else
  1332. InternalError(777005);
  1333. end;
  1334. objectoutput^.writebytes(bytes,1);
  1335. end;
  1336. 8,9,10 :
  1337. begin
  1338. bytes[0]:=ord(codes^)+regval(oper[c-8].reg);
  1339. inc(codes);
  1340. objectoutput^.writebytes(bytes,1);
  1341. end;
  1342. 15 :
  1343. begin
  1344. bytes[0]:=0;
  1345. objectoutput^.writebytes(bytes,1);
  1346. end;
  1347. 12,13,14 :
  1348. begin
  1349. getvalsym(c-12);
  1350. if (currval<-128) or (currval>127) then
  1351. Message2(asmw_e_value_exceeds_bounds,'signed byte',tostr(currval));
  1352. if assigned(currsym) then
  1353. objectoutput^.writereloc(currval,1,currsym,relative_false)
  1354. else
  1355. objectoutput^.writebytes(currval,1);
  1356. end;
  1357. 16,17,18 :
  1358. begin
  1359. getvalsym(c-16);
  1360. if (currval<-256) or (currval>255) then
  1361. Message2(asmw_e_value_exceeds_bounds,'byte',tostr(currval));
  1362. if assigned(currsym) then
  1363. objectoutput^.writereloc(currval,1,currsym,relative_false)
  1364. else
  1365. objectoutput^.writebytes(currval,1);
  1366. end;
  1367. 20,21,22 :
  1368. begin
  1369. getvalsym(c-20);
  1370. if (currval<0) or (currval>255) then
  1371. Message2(asmw_e_value_exceeds_bounds,'unsigned byte',tostr(currval));
  1372. if assigned(currsym) then
  1373. objectoutput^.writereloc(currval,1,currsym,relative_false)
  1374. else
  1375. objectoutput^.writebytes(currval,1);
  1376. end;
  1377. 24,25,26 :
  1378. begin
  1379. getvalsym(c-24);
  1380. if (currval<-65536) or (currval>65535) then
  1381. Message2(asmw_e_value_exceeds_bounds,'word',tostr(currval));
  1382. if assigned(currsym) then
  1383. objectoutput^.writereloc(currval,2,currsym,relative_false)
  1384. else
  1385. objectoutput^.writebytes(currval,2);
  1386. end;
  1387. 28,29,30 :
  1388. begin
  1389. getvalsym(c-28);
  1390. if assigned(currsym) then
  1391. objectoutput^.writereloc(currval,4,currsym,relative_false)
  1392. else
  1393. objectoutput^.writebytes(currval,4);
  1394. end;
  1395. 32,33,34 :
  1396. begin
  1397. getvalsym(c-32);
  1398. if assigned(currsym) then
  1399. objectoutput^.writereloc(currval,4,currsym,relative_false)
  1400. else
  1401. objectoutput^.writebytes(currval,4);
  1402. end;
  1403. 40,41,42 :
  1404. begin
  1405. getvalsym(c-40);
  1406. data:=currval-insend;
  1407. if assigned(currsym) then
  1408. inc(data,currsym^.address);
  1409. if (data>127) or (data<-128) then
  1410. Message1(asmw_e_short_jmp_out_of_range,tostr(data));
  1411. objectoutput^.writebytes(data,1);
  1412. end;
  1413. 52,53,54 :
  1414. begin
  1415. getvalsym(c-52);
  1416. if assigned(currsym) then
  1417. objectoutput^.writereloc(currval,4,currsym,relative_true)
  1418. else
  1419. objectoutput^.writereloc(currval-insend,4,nil,relative_false)
  1420. end;
  1421. 56,57,58 :
  1422. begin
  1423. getvalsym(c-56);
  1424. if assigned(currsym) then
  1425. objectoutput^.writereloc(currval,4,currsym,relative_true)
  1426. else
  1427. objectoutput^.writereloc(currval-insend,4,nil,relative_false)
  1428. end;
  1429. 192,193,194 :
  1430. begin
  1431. if NeedAddrPrefix(c-192) then
  1432. begin
  1433. bytes[0]:=$67;
  1434. objectoutput^.writebytes(bytes,1);
  1435. end;
  1436. end;
  1437. 200 :
  1438. begin
  1439. bytes[0]:=$67;
  1440. objectoutput^.writebytes(bytes,1);
  1441. end;
  1442. 208 :
  1443. begin
  1444. bytes[0]:=$66;
  1445. objectoutput^.writebytes(bytes,1);
  1446. end;
  1447. 216 :
  1448. begin
  1449. bytes[0]:=ord(codes^)+condval[condition];
  1450. inc(codes);
  1451. objectoutput^.writebytes(bytes,1);
  1452. end;
  1453. 201,
  1454. 202,
  1455. 209,
  1456. 210,
  1457. 217,218,219 :
  1458. begin
  1459. { these are dissambler hints or 32 bit prefixes which
  1460. are not needed }
  1461. end;
  1462. 31,
  1463. 48,49,50,
  1464. 224,225,226 :
  1465. begin
  1466. InternalError(777006);
  1467. end
  1468. else
  1469. begin
  1470. if (c>=64) and (c<=191) then
  1471. begin
  1472. if (c<127) then
  1473. begin
  1474. if (oper[c and 7].typ=top_reg) then
  1475. rfield:=regval(oper[c and 7].reg)
  1476. else
  1477. rfield:=regval(oper[c and 7].ref^.base);
  1478. end
  1479. else
  1480. rfield:=c and 7;
  1481. opidx:=(c shr 3) and 7;
  1482. if not process_ea(oper[opidx], ea_data, rfield) then
  1483. Message(asmw_e_invalid_effective_address);
  1484. pb:=@bytes;
  1485. pb^:=chr(ea_data.modrm);
  1486. inc(pb);
  1487. if ea_data.sib_present then
  1488. begin
  1489. pb^:=chr(ea_data.sib);
  1490. inc(pb);
  1491. end;
  1492. s:=pb-pchar(@bytes);
  1493. objectoutput^.writebytes(bytes,s);
  1494. case ea_data.bytes of
  1495. 0 : ;
  1496. 1 :
  1497. begin
  1498. if (oper[opidx].ot and OT_MEMORY)=OT_MEMORY then
  1499. objectoutput^.writereloc(oper[opidx].ref^.offset,1,oper[opidx].ref^.symbol,relative_false)
  1500. else
  1501. begin
  1502. bytes[0]:=oper[opidx].ref^.offset;
  1503. objectoutput^.writebytes(bytes,1);
  1504. end;
  1505. inc(s);
  1506. end;
  1507. 2,4 :
  1508. begin
  1509. objectoutput^.writereloc(oper[opidx].ref^.offset,ea_data.bytes,
  1510. oper[opidx].ref^.symbol,relative_false);
  1511. inc(s,ea_data.bytes);
  1512. end;
  1513. end;
  1514. end
  1515. else
  1516. InternalError(777007);
  1517. end;
  1518. end;
  1519. until false;
  1520. end;
  1521. {$endif NOAG386BIN}
  1522. end.
  1523. {
  1524. $Log$
  1525. Revision 1.5 2000-09-24 15:06:14 peter
  1526. * use defines.inc
  1527. Revision 1.4 2000/08/27 16:11:50 peter
  1528. * moved some util functions from globals,cobjects to cutils
  1529. * splitted files into finput,fmodule
  1530. Revision 1.3 2000/07/13 12:08:25 michael
  1531. + patched to 1.1.0 with former 1.09patch from peter
  1532. Revision 1.2 2000/07/13 11:32:38 michael
  1533. + removed logs
  1534. }