cpuasm.pas 50 KB

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