cpuasm.pas 49 KB

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