assemble.pas 43 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433
  1. {
  2. Copyright (c) 1998-2004 by Peter Vreman
  3. This unit handles the assemblerfile write and assembler calls of FPC
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program; if not, write to the Free Software
  14. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  15. ****************************************************************************
  16. }
  17. {# @abstract(This unit handles the assembler file write and assembler calls of FPC)
  18. Handles the calls to the actual external assemblers, as well as the generation
  19. of object files for smart linking. Also contains the base class for writing
  20. the assembler statements to file.
  21. }
  22. unit assemble;
  23. {$i fpcdefs.inc}
  24. interface
  25. uses
  26. SysUtils,
  27. systems,globtype,globals,aasmbase,aasmtai,aasmdata,ogbase;
  28. const
  29. { maximum of aasmoutput lists there will be }
  30. maxoutputlists = 20;
  31. { buffer size for writing the .s file }
  32. AsmOutSize=32768*4;
  33. type
  34. TAssembler=class(TAbstractAssembler)
  35. public
  36. {filenames}
  37. path : string;
  38. name : string;
  39. AsmFileName, { current .s and .o file }
  40. ObjFileName,
  41. ppufilename : string;
  42. asmprefix : string;
  43. SmartAsm : boolean;
  44. SmartFilesCount,
  45. SmartHeaderCount : longint;
  46. Constructor Create(smart:boolean);virtual;
  47. Destructor Destroy;override;
  48. procedure NextSmartName(place:tcutplace);
  49. procedure MakeObject;virtual;abstract;
  50. end;
  51. {# This is the base class which should be overriden for each each
  52. assembler writer. It is used to actually assembler a file,
  53. and write the output to the assembler file.
  54. }
  55. TExternalAssembler=class(TAssembler)
  56. private
  57. procedure CreateSmartLinkPath(const s:string);
  58. protected
  59. {outfile}
  60. AsmSize,
  61. AsmStartSize,
  62. outcnt : longint;
  63. outbuf : array[0..AsmOutSize-1] of char;
  64. outfile : file;
  65. ioerror : boolean;
  66. public
  67. {# Returns the complete path and executable name of the assembler
  68. program.
  69. It first tries looking in the UTIL directory if specified,
  70. otherwise it searches in the free pascal binary directory, in
  71. the current working directory and then in the directories
  72. in the $PATH environment.}
  73. Function FindAssembler:string;
  74. {# Actually does the call to the assembler file. Returns false
  75. if the assembling of the file failed.}
  76. Function CallAssembler(const command:string; const para:TCmdStr):Boolean;
  77. Function DoAssemble:boolean;virtual;
  78. Procedure RemoveAsm;
  79. Procedure AsmFlush;
  80. Procedure AsmClear;
  81. {# Write a string to the assembler file }
  82. Procedure AsmWrite(const s:string);
  83. {# Write a string to the assembler file }
  84. Procedure AsmWritePChar(p:pchar);
  85. {# Write a string to the assembler file followed by a new line }
  86. Procedure AsmWriteLn(const s:string);
  87. {# Write a new line to the assembler file }
  88. Procedure AsmLn;
  89. procedure AsmCreate(Aplace:tcutplace);
  90. procedure AsmClose;
  91. {# This routine should be overriden for each assembler, it is used
  92. to actually write the abstract assembler stream to file.}
  93. procedure WriteTree(p:TAsmList);virtual;
  94. {# This routine should be overriden for each assembler, it is used
  95. to actually write all the different abstract assembler streams
  96. by calling for each stream type, the @var(WriteTree) method.}
  97. procedure WriteAsmList;virtual;
  98. {# Constructs the command line for calling the assembler }
  99. function MakeCmdLine: TCmdStr; virtual;
  100. public
  101. Constructor Create(smart:boolean);override;
  102. procedure MakeObject;override;
  103. end;
  104. TInternalAssembler=class(TAssembler)
  105. private
  106. FCObjOutput : TObjOutputclass;
  107. { the aasmoutput lists that need to be processed }
  108. lists : byte;
  109. list : array[1..maxoutputlists] of TAsmList;
  110. { current processing }
  111. currlistidx : byte;
  112. currlist : TAsmList;
  113. procedure WriteStab(p:pchar);
  114. function MaybeNextList(var hp:Tai):boolean;
  115. function TreePass0(hp:Tai):Tai;
  116. function TreePass1(hp:Tai):Tai;
  117. function TreePass2(hp:Tai):Tai;
  118. procedure writetree;
  119. procedure writetreesmart;
  120. protected
  121. ObjData : TObjData;
  122. ObjOutput : tObjOutput;
  123. property CObjOutput:TObjOutputclass read FCObjOutput write FCObjOutput;
  124. public
  125. constructor create(smart:boolean);override;
  126. destructor destroy;override;
  127. procedure MakeObject;override;
  128. end;
  129. TAssemblerClass = class of TAssembler;
  130. Procedure GenerateAsm(smart:boolean);
  131. Procedure OnlyAsm;
  132. procedure RegisterAssembler(const r:tasminfo;c:TAssemblerClass);
  133. procedure InitAssembler;
  134. procedure DoneAssembler;
  135. Implementation
  136. uses
  137. {$ifdef hasunix}
  138. unix,
  139. {$endif}
  140. cutils,cfileutils,
  141. {$ifdef memdebug}
  142. cclasses,
  143. {$endif memdebug}
  144. script,fmodule,verbose,
  145. {$ifdef m68k}
  146. cpuinfo,
  147. {$endif m68k}
  148. aasmcpu,
  149. owbase,owar
  150. ;
  151. var
  152. CAssembler : array[tasm] of TAssemblerClass;
  153. {*****************************************************************************
  154. TAssembler
  155. *****************************************************************************}
  156. Constructor TAssembler.Create(smart:boolean);
  157. begin
  158. { load start values }
  159. AsmFileName:=current_module.AsmFilename^;
  160. ObjFileName:=current_module.ObjFileName^;
  161. name:=Lower(current_module.modulename^);
  162. path:=current_module.outputpath^;
  163. asmprefix := current_module.asmprefix^;
  164. if not assigned(current_module.outputpath) then
  165. ppufilename := ''
  166. else
  167. ppufilename := current_module.ppufilename^;
  168. SmartAsm:=smart;
  169. SmartFilesCount:=0;
  170. SmartHeaderCount:=0;
  171. SmartLinkOFiles.Clear;
  172. end;
  173. Destructor TAssembler.Destroy;
  174. begin
  175. end;
  176. procedure TAssembler.NextSmartName(place:tcutplace);
  177. var
  178. s : string;
  179. begin
  180. inc(SmartFilesCount);
  181. if SmartFilesCount>999999 then
  182. Message(asmw_f_too_many_asm_files);
  183. case place of
  184. cut_begin :
  185. begin
  186. inc(SmartHeaderCount);
  187. s:=asmprefix+tostr(SmartHeaderCount)+'h';
  188. end;
  189. cut_normal :
  190. s:=asmprefix+tostr(SmartHeaderCount)+'s';
  191. cut_end :
  192. s:=asmprefix+tostr(SmartHeaderCount)+'t';
  193. end;
  194. AsmFileName:=Path+FixFileName(s+tostr(SmartFilesCount)+target_info.asmext);
  195. ObjFileName:=Path+FixFileName(s+tostr(SmartFilesCount)+target_info.objext);
  196. { insert in container so it can be cleared after the linking }
  197. SmartLinkOFiles.Insert(ObjFileName);
  198. end;
  199. {*****************************************************************************
  200. TExternalAssembler
  201. *****************************************************************************}
  202. Function DoPipe:boolean;
  203. begin
  204. DoPipe:=(cs_asm_pipe in current_settings.globalswitches) and
  205. (([cs_asm_leave,cs_link_on_target] * current_settings.globalswitches) = []) and
  206. ((target_asm.id in [as_gas,as_ggas,as_darwin]));
  207. end;
  208. Constructor TExternalAssembler.Create(smart:boolean);
  209. begin
  210. inherited Create(smart);
  211. if SmartAsm then
  212. begin
  213. path:=FixPath(ChangeFileExt(AsmFileName,target_info.smartext),false);
  214. CreateSmartLinkPath(path);
  215. end;
  216. Outcnt:=0;
  217. end;
  218. procedure TExternalAssembler.CreateSmartLinkPath(const s:string);
  219. procedure DeleteFilesWithExt(const AExt:string);
  220. var
  221. dir : TSearchRec;
  222. begin
  223. if findfirst(s+source_info.dirsep+'*'+AExt,faAnyFile,dir) = 0 then
  224. begin
  225. repeat
  226. DeleteFile(s+source_info.dirsep+dir.name);
  227. until findnext(dir) <> 0;
  228. end;
  229. findclose(dir);
  230. end;
  231. var
  232. dir : TSearchRec;
  233. hs : string;
  234. begin
  235. if PathExists(s,false) then
  236. begin
  237. { the path exists, now we clean only all the .o and .s files }
  238. DeleteFilesWithExt(target_info.objext);
  239. DeleteFilesWithExt(target_info.asmext);
  240. end
  241. else
  242. begin
  243. hs:=s;
  244. if hs[length(hs)] in ['/','\'] then
  245. delete(hs,length(hs),1);
  246. {$I-}
  247. mkdir(hs);
  248. {$I+}
  249. if ioresult<>0 then;
  250. end;
  251. end;
  252. const
  253. lastas : byte=255;
  254. var
  255. LastASBin : TCmdStr;
  256. Function TExternalAssembler.FindAssembler:string;
  257. var
  258. asfound : boolean;
  259. UtilExe : string;
  260. begin
  261. asfound:=false;
  262. if cs_link_on_target in current_settings.globalswitches then
  263. begin
  264. { If linking on target, don't add any path PM }
  265. FindAssembler:=utilsprefix+ChangeFileExt(target_asm.asmbin,target_info.exeext);
  266. exit;
  267. end
  268. else
  269. UtilExe:=utilsprefix+ChangeFileExt(target_asm.asmbin,source_info.exeext);
  270. if lastas<>ord(target_asm.id) then
  271. begin
  272. lastas:=ord(target_asm.id);
  273. { is an assembler passed ? }
  274. if utilsdirectory<>'' then
  275. asfound:=FindFile(UtilExe,utilsdirectory,false,LastASBin);
  276. if not AsFound then
  277. asfound:=FindExe(UtilExe,false,LastASBin);
  278. if (not asfound) and not(cs_asm_extern in current_settings.globalswitches) then
  279. begin
  280. Message1(exec_e_assembler_not_found,LastASBin);
  281. current_settings.globalswitches:=current_settings.globalswitches+[cs_asm_extern];
  282. end;
  283. if asfound then
  284. Message1(exec_t_using_assembler,LastASBin);
  285. end;
  286. FindAssembler:=LastASBin;
  287. end;
  288. Function TExternalAssembler.CallAssembler(const command:string; const para:TCmdStr):Boolean;
  289. var
  290. DosExitCode : Integer;
  291. begin
  292. result:=true;
  293. if (cs_asm_extern in current_settings.globalswitches) then
  294. begin
  295. AsmRes.AddAsmCommand(command,para,name);
  296. exit;
  297. end;
  298. try
  299. FlushOutput;
  300. DosExitCode := ExecuteProcess(command,para);
  301. if DosExitCode <>0
  302. then begin
  303. Message1(exec_e_error_while_assembling,tostr(dosexitcode));
  304. result:=false;
  305. end;
  306. except on E:EOSError do
  307. begin
  308. Message1(exec_e_cant_call_assembler,tostr(E.ErrorCode));
  309. current_settings.globalswitches:=current_settings.globalswitches+[cs_asm_extern];
  310. result:=false;
  311. end;
  312. end;
  313. end;
  314. procedure TExternalAssembler.RemoveAsm;
  315. var
  316. g : file;
  317. begin
  318. if cs_asm_leave in current_settings.globalswitches then
  319. exit;
  320. if cs_asm_extern in current_settings.globalswitches then
  321. AsmRes.AddDeleteCommand(AsmFileName)
  322. else
  323. begin
  324. assign(g,AsmFileName);
  325. {$I-}
  326. erase(g);
  327. {$I+}
  328. if ioresult<>0 then;
  329. end;
  330. end;
  331. Function TExternalAssembler.DoAssemble:boolean;
  332. begin
  333. DoAssemble:=true;
  334. if DoPipe then
  335. exit;
  336. if not(cs_asm_extern in current_settings.globalswitches) then
  337. begin
  338. if SmartAsm then
  339. begin
  340. if (SmartFilesCount<=1) then
  341. Message1(exec_i_assembling_smart,name);
  342. end
  343. else
  344. Message1(exec_i_assembling,name);
  345. end;
  346. if CallAssembler(FindAssembler,MakeCmdLine) then
  347. RemoveAsm
  348. else
  349. begin
  350. DoAssemble:=false;
  351. GenerateError;
  352. end;
  353. end;
  354. Procedure TExternalAssembler.AsmFlush;
  355. begin
  356. if outcnt>0 then
  357. begin
  358. { suppress i/o error }
  359. {$i-}
  360. BlockWrite(outfile,outbuf,outcnt);
  361. {$i+}
  362. ioerror:=ioerror or (ioresult<>0);
  363. outcnt:=0;
  364. end;
  365. end;
  366. Procedure TExternalAssembler.AsmClear;
  367. begin
  368. outcnt:=0;
  369. end;
  370. Procedure TExternalAssembler.AsmWrite(const s:string);
  371. begin
  372. if OutCnt+length(s)>=AsmOutSize then
  373. AsmFlush;
  374. Move(s[1],OutBuf[OutCnt],length(s));
  375. inc(OutCnt,length(s));
  376. inc(AsmSize,length(s));
  377. end;
  378. Procedure TExternalAssembler.AsmWriteLn(const s:string);
  379. begin
  380. AsmWrite(s);
  381. AsmLn;
  382. end;
  383. Procedure TExternalAssembler.AsmWritePChar(p:pchar);
  384. var
  385. i,j : longint;
  386. begin
  387. i:=StrLen(p);
  388. j:=i;
  389. while j>0 do
  390. begin
  391. i:=min(j,AsmOutSize);
  392. if OutCnt+i>=AsmOutSize then
  393. AsmFlush;
  394. Move(p[0],OutBuf[OutCnt],i);
  395. inc(OutCnt,i);
  396. inc(AsmSize,i);
  397. dec(j,i);
  398. p:=pchar(@p[i]);
  399. end;
  400. end;
  401. Procedure TExternalAssembler.AsmLn;
  402. begin
  403. if OutCnt>=AsmOutSize-2 then
  404. AsmFlush;
  405. if (cs_link_on_target in current_settings.globalswitches) then
  406. begin
  407. OutBuf[OutCnt]:=target_info.newline[1];
  408. inc(OutCnt);
  409. inc(AsmSize);
  410. if length(target_info.newline)>1 then
  411. begin
  412. OutBuf[OutCnt]:=target_info.newline[2];
  413. inc(OutCnt);
  414. inc(AsmSize);
  415. end;
  416. end
  417. else
  418. begin
  419. OutBuf[OutCnt]:=source_info.newline[1];
  420. inc(OutCnt);
  421. inc(AsmSize);
  422. if length(source_info.newline)>1 then
  423. begin
  424. OutBuf[OutCnt]:=source_info.newline[2];
  425. inc(OutCnt);
  426. inc(AsmSize);
  427. end;
  428. end;
  429. end;
  430. function TExternalAssembler.MakeCmdLine: TCmdStr;
  431. begin
  432. result:=target_asm.asmcmd;
  433. {$ifdef m68k}
  434. if current_settings.cputype = cpu_MC68020 then
  435. result:='-m68020 '+result
  436. else
  437. result:='-m68000 '+result;
  438. {$endif}
  439. if (cs_link_on_target in current_settings.globalswitches) then
  440. begin
  441. Replace(result,'$ASM',maybequoted(ScriptFixFileName(AsmFileName)));
  442. Replace(result,'$OBJ',maybequoted(ScriptFixFileName(ObjFileName)));
  443. end
  444. else
  445. begin
  446. {$ifdef hasunix}
  447. if DoPipe then
  448. Replace(result,'$ASM','')
  449. else
  450. {$endif}
  451. Replace(result,'$ASM',maybequoted(AsmFileName));
  452. Replace(result,'$OBJ',maybequoted(ObjFileName));
  453. end;
  454. end;
  455. procedure TExternalAssembler.AsmCreate(Aplace:tcutplace);
  456. begin
  457. if SmartAsm then
  458. NextSmartName(Aplace);
  459. {$ifdef hasunix}
  460. if DoPipe then
  461. begin
  462. if SmartAsm then
  463. begin
  464. if (SmartFilesCount<=1) then
  465. Message1(exec_i_assembling_smart,name);
  466. end
  467. else
  468. Message1(exec_i_assembling_pipe,AsmFileName);
  469. POpen(outfile,FindAssembler+' '+MakeCmdLine,'W');
  470. end
  471. else
  472. {$endif}
  473. begin
  474. Assign(outfile,AsmFileName);
  475. {$I-}
  476. Rewrite(outfile,1);
  477. {$I+}
  478. if ioresult<>0 then
  479. begin
  480. ioerror:=true;
  481. Message1(exec_d_cant_create_asmfile,AsmFileName);
  482. end;
  483. end;
  484. outcnt:=0;
  485. AsmSize:=0;
  486. AsmStartSize:=0;
  487. end;
  488. procedure TExternalAssembler.AsmClose;
  489. var
  490. f : file;
  491. FileAge : longint;
  492. begin
  493. AsmFlush;
  494. {$ifdef hasunix}
  495. if DoPipe then
  496. begin
  497. if PClose(outfile) <> 0 then
  498. GenerateError;
  499. end
  500. else
  501. {$endif}
  502. begin
  503. {Touch Assembler time to ppu time is there is a ppufilename}
  504. if ppufilename<>'' then
  505. begin
  506. Assign(f,ppufilename);
  507. {$I-}
  508. reset(f,1);
  509. {$I+}
  510. if ioresult=0 then
  511. begin
  512. FileAge := FileGetDate(GetFileHandle(f));
  513. close(f);
  514. reset(outfile,1);
  515. FileSetDate(GetFileHandle(outFile),FileAge);
  516. end;
  517. end;
  518. close(outfile);
  519. end;
  520. end;
  521. procedure TExternalAssembler.WriteTree(p:TAsmList);
  522. begin
  523. end;
  524. procedure TExternalAssembler.WriteAsmList;
  525. begin
  526. end;
  527. procedure TExternalAssembler.MakeObject;
  528. begin
  529. AsmCreate(cut_normal);
  530. WriteAsmList;
  531. AsmClose;
  532. if not(ioerror) then
  533. DoAssemble;
  534. end;
  535. {*****************************************************************************
  536. TInternalAssembler
  537. *****************************************************************************}
  538. constructor TInternalAssembler.create(smart:boolean);
  539. begin
  540. inherited create(smart);
  541. ObjOutput:=nil;
  542. ObjData:=nil;
  543. SmartAsm:=smart;
  544. end;
  545. destructor TInternalAssembler.destroy;
  546. begin
  547. if assigned(ObjData) then
  548. ObjData.free;
  549. if assigned(ObjOutput) then
  550. ObjOutput.free;
  551. end;
  552. procedure TInternalAssembler.WriteStab(p:pchar);
  553. function consumecomma(var p:pchar):boolean;
  554. begin
  555. while (p^=' ') do
  556. inc(p);
  557. result:=(p^=',');
  558. inc(p);
  559. end;
  560. function consumenumber(var p:pchar;out value:longint):boolean;
  561. var
  562. hs : string;
  563. len,
  564. code : integer;
  565. begin
  566. value:=0;
  567. while (p^=' ') do
  568. inc(p);
  569. len:=0;
  570. while (p^ in ['0'..'9']) do
  571. begin
  572. inc(len);
  573. hs[len]:=p^;
  574. inc(p);
  575. end;
  576. if len>0 then
  577. begin
  578. hs[0]:=chr(len);
  579. val(hs,value,code);
  580. end
  581. else
  582. code:=-1;
  583. result:=(code=0);
  584. end;
  585. function consumeoffset(var p:pchar;out relocsym:tobjsymbol;out value:longint):boolean;
  586. var
  587. hs : string;
  588. len,
  589. code : integer;
  590. pstart : pchar;
  591. sym : tobjsymbol;
  592. exprvalue : longint;
  593. gotmin,
  594. dosub : boolean;
  595. begin
  596. result:=false;
  597. value:=0;
  598. relocsym:=nil;
  599. gotmin:=false;
  600. repeat
  601. dosub:=false;
  602. exprvalue:=0;
  603. if gotmin then
  604. begin
  605. dosub:=true;
  606. gotmin:=false;
  607. end;
  608. while (p^=' ') do
  609. inc(p);
  610. case p^ of
  611. #0 :
  612. break;
  613. ' ' :
  614. inc(p);
  615. '0'..'9' :
  616. begin
  617. len:=0;
  618. while (p^ in ['0'..'9']) do
  619. begin
  620. inc(len);
  621. hs[len]:=p^;
  622. inc(p);
  623. end;
  624. hs[0]:=chr(len);
  625. val(hs,exprvalue,code);
  626. end;
  627. '.','_',
  628. 'A'..'Z',
  629. 'a'..'z' :
  630. begin
  631. pstart:=p;
  632. while not(p^ in [#0,' ','-','+']) do
  633. inc(p);
  634. len:=p-pstart;
  635. if len>255 then
  636. internalerror(200509187);
  637. move(pstart^,hs[1],len);
  638. hs[0]:=chr(len);
  639. sym:=objdata.symbolref(hs);
  640. { Second symbol? }
  641. if assigned(relocsym) then
  642. begin
  643. if (relocsym.objsection<>sym.objsection) then
  644. internalerror(2005091810);
  645. relocsym:=nil;
  646. end
  647. else
  648. relocsym:=sym;
  649. exprvalue:=sym.address;
  650. end;
  651. '+' :
  652. begin
  653. { nothing, by default addition is done }
  654. inc(p);
  655. end;
  656. '-' :
  657. begin
  658. gotmin:=true;
  659. inc(p);
  660. end;
  661. else
  662. internalerror(200509189);
  663. end;
  664. if dosub then
  665. dec(value,exprvalue)
  666. else
  667. inc(value,exprvalue);
  668. until false;
  669. result:=true;
  670. end;
  671. const
  672. N_Function = $24; { function or const }
  673. var
  674. stabstrlen,
  675. ofs,
  676. nline,
  677. nidx,
  678. nother,
  679. i : longint;
  680. stab : TObjStabEntry;
  681. relocsym : TObjSymbol;
  682. pstr,
  683. pcurr,
  684. pendquote : pchar;
  685. oldsec : TObjSection;
  686. reltype : TObjRelocationType;
  687. begin
  688. pcurr:=nil;
  689. pstr:=nil;
  690. pendquote:=nil;
  691. { Parse string part }
  692. if (p[0]='"') then
  693. begin
  694. pstr:=@p[1];
  695. { Ignore \" inside the string }
  696. i:=1;
  697. while not((p[i]='"') and (p[i-1]<>'\')) and
  698. (p[i]<>#0) do
  699. inc(i);
  700. pendquote:=@p[i];
  701. pendquote^:=#0;
  702. pcurr:=@p[i+1];
  703. if not consumecomma(pcurr) then
  704. internalerror(200509181);
  705. end
  706. else
  707. pcurr:=p;
  708. { When in pass 1 then only alloc and leave }
  709. if ObjData.currpass=1 then
  710. begin
  711. ObjData.StabsSec.Alloc(sizeof(TObjStabEntry));
  712. if assigned(pstr) and (pstr[0]<>#0) then
  713. ObjData.StabStrSec.Alloc(strlen(pstr)+1);
  714. end
  715. else
  716. begin
  717. { Stabs format: nidx,nother,nline[,offset] }
  718. if not consumenumber(pcurr,nidx) then
  719. internalerror(200509182);
  720. if not consumecomma(pcurr) then
  721. internalerror(200509183);
  722. if not consumenumber(pcurr,nother) then
  723. internalerror(200509184);
  724. if not consumecomma(pcurr) then
  725. internalerror(200509185);
  726. if not consumenumber(pcurr,nline) then
  727. internalerror(200509186);
  728. if consumecomma(pcurr) then
  729. consumeoffset(pcurr,relocsym,ofs)
  730. else
  731. begin
  732. ofs:=0;
  733. relocsym:=nil;
  734. end;
  735. if assigned(relocsym) and
  736. (relocsym.bind<>AB_LOCAL) then
  737. ofs:=0;
  738. { Generate stab entry }
  739. if assigned(pstr) and (pstr[0]<>#0) then
  740. begin
  741. stabstrlen:=strlen(pstr);
  742. {$ifdef optimizestabs}
  743. StabStrEntry:=nil;
  744. if (nidx=N_SourceFile) or (nidx=N_IncludeFile) then
  745. begin
  746. hs:=strpas(pstr);
  747. StabstrEntry:=StabStrDict.Find(hs);
  748. if not assigned(StabstrEntry) then
  749. begin
  750. StabstrEntry:=TStabStrEntry.Create(hs);
  751. StabstrEntry:=StabStrSec.Size;
  752. StabStrDict.Insert(StabstrEntry);
  753. { generate new stab }
  754. StabstrEntry:=nil;
  755. end;
  756. end;
  757. if assigned(StabstrEntry) then
  758. stab.strpos:=StabstrEntry.strpos
  759. else
  760. {$endif optimizestabs}
  761. begin
  762. stab.strpos:=ObjData.StabStrSec.Size;
  763. ObjData.StabStrSec.write(pstr^,stabstrlen+1);
  764. end;
  765. end
  766. else
  767. stab.strpos:=0;
  768. stab.ntype:=byte(nidx);
  769. stab.ndesc:=word(nline);
  770. stab.nother:=byte(nother);
  771. stab.nvalue:=ofs;
  772. { Write the stab first without the value field. Then
  773. write a the value field with relocation }
  774. oldsec:=ObjData.CurrObjSec;
  775. ObjData.SetSection(ObjData.StabsSec);
  776. ObjData.Writebytes(stab,sizeof(TObjStabEntry)-4);
  777. if assigned(relocsym) and
  778. (target_info.system in system_windows+system_wince) and
  779. (DLLSource and RelocSection) then
  780. reltype:=RELOC_RVA
  781. else
  782. reltype:=RELOC_ABSOLUTE;
  783. ObjData.Writereloc(stab.nvalue,4,relocsym,reltype);
  784. ObjData.setsection(oldsec);
  785. end;
  786. if assigned(pendquote) then
  787. pendquote^:='"';
  788. end;
  789. function TInternalAssembler.MaybeNextList(var hp:Tai):boolean;
  790. begin
  791. { maybe end of list }
  792. while not assigned(hp) do
  793. begin
  794. if currlistidx<lists then
  795. begin
  796. inc(currlistidx);
  797. currlist:=list[currlistidx];
  798. hp:=Tai(currList.first);
  799. end
  800. else
  801. begin
  802. MaybeNextList:=false;
  803. exit;
  804. end;
  805. end;
  806. MaybeNextList:=true;
  807. end;
  808. function TInternalAssembler.TreePass0(hp:Tai):Tai;
  809. begin
  810. while assigned(hp) do
  811. begin
  812. case hp.typ of
  813. ait_align :
  814. begin
  815. { always use the maximum fillsize in this pass to avoid possible
  816. short jumps to become out of range }
  817. Tai_align_abstract(hp).fillsize:=Tai_align_abstract(hp).aligntype;
  818. ObjData.alloc(Tai_align_abstract(hp).fillsize);
  819. end;
  820. ait_datablock :
  821. begin
  822. ObjData.allocalign(used_align(size_2_align(Tai_datablock(hp).size),0,ObjData.CurrObjSec.secalign));
  823. ObjData.SymbolDefine(Tai_datablock(hp).sym);
  824. ObjData.alloc(Tai_datablock(hp).size);
  825. end;
  826. ait_real_80bit :
  827. ObjData.alloc(10);
  828. ait_real_64bit :
  829. ObjData.alloc(8);
  830. ait_real_32bit :
  831. ObjData.alloc(4);
  832. ait_comp_64bit :
  833. ObjData.alloc(8);
  834. ait_const:
  835. ObjData.alloc(tai_const(hp).size);
  836. ait_section:
  837. begin
  838. ObjData.CreateSection(Tai_section(hp).sectype,Tai_section(hp).name^,Tai_section(hp).secorder);
  839. Tai_section(hp).sec:=ObjData.CurrObjSec;
  840. end;
  841. ait_symbol :
  842. ObjData.SymbolDefine(Tai_symbol(hp).sym);
  843. ait_label :
  844. ObjData.SymbolDefine(Tai_label(hp).labsym);
  845. ait_string :
  846. ObjData.alloc(Tai_string(hp).len);
  847. ait_instruction :
  848. begin
  849. { reset instructions which could change in pass 2 }
  850. Taicpu(hp).resetpass2;
  851. ObjData.alloc(Taicpu(hp).Pass1(ObjData));
  852. end;
  853. ait_cutobject :
  854. if SmartAsm then
  855. break;
  856. end;
  857. hp:=Tai(hp.next);
  858. end;
  859. TreePass0:=hp;
  860. end;
  861. function TInternalAssembler.TreePass1(hp:Tai):Tai;
  862. var
  863. InlineLevel : longint;
  864. objsym : TObjSymbol;
  865. begin
  866. inlinelevel:=0;
  867. while assigned(hp) do
  868. begin
  869. case hp.typ of
  870. ait_align :
  871. begin
  872. { here we must determine the fillsize which is used in pass2 }
  873. Tai_align_abstract(hp).fillsize:=align(ObjData.CurrObjSec.Size,Tai_align_abstract(hp).aligntype)-
  874. ObjData.CurrObjSec.Size;
  875. ObjData.alloc(Tai_align_abstract(hp).fillsize);
  876. end;
  877. ait_datablock :
  878. begin
  879. if (oso_data in ObjData.CurrObjSec.secoptions) then
  880. Message(asmw_e_alloc_data_only_in_bss);
  881. ObjData.allocalign(used_align(size_2_align(Tai_datablock(hp).size),0,ObjData.CurrObjSec.secalign));
  882. objsym:=ObjData.SymbolDefine(Tai_datablock(hp).sym);
  883. objsym.size:=Tai_datablock(hp).size;
  884. ObjData.alloc(Tai_datablock(hp).size);
  885. end;
  886. ait_real_80bit :
  887. ObjData.alloc(10);
  888. ait_real_64bit :
  889. ObjData.alloc(8);
  890. ait_real_32bit :
  891. ObjData.alloc(4);
  892. ait_comp_64bit :
  893. ObjData.alloc(8);
  894. ait_const:
  895. begin
  896. ObjData.alloc(tai_const(hp).size);
  897. if assigned(Tai_const(hp).sym) then
  898. ObjData.SymbolRef(Tai_const(hp).sym);
  899. if assigned(Tai_const(hp).endsym) then
  900. ObjData.SymbolRef(Tai_const(hp).endsym);
  901. end;
  902. ait_section:
  903. begin
  904. { use cached value }
  905. ObjData.setsection(Tai_section(hp).sec);
  906. end;
  907. ait_stab :
  908. begin
  909. if assigned(Tai_stab(hp).str) then
  910. WriteStab(Tai_stab(hp).str);
  911. end;
  912. ait_symbol :
  913. ObjData.SymbolDefine(Tai_symbol(hp).sym);
  914. ait_symbol_end :
  915. begin
  916. objsym:=ObjData.SymbolRef(Tai_symbol_end(hp).sym);
  917. objsym.size:=ObjData.CurrObjSec.Size-objsym.offset;
  918. end;
  919. ait_label :
  920. ObjData.SymbolDefine(Tai_label(hp).labsym);
  921. ait_string :
  922. ObjData.alloc(Tai_string(hp).len);
  923. ait_instruction :
  924. ObjData.alloc(Taicpu(hp).Pass1(ObjData));
  925. ait_cutobject :
  926. if SmartAsm then
  927. break;
  928. ait_marker :
  929. if tai_marker(hp).kind=mark_InlineStart then
  930. inc(InlineLevel)
  931. else if tai_marker(hp).kind=mark_InlineEnd then
  932. dec(InlineLevel);
  933. end;
  934. hp:=Tai(hp.next);
  935. end;
  936. TreePass1:=hp;
  937. end;
  938. function TInternalAssembler.TreePass2(hp:Tai):Tai;
  939. var
  940. fillbuffer : tfillbuffer;
  941. InlineLevel,
  942. v : int64;
  943. {$ifdef x86}
  944. co : comp;
  945. {$endif x86}
  946. objsym,
  947. objsymend : TObjSymbol;
  948. leblen : byte;
  949. lebbuf : array[0..63] of byte;
  950. begin
  951. inlinelevel:=0;
  952. { main loop }
  953. while assigned(hp) do
  954. begin
  955. case hp.typ of
  956. ait_align :
  957. begin
  958. if (oso_data in ObjData.CurrObjSec.secoptions) then
  959. ObjData.writebytes(Tai_align_abstract(hp).calculatefillbuf(fillbuffer)^,Tai_align_abstract(hp).fillsize)
  960. else
  961. ObjData.alloc(Tai_align_abstract(hp).fillsize);
  962. end;
  963. ait_section :
  964. begin
  965. { use cached value }
  966. ObjData.setsection(Tai_section(hp).sec);
  967. end;
  968. ait_symbol :
  969. begin
  970. ObjOutput.exportsymbol(ObjData.SymbolRef(Tai_symbol(hp).sym));
  971. end;
  972. ait_datablock :
  973. begin
  974. ObjData.allocalign(used_align(size_2_align(Tai_datablock(hp).size),0,ObjData.CurrObjSec.secalign));
  975. ObjOutput.exportsymbol(ObjData.SymbolRef(Tai_datablock(hp).sym));
  976. ObjData.alloc(Tai_datablock(hp).size);
  977. end;
  978. ait_real_80bit :
  979. ObjData.writebytes(Tai_real_80bit(hp).value,10);
  980. ait_real_64bit :
  981. ObjData.writebytes(Tai_real_64bit(hp).value,8);
  982. ait_real_32bit :
  983. ObjData.writebytes(Tai_real_32bit(hp).value,4);
  984. ait_comp_64bit :
  985. begin
  986. {$ifdef x86}
  987. co:=comp(Tai_comp_64bit(hp).value);
  988. ObjData.writebytes(co,8);
  989. {$endif x86}
  990. end;
  991. ait_string :
  992. ObjData.writebytes(Tai_string(hp).str^,Tai_string(hp).len);
  993. ait_const :
  994. begin
  995. case tai_const(hp).consttype of
  996. aitconst_64bit,
  997. aitconst_32bit,
  998. aitconst_16bit,
  999. aitconst_8bit :
  1000. begin
  1001. if assigned(tai_const(hp).sym) then
  1002. begin
  1003. objsym:=Objdata.SymbolRef(tai_const(hp).sym);
  1004. if assigned(tai_const(hp).endsym) then
  1005. begin
  1006. objsymend:=Objdata.SymbolRef(tai_const(hp).endsym);
  1007. if objsymend.objsection<>objsym.objsection then
  1008. internalerror(200404124);
  1009. v:=objsymend.address-objsym.address+Tai_const(hp).value;
  1010. ObjData.writebytes(v,tai_const(hp).size);
  1011. end
  1012. else
  1013. ObjData.writereloc(Tai_const(hp).value,Tai_const(hp).size,objsym,RELOC_ABSOLUTE);
  1014. end
  1015. else
  1016. ObjData.writebytes(Tai_const(hp).value,tai_const(hp).size);
  1017. end;
  1018. aitconst_rva_symbol :
  1019. { PE32+? }
  1020. if target_info.system=system_x86_64_win64 then
  1021. ObjData.writereloc(Tai_const(hp).value,sizeof(longint),Objdata.SymbolRef(tai_const(hp).sym),RELOC_RVA)
  1022. else
  1023. ObjData.writereloc(Tai_const(hp).value,sizeof(aint),Objdata.SymbolRef(tai_const(hp).sym),RELOC_RVA);
  1024. aitconst_uleb128bit :
  1025. begin
  1026. leblen:=EncodeUleb128(Tai_const(hp).value,lebbuf);
  1027. ObjData.writebytes(lebbuf,leblen);
  1028. end;
  1029. aitconst_sleb128bit :
  1030. begin
  1031. leblen:=EncodeSleb128(Tai_const(hp).value,lebbuf);
  1032. ObjData.writebytes(lebbuf,leblen);
  1033. end;
  1034. else
  1035. internalerror(200603254);
  1036. end;
  1037. end;
  1038. ait_label :
  1039. begin
  1040. { exporting shouldn't be necessary as labels are local,
  1041. but it's better to be on the safe side (PFV) }
  1042. ObjOutput.exportsymbol(ObjData.SymbolRef(Tai_label(hp).labsym));
  1043. end;
  1044. ait_instruction :
  1045. Taicpu(hp).Pass2(ObjData);
  1046. ait_stab :
  1047. WriteStab(Tai_stab(hp).str);
  1048. ait_function_name,
  1049. ait_force_line : ;
  1050. ait_cutobject :
  1051. if SmartAsm then
  1052. break;
  1053. ait_marker :
  1054. if tai_marker(hp).kind=mark_InlineStart then
  1055. inc(InlineLevel)
  1056. else if tai_marker(hp).kind=mark_InlineEnd then
  1057. dec(InlineLevel);
  1058. end;
  1059. hp:=Tai(hp.next);
  1060. end;
  1061. TreePass2:=hp;
  1062. end;
  1063. procedure TInternalAssembler.writetree;
  1064. label
  1065. doexit;
  1066. var
  1067. hp : Tai;
  1068. ObjWriter : TObjectWriter;
  1069. begin
  1070. ObjWriter:=TObjectwriter.create;
  1071. ObjOutput:=CObjOutput.Create(ObjWriter);
  1072. ObjData:=ObjOutput.newObjData(ObjFileName);
  1073. { Pass 0 }
  1074. ObjData.currpass:=0;
  1075. ObjData.createsection(sec_code);
  1076. ObjData.beforealloc;
  1077. { start with list 1 }
  1078. currlistidx:=1;
  1079. currlist:=list[currlistidx];
  1080. hp:=Tai(currList.first);
  1081. while assigned(hp) do
  1082. begin
  1083. hp:=TreePass0(hp);
  1084. MaybeNextList(hp);
  1085. end;
  1086. ObjData.afteralloc;
  1087. { leave if errors have occured }
  1088. if errorcount>0 then
  1089. goto doexit;
  1090. { Pass 1 }
  1091. ObjData.currpass:=1;
  1092. ObjData.resetsections;
  1093. ObjData.beforealloc;
  1094. ObjData.createsection(sec_code);
  1095. { start with list 1 }
  1096. currlistidx:=1;
  1097. currlist:=list[currlistidx];
  1098. hp:=Tai(currList.first);
  1099. while assigned(hp) do
  1100. begin
  1101. hp:=TreePass1(hp);
  1102. MaybeNextList(hp);
  1103. end;
  1104. ObjData.createsection(sec_code);
  1105. ObjData.afteralloc;
  1106. { leave if errors have occured }
  1107. if errorcount>0 then
  1108. goto doexit;
  1109. { Pass 2 }
  1110. ObjData.currpass:=2;
  1111. ObjData.resetsections;
  1112. ObjData.beforewrite;
  1113. ObjData.createsection(sec_code);
  1114. { start with list 1 }
  1115. currlistidx:=1;
  1116. currlist:=list[currlistidx];
  1117. hp:=Tai(currList.first);
  1118. while assigned(hp) do
  1119. begin
  1120. hp:=TreePass2(hp);
  1121. MaybeNextList(hp);
  1122. end;
  1123. ObjData.createsection(sec_code);
  1124. ObjData.afterwrite;
  1125. { don't write the .o file if errors have occured }
  1126. if errorcount=0 then
  1127. begin
  1128. { write objectfile }
  1129. ObjOutput.startobjectfile(ObjFileName);
  1130. ObjOutput.writeobjectfile(ObjData);
  1131. end;
  1132. doexit:
  1133. { Cleanup }
  1134. ObjData.free;
  1135. ObjData:=nil;
  1136. ObjWriter.free;
  1137. end;
  1138. procedure TInternalAssembler.writetreesmart;
  1139. var
  1140. hp : Tai;
  1141. startsectype : TAsmSectiontype;
  1142. place: tcutplace;
  1143. ObjWriter : TObjectWriter;
  1144. begin
  1145. if not(cs_asm_leave in current_settings.globalswitches) then
  1146. ObjWriter:=TARObjectWriter.create(current_module.staticlibfilename^)
  1147. else
  1148. ObjWriter:=TObjectwriter.create;
  1149. NextSmartName(cut_normal);
  1150. ObjOutput:=CObjOutput.Create(ObjWriter);
  1151. startsectype:=sec_code;
  1152. { start with list 1 }
  1153. currlistidx:=1;
  1154. currlist:=list[currlistidx];
  1155. hp:=Tai(currList.first);
  1156. while assigned(hp) do
  1157. begin
  1158. ObjData:=ObjOutput.newObjData(ObjFileName);
  1159. { Pass 0 }
  1160. ObjData.currpass:=0;
  1161. ObjData.resetsections;
  1162. ObjData.beforealloc;
  1163. ObjData.createsection(startsectype);
  1164. TreePass0(hp);
  1165. ObjData.afteralloc;
  1166. { leave if errors have occured }
  1167. if errorcount>0 then
  1168. break;
  1169. { Pass 1 }
  1170. ObjData.currpass:=1;
  1171. ObjData.resetsections;
  1172. ObjData.beforealloc;
  1173. ObjData.createsection(startsectype);
  1174. TreePass1(hp);
  1175. ObjData.afteralloc;
  1176. { leave if errors have occured }
  1177. if errorcount>0 then
  1178. break;
  1179. { Pass 2 }
  1180. ObjData.currpass:=2;
  1181. ObjOutput.startobjectfile(ObjFileName);
  1182. ObjData.resetsections;
  1183. ObjData.beforewrite;
  1184. ObjData.createsection(startsectype);
  1185. hp:=TreePass2(hp);
  1186. ObjData.afterwrite;
  1187. { leave if errors have occured }
  1188. if errorcount>0 then
  1189. break;
  1190. { write the current objectfile }
  1191. ObjOutput.writeobjectfile(ObjData);
  1192. ObjData.free;
  1193. ObjData:=nil;
  1194. { end of lists? }
  1195. if not MaybeNextList(hp) then
  1196. break;
  1197. { we will start a new objectfile so reset everything }
  1198. { The place can still change in the next while loop, so don't init }
  1199. { the writer yet (JM) }
  1200. if (hp.typ=ait_cutobject) then
  1201. place := Tai_cutobject(hp).place
  1202. else
  1203. place := cut_normal;
  1204. { avoid empty files }
  1205. startsectype:=sec_code;
  1206. while assigned(hp) and
  1207. (Tai(hp).typ in [ait_marker,ait_comment,ait_section,ait_cutobject]) do
  1208. begin
  1209. if Tai(hp).typ=ait_section then
  1210. startsectype:=Tai_section(hp).sectype;
  1211. if (Tai(hp).typ=ait_cutobject) then
  1212. place:=Tai_cutobject(hp).place;
  1213. hp:=Tai(hp.next);
  1214. end;
  1215. if not MaybeNextList(hp) then
  1216. break;
  1217. { start next objectfile }
  1218. NextSmartName(place);
  1219. end;
  1220. ObjData.free;
  1221. ObjData:=nil;
  1222. ObjWriter.free;
  1223. end;
  1224. procedure TInternalAssembler.MakeObject;
  1225. var to_do:set of TasmlistType;
  1226. i:TasmlistType;
  1227. procedure addlist(p:TAsmList);
  1228. begin
  1229. inc(lists);
  1230. list[lists]:=p;
  1231. end;
  1232. begin
  1233. to_do:=[low(Tasmlisttype)..high(Tasmlisttype)];
  1234. if usedeffileforexports then
  1235. exclude(to_do,al_exports);
  1236. if not(tf_section_threadvars in target_info.flags) then
  1237. exclude(to_do,al_threadvars);
  1238. for i:=low(TasmlistType) to high(TasmlistType) do
  1239. if (i in to_do) and (current_asmdata.asmlists[i]<>nil) then
  1240. addlist(current_asmdata.asmlists[i]);
  1241. if SmartAsm then
  1242. writetreesmart
  1243. else
  1244. writetree;
  1245. end;
  1246. {*****************************************************************************
  1247. Generate Assembler Files Main Procedure
  1248. *****************************************************************************}
  1249. Procedure GenerateAsm(smart:boolean);
  1250. var
  1251. a : TAssembler;
  1252. begin
  1253. if not assigned(CAssembler[target_asm.id]) then
  1254. Message(asmw_f_assembler_output_not_supported);
  1255. a:=CAssembler[target_asm.id].Create(smart);
  1256. a.MakeObject;
  1257. a.Free;
  1258. end;
  1259. Procedure OnlyAsm;
  1260. var
  1261. a : TExternalAssembler;
  1262. begin
  1263. a:=TExternalAssembler.Create(false);
  1264. a.DoAssemble;
  1265. a.Free;
  1266. end;
  1267. {*****************************************************************************
  1268. Init/Done
  1269. *****************************************************************************}
  1270. procedure RegisterAssembler(const r:tasminfo;c:TAssemblerClass);
  1271. var
  1272. t : tasm;
  1273. begin
  1274. t:=r.id;
  1275. if assigned(asminfos[t]) then
  1276. writeln('Warning: Assembler is already registered!')
  1277. else
  1278. Getmem(asminfos[t],sizeof(tasminfo));
  1279. asminfos[t]^:=r;
  1280. CAssembler[t]:=c;
  1281. end;
  1282. procedure InitAssembler;
  1283. begin
  1284. end;
  1285. procedure DoneAssembler;
  1286. begin
  1287. end;
  1288. end.