PCAAMD64.Mod 56 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215
  1. MODULE PCAAMD64; (** AUTHOR "negelef"; PURPOSE "AMD64 assembler"; *)
  2. IMPORT
  3. SYSTEM, Modules, Commands, Streams, CompilerInterface, PCLIR, PCP, PCS, PCT, PCBT, PCM, Diagnostics,
  4. Texts, TextUtilities, Files, ASM := ASMAMD64, StringPool, Strings;
  5. CONST
  6. maxName = 128; (* maximum name length for labels and identifiers*)
  7. maxPasses = 2; (* two pass assembler *)
  8. binSuffix = ".Bin";
  9. (* scanner codes *)
  10. TAB = 09X;
  11. LF = 0AX;
  12. CR = 0DX;
  13. SPACE = 20X;
  14. (* symbol values *)
  15. symNone = 0;
  16. symIdent = 1;
  17. symLabel = 2;
  18. symNumber = 3;
  19. symSemicolon = 4;
  20. symColon = 5;
  21. symLn = 6;
  22. symComma = 7;
  23. symString = 8;
  24. symPlus = 9;
  25. symMinus = 10;
  26. symTimes = 11;
  27. symDiv = 12;
  28. symLParen = 13;
  29. symRParen = 14;
  30. symLBrace = 15;
  31. symRBrace = 16;
  32. symLBraket = 17;
  33. symRBraket = 18;
  34. symPC = 19;
  35. symPCOffset = 20;
  36. symNegate = 21;
  37. symComposite = 22;
  38. symMod = 23;
  39. symPeriod = 24;
  40. (* rex prefix bit positions *)
  41. rexB = 0;
  42. rexX = 1;
  43. rexR = 2;
  44. rexW= 3;
  45. rex = 4;
  46. rAX = 0;
  47. rCX = 1;
  48. rDX = 2;
  49. rBX = 3;
  50. rSP = 4;
  51. rBP = 5;
  52. rSI = 6;
  53. rDI = 7;
  54. r8 = 8;
  55. r9 = 9;
  56. r10 = 10;
  57. r11 = 11;
  58. r12 = 12;
  59. r13 = 13;
  60. r14 = 14;
  61. r15 = 15;
  62. rIP = 16;
  63. (* segment registers *)
  64. segES = 0;
  65. segCS = 1;
  66. segSS = 2;
  67. segDS = 3;
  68. segFS = 4;
  69. segGS = 5;
  70. regIP = 109;
  71. regRIP = 110;
  72. (* sizes *)
  73. default* = 0;
  74. size8 = 8;
  75. size16 = 16;
  76. size32 = 32;
  77. size64 = 64;
  78. size128 = 128;
  79. TYPE
  80. Name = ARRAY maxName OF CHAR;
  81. Size = LONGINT;
  82. Label = POINTER TO RECORD;
  83. name: Name;
  84. pc, pass: LONGINT;
  85. equ: BOOLEAN;
  86. next: Label;
  87. END;
  88. Operand* = OBJECT (PCLIR.InstructionAttribute)
  89. PROCEDURE Matches (type: ASM.OperandType): BOOLEAN;
  90. END Matches;
  91. END Operand;
  92. Reg* = OBJECT (Operand)
  93. VAR
  94. index-: LONGINT;
  95. PROCEDURE &New *(i: LONGINT);
  96. BEGIN index := i END New;
  97. END Reg;
  98. Reg8* = OBJECT (Reg)
  99. PROCEDURE Matches (type: ASM.OperandType): BOOLEAN;
  100. BEGIN
  101. CASE type OF
  102. ASM.reg8, ASM.regmem8:
  103. RETURN TRUE;
  104. | ASM.AL, ASM.rAX:
  105. RETURN index = rAX;
  106. | ASM.CL:
  107. RETURN index = rCX;
  108. ELSE
  109. RETURN FALSE;
  110. END;
  111. END Matches;
  112. END Reg8;
  113. MemReg = OBJECT (Reg)
  114. END MemReg;
  115. Reg16* = OBJECT (MemReg)
  116. PROCEDURE Matches (type: ASM.OperandType): BOOLEAN;
  117. BEGIN
  118. CASE type OF
  119. ASM.reg16, ASM.regmem16:
  120. RETURN TRUE;
  121. | ASM.AX, ASM.rAX:
  122. RETURN index = rAX;
  123. | ASM.DX:
  124. RETURN index = rDX;
  125. ELSE
  126. RETURN FALSE;
  127. END;
  128. END Matches;
  129. END Reg16;
  130. Reg32* = OBJECT (MemReg)
  131. PROCEDURE Matches (type: ASM.OperandType): BOOLEAN;
  132. BEGIN
  133. CASE type OF
  134. ASM.reg32, ASM.regmem32:
  135. RETURN TRUE;
  136. | ASM.EAX, ASM.rAX:
  137. RETURN index = rAX;
  138. ELSE
  139. RETURN FALSE;
  140. END;
  141. END Matches;
  142. END Reg32;
  143. Reg64* = OBJECT (MemReg)
  144. PROCEDURE Matches (type: ASM.OperandType): BOOLEAN;
  145. BEGIN
  146. CASE type OF
  147. ASM.reg64, ASM.regmem64:
  148. RETURN TRUE;
  149. | ASM.RAX, ASM.rAX:
  150. RETURN index = rAX;
  151. ELSE
  152. RETURN FALSE;
  153. END;
  154. END Matches;
  155. END Reg64;
  156. RegCR* = OBJECT (Reg)
  157. PROCEDURE Matches (type: ASM.OperandType): BOOLEAN;
  158. BEGIN
  159. CASE type OF
  160. ASM.CRn:
  161. RETURN TRUE;
  162. | ASM.CR8:
  163. RETURN index = 8;
  164. ELSE
  165. RETURN FALSE;
  166. END;
  167. END Matches;
  168. END RegCR;
  169. RegDR* = OBJECT (Reg)
  170. PROCEDURE Matches (type: ASM.OperandType): BOOLEAN;
  171. BEGIN
  172. RETURN type = ASM.DRn;
  173. END Matches;
  174. END RegDR;
  175. SegReg* = OBJECT (Reg)
  176. PROCEDURE Matches (type: ASM.OperandType): BOOLEAN;
  177. BEGIN
  178. CASE type OF
  179. ASM.segReg:
  180. RETURN TRUE;
  181. | ASM.ES:
  182. RETURN index = segES;
  183. | ASM.CS:
  184. RETURN index = segCS;
  185. | ASM.SS:
  186. RETURN index = segSS;
  187. | ASM.DS:
  188. RETURN index = segDS;
  189. | ASM.FS:
  190. RETURN index = segFS;
  191. | ASM.GS:
  192. RETURN index = segGS;
  193. ELSE
  194. RETURN FALSE;
  195. END
  196. END Matches;
  197. END SegReg;
  198. FPReg* = OBJECT (Reg)
  199. PROCEDURE Matches (type: ASM.OperandType): BOOLEAN;
  200. BEGIN
  201. CASE type OF
  202. ASM.sti:
  203. RETURN TRUE;
  204. | ASM.st0:
  205. RETURN index = 0;
  206. ELSE
  207. RETURN FALSE;
  208. END
  209. END Matches;
  210. END FPReg;
  211. MMXReg* = OBJECT (Reg)
  212. PROCEDURE Matches (type: ASM.OperandType): BOOLEAN;
  213. BEGIN
  214. CASE type OF
  215. ASM.mmx, ASM.mmxmem32, ASM.mmxmem64:
  216. RETURN TRUE;
  217. ELSE
  218. RETURN FALSE;
  219. END
  220. END Matches;
  221. END MMXReg;
  222. XMMReg* = OBJECT (Reg)
  223. PROCEDURE Matches (type: ASM.OperandType): BOOLEAN;
  224. BEGIN
  225. CASE type OF
  226. ASM.xmm, ASM.xmmmem32, ASM.xmmmem64, ASM.xmmmem128:
  227. RETURN TRUE;
  228. ELSE
  229. RETURN FALSE;
  230. END
  231. END Matches;
  232. END XMMReg;
  233. Mem* = OBJECT (Operand)
  234. VAR
  235. size-: Size;
  236. seg, reg, index: Reg;
  237. scale, displacement: LONGINT;
  238. fixup: PCM.Attribute;
  239. PROCEDURE &New *(s: Size);
  240. BEGIN size := s; displacement := 0; scale := 1
  241. END New;
  242. PROCEDURE Matches (type: ASM.OperandType): BOOLEAN;
  243. BEGIN
  244. CASE type OF
  245. | ASM.mem:
  246. RETURN TRUE;
  247. | ASM.mem8:
  248. RETURN (size = default) OR (size = size8);
  249. | ASM.regmem8:
  250. RETURN ((size = default) OR (size = size8)) & ((reg = NIL) OR (reg IS MemReg));
  251. | ASM.mem16:
  252. RETURN (size = default) OR (size = size16);
  253. | ASM.regmem16:
  254. RETURN ((size = default) OR (size = size16)) & ((reg = NIL) OR (reg IS MemReg));
  255. | ASM.mem32:
  256. RETURN (size = default) OR (size = size32);
  257. | ASM.regmem32, ASM.mmxmem32, ASM.xmmmem32:
  258. RETURN ((size = default) OR (size = size32)) & ((reg = NIL) OR (reg IS MemReg));
  259. | ASM.mem64:
  260. RETURN (size = default) OR (size = size64);
  261. | ASM.regmem64, ASM.mmxmem64, ASM.xmmmem64:
  262. RETURN ((size = default) OR (size = size64)) & ((reg = NIL) OR (reg IS MemReg));
  263. | ASM.mem128:
  264. RETURN (size = default) OR (size = size128);
  265. | ASM.xmmmem128:
  266. RETURN ((size = default) OR (size = size128)) & ((reg = NIL) OR (reg IS MemReg));
  267. | ASM.moffset8:
  268. RETURN ((size = default) OR (size = size8)) & (reg = NIL);
  269. | ASM.moffset16:
  270. RETURN ((size = default) OR (size = size16)) & (reg = NIL);
  271. | ASM.moffset32:
  272. RETURN ((size = default) OR (size = size32)) & (reg = NIL);
  273. | ASM.moffset64:
  274. RETURN ((size = default) OR (size = size64)) & (reg = NIL);
  275. ELSE
  276. RETURN FALSE;
  277. END;
  278. END Matches;
  279. END Mem;
  280. Imm* = OBJECT (Operand)
  281. VAR
  282. size: Size;
  283. val-: HUGEINT;
  284. pc-: LONGINT;
  285. fixup: PCM.Attribute;
  286. PROCEDURE &New *(s: Size; v: HUGEINT);
  287. BEGIN size:= s; val := v; pc := -1
  288. END New;
  289. PROCEDURE Matches (type: ASM.OperandType): BOOLEAN;
  290. BEGIN
  291. CASE type OF
  292. ASM.one:
  293. RETURN val = 1
  294. | ASM.three:
  295. RETURN val = 3
  296. | ASM.rel8off:
  297. RETURN (size = default) OR (size = size8)
  298. | ASM.imm8:
  299. RETURN ((size = default) OR (size = size8)) & (val >= -80H) & (val < 100H)
  300. | ASM.simm8:
  301. RETURN ((size = default) OR (size = size8)) & (val >= -80H) & (val < 80H)
  302. | ASM.uimm8:
  303. RETURN ((size = default) OR (size = size8)) & (val >= 0H) & (val < 100H)
  304. | ASM.rel16off:
  305. RETURN (size = default) OR (size = size16)
  306. | ASM.imm16:
  307. RETURN ((size = default) OR (size = size16)) & (val >= -8000H) & (val < 10000H)
  308. | ASM.simm16:
  309. RETURN ((size = default) OR (size = size16)) & (val >= -8000H) & (val < 8000H)
  310. | ASM.uimm16:
  311. RETURN ((size = default) OR (size = size16)) & (val >= 0H) & (val < 10000H)
  312. | ASM.rel32off:
  313. RETURN (size = default) OR (size = size32)
  314. | ASM.imm32:
  315. RETURN ((size = default) OR (size = size32)) (* & & (val >= -80000000H) & (val < 100000000H) PACO confused? *)
  316. | ASM.simm32:
  317. RETURN ((size = default) OR (size = size32)) (* & & (val >= -80000000H) & (val < 80000000H) PACO confused? *)
  318. | ASM.uimm32:
  319. RETURN ((size = default) OR (size = size32)) & (val >= 0H) (* & (val < 100000000H) PACO confused? *)
  320. | ASM.imm64:
  321. RETURN (size = default) OR (size = size64)
  322. ELSE
  323. RETURN FALSE
  324. END
  325. END Matches;
  326. END Imm;
  327. Offset* = OBJECT (Imm)
  328. END Offset;
  329. Pntr1616 = OBJECT (Operand)
  330. VAR
  331. selector, offset: LONGINT;
  332. PROCEDURE Matches (type: ASM.OperandType): BOOLEAN;
  333. BEGIN RETURN type = ASM.pntr1616;
  334. END Matches;
  335. PROCEDURE &New *(s, o: LONGINT);
  336. BEGIN selector := s; offset := o
  337. END New;
  338. END Pntr1616;
  339. Pntr1632 = OBJECT (Pntr1616)
  340. PROCEDURE Matches (type: ASM.OperandType): BOOLEAN;
  341. BEGIN
  342. RETURN type = ASM.pntr1632;
  343. END Matches;
  344. END Pntr1632;
  345. Assembly* = OBJECT (PCLIR.AsmInline)
  346. VAR
  347. pc-, pcOffset, errPos*: LONGINT;
  348. current: PCLIR.AsmBlock;
  349. bits: Size;
  350. cpuoptions: ASM.CPUOptions;
  351. firstLabel: Label;
  352. diagnostics: Diagnostics.Diagnostics;
  353. listing: Streams.Writer;
  354. PROCEDURE &Init *(d: Diagnostics.Diagnostics; list: Streams.Writer);
  355. BEGIN
  356. NEW (code);
  357. Reset;
  358. current.len := 0;
  359. diagnostics := d;
  360. listing := list;
  361. END Init;
  362. PROCEDURE Reset*;
  363. BEGIN
  364. current := code;
  365. pc := 0;
  366. pcOffset := 0;
  367. bits := 64;
  368. cpuoptions := {ASM.cpu8086 .. ASM.cpuAMD64} + ASM.cpuOptions;
  369. END Reset;
  370. PROCEDURE SetPC* (newPC: LONGINT);
  371. BEGIN
  372. current := code;
  373. pc := newPC;
  374. pcOffset := 0;
  375. WHILE newPC - pcOffset > current.len DO
  376. INC (pcOffset, current.len);
  377. current := current.next;
  378. END;
  379. END SetPC;
  380. PROCEDURE AddFixup (adr: PCM.Attribute; offset: LONGINT);
  381. VAR asmFixup: PCLIR.AsmFixup;
  382. BEGIN
  383. NEW (asmFixup);
  384. asmFixup.offset := offset;
  385. asmFixup.adr := adr;
  386. asmFixup.next := fixup;
  387. fixup := asmFixup;
  388. END AddFixup;
  389. PROCEDURE PutByte* (b: LONGINT);
  390. BEGIN
  391. IF pc - pcOffset = LEN (current.code) THEN
  392. IF current.next = NIL THEN
  393. NEW (current.next);
  394. current.next.len := 0;
  395. END;
  396. INC (pcOffset, current.len);
  397. current := current.next;
  398. END;
  399. current.code[pc - pcOffset] := SYSTEM.VAL (CHAR, b);
  400. IF (current.len = pc - pcOffset) THEN INC (current.len) END;
  401. INC (pc);
  402. END PutByte;
  403. PROCEDURE GetByte* (): CHAR;
  404. BEGIN
  405. IF pc - pcOffset = current.len THEN
  406. INC (pcOffset, current.len);
  407. current := current.next;
  408. END;
  409. INC (pc);
  410. RETURN current.code[pc - pcOffset - 1];
  411. END GetByte;
  412. PROCEDURE GetWord* (): INTEGER;
  413. VAR word: INTEGER;
  414. BEGIN
  415. word := ORD (GetByte ());
  416. INC (word, ORD (GetByte ()) * 100H);
  417. RETURN word;
  418. END GetWord;
  419. PROCEDURE GetDWord* (): LONGINT;
  420. VAR dword, byte: LONGINT;
  421. BEGIN
  422. dword := ORD (GetByte ());
  423. INC (dword, LONG (ORD (GetByte ())) * 100H);
  424. INC (dword, LONG (ORD (GetByte ())) * 10000H);
  425. byte := LONG (ORD (GetByte ()));
  426. IF byte >= 128 THEN DEC (byte, 256) END;
  427. RETURN dword + byte * 1000000H;
  428. END GetDWord;
  429. PROCEDURE PutWord* (w: LONGINT);
  430. BEGIN
  431. PutByte (w MOD 100H);
  432. PutByte ((w DIV 100H) MOD 100H);
  433. END PutWord;
  434. PROCEDURE PutDWord* (d: LONGINT);
  435. BEGIN
  436. PutByte (d MOD 100H);
  437. PutByte ((d DIV 100H) MOD 100H);
  438. PutByte ((d DIV 10000H) MOD 100H);
  439. PutByte ((d DIV 1000000H) MOD 100H);
  440. END PutDWord;
  441. PROCEDURE PutQWord* (q: HUGEINT);
  442. VAR d: LONGINT;
  443. BEGIN
  444. SYSTEM.GET (ADDRESSOF (q), d);
  445. PutDWord (d);
  446. SYSTEM.GET (ADDRESSOF (q) + 4, d);
  447. PutDWord (d);
  448. END PutQWord;
  449. PROCEDURE Put (data: LONGINT; size: Size);
  450. BEGIN
  451. CASE size OF
  452. size8: PutByte (data);
  453. | size16: PutWord (data);
  454. | size32: PutDWord (data);
  455. END
  456. END Put;
  457. PROCEDURE InsertLabel (CONST name: ARRAY OF CHAR): Label;
  458. VAR label: Label;
  459. BEGIN
  460. label := GetLabel (name);
  461. IF label = NIL THEN
  462. NEW (label);
  463. COPY (name, label.name);
  464. label.next := firstLabel;
  465. label.pass := -1;
  466. label.equ := FALSE;
  467. firstLabel := label;
  468. END;
  469. RETURN label;
  470. END InsertLabel;
  471. PROCEDURE GetLabel (CONST name: ARRAY OF CHAR): Label;
  472. VAR label: Label;
  473. BEGIN
  474. label := firstLabel;
  475. WHILE (label # NIL) & (label.name # name) DO label := label.next END;
  476. RETURN label;
  477. END GetLabel;
  478. PROCEDURE Assemble (scan: PCS.Scanner; scope: PCT.Scope; exported, inlined, inlineAssembly: BOOLEAN);
  479. VAR
  480. scanner: PCS.Scanner;
  481. symbol, reg: LONGINT;
  482. ident, idents: Name;
  483. val, times, val2, val3: LONGINT;
  484. currentLabel: Label;
  485. prevPC: LONGINT;
  486. pass: LONGINT;
  487. absoluteMode: BOOLEAN;
  488. absoluteOffset: LONGINT;
  489. orgOffset: LONGINT;
  490. PROCEDURE NextChar;
  491. BEGIN IF (listing # NIL) & (pass = maxPasses) THEN listing.Char (scanner.ch) END; scanner.NextChar
  492. END NextChar;
  493. PROCEDURE SkipBlanks;
  494. BEGIN
  495. (* tf returns 01X when an embedded object is encountered *)
  496. WHILE (scanner.ch = SPACE) OR (scanner.ch = TAB) OR (scanner.ch = 01X) DO NextChar END;
  497. IF scanner.ch = ";" THEN
  498. WHILE (scanner.ch # CR) & (scanner.ch # LF) DO NextChar END (* Skip comments *)
  499. END;
  500. END SkipBlanks;
  501. PROCEDURE GetNumber (VAR intval: LONGINT);
  502. VAR i, m, n: INTEGER; dig: ARRAY 24 OF CHAR;
  503. BEGIN
  504. i := 0; m := 0; n := 0;
  505. WHILE ('0' <= scanner.ch) & (scanner.ch <= '9') OR ('A' <= CAP (scanner.ch)) & (CAP (scanner.ch) <= 'F') DO
  506. IF (m > 0) OR (scanner.ch # "0") THEN (* ignore leading zeros *)
  507. IF n < LEN(dig) THEN dig[n] := scanner.ch; INC(n) END;
  508. INC(m)
  509. END;
  510. NextChar; INC(i)
  511. END;
  512. IF n = m THEN intval := 0; i := 0;
  513. IF CAP (scanner.ch) = "H" THEN NextChar;
  514. IF (n = PCM.MaxHDig) & (dig[0] > "7") THEN (* prevent overflow *) intval := -1 END;
  515. WHILE i < n DO intval := intval * 10H + HexOrd (dig[i]); INC(i) END;
  516. ELSE
  517. IF (n = PCM.MaxHDig) & (dig[0] > "7") THEN (* prevent overflow *) intval := -1 END;
  518. WHILE i < n DO intval := intval * 10 + Ord (dig[i]); INC(i) END
  519. END
  520. END;
  521. END GetNumber;
  522. PROCEDURE GetIdentifier;
  523. VAR i: LONGINT;
  524. BEGIN
  525. i := 0;
  526. REPEAT
  527. IF i < maxName - 1 THEN
  528. IF ('0' <= scanner.ch) & (scanner.ch <= '9') THEN
  529. ident[i] := scanner.ch; idents[i] := scanner.ch;
  530. ELSE
  531. ident[i] := CAP (scanner.ch); idents[i] := scanner.ch; END;
  532. INC (i);
  533. END;
  534. NextChar
  535. UNTIL ~((('A' <= CAP(scanner.ch)) & (CAP(scanner.ch) <= 'Z')) OR (('0' <= scanner.ch) & (scanner.ch <= '9')));
  536. ident[i] := 0X; idents[i] := 0X;
  537. END GetIdentifier;
  538. PROCEDURE GetString;
  539. VAR i: LONGINT;
  540. BEGIN
  541. i := 0;
  542. NextChar;
  543. WHILE (scanner.ch # "'") & (i < maxName - 1) DO
  544. ident[i] := scanner.ch; INC (i);
  545. NextChar;
  546. END;
  547. ident[i] := 0X;
  548. NextChar;
  549. END GetString;
  550. PROCEDURE NextSymbol;
  551. BEGIN
  552. SkipBlanks;
  553. errPos := scanner.curpos - 1;
  554. CASE scanner.ch OF
  555. 'A' .. 'Z', 'a' .. 'z' :
  556. GetIdentifier;
  557. SkipBlanks;
  558. IF scanner.ch = ':' THEN
  559. NextChar; symbol := symLabel;
  560. ELSE
  561. symbol := symIdent;
  562. END;
  563. | '0' .. '9':
  564. GetNumber (val);
  565. symbol := symNumber;
  566. | "'": GetString;
  567. symbol := symString;
  568. | '.': symbol := symPeriod;
  569. NextChar;
  570. | ';': symbol := symSemicolon;
  571. NextChar;
  572. | ':': symbol := symColon;
  573. NextChar;
  574. | CR, LF: symbol := symLn;
  575. NextChar;
  576. | ',': symbol := symComma;
  577. NextChar;
  578. | '+': symbol := symPlus;
  579. NextChar;
  580. | '-': symbol := symMinus;
  581. NextChar;
  582. | '*': symbol := symTimes;
  583. NextChar;
  584. | '/': symbol := symDiv;
  585. NextChar;
  586. | '%': symbol := symMod;
  587. NextChar;
  588. | '~': symbol := symNegate;
  589. NextChar;
  590. | '(': symbol := symLParen;
  591. NextChar;
  592. | ')': symbol := symRParen;
  593. NextChar;
  594. | '[': symbol := symLBraket;
  595. NextChar;
  596. | ']': symbol := symRBraket;
  597. NextChar;
  598. | '{': symbol := symLBrace;
  599. NextChar;
  600. | '}': symbol := symRBrace;
  601. NextChar;
  602. | '$': NextChar;
  603. IF scanner.ch = '$' THEN
  604. symbol := symPCOffset; NextChar;
  605. ELSE
  606. symbol := symPC;
  607. END
  608. ELSE
  609. symbol := symNone;
  610. NextChar;
  611. END;
  612. END NextSymbol;
  613. PROCEDURE SkipLine;
  614. BEGIN
  615. WHILE (symbol # symLn) & (symbol # symNone) DO
  616. NextSymbol;
  617. END;
  618. END SkipLine;
  619. PROCEDURE Ensure (desiredSymbol, errNumber : LONGINT) : BOOLEAN;
  620. BEGIN
  621. IF symbol = desiredSymbol THEN
  622. NextSymbol;
  623. RETURN TRUE;
  624. ELSE
  625. PCM.Error (errNumber, errPos, "");
  626. RETURN FALSE;
  627. END;
  628. END Ensure;
  629. PROCEDURE SetBits (newBits: LONGINT): BOOLEAN;
  630. BEGIN
  631. CASE newBits OF
  632. 16: bits := size16;
  633. | 32: bits := size32;
  634. | 64: bits := size64;
  635. ELSE
  636. PCM.Error (553, errPos, ""); RETURN FALSE;
  637. END;
  638. RETURN TRUE;
  639. END SetBits;
  640. PROCEDURE GetCPU (cumulateOptions: BOOLEAN): BOOLEAN;
  641. VAR i: LONGINT;
  642. BEGIN
  643. SkipBlanks;
  644. GetIdentifier;
  645. i := ASM.FindCPU (ident);
  646. IF i # ASM.none THEN
  647. IF cumulateOptions THEN
  648. cpuoptions := cpuoptions + ASM.cpus[i].cpuoptions;
  649. ELSE
  650. cpuoptions := ASM.cpus[i].cpuoptions + ASM.cpuOptions;
  651. END;
  652. NextSymbol;
  653. RETURN TRUE;
  654. ELSE
  655. PCM.Error (552, errPos, ident);
  656. RETURN FALSE;
  657. END;
  658. END GetCPU;
  659. PROCEDURE GetScopeSymbol (ident: ARRAY OF CHAR): PCT.Symbol;
  660. VAR idx: LONGINT;
  661. BEGIN
  662. StringPool.GetIndex(ident, idx);
  663. RETURN PCT.Find (scope, scope, idx, PCT.procdeclared, TRUE);
  664. END GetScopeSymbol;
  665. PROCEDURE Factor (VAR x: LONGINT; critical: BOOLEAN): BOOLEAN;
  666. VAR label: Label; scopeSymbol: PCT.Symbol; l: LONGINT;
  667. BEGIN
  668. IF symbol = symNumber THEN
  669. x := val; NextSymbol; RETURN TRUE;
  670. ELSIF symbol = symPC THEN
  671. x := orgOffset + pc; NextSymbol; RETURN TRUE;
  672. ELSIF symbol = symPCOffset THEN
  673. x := orgOffset; NextSymbol; RETURN TRUE;
  674. ELSIF symbol = symString THEN
  675. x := 0; l := Strings.Length (ident);
  676. IF l > 0 THEN INC (x, ORD (ident [0])) END;
  677. IF l > 1 THEN INC (x, ORD (ident [1])*100H) END;
  678. IF l > 2 THEN INC (x, ORD (ident [2])*10000H) END;
  679. IF l > 3 THEN INC (x, ORD (ident [3])*1000000H) END;
  680. NextSymbol; RETURN TRUE;
  681. ELSIF symbol = symIdent THEN
  682. label := GetLabel (ident); NextSymbol;
  683. IF label # NIL THEN
  684. IF label.equ THEN
  685. x := label.pc;
  686. ELSE
  687. x := orgOffset + label.pc;
  688. END;
  689. RETURN TRUE;
  690. ELSIF inlineAssembly THEN
  691. scopeSymbol := GetScopeSymbol (idents);
  692. IF scopeSymbol # NIL THEN
  693. IF scopeSymbol IS PCT.Value THEN
  694. IF scopeSymbol.type = PCT.Char8 THEN
  695. x := scopeSymbol(PCT.Value).const.int
  696. ELSIF PCT.IsCardinalType(scopeSymbol.type) THEN
  697. x := scopeSymbol(PCT.Value).const.int
  698. ELSE
  699. PCM.Error(51, errPos, "");
  700. RETURN FALSE;
  701. END;
  702. RETURN TRUE;
  703. ELSIF pass = maxPasses THEN
  704. PCM.Error (560, errPos, idents);
  705. RETURN FALSE;
  706. END;
  707. END
  708. END;
  709. IF (~critical) & (pass # maxPasses) THEN
  710. x := 0;
  711. RETURN TRUE
  712. END;
  713. PCM.Error (554, errPos, idents);
  714. RETURN FALSE;
  715. ELSIF symbol = symLParen THEN
  716. NextSymbol;
  717. RETURN Expression (x, critical) & Ensure (symRParen, 555);
  718. END;
  719. PCM.Error (555, errPos, "");
  720. RETURN FALSE
  721. END Factor;
  722. PROCEDURE Term (VAR x: LONGINT; critical: BOOLEAN): BOOLEAN;
  723. VAR y, op : LONGINT;
  724. BEGIN
  725. IF Factor (x, critical) THEN
  726. WHILE (symbol = symTimes) OR (symbol = symDiv) OR (symbol = symMod) DO
  727. op := symbol; NextSymbol;
  728. IF Factor (y, critical) THEN
  729. IF op = symTimes THEN x := x * y
  730. ELSIF op = symDiv THEN x := x DIV y
  731. ELSE x := x MOD y
  732. END;
  733. ELSE
  734. RETURN FALSE;
  735. END;
  736. END;
  737. RETURN TRUE;
  738. ELSE
  739. RETURN FALSE;
  740. END;
  741. END Term;
  742. PROCEDURE Expression (VAR x: LONGINT; critical: BOOLEAN): BOOLEAN;
  743. VAR y, op : LONGINT;
  744. BEGIN
  745. IF symbol = symMinus THEN
  746. op := symbol; NextSymbol;
  747. IF Term (x, critical) THEN
  748. x := -x
  749. ELSE
  750. RETURN FALSE;
  751. END;
  752. ELSIF symbol = symPlus THEN
  753. op := symbol; NextSymbol;
  754. IF ~Term (x, critical) THEN
  755. RETURN FALSE;
  756. END;
  757. ELSIF symbol = symNegate THEN
  758. op := symbol; NextSymbol;
  759. IF Term (x, critical) THEN
  760. x := -x - 1
  761. ELSE
  762. RETURN FALSE;
  763. END;
  764. ELSIF ~Term (x, critical) THEN
  765. RETURN FALSE;
  766. END;
  767. WHILE (symbol = symPlus) OR (symbol = symMinus) DO
  768. op := symbol; NextSymbol;
  769. IF Term (y, critical) THEN
  770. IF op = symPlus THEN x := x + y ELSE x := x - y END;
  771. ELSE
  772. RETURN FALSE;
  773. END;
  774. END;
  775. RETURN TRUE;
  776. END Expression;
  777. PROCEDURE PutData (size: Size): BOOLEAN;
  778. VAR i: LONGINT;
  779. BEGIN
  780. NextSymbol;
  781. WHILE symbol # symLn DO
  782. IF symbol = symString THEN
  783. i := 0;
  784. WHILE ident[i] # 0X DO
  785. PutByte (ORD (ident[i]));
  786. INC (i);
  787. END;
  788. IF size # size8 THEN
  789. i := (size DIV 8) - i MOD (size DIV 8);
  790. WHILE i # 0 DO PutByte (0); DEC (i) END;
  791. END;
  792. NextSymbol;
  793. ELSIF Expression (i, FALSE) THEN
  794. Put (i, size);
  795. ELSE
  796. RETURN FALSE;
  797. END;
  798. IF symbol = symComma THEN
  799. NextSymbol;
  800. ELSIF symbol # symLn THEN
  801. PCM.Error(511, errPos, "");
  802. END
  803. END;
  804. Duplicate (pc - prevPC, NIL);
  805. RETURN TRUE;
  806. END PutData;
  807. PROCEDURE Duplicate (size: LONGINT; fixup: PCLIR.AsmFixup);
  808. VAR i: LONGINT; buffer: ARRAY 100 OF CHAR;
  809. BEGIN
  810. IF times = 1 THEN RETURN END;
  811. SetPC (prevPC);
  812. IF times > 0 THEN
  813. IF (listing # NIL) & (pass = maxPasses) THEN listing.Hex (pc, 0); listing.Char (' ') END;
  814. FOR i := 0 TO size - 1 DO
  815. buffer[i] := GetByte ();
  816. IF (listing # NIL) & (pass = maxPasses) THEN listing.Hex (ORD (buffer[i]), -2); END;
  817. END;
  818. WHILE times # 1 DO
  819. IF fixup # NIL THEN
  820. AddFixup (fixup.adr, pc + fixup.offset - prevPC);
  821. END;
  822. FOR i := 0 TO size - 1 DO
  823. PutByte (ORD (buffer[i]));
  824. IF (listing # NIL) & (pass = maxPasses) THEN listing.Hex (ORD (buffer[i]), -2); END;
  825. END;
  826. DEC (times);
  827. END;
  828. ELSE
  829. times := 1;
  830. END;
  831. IF (listing # NIL) & (pass = maxPasses) THEN listing.Ln END;
  832. END Duplicate;
  833. PROCEDURE Reserve (size: Size) : BOOLEAN;
  834. BEGIN
  835. IF Expression (val2, TRUE) THEN
  836. absoluteOffset := absoluteOffset + val * size;
  837. RETURN TRUE;
  838. ELSE
  839. RETURN FALSE;
  840. END;
  841. END Reserve;
  842. PROCEDURE GetMemFixup (CONST ident: ARRAY OF CHAR; VAR mem: Mem);
  843. VAR scopeSymbol: PCT.Symbol;
  844. BEGIN
  845. scopeSymbol := GetScopeSymbol (ident);
  846. IF scopeSymbol = NIL THEN RETURN END;
  847. IF (scopeSymbol IS PCT.GlobalVar) THEN
  848. RETURN;
  849. IF ~inlined OR ~exported THEN
  850. mem.displacement := scopeSymbol.adr(PCBT.GlobalVariable).offset;
  851. END;
  852. ELSIF scopeSymbol IS PCT.Parameter THEN
  853. mem.displacement := scopeSymbol.adr(PCBT.Variable).offset;
  854. ELSIF scopeSymbol IS PCT.Variable THEN
  855. mem.displacement := scopeSymbol.adr(PCBT.Variable).offset;
  856. ELSE
  857. RETURN;
  858. END;
  859. mem.fixup := scopeSymbol.adr;
  860. NextSymbol;
  861. END GetMemFixup;
  862. PROCEDURE GetOffsetFixup (CONST ident: ARRAY OF CHAR; VAR offset: Offset);
  863. VAR scopeSymbol: PCT.Symbol;
  864. BEGIN
  865. scopeSymbol := GetScopeSymbol (ident);
  866. IF scopeSymbol = NIL THEN RETURN END;
  867. IF (scopeSymbol IS PCT.GlobalVar) THEN
  868. IF ~inlined OR ~exported THEN
  869. offset.val := scopeSymbol.adr(PCBT.GlobalVariable).offset;
  870. ELSE
  871. RETURN;
  872. END;
  873. ELSIF (scopeSymbol IS PCT.Proc) THEN
  874. IF ~inlined OR ~exported THEN
  875. offset.val := scopeSymbol.adr(PCBT.Procedure).codeoffset;
  876. ELSE
  877. RETURN;
  878. END;
  879. ELSE
  880. RETURN;
  881. END;
  882. offset.size := size64;
  883. offset.fixup := scopeSymbol.adr;
  884. END GetOffsetFixup;
  885. PROCEDURE GetInstruction (): BOOLEAN;
  886. VAR
  887. mnem, opCount: LONGINT;
  888. size: Size;
  889. operands: ARRAY ASM.maxOperands OF Operand;
  890. prevFixup: PCLIR.AsmFixup;
  891. mem: Mem;
  892. offset: Offset;
  893. BEGIN
  894. mnem := ASM.FindMnem (ident);
  895. IF mnem = ASM.none THEN
  896. PCM.Error (554, errPos, idents);
  897. RETURN FALSE;
  898. END;
  899. opCount := 0;
  900. NextSymbol;
  901. WHILE (symbol # symLn) & (symbol # symNone) DO
  902. IF symbol = symIdent THEN
  903. IF (ident = "BYTE") OR (ident = "SHORT") THEN
  904. size := size8; NextSymbol;
  905. ELSIF (ident = "WORD") OR (ident = "NEAR") THEN
  906. size := size16; NextSymbol;
  907. ELSIF ident = "DWORD" THEN
  908. size := size32; NextSymbol;
  909. ELSIF ident = "QWORD" THEN
  910. size := size64; NextSymbol;
  911. ELSIF ident = "TWORD" THEN
  912. size := size128; NextSymbol;
  913. ELSE
  914. size := default;
  915. END;
  916. ELSE
  917. size := default;
  918. END;
  919. IF symbol = symIdent THEN
  920. reg := ASM.FindReg (ident);
  921. IF reg # ASM.none THEN
  922. IF size # default THEN
  923. PCM.Error (562, errPos, ""); RETURN FALSE;
  924. END;
  925. operands[opCount] := NewReg (ASM.registers[reg].type, ASM.registers[reg].index);
  926. INC (opCount);
  927. NextSymbol;
  928. END;
  929. ELSE
  930. reg := ASM.none;
  931. END;
  932. IF reg = ASM.none THEN
  933. IF symbol = symLBraket THEN
  934. NextSymbol;
  935. NEW (mem, size);
  936. operands[opCount] := mem;
  937. INC (opCount);
  938. IF symbol = symLabel THEN
  939. reg := ASM.FindReg (ident);
  940. IF reg = ASM.none THEN
  941. PCM.Error (554, errPos, idents); RETURN FALSE;
  942. END;
  943. mem.seg := NewReg (ASM.registers[reg].type, ASM.registers[reg].index);
  944. NextSymbol;
  945. END;
  946. IF symbol = symIdent THEN
  947. reg := ASM.FindReg (ident);
  948. IF reg # ASM.none THEN
  949. mem.reg := NewReg (ASM.registers[reg].type, ASM.registers[reg].index);
  950. NextSymbol;
  951. IF symbol = symTimes THEN
  952. NextSymbol;
  953. IF ~Factor (mem.scale, FALSE) THEN
  954. RETURN FALSE;
  955. END;
  956. mem.index := mem.reg;
  957. mem.reg := NIL;
  958. END;
  959. IF symbol = symPlus THEN
  960. NextSymbol;
  961. IF symbol = symIdent THEN
  962. reg := ASM.FindReg (ident);
  963. IF reg # ASM.none THEN
  964. NextSymbol;
  965. IF mem.index = NIL THEN
  966. mem.index := NewReg (ASM.registers[reg].type, ASM.registers[reg].index);
  967. IF symbol = symTimes THEN
  968. NextSymbol;
  969. IF ~Factor (mem.scale, FALSE) THEN
  970. RETURN FALSE;
  971. END;
  972. END;
  973. ELSE
  974. mem.reg := NewReg (ASM.registers[reg].type, ASM.registers[reg].index);
  975. END;
  976. END;
  977. END;
  978. END;
  979. END;
  980. END;
  981. IF symbol = symPlus THEN
  982. NextSymbol;
  983. END;
  984. IF inlineAssembly & (symbol = symIdent) THEN
  985. GetMemFixup (idents, mem);
  986. END;
  987. IF (symbol # symRBraket) & (symbol # symNegate) THEN
  988. val2 := 0;
  989. IF ~Expression (val2, FALSE) THEN
  990. RETURN FALSE;
  991. END;
  992. INC (mem.displacement, val2);
  993. ELSIF (mem.reg = NIL) & (mem.index = NIL) THEN
  994. PCM.Error (511, errPos, ""); RETURN FALSE;
  995. END;
  996. IF ~Ensure (symRBraket, 556) THEN
  997. RETURN FALSE;
  998. END;
  999. ELSE
  1000. offset := NewOffset (size, val2);
  1001. IF inlineAssembly & (symbol = symIdent) THEN
  1002. GetOffsetFixup (idents, offset);
  1003. END;
  1004. IF offset.fixup = NIL THEN
  1005. IF ~Expression (val2, FALSE) THEN
  1006. RETURN FALSE;
  1007. END;
  1008. offset.val := val2;
  1009. IF symbol = symColon THEN
  1010. NextSymbol;
  1011. IF ~Expression (val3, FALSE) THEN
  1012. RETURN FALSE;
  1013. END;
  1014. operands[opCount] := NewOffset (default, val3);
  1015. INC (opCount);
  1016. END;
  1017. ELSE
  1018. NextSymbol;
  1019. END;
  1020. operands[opCount] := offset;
  1021. INC (opCount);
  1022. END;
  1023. END;
  1024. IF symbol = symComma THEN
  1025. NextSymbol;
  1026. ELSIF symbol # symLn THEN
  1027. PCM.Error(511, errPos, "");
  1028. END
  1029. END;
  1030. prevFixup := fixup;
  1031. IF ~EmitInstr (mnem, operands, pass = maxPasses) THEN
  1032. RETURN FALSE;
  1033. END;
  1034. IF fixup = prevFixup THEN
  1035. Duplicate (pc - prevPC, NIL);
  1036. ELSE
  1037. Duplicate (pc - prevPC, fixup);
  1038. END;
  1039. RETURN TRUE;
  1040. END GetInstruction;
  1041. BEGIN
  1042. FOR pass := 1 TO maxPasses DO
  1043. scanner := PCS.ForkScanner (scan);
  1044. Reset;
  1045. times := 1;
  1046. prevPC := pc;
  1047. currentLabel := NIL;
  1048. absoluteMode := FALSE;
  1049. orgOffset := 0;
  1050. NextSymbol;
  1051. IF inlineAssembly THEN
  1052. cpuoptions := {};
  1053. IF ~Ensure (symLBrace, 550) THEN
  1054. RETURN
  1055. END;
  1056. LOOP
  1057. IF ~Ensure (symIdent, 551) THEN
  1058. RETURN
  1059. END;
  1060. IF ident # "SYSTEM" THEN
  1061. PCM.Error (552, errPos, ident); RETURN
  1062. END;
  1063. IF symbol # symPeriod THEN
  1064. PCM.Error (551, errPos, ""); RETURN;
  1065. END;
  1066. IF ~GetCPU (TRUE) THEN
  1067. RETURN;
  1068. END;
  1069. IF symbol = symRBrace THEN
  1070. EXIT
  1071. ELSIF symbol = symComma THEN
  1072. NextSymbol
  1073. ELSE
  1074. PCM.Error (550, errPos, ident); RETURN;
  1075. END;
  1076. END;
  1077. NextSymbol;
  1078. END;
  1079. LOOP
  1080. IF (listing # NIL) & (pass = maxPasses) THEN listing.Char (9X); listing.Char (9X) END;
  1081. IF symbol = symLn THEN
  1082. NextSymbol;
  1083. ELSIF symbol = symLabel THEN
  1084. currentLabel := InsertLabel (ident);
  1085. IF absoluteMode THEN
  1086. currentLabel.pc := absoluteOffset;
  1087. ELSE
  1088. currentLabel.pc := pc;
  1089. END;
  1090. IF currentLabel.pass < pass THEN
  1091. currentLabel.pass := pass;
  1092. ELSE
  1093. PCM.Error (1, errPos, ident);
  1094. END;
  1095. NextSymbol;
  1096. ELSIF symbol = symIdent THEN
  1097. IF ident = "END" THEN
  1098. symbol := symNone;
  1099. ELSIF ~inlineAssembly & (ident = "BITS") THEN
  1100. NextSymbol;
  1101. IF ~Ensure (symNumber, 553) OR ~SetBits (val) THEN
  1102. SkipLine;
  1103. ELSE
  1104. NextSymbol;
  1105. END;
  1106. ELSIF ~inlineAssembly & (ident = "CPU") THEN
  1107. IF ~GetCPU (FALSE) THEN
  1108. SkipLine;
  1109. END;
  1110. ELSIF ~inlineAssembly & (ident = "ABSOLUTE") THEN
  1111. absoluteMode := TRUE;
  1112. NextSymbol;
  1113. IF ~Expression (absoluteOffset, TRUE) THEN
  1114. SkipLine;
  1115. END;
  1116. ELSIF ~inlineAssembly & (ident = "ORG") THEN
  1117. NextSymbol;
  1118. IF (orgOffset # 0) OR ~Expression (orgOffset, TRUE) THEN
  1119. SkipLine;
  1120. END;
  1121. ELSIF ~inlineAssembly & (ident = "RESB") THEN
  1122. NextSymbol;
  1123. IF ~Reserve (1) THEN SkipLine END;
  1124. ELSIF ~inlineAssembly & (ident = "RESW") THEN
  1125. NextSymbol;
  1126. IF ~Reserve (2) THEN SkipLine END;
  1127. ELSIF ~inlineAssembly & (ident = "RESD") THEN
  1128. NextSymbol;
  1129. IF ~Reserve (4) THEN SkipLine END;
  1130. ELSIF ident = "EQU" THEN
  1131. IF currentLabel # NIL THEN
  1132. NextSymbol;
  1133. IF Expression (val2, FALSE) THEN
  1134. currentLabel.pc := val2;
  1135. currentLabel.equ := TRUE;
  1136. ELSE
  1137. SkipLine;
  1138. END;
  1139. ELSE
  1140. PCM.Error (520, errPos, ""); RETURN;
  1141. END;
  1142. ELSIF ident = "TIMES" THEN
  1143. NextSymbol;
  1144. IF ~Expression (times, TRUE) THEN
  1145. SkipLine;
  1146. ELSIF times < 0 THEN
  1147. PCM.Error (561, errPos, ""); RETURN;
  1148. ELSE
  1149. prevPC := pc;
  1150. END;
  1151. ELSIF ident = "DB" THEN
  1152. IF ~PutData (size8) THEN SkipLine END;
  1153. ELSIF ident = "DW" THEN
  1154. IF ~PutData (size16) THEN SkipLine END;
  1155. ELSIF ident = "DD" THEN
  1156. IF ~PutData (size32) THEN SkipLine END;
  1157. ELSIF ident = "REP" THEN
  1158. NextSymbol;
  1159. PutByte (ASM.prfREP);
  1160. ELSIF ident = "LOCK" THEN
  1161. NextSymbol;
  1162. PutByte (ASM.prfLOCK);
  1163. ELSIF ident = "REPE" THEN
  1164. NextSymbol;
  1165. PutByte (ASM.prfREPE);
  1166. ELSIF ident = "REPZ" THEN
  1167. NextSymbol;
  1168. PutByte (ASM.prfREPZ);
  1169. ELSIF ident = "REPNE" THEN
  1170. NextSymbol;
  1171. PutByte (ASM.prfREPNE);
  1172. ELSIF ident = "REPNZ" THEN
  1173. NextSymbol;
  1174. PutByte (ASM.prfREPNZ);
  1175. ELSIF ~GetInstruction () THEN
  1176. SkipLine
  1177. END;
  1178. currentLabel := NIL;
  1179. ELSIF symbol = symNone THEN
  1180. EXIT
  1181. ELSE
  1182. PCM.Error (551, errPos, "");
  1183. RETURN;
  1184. END;
  1185. END;
  1186. END;
  1187. END Assemble;
  1188. PROCEDURE EmitPrefix* (prefix: LONGINT);
  1189. BEGIN PutByte (prefix);
  1190. END EmitPrefix;
  1191. PROCEDURE Emit* (mnem: LONGINT; op1, op2, op3: Operand);
  1192. VAR operands: ARRAY ASM.maxOperands OF Operand; res: BOOLEAN;
  1193. BEGIN
  1194. operands[0] := op1;
  1195. operands[1] := op2;
  1196. operands[2] := op3;
  1197. res := EmitInstr (mnem, operands, TRUE);
  1198. END Emit;
  1199. PROCEDURE EmitInstr (mnem: LONGINT; operands: ARRAY OF Operand; lastPass: BOOLEAN): BOOLEAN;
  1200. VAR instr, i, oppos, op: LONGINT;
  1201. val: LONGINT;
  1202. regOperand: LONGINT;
  1203. addressOperand: LONGINT;
  1204. regField, modField, rmField: LONGINT;
  1205. scaleField, indexField, baseField: LONGINT;
  1206. free: ARRAY ASM.maxOperands OF BOOLEAN;
  1207. byte: LONGINT;
  1208. offset: LONGINT;
  1209. mem: Mem;
  1210. lastPC: LONGINT;
  1211. opPrefix, adrPrefix: BOOLEAN;
  1212. segPrefix: LONGINT; rexPrefix: SET;
  1213. PROCEDURE MatchesInstruction (): BOOLEAN;
  1214. BEGIN
  1215. FOR i := 0 TO ASM.maxOperands - 1 DO
  1216. IF operands[i] = NIL THEN
  1217. IF ASM.instructions[instr].operands[i] # ASM.none THEN RETURN FALSE END;
  1218. ELSIF ~operands[i].Matches (ASM.instructions[instr].operands[i]) THEN
  1219. RETURN FALSE
  1220. ELSIF (bits = size64) & (ASM.optI64 IN ASM.instructions[instr].options) THEN
  1221. RETURN FALSE;
  1222. END;
  1223. END;
  1224. RETURN TRUE;
  1225. END MatchesInstruction;
  1226. PROCEDURE GetRegOperand (): LONGINT;
  1227. VAR i: LONGINT;
  1228. BEGIN
  1229. FOR i := 0 TO ASM.maxOperands -1 DO
  1230. CASE ASM.instructions[instr].operands[i] OF
  1231. ASM.reg8, ASM.reg16, ASM.reg32, ASM.reg64, ASM.xmm, ASM.mmx:
  1232. RETURN i;
  1233. ELSE
  1234. END;
  1235. END;
  1236. RETURN ASM.none;
  1237. END GetRegOperand;
  1238. PROCEDURE GetAddressOperand (): LONGINT;
  1239. VAR i: LONGINT;
  1240. BEGIN
  1241. FOR i := 0 TO ASM.maxOperands -1 DO
  1242. CASE ASM.instructions[instr].operands[i] OF
  1243. ASM.mem,
  1244. ASM.mem8, ASM.mem16, ASM.mem32, ASM.mem64, ASM.mem128,
  1245. ASM.regmem8, ASM.regmem16, ASM.regmem32, ASM.regmem64,
  1246. ASM.mmxmem32, ASM.mmxmem64,
  1247. ASM.xmmmem32, ASM.xmmmem64, ASM.xmmmem128:
  1248. RETURN i;
  1249. ELSE
  1250. END;
  1251. END;
  1252. RETURN ASM.none;
  1253. END GetAddressOperand;
  1254. PROCEDURE GetSpecialOperand (): LONGINT;
  1255. VAR i: LONGINT;
  1256. BEGIN
  1257. FOR i := 0 TO ASM.maxOperands -1 DO
  1258. CASE ASM.instructions[instr].operands[i] OF
  1259. ASM.segReg, ASM.mmx, ASM.xmm, ASM.CRn, ASM.DRn:
  1260. RETURN i;
  1261. ELSE
  1262. END;
  1263. END;
  1264. RETURN ASM.none;
  1265. END GetSpecialOperand;
  1266. PROCEDURE ModRM (mod, reg, rm: LONGINT);
  1267. BEGIN PutByte (mod MOD 4 * 40H + reg MOD 8 * 8H + rm MOD 8);
  1268. END ModRM;
  1269. PROCEDURE SIB (scale, index, base: LONGINT);
  1270. BEGIN PutByte (scale MOD 4 * 40H + index MOD 8 * 8H + base MOD 8);
  1271. END SIB;
  1272. BEGIN
  1273. instr := ASM.mnemonics[mnem].firstInstr;
  1274. WHILE (~MatchesInstruction ()) & (instr # ASM.mnemonics[mnem].lastInstr) DO INC (instr); END;
  1275. IF instr = ASM.mnemonics[mnem].lastInstr THEN
  1276. PCM.Error (557, errPos, ASM.mnemonics[mnem].name); RETURN FALSE;
  1277. ELSIF ASM.instructions[instr].cpuoptions * cpuoptions # ASM.instructions[instr].cpuoptions THEN
  1278. PCM.Error (558, errPos, ASM.mnemonics[mnem].name); RETURN FALSE;
  1279. END;
  1280. oppos := 0;
  1281. val := -1;
  1282. lastPC := pc;
  1283. opPrefix := FALSE;
  1284. adrPrefix := FALSE;
  1285. segPrefix := ASM.none;
  1286. rexPrefix := {};
  1287. IF (ASM.optO16 IN ASM.instructions[instr].options) & (bits # size16) THEN
  1288. opPrefix := TRUE;
  1289. END;
  1290. IF (ASM.optO32 IN ASM.instructions[instr].options) & (bits = size16) THEN
  1291. opPrefix := TRUE;
  1292. END;
  1293. IF (ASM.optO64 IN ASM.instructions[instr].options) & (bits = size64) THEN
  1294. INCL (rexPrefix, rexW)
  1295. END;
  1296. IF ASM.optPOP IN ASM.instructions[instr].options THEN
  1297. opPrefix := TRUE;
  1298. END;
  1299. regOperand := GetSpecialOperand ();
  1300. addressOperand := GetAddressOperand ();
  1301. IF regOperand = ASM.none THEN
  1302. regOperand := GetRegOperand ();
  1303. END;
  1304. IF addressOperand = ASM.none THEN
  1305. addressOperand := GetRegOperand();
  1306. END;
  1307. (* KernelLog.String (ASM.mnemonics[mnem].name); KernelLog.Int (regOperand, 10); KernelLog.Int (addressOperand, 10); KernelLog.Ln; *)
  1308. FOR i := 0 TO ASM.maxOperands - 1 DO
  1309. IF operands[i] # NIL THEN
  1310. IF operands[i] IS Mem THEN
  1311. mem := operands[i](Mem);
  1312. IF mem.seg # NIL THEN
  1313. segPrefix := mem.seg.index;
  1314. END;
  1315. IF mem.reg # NIL THEN
  1316. IF (mem.reg.index >= 8) THEN
  1317. INCL (rexPrefix, rexB)
  1318. END;
  1319. IF (mem.reg IS Reg32) & (bits # size32) THEN
  1320. adrPrefix := TRUE;
  1321. END;
  1322. IF mem.reg IS Reg16 THEN
  1323. IF bits = size64 THEN
  1324. PCM.Error (556, errPos, ""); RETURN FALSE;
  1325. ELSIF bits = size32 THEN
  1326. adrPrefix := TRUE;
  1327. END;
  1328. END;
  1329. END;
  1330. IF mem.index # NIL THEN
  1331. IF (mem.index IS Reg64) & (mem.index.index >= 8) THEN
  1332. INCL (rexPrefix, rexX)
  1333. END
  1334. END;
  1335. IF (mem.size = size64) & ~(ASM.optD64 IN ASM.instructions[instr].options) THEN
  1336. INCL (rexPrefix, rexW)
  1337. END;
  1338. IF ASM.instructions[instr].operands[i] = ASM.moffset64 THEN
  1339. adrPrefix := TRUE;
  1340. END;
  1341. ELSIF operands[i] IS Reg THEN
  1342. IF (operands[i] IS Reg64) & ~(ASM.optD64 IN ASM.instructions[instr].options) THEN
  1343. INCL (rexPrefix, rexW)
  1344. END;
  1345. IF operands[i](Reg).index >= 8 THEN
  1346. IF i = addressOperand THEN
  1347. INCL (rexPrefix, rexB)
  1348. ELSIF i = regOperand THEN
  1349. INCL (rexPrefix, rexR)
  1350. END;
  1351. ELSIF (bits = size64) & (operands[i] IS Reg8) & (operands[i](Reg).index >= 4) THEN
  1352. INCL (rexPrefix, rex);
  1353. END;
  1354. END;
  1355. END;
  1356. free[i] := operands[i] # NIL;
  1357. END;
  1358. CASE segPrefix OF
  1359. ASM.none:
  1360. | segES: PutByte (ASM.prfES);
  1361. | segCS: PutByte (ASM.prfCS);
  1362. | segSS: PutByte (ASM.prfSS);
  1363. | segDS: PutByte (ASM.prfDS);
  1364. | segFS: PutByte (ASM.prfFS);
  1365. | segGS: PutByte (ASM.prfGS);
  1366. END;
  1367. IF opPrefix THEN PutByte (ASM.prfOP) END;
  1368. IF adrPrefix THEN PutByte (ASM.prfADR) END;
  1369. IF ASM.optPLOCK IN ASM.instructions[instr].options THEN PutByte (ASM.prfLOCK) END;
  1370. IF ASM.optPREP IN ASM.instructions[instr].options THEN PutByte (ASM.prfREP) END;
  1371. IF ASM.optPREPN IN ASM.instructions[instr].options THEN PutByte (ASM.prfREPNE) END;
  1372. IF rexPrefix # {} THEN
  1373. byte := 40H;
  1374. IF rexB IN rexPrefix THEN byte := byte + 1H END;
  1375. IF rexX IN rexPrefix THEN byte := byte + 2H END;
  1376. IF rexR IN rexPrefix THEN byte := byte + 4H END;
  1377. IF rexW IN rexPrefix THEN byte := byte + 8H END;
  1378. PutByte (byte);
  1379. END;
  1380. op := 0;
  1381. WHILE ASM.instructions[instr].opcode[oppos] # 0X DO
  1382. IF ASM.instructions[instr].opcode[oppos] = 'i' THEN
  1383. IF val # -1 THEN PutByte (val); val := -1 END;
  1384. CASE ASM.instructions[instr].opcode[oppos + 1] OF
  1385. 'b': FOR i := 0 TO ASM.maxOperands - 1 DO
  1386. IF (free[i]) & (operands[i] IS Imm) THEN
  1387. offset := SHORT (operands[i](Imm).val);
  1388. IF FALSE & lastPass & ~ValueInByteRange (offset) THEN
  1389. PCM.Error (559, errPos, ""); RETURN FALSE;
  1390. END;
  1391. operands[i](Imm).pc := pc;
  1392. PutByte (SHORT (operands[i](Imm).val));
  1393. free[i] := FALSE; i:= ASM.maxOperands;
  1394. END
  1395. END;
  1396. | 'w': FOR i := 0 TO ASM.maxOperands - 1 DO
  1397. IF (free[i]) & (operands[i] IS Imm) THEN
  1398. operands[i](Imm).pc := pc;
  1399. PutWord (SHORT (operands[i](Imm).val));
  1400. free[i] := FALSE; i:= ASM.maxOperands;
  1401. END
  1402. END;
  1403. | 'd': FOR i := 0 TO ASM.maxOperands - 1 DO
  1404. IF (free[i]) & (operands[i] IS Imm) THEN
  1405. operands[i](Imm).pc := pc;
  1406. PutDWord (SHORT (operands[i](Imm).val));
  1407. free[i] := FALSE; i:= ASM.maxOperands;
  1408. END
  1409. END;
  1410. | 'q': FOR i := 0 TO ASM.maxOperands - 1 DO
  1411. IF (free[i]) & (operands[i] IS Imm) THEN
  1412. operands[i](Imm).pc := pc;
  1413. IF lastPass & (operands[i](Imm).fixup # NIL) THEN
  1414. AddFixup (operands[i](Imm).fixup, pc);
  1415. END;
  1416. PutQWord (operands[i](Imm).val);
  1417. free[i] := FALSE; i:= ASM.maxOperands;
  1418. END
  1419. END;
  1420. END;
  1421. ELSIF ASM.instructions[instr].opcode[oppos] = 'c' THEN
  1422. IF val # -1 THEN PutByte (val); val := -1 END;
  1423. CASE ASM.instructions[instr].opcode[oppos + 1] OF
  1424. 'b': FOR i := 0 TO ASM.maxOperands - 1 DO
  1425. IF (free[i]) & (operands[i] IS Offset) THEN
  1426. offset := SHORT (operands[i](Offset).val - pc - 1);
  1427. IF lastPass & ~ValueInByteRange (offset) THEN
  1428. PCM.Error (559, errPos, ""); RETURN FALSE;
  1429. END;
  1430. operands[i](Offset).pc := pc;
  1431. PutByte (offset);
  1432. free[i] := FALSE; i:= ASM.maxOperands;
  1433. ELSIF (free[i]) & (operands[i] IS Imm) THEN
  1434. offset := SHORT (operands[i](Imm).val);
  1435. IF lastPass & ~ValueInByteRange (offset) THEN
  1436. PCM.Error (559, errPos, ""); RETURN FALSE;
  1437. END;
  1438. operands[i](Imm).pc := pc;
  1439. PutByte (offset);
  1440. free[i] := FALSE; i:= ASM.maxOperands;
  1441. END
  1442. END;
  1443. |'w': FOR i := 0 TO ASM.maxOperands - 1 DO
  1444. IF (free[i]) & (operands[i] IS Offset) THEN
  1445. offset := SHORT (operands[i](Offset).val - pc - 2);
  1446. IF lastPass & ~ValueInWordRange (offset) THEN
  1447. PCM.Error (559, errPos, ""); RETURN FALSE;
  1448. END;
  1449. operands[i](Offset).pc := pc;
  1450. PutWord (offset);
  1451. free[i] := FALSE; i:= ASM.maxOperands;
  1452. ELSIF (free[i]) & (operands[i] IS Imm) THEN
  1453. offset := SHORT (operands[i](Imm).val);
  1454. IF lastPass & ~ValueInWordRange (offset) THEN
  1455. PCM.Error (559, errPos, ""); RETURN FALSE;
  1456. END;
  1457. operands[i](Imm).pc := pc;
  1458. PutWord (offset);
  1459. free[i] := FALSE; i:= ASM.maxOperands;
  1460. END
  1461. END;
  1462. |'d': FOR i := 0 TO ASM.maxOperands - 1 DO
  1463. IF (free[i]) & (operands[i] IS Offset) THEN
  1464. operands[i](Offset).pc := pc;
  1465. PutDWord (SHORT (operands[i](Offset).val - pc - 4));
  1466. free[i] := FALSE; i:= ASM.maxOperands;
  1467. ELSIF (free[i]) & (operands[i] IS Imm) THEN
  1468. operands[i](Imm).pc := pc;
  1469. PutDWord (SHORT (operands[i](Imm).val));
  1470. free[i] := FALSE; i:= ASM.maxOperands;
  1471. END
  1472. END;
  1473. END;
  1474. ELSIF ASM.instructions[instr].opcode[oppos] = '/' THEN
  1475. IF val # -1 THEN PutByte (val); val := -1 END;
  1476. CASE ASM.instructions[instr].opcode[oppos + 1] OF
  1477. 'r':
  1478. regField := operands[regOperand](Reg).index MOD 8;
  1479. | '0'..'9':
  1480. regField := ORD (ASM.instructions[instr].opcode[oppos + 1]) - ORD ('0');
  1481. END;
  1482. IF operands[addressOperand] IS Reg THEN
  1483. ModRM (3, regField, operands[addressOperand](Reg).index MOD 8);
  1484. ELSIF (bits = size16) & ((operands[addressOperand](Mem).reg = NIL) OR ~(operands[addressOperand](Mem).reg IS Reg32)) THEN
  1485. mem := operands[addressOperand](Mem);
  1486. IF (mem.scale # 1) OR (mem.fixup # NIL) THEN
  1487. PCM.Error (556, errPos, ""); RETURN FALSE;
  1488. ELSIF mem.reg = NIL THEN
  1489. IF mem.index # NIL THEN
  1490. PCM.Error (556, errPos, ""); RETURN FALSE;
  1491. END;
  1492. ModRM (0, regField, 6);
  1493. PutWord (mem.displacement);
  1494. ELSIF mem.reg IS Reg16 THEN
  1495. IF mem.displacement = 0 THEN
  1496. modField := 0;
  1497. ELSIF (mem.displacement >= -80H) & (mem.displacement < 80H) THEN
  1498. modField := 1;
  1499. ELSIF (mem.displacement >= -8000H) & (mem.displacement < 8000H) THEN
  1500. modField := 2;
  1501. ELSE
  1502. PCM.Error (559, errPos, ""); RETURN FALSE;
  1503. END;
  1504. CASE mem.reg.index OF
  1505. | rBX:
  1506. IF mem.index = NIL THEN
  1507. rmField := 7;
  1508. ELSIF mem.index.index = rSI THEN
  1509. rmField := 0;
  1510. ELSIF mem.index.index = rDI THEN
  1511. rmField := 1;
  1512. ELSE
  1513. PCM.Error (556, errPos, ""); RETURN FALSE;
  1514. END
  1515. | rBP:
  1516. IF mem.index = NIL THEN
  1517. rmField := 6;
  1518. IF modField = 0 THEN modField := 1 END;
  1519. ELSIF mem.index.index = rSI THEN
  1520. rmField := 2;
  1521. ELSIF mem.index.index = rDI THEN
  1522. rmField := 3;
  1523. ELSE
  1524. PCM.Error (556, errPos, ""); RETURN FALSE;
  1525. END
  1526. | rSI:
  1527. IF mem.index = NIL THEN
  1528. rmField := 4;
  1529. ELSIF mem.index.index = rBX THEN
  1530. rmField := 0;
  1531. ELSIF mem.index.index = rBP THEN
  1532. rmField := 2;
  1533. ELSE
  1534. PCM.Error (556, errPos, ""); RETURN FALSE;
  1535. END;
  1536. | rDI:
  1537. IF mem.index = NIL THEN
  1538. rmField := 5;
  1539. ELSIF mem.index.index = rBX THEN
  1540. rmField := 1;
  1541. ELSIF mem.index.index = rBP THEN
  1542. rmField := 3;
  1543. ELSE
  1544. PCM.Error (556, errPos, ""); RETURN FALSE;
  1545. END;
  1546. ELSE
  1547. PCM.Error (556, errPos, ""); RETURN FALSE;
  1548. END;
  1549. ModRM (modField, regField, rmField);
  1550. IF modField = 1 THEN
  1551. PutByte (mem.displacement);
  1552. ELSIF modField = 2 THEN
  1553. PutWord (mem.displacement);
  1554. END;
  1555. END;
  1556. ELSE
  1557. mem := operands[addressOperand](Mem);
  1558. IF (mem.reg = NIL) & (mem.index = NIL) THEN
  1559. IF mem.scale # 1 THEN
  1560. PCM.Error (556, errPos, ""); RETURN FALSE;
  1561. END;
  1562. IF bits = size64 THEN
  1563. ModRM (0, regField, 4);
  1564. SIB (0, 4, 5);
  1565. ELSE
  1566. ModRM (0, regField, 5);
  1567. END;
  1568. (* fixup must be 8bit wide for linker!
  1569. IF lastPass & (mem.fixup # NIL) THEN
  1570. AddFixup (mem.fixup, pc);
  1571. END;
  1572. *)
  1573. PutDWord (mem.displacement);
  1574. ELSE
  1575. IF (mem.index # NIL) THEN
  1576. IF (mem.index.index = rSP) OR (mem.index.index = rIP) THEN
  1577. PCM.Error (556, errPos, ""); RETURN FALSE;
  1578. END;
  1579. IF (mem.reg # NIL) & (mem.reg.index = rIP) THEN
  1580. PCM.Error (556, errPos, ""); RETURN FALSE;
  1581. END;
  1582. CASE mem.scale OF
  1583. 1: scaleField := 0;
  1584. | 2: scaleField := 1;
  1585. | 4: scaleField := 2;
  1586. | 8: scaleField := 3;
  1587. ELSE
  1588. PCM.Error (556, errPos, ""); RETURN FALSE;
  1589. END;
  1590. rmField := 4;
  1591. ELSE
  1592. IF (mem.scale # 1) THEN
  1593. PCM.Error (556, errPos, ""); RETURN FALSE;
  1594. END;
  1595. IF mem.reg.index = rIP THEN
  1596. rmField := 5;
  1597. ELSIF mem.reg.index MOD 8 = rSP THEN
  1598. rmField := 4;
  1599. ELSE
  1600. rmField := mem.reg.index MOD 8;
  1601. END;
  1602. END;
  1603. (* IF mem.fixup # NIL THEN
  1604. modField := 2;
  1605. mem fixups only for local variables and parameters
  1606. *)
  1607. IF mem.displacement = 0 THEN
  1608. IF (mem.reg # NIL) & (mem.reg.index = rBP) THEN
  1609. modField := 1;
  1610. ELSE
  1611. modField := 0;
  1612. END;
  1613. ELSIF (mem.reg # NIL) & (mem.reg.index = rIP) THEN
  1614. modField := 0;
  1615. ELSIF (mem.displacement >= -80H) & (mem.displacement < 80H) THEN
  1616. modField := 1;
  1617. ELSE
  1618. modField := 2;
  1619. END;
  1620. ModRM (modField, regField, rmField);
  1621. IF (mem.index # NIL) OR (mem.reg.index MOD 8 = rSP) THEN
  1622. IF mem.index # NIL THEN
  1623. indexField := mem.index.index MOD 8;
  1624. ELSE
  1625. indexField := 4;
  1626. END;
  1627. IF mem.reg # NIL THEN
  1628. baseField := mem.reg.index MOD 8;
  1629. ELSE
  1630. baseField := 5;
  1631. END;
  1632. SIB (scaleField, indexField, baseField);
  1633. END;
  1634. IF (modField = 0) & (mem.reg # NIL) & (mem.reg.index = rIP) THEN
  1635. PutDWord (mem.displacement);
  1636. ELSIF modField = 1 THEN
  1637. PutByte (mem.displacement);
  1638. ELSIF modField = 2 THEN
  1639. (* fixup must be 8bit wide for linker!
  1640. IF lastPass & (mem.fixup # NIL) THEN
  1641. AddFixup (mem.fixup, pc);
  1642. END;
  1643. *)
  1644. PutDWord (mem.displacement);
  1645. END;
  1646. END;
  1647. END;
  1648. ELSIF ASM.instructions[instr].opcode[oppos] = '+' THEN
  1649. CASE ASM.instructions[instr].opcode[oppos + 1] OF
  1650. 'o':
  1651. IF val # -1 THEN PutByte (val); val := -1 END;
  1652. FOR i := 0 TO ASM.maxOperands - 1 DO
  1653. IF (free[i]) & (operands[i] IS Mem) THEN
  1654. mem := operands[i](Mem);
  1655. IF bits = size16 THEN
  1656. PutWord (mem.displacement);
  1657. ELSE
  1658. IF lastPass & (mem.fixup # NIL) THEN
  1659. AddFixup (mem.fixup, pc);
  1660. END;
  1661. PutDWord (mem.displacement);
  1662. END;
  1663. free[i] := FALSE; i:= ASM.maxOperands;
  1664. END;
  1665. END;
  1666. | 'i': FOR i := 0 TO ASM.maxOperands - 1 DO
  1667. IF (free[i]) & (operands[i] IS FPReg) & (ASM.instructions[instr].operands[i] # ASM.st0) THEN
  1668. val := val + operands[i](FPReg).index;
  1669. PutByte (val); val := -1;
  1670. free[i] := FALSE; i:= ASM.maxOperands;
  1671. END;
  1672. END;
  1673. END;
  1674. ELSIF ASM.instructions[instr].opcode[oppos] = 'r' THEN
  1675. regOperand := GetRegOperand ();
  1676. val := val + operands[regOperand](Reg).index MOD 8;
  1677. PutByte (val); val := -1;
  1678. free[regOperand] := FALSE;
  1679. ELSE
  1680. IF val # -1 THEN PutByte (val) END;
  1681. val := HexOrd (ASM.instructions[instr].opcode[oppos]) * 10H + HexOrd (ASM.instructions[instr].opcode[oppos + 1]);
  1682. END;
  1683. INC (oppos, 2);
  1684. END;
  1685. IF val # -1 THEN PutByte (val) END;
  1686. RETURN TRUE;
  1687. END EmitInstr;
  1688. END Assembly;
  1689. (** Text processing handler registered at CompilerInterface *)
  1690. PROCEDURE AssembleText(
  1691. text : Texts.Text;
  1692. CONST source: ARRAY OF CHAR;
  1693. pos: LONGINT; (* ignore *)
  1694. CONST pc,opt: ARRAY OF CHAR; (* filename *)
  1695. log: Streams.Writer; diagnostics : Diagnostics.Diagnostics; VAR error: BOOLEAN);
  1696. VAR
  1697. assembly: Assembly;
  1698. destFile : Files.FileName;
  1699. BEGIN
  1700. ASSERT(text # NIL);
  1701. ASSERT(log # NIL);
  1702. ASSERT(diagnostics # NIL);
  1703. IF (opt = "") THEN
  1704. log.String("Error: Expected target filename as parameter"); log.Ln;
  1705. log.Update;
  1706. RETURN;
  1707. END;
  1708. PCM.Init(source, NIL, diagnostics);
  1709. NEW (assembly, diagnostics, NIL);
  1710. assembly.Assemble (PCS.InitWithText (text, 0), NIL, FALSE, FALSE, FALSE);
  1711. error := PCM.error;
  1712. IF error THEN
  1713. (* error reported to diagnostics interface *)
  1714. ELSE
  1715. COPY(opt, destFile);
  1716. ReplaceSuffix(destFile, binSuffix);
  1717. log.String("Assembling "); log.String(destFile); log.String("... "); log.Update;
  1718. WriteBinary(destFile, assembly, diagnostics, error);
  1719. IF error THEN
  1720. log.String("error: could not write binary.");
  1721. ELSE
  1722. log.String("done.");
  1723. END;
  1724. log.Update;
  1725. END;
  1726. END AssembleText;
  1727. PROCEDURE AssembleFile* (CONST fileName: ARRAY OF CHAR; diagnostics: Diagnostics.Diagnostics; labels, listing: Streams.Writer);
  1728. VAR
  1729. format: LONGINT; res: WORD;
  1730. text: Texts.Text;
  1731. assembly: Assembly;
  1732. destFile: ARRAY Files.NameLength OF CHAR;
  1733. label: Label;
  1734. ignore : BOOLEAN;
  1735. BEGIN
  1736. PCM.Init (fileName, NIL, diagnostics);
  1737. NEW (text);
  1738. TextUtilities.LoadAuto (text, fileName, format, res);
  1739. IF res # 0 THEN
  1740. diagnostics.Error (fileName, Streams.Invalid, "failed to open file"); RETURN;
  1741. END;
  1742. NEW (assembly, diagnostics, NIL);
  1743. assembly.Assemble (PCS.InitWithText (text, 0), NIL, FALSE, FALSE, FALSE);
  1744. IF PCM.error THEN
  1745. (* error reported to diagnostics interface *)
  1746. ELSE
  1747. COPY (fileName, destFile);
  1748. ReplaceSuffix(destFile, binSuffix);
  1749. WriteBinary(destFile, assembly, diagnostics, ignore);
  1750. IF labels # NIL THEN
  1751. label := assembly.firstLabel;
  1752. WHILE label # NIL DO
  1753. labels.String (label.name); labels.String (" := ");
  1754. labels.Int (label.pc, 0); labels.String (" (");
  1755. labels.Hex (label.pc, 0); labels.String (")");
  1756. labels.Ln;
  1757. label := label.next;
  1758. END;
  1759. END;
  1760. END;
  1761. END AssembleFile;
  1762. (* Assemble file: usage: PCAAMD64.Assemble file [l] *)
  1763. PROCEDURE Assemble* (context: Commands.Context);
  1764. VAR fileName: Files.FileName; labels: Streams.Writer; diagnostics: Diagnostics.StreamDiagnostics;
  1765. BEGIN
  1766. context.arg.SkipWhitespace; context.arg.String (fileName); context.arg.SkipWhitespace;
  1767. IF context.arg.Peek () = 'l' THEN labels := context.out ELSE labels := NIL END;
  1768. NEW (diagnostics, context.error);
  1769. AssembleFile (fileName, diagnostics, labels, context.out);
  1770. END Assemble;
  1771. PROCEDURE InlineAssemble (scanner: PCS.Scanner; scope: PCT.Scope; exported, inlined: BOOLEAN): PCM.Attribute;
  1772. VAR assembly: Assembly;
  1773. BEGIN
  1774. NEW (assembly, PCM.diagnostics, NIL);
  1775. assembly.Assemble (scanner, scope, exported, inlined, TRUE);
  1776. RETURN assembly;
  1777. END InlineAssemble;
  1778. PROCEDURE WriteBinary(CONST filename : ARRAY OF CHAR; assembly : Assembly; diagnostics : Diagnostics.Diagnostics; VAR error : BOOLEAN);
  1779. VAR file : Files.File; writer : Files.Writer; asmblock: PCLIR.AsmBlock;
  1780. BEGIN
  1781. ASSERT(assembly # NIL);
  1782. ASSERT(diagnostics # NIL);
  1783. file := Files.New (filename);
  1784. IF (file # NIL) THEN
  1785. error := FALSE;
  1786. Files.OpenWriter (writer, file, 0);
  1787. asmblock := assembly.code;
  1788. WHILE asmblock # NIL DO
  1789. writer.Bytes (asmblock.code, 0, asmblock.len);
  1790. asmblock := asmblock.next;
  1791. END;
  1792. writer.Update;
  1793. Files.Register(file);
  1794. ELSE
  1795. diagnostics.Error(filename, Streams.Invalid, "Could not create output file");
  1796. error := TRUE;
  1797. END;
  1798. END WriteBinary;
  1799. PROCEDURE ReplaceSuffix (VAR destFile : ARRAY OF CHAR; CONST suffix: ARRAY OF CHAR);
  1800. VAR i, j: LONGINT; fileName : Files.FileName;
  1801. BEGIN
  1802. COPY(destFile, fileName);
  1803. i := 0; WHILE (fileName[i] # 0X) & (fileName[i] # '.') DO destFile[i] := fileName[i]; INC(i) END;
  1804. j := 0; WHILE suffix[j] # 0X DO destFile[i+j] := suffix[j]; INC(j) END;
  1805. destFile[i+j] := 0X;
  1806. END ReplaceSuffix;
  1807. PROCEDURE Ord (ch: CHAR): INTEGER;
  1808. BEGIN RETURN ORD (ch) - ORD ("0")
  1809. END Ord;
  1810. PROCEDURE HexOrd (ch: CHAR): INTEGER;
  1811. BEGIN
  1812. IF ch <= "9" THEN RETURN ORD (ch) - ORD ("0")
  1813. ELSE RETURN ORD (CAP (ch)) - ORD ("A") + 10
  1814. END
  1815. END HexOrd;
  1816. PROCEDURE ValueInByteRange (value: HUGEINT): BOOLEAN;
  1817. BEGIN RETURN SYSTEM.VAL (SHORTINT, value) = value
  1818. END ValueInByteRange;
  1819. PROCEDURE ValueInWordRange (value: HUGEINT): BOOLEAN;
  1820. BEGIN RETURN SYSTEM.VAL (INTEGER, value) = value
  1821. END ValueInWordRange;
  1822. PROCEDURE NewReg (type, index: LONGINT): Reg;
  1823. BEGIN
  1824. CASE type OF
  1825. ASM.reg8: RETURN NewReg8 (index);
  1826. | ASM.reg16: RETURN NewReg16 (index);
  1827. | ASM.reg32: RETURN NewReg32 (index);
  1828. | ASM.reg64: RETURN NewReg64 (index);
  1829. | ASM.segReg: RETURN NewSegReg (index);
  1830. | ASM.CRn: RETURN NewRegCR (index);
  1831. | ASM.DRn: RETURN NewRegDR (index);
  1832. | ASM.st0: RETURN NewFPReg (0);
  1833. | ASM.sti: RETURN NewFPReg (index);
  1834. | ASM.xmm: RETURN NewXMMReg (index);
  1835. | ASM.mmx: RETURN NewMMXReg (index);
  1836. END;
  1837. END NewReg;
  1838. PROCEDURE NewReg8* (index: LONGINT): Reg8;
  1839. VAR reg8: Reg8;
  1840. BEGIN
  1841. NEW (reg8, index);
  1842. RETURN reg8;
  1843. END NewReg8;
  1844. PROCEDURE NewReg16* (index: LONGINT): Reg16;
  1845. VAR reg16: Reg16;
  1846. BEGIN
  1847. NEW (reg16, index);
  1848. RETURN reg16;
  1849. END NewReg16;
  1850. PROCEDURE NewReg32* (index: LONGINT): Reg32;
  1851. VAR reg32: Reg32;
  1852. BEGIN
  1853. NEW (reg32, index);
  1854. RETURN reg32;
  1855. END NewReg32;
  1856. PROCEDURE NewReg64* (index: LONGINT): Reg64;
  1857. VAR reg64: Reg64;
  1858. BEGIN
  1859. NEW (reg64, index);
  1860. RETURN reg64;
  1861. END NewReg64;
  1862. PROCEDURE NewRegCR* (index: LONGINT): RegCR;
  1863. VAR regCR: RegCR;
  1864. BEGIN
  1865. NEW (regCR, index);
  1866. RETURN regCR;
  1867. END NewRegCR;
  1868. PROCEDURE NewRegDR* (index: LONGINT): RegDR;
  1869. VAR regDR: RegDR;
  1870. BEGIN
  1871. NEW (regDR, index);
  1872. RETURN regDR;
  1873. END NewRegDR;
  1874. PROCEDURE NewSegReg* (index: LONGINT): SegReg;
  1875. VAR segReg: SegReg;
  1876. BEGIN
  1877. NEW (segReg, index);
  1878. RETURN segReg;
  1879. END NewSegReg;
  1880. PROCEDURE NewFPReg* (index: LONGINT): FPReg;
  1881. VAR fpReg: FPReg;
  1882. BEGIN
  1883. NEW (fpReg, index);
  1884. RETURN fpReg;
  1885. END NewFPReg;
  1886. PROCEDURE NewMMXReg* (index: LONGINT): MMXReg;
  1887. VAR mmxReg: MMXReg;
  1888. BEGIN
  1889. NEW (mmxReg, index);
  1890. RETURN mmxReg;
  1891. END NewMMXReg;
  1892. PROCEDURE NewXMMReg* (index: LONGINT): XMMReg;
  1893. VAR xmmReg: XMMReg;
  1894. BEGIN
  1895. NEW (xmmReg, index);
  1896. RETURN xmmReg;
  1897. END NewXMMReg;
  1898. PROCEDURE NewMem (size: Size; reg: Reg; displacement: LONGINT): Mem;
  1899. VAR mem: Mem;
  1900. BEGIN
  1901. NEW (mem, size);
  1902. mem.reg := reg;
  1903. mem.displacement := displacement;
  1904. RETURN mem;
  1905. END NewMem;
  1906. PROCEDURE NewMem8* (reg: Reg; displacement: LONGINT): Mem;
  1907. BEGIN RETURN NewMem (size8, reg, displacement);
  1908. END NewMem8;
  1909. PROCEDURE NewMem16* (reg: Reg; displacement: LONGINT): Mem;
  1910. BEGIN RETURN NewMem (size16, reg, displacement);
  1911. END NewMem16;
  1912. PROCEDURE NewMem32* (reg: Reg; displacement: LONGINT): Mem;
  1913. BEGIN RETURN NewMem (size32, reg, displacement);
  1914. END NewMem32;
  1915. PROCEDURE NewMem64* (reg: Reg; displacement: LONGINT): Mem;
  1916. BEGIN RETURN NewMem (size64, reg, displacement);
  1917. END NewMem64;
  1918. PROCEDURE NewMem128* (reg: Reg; displacement: LONGINT): Mem;
  1919. BEGIN RETURN NewMem (size128, reg, displacement);
  1920. END NewMem128;
  1921. PROCEDURE NewImm* (size: LONGINT; val: HUGEINT): Imm;
  1922. VAR imm: Imm;
  1923. BEGIN
  1924. NEW (imm, size, val);
  1925. RETURN imm;
  1926. END NewImm;
  1927. PROCEDURE NewImm8* (val: HUGEINT): Imm;
  1928. BEGIN RETURN NewImm (size8, val);
  1929. END NewImm8;
  1930. PROCEDURE NewImm16* (val: HUGEINT): Imm;
  1931. BEGIN RETURN NewImm (size16, val);
  1932. END NewImm16;
  1933. PROCEDURE NewImm32* (val: HUGEINT): Imm;
  1934. BEGIN RETURN NewImm (size32, val);
  1935. END NewImm32;
  1936. PROCEDURE NewImm64* (val: HUGEINT): Imm;
  1937. BEGIN RETURN NewImm (size64, val);
  1938. END NewImm64;
  1939. PROCEDURE NewOffset* (size: LONGINT; val: HUGEINT): Offset;
  1940. VAR offset: Offset;
  1941. BEGIN
  1942. NEW (offset, size, val);
  1943. RETURN offset;
  1944. END NewOffset;
  1945. PROCEDURE NewOffset8* (val: HUGEINT): Offset;
  1946. BEGIN RETURN NewOffset (size8, val);
  1947. END NewOffset8;
  1948. PROCEDURE NewOffset16* (val: HUGEINT): Offset;
  1949. BEGIN RETURN NewOffset (size16, val);
  1950. END NewOffset16;
  1951. PROCEDURE NewOffset32* (val: HUGEINT): Offset;
  1952. BEGIN RETURN NewOffset (size32, val);
  1953. END NewOffset32;
  1954. PROCEDURE NewOffset64* (val: HUGEINT): Offset;
  1955. BEGIN RETURN NewOffset (size64, val);
  1956. END NewOffset64;
  1957. PROCEDURE NewPntr1616* (s, o: LONGINT): Pntr1616;
  1958. VAR pntr1616: Pntr1616;
  1959. BEGIN
  1960. NEW (pntr1616, s, o);
  1961. RETURN pntr1616;
  1962. END NewPntr1616;
  1963. PROCEDURE NewPntr1632* (s, o: LONGINT): Pntr1632;
  1964. VAR pntr1632: Pntr1632;
  1965. BEGIN
  1966. NEW (pntr1632, s, o);
  1967. RETURN pntr1632;
  1968. END NewPntr1632;
  1969. PROCEDURE Install*;
  1970. BEGIN PCP.Assemble := InlineAssemble;
  1971. END Install;
  1972. PROCEDURE Cleanup;
  1973. BEGIN
  1974. CompilerInterface.Unregister("AAMD64");
  1975. END Cleanup;
  1976. BEGIN
  1977. Modules.InstallTermHandler(Cleanup);
  1978. CompilerInterface.Register("AAMD64", "AMD64 Assembler", "ASM", AssembleText);
  1979. END PCAAMD64.