assemble.pas 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667
  1. {
  2. $Id$
  3. Copyright (c) 1998-2000 by Peter Vreman
  4. This unit handles the assemblerfile write and assembler calls of FPC
  5. This program is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 2 of the License, or
  8. (at your option) any later version.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with this program; if not, write to the Free Software
  15. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  16. ****************************************************************************
  17. }
  18. unit assemble;
  19. {$i defines.inc}
  20. interface
  21. uses
  22. {$ifdef Delphi}
  23. sysutils,
  24. dmisc,
  25. {$else Delphi}
  26. strings,
  27. dos,
  28. {$endif Delphi}
  29. cobjects,globtype,globals,aasm;
  30. const
  31. AsmOutSize=32768;
  32. type
  33. TAssembler=class
  34. public
  35. {filenames}
  36. path : pathstr;
  37. name : namestr;
  38. asmfile, { current .s and .o file }
  39. objfile : string;
  40. SmartAsm : boolean;
  41. SmartFilesCount,
  42. SmartHeaderCount : longint;
  43. Constructor Create(smart:boolean);
  44. Destructor Destroy;override;
  45. procedure WriteTree(p:TAAsmoutput);virtual;
  46. procedure WriteAsmList;virtual;
  47. procedure NextSmartName(place:tcutplace);
  48. end;
  49. TExternalAssembler=class(TAssembler)
  50. private
  51. procedure CreateSmartLinkPath(const s:string);
  52. protected
  53. {outfile}
  54. AsmSize,
  55. AsmStartSize,
  56. outcnt : longint;
  57. outbuf : array[0..AsmOutSize-1] of char;
  58. outfile : file;
  59. public
  60. Function FindAssembler:string;
  61. Function CallAssembler(const command,para:string):Boolean;
  62. Function DoAssemble:boolean;
  63. Procedure RemoveAsm;
  64. Procedure AsmFlush;
  65. Procedure AsmClear;
  66. Procedure AsmWrite(const s:string);
  67. Procedure AsmWritePChar(p:pchar);
  68. Procedure AsmWriteLn(const s:string);
  69. Procedure AsmLn;
  70. procedure AsmCreate(Aplace:tcutplace);
  71. procedure AsmClose;
  72. procedure Synchronize;
  73. public
  74. Constructor Create(smart:boolean);
  75. end;
  76. Procedure GenerateAsm(smart:boolean);
  77. Procedure OnlyAsm;
  78. Implementation
  79. uses
  80. cutils,script,fmodule,systems,verbose
  81. {$ifdef unix}
  82. {$ifdef ver1_0}
  83. ,linux
  84. {$else}
  85. ,unix
  86. {$endif}
  87. {$endif}
  88. {$ifdef i386}
  89. {$ifndef NoAg386Bin}
  90. ,ag386bin
  91. {$endif}
  92. {$ifndef NoAg386Att}
  93. ,ag386att
  94. {$endif NoAg386Att}
  95. {$ifndef NoAg386Nsm}
  96. ,ag386nsm
  97. {$endif NoAg386Nsm}
  98. {$ifndef NoAg386Int}
  99. ,ag386int
  100. {$endif NoAg386Int}
  101. {$ifdef Ag386Cof}
  102. ,ag386cof
  103. {$endif Ag386Cof}
  104. {$endif}
  105. {$ifdef m68k}
  106. {$ifndef NoAg68kGas}
  107. ,ag68kgas
  108. {$endif NoAg68kGas}
  109. {$ifndef NoAg68kMot}
  110. ,ag68kmot
  111. {$endif NoAg68kMot}
  112. {$ifndef NoAg68kMit}
  113. ,ag68kmit
  114. {$endif NoAg68kMit}
  115. {$ifndef NoAg68kMpw}
  116. ,ag68kmpw
  117. {$endif NoAg68kMpw}
  118. {$endif}
  119. ;
  120. {*****************************************************************************
  121. TAssembler
  122. *****************************************************************************}
  123. Constructor TAssembler.Create(smart:boolean);
  124. begin
  125. { load start values }
  126. asmfile:=current_module.asmfilename^;
  127. objfile:=current_module.objfilename^;
  128. name:=Lower(current_module.modulename^);
  129. path:=current_module.outputpath^;
  130. SmartAsm:=smart;
  131. SmartFilesCount:=0;
  132. SmartHeaderCount:=0;
  133. SmartLinkOFiles.Clear;
  134. end;
  135. Destructor TAssembler.Destroy;
  136. begin
  137. end;
  138. procedure TAssembler.WriteTree(p:TAAsmoutput);
  139. begin
  140. end;
  141. procedure TAssembler.WriteAsmList;
  142. begin
  143. end;
  144. procedure TAssembler.NextSmartName(place:tcutplace);
  145. var
  146. s : string;
  147. begin
  148. inc(SmartFilesCount);
  149. if SmartFilesCount>999999 then
  150. Message(asmw_f_too_many_asm_files);
  151. case place of
  152. cut_begin :
  153. begin
  154. inc(SmartHeaderCount);
  155. s:=current_module.asmprefix^+tostr(SmartHeaderCount)+'h';
  156. end;
  157. cut_normal :
  158. s:=current_module.asmprefix^+tostr(SmartHeaderCount)+'s';
  159. cut_end :
  160. s:=current_module.asmprefix^+tostr(SmartHeaderCount)+'t';
  161. end;
  162. AsmFile:=Path+FixFileName(s+tostr(SmartFilesCount)+target_info.asmext);
  163. ObjFile:=Path+FixFileName(s+tostr(SmartFilesCount)+target_info.objext);
  164. { insert in container so it can be cleared after the linking }
  165. SmartLinkOFiles.Insert(Objfile);
  166. end;
  167. {*****************************************************************************
  168. TExternalAssembler
  169. *****************************************************************************}
  170. Function DoPipe:boolean;
  171. begin
  172. DoPipe:=(cs_asm_pipe in aktglobalswitches) and
  173. not(cs_asm_leave in aktglobalswitches)
  174. {$ifdef i386}
  175. and (aktoutputformat=as_i386_as)
  176. {$endif i386}
  177. {$ifdef m68k}
  178. and (aktoutputformat=as_m68k_as);
  179. {$endif m68k}
  180. end;
  181. Constructor TExternalAssembler.Create(smart:boolean);
  182. begin
  183. inherited Create(smart);
  184. if SmartAsm then
  185. begin
  186. path:=FixPath(current_module.outputpath^+FixFileName(current_module.modulename^)+target_info.smartext,false);
  187. CreateSmartLinkPath(path);
  188. end;
  189. Outcnt:=0;
  190. end;
  191. procedure TExternalAssembler.CreateSmartLinkPath(const s:string);
  192. var
  193. dir : searchrec;
  194. hs : string;
  195. begin
  196. if PathExists(s) then
  197. begin
  198. { the path exists, now we clean only all the .o and .s files }
  199. { .o files }
  200. findfirst(s+dirsep+'*'+target_info.objext,anyfile,dir);
  201. while (doserror=0) do
  202. begin
  203. RemoveFile(s+dirsep+dir.name);
  204. findnext(dir);
  205. end;
  206. findclose(dir);
  207. { .s files }
  208. findfirst(s+dirsep+'*'+target_info.asmext,anyfile,dir);
  209. while (doserror=0) do
  210. begin
  211. RemoveFile(s+dirsep+dir.name);
  212. findnext(dir);
  213. end;
  214. findclose(dir);
  215. end
  216. else
  217. begin
  218. hs:=s;
  219. if hs[length(hs)] in ['/','\'] then
  220. delete(hs,length(hs),1);
  221. {$I-}
  222. mkdir(hs);
  223. {$I+}
  224. if ioresult<>0 then;
  225. end;
  226. end;
  227. const
  228. lastas : byte=255;
  229. var
  230. LastASBin : pathstr;
  231. Function TExternalAssembler.FindAssembler:string;
  232. var
  233. asfound : boolean;
  234. UtilExe : string;
  235. begin
  236. asfound:=false;
  237. UtilExe:=AddExtension(target_asm.asmbin,source_os.exeext);
  238. if lastas<>ord(target_asm.id) then
  239. begin
  240. lastas:=ord(target_asm.id);
  241. { is an assembler passed ? }
  242. if utilsdirectory<>'' then
  243. asfound:=FindFile(UtilExe,utilsdirectory,LastASBin);
  244. if not AsFound then
  245. asfound:=FindExe(UtilExe,LastASBin);
  246. if (not asfound) and not(cs_asm_extern in aktglobalswitches) then
  247. begin
  248. Message1(exec_w_assembler_not_found,LastASBin);
  249. aktglobalswitches:=aktglobalswitches+[cs_asm_extern];
  250. end;
  251. if asfound then
  252. Message1(exec_t_using_assembler,LastASBin);
  253. end;
  254. FindAssembler:=LastASBin;
  255. end;
  256. Function TExternalAssembler.CallAssembler(const command,para:string):Boolean;
  257. begin
  258. callassembler:=true;
  259. if not(cs_asm_extern in aktglobalswitches) then
  260. begin
  261. swapvectors;
  262. exec(command,para);
  263. swapvectors;
  264. if (doserror<>0) then
  265. begin
  266. Message1(exec_w_cant_call_assembler,tostr(doserror));
  267. aktglobalswitches:=aktglobalswitches+[cs_asm_extern];
  268. callassembler:=false;
  269. end
  270. else
  271. if (dosexitcode<>0) then
  272. begin
  273. Message1(exec_w_error_while_assembling,tostr(dosexitcode));
  274. callassembler:=false;
  275. end;
  276. end
  277. else
  278. AsmRes.AddAsmCommand(command,para,name);
  279. end;
  280. procedure TExternalAssembler.RemoveAsm;
  281. var
  282. g : file;
  283. begin
  284. if cs_asm_leave in aktglobalswitches then
  285. exit;
  286. if cs_asm_extern in aktglobalswitches then
  287. AsmRes.AddDeleteCommand(AsmFile)
  288. else
  289. begin
  290. assign(g,AsmFile);
  291. {$I-}
  292. erase(g);
  293. {$I+}
  294. if ioresult<>0 then;
  295. end;
  296. end;
  297. Function TExternalAssembler.DoAssemble:boolean;
  298. var
  299. s : string;
  300. begin
  301. DoAssemble:=true;
  302. if DoPipe then
  303. exit;
  304. if not(cs_asm_extern in aktglobalswitches) then
  305. begin
  306. if SmartAsm then
  307. begin
  308. if (SmartFilesCount<=1) then
  309. Message1(exec_i_assembling_smart,name);
  310. end
  311. else
  312. Message1(exec_i_assembling,name);
  313. end;
  314. s:=target_asm.asmcmd;
  315. Replace(s,'$ASM',AsmFile);
  316. Replace(s,'$OBJ',ObjFile);
  317. if CallAssembler(FindAssembler,s) then
  318. RemoveAsm
  319. else
  320. begin
  321. DoAssemble:=false;
  322. GenerateError;
  323. end;
  324. end;
  325. Procedure TExternalAssembler.AsmFlush;
  326. begin
  327. if outcnt>0 then
  328. begin
  329. BlockWrite(outfile,outbuf,outcnt);
  330. outcnt:=0;
  331. end;
  332. end;
  333. Procedure TExternalAssembler.AsmClear;
  334. begin
  335. outcnt:=0;
  336. end;
  337. Procedure TExternalAssembler.AsmWrite(const s:string);
  338. begin
  339. if OutCnt+length(s)>=AsmOutSize then
  340. AsmFlush;
  341. Move(s[1],OutBuf[OutCnt],length(s));
  342. inc(OutCnt,length(s));
  343. inc(AsmSize,length(s));
  344. end;
  345. Procedure TExternalAssembler.AsmWriteLn(const s:string);
  346. begin
  347. AsmWrite(s);
  348. AsmLn;
  349. end;
  350. Procedure TExternalAssembler.AsmWritePChar(p:pchar);
  351. var
  352. i,j : longint;
  353. begin
  354. i:=StrLen(p);
  355. j:=i;
  356. while j>0 do
  357. begin
  358. i:=min(j,AsmOutSize);
  359. if OutCnt+i>=AsmOutSize then
  360. AsmFlush;
  361. Move(p[0],OutBuf[OutCnt],i);
  362. inc(OutCnt,i);
  363. inc(AsmSize,i);
  364. dec(j,i);
  365. p:=pchar(@p[i]);
  366. end;
  367. end;
  368. Procedure TExternalAssembler.AsmLn;
  369. begin
  370. if OutCnt>=AsmOutSize-2 then
  371. AsmFlush;
  372. OutBuf[OutCnt]:=target_os.newline[1];
  373. inc(OutCnt);
  374. inc(AsmSize);
  375. if length(target_os.newline)>1 then
  376. begin
  377. OutBuf[OutCnt]:=target_os.newline[2];
  378. inc(OutCnt);
  379. inc(AsmSize);
  380. end;
  381. end;
  382. procedure TExternalAssembler.AsmCreate(Aplace:tcutplace);
  383. begin
  384. if SmartAsm then
  385. NextSmartName(Aplace);
  386. {$ifdef unix}
  387. if DoPipe then
  388. begin
  389. Message1(exec_i_assembling_pipe,asmfile);
  390. POpen(outfile,'as -o '+objfile,'W');
  391. end
  392. else
  393. {$endif}
  394. begin
  395. Assign(outfile,asmfile);
  396. {$I-}
  397. Rewrite(outfile,1);
  398. {$I+}
  399. if ioresult<>0 then
  400. Message1(exec_d_cant_create_asmfile,asmfile);
  401. end;
  402. outcnt:=0;
  403. AsmSize:=0;
  404. AsmStartSize:=0;
  405. end;
  406. procedure TExternalAssembler.AsmClose;
  407. var
  408. f : file;
  409. l : longint;
  410. begin
  411. AsmFlush;
  412. {$ifdef unix}
  413. if DoPipe then
  414. PClose(outfile)
  415. else
  416. {$endif}
  417. begin
  418. {Touch Assembler time to ppu time is there is a ppufilename}
  419. if Assigned(current_module.ppufilename) then
  420. begin
  421. Assign(f,current_module.ppufilename^);
  422. {$I-}
  423. reset(f,1);
  424. {$I+}
  425. if ioresult=0 then
  426. begin
  427. getftime(f,l);
  428. close(f);
  429. reset(outfile,1);
  430. setftime(outfile,l);
  431. end;
  432. end;
  433. close(outfile);
  434. end;
  435. end;
  436. {Touch Assembler and object time to ppu time is there is a ppufilename}
  437. procedure TExternalAssembler.Synchronize;
  438. begin
  439. {Touch Assembler time to ppu time is there is a ppufilename}
  440. if Assigned(current_module.ppufilename) then
  441. begin
  442. SynchronizeFileTime(current_module.ppufilename^,asmfile);
  443. if not(cs_asm_extern in aktglobalswitches) then
  444. SynchronizeFileTime(current_module.ppufilename^,objfile);
  445. end;
  446. end;
  447. {*****************************************************************************
  448. Generate Assembler Files Main Procedure
  449. *****************************************************************************}
  450. Procedure GenerateAsm(smart:boolean);
  451. var
  452. a : TExternalAssembler;
  453. {$ifdef i386}
  454. {$ifndef NoAg386Bin}
  455. b : TInternalAssembler;
  456. {$endif}
  457. {$endif}
  458. begin
  459. case aktoutputformat of
  460. as_none : ;
  461. {$ifdef i386}
  462. {$ifndef NoAg386Bin}
  463. as_i386_dbg,
  464. as_i386_coff,
  465. as_i386_pecoff,
  466. as_i386_elf :
  467. begin
  468. case aktoutputformat of
  469. as_i386_dbg :
  470. b:=TInternalAssembler.Create(og_dbg,smart);
  471. as_i386_coff :
  472. b:=TInternalAssembler.Create(og_coff,smart);
  473. as_i386_pecoff :
  474. b:=TInternalAssembler.Create(og_pecoff,smart);
  475. as_i386_elf :
  476. b:=TInternalAssembler.Create(og_elf,smart);
  477. end;
  478. b.WriteBin;
  479. b.Free;
  480. if assigned(current_module.ppufilename) then
  481. begin
  482. if smart then
  483. SynchronizeFileTime(current_module.ppufilename^,current_module.staticlibfilename^)
  484. else
  485. SynchronizeFileTime(current_module.ppufilename^,current_module.objfilename^);
  486. end;
  487. exit;
  488. end;
  489. {$endif NoAg386Bin}
  490. {$ifndef NoAg386Att}
  491. as_i386_as,
  492. as_i386_as_aout,
  493. as_i386_asw :
  494. a:=T386ATTAssembler.create(smart);
  495. {$endif NoAg386Att}
  496. {$ifndef NoAg386Nsm}
  497. as_i386_nasmcoff,
  498. as_i386_nasmwin32,
  499. as_i386_nasmelf,
  500. as_i386_nasmobj :
  501. a:=T386NasmAssembler.Create(smart);
  502. {$endif NoAg386Nsm}
  503. {$ifndef NoAg386Int}
  504. as_i386_masm,
  505. as_i386_tasm :
  506. a:=T386IntelAssembler.Create(smart);
  507. {$endif NoAg386Int}
  508. {$endif}
  509. {$ifdef m68k}
  510. {$ifndef NoAg68kGas}
  511. as_m68k_as,
  512. as_m68k_gas :
  513. a:=new(pm68kgasasmlist,Init(smart));
  514. {$endif NoAg86KGas}
  515. {$ifndef NoAg68kMot}
  516. as_m68k_mot :
  517. a:=new(pm68kmoTExternalAssembler,Init(smart));
  518. {$endif NoAg86kMot}
  519. {$ifndef NoAg68kMit}
  520. as_m68k_mit :
  521. a:=new(pm68kmiTExternalAssembler,Init(smart));
  522. {$endif NoAg86KMot}
  523. {$ifndef NoAg68kMpw}
  524. as_m68k_mpw :
  525. a:=new(pm68kmpwasmlist,Init(smart));
  526. {$endif NoAg68kMpw}
  527. {$endif}
  528. else
  529. Message(asmw_f_assembler_output_not_supported);
  530. end;
  531. a.AsmCreate(cut_normal);
  532. a.WriteAsmList;
  533. a.AsmClose;
  534. a.DoAssemble;
  535. a.synchronize;
  536. a.Free;
  537. end;
  538. Procedure OnlyAsm;
  539. var
  540. a : TExternalAssembler;
  541. begin
  542. a:=TExternalAssembler.Create(false);
  543. a.DoAssemble;
  544. a.Free;
  545. end;
  546. end.
  547. {
  548. $Log$
  549. Revision 1.16 2001-03-13 18:42:39 peter
  550. * don't create temporary smartlink dir for internalassembler
  551. Revision 1.15 2001/03/05 21:39:11 peter
  552. * changed to class with common TAssembler also for internal assembler
  553. Revision 1.14 2001/02/26 08:08:16 michael
  554. * bug correction: pipes must be closed by pclose (not close);
  555. There was too many not closed processes under Linux before patch.
  556. Test this by making a compiler under Linux with command
  557. OPT="-P" make
  558. and check a list of processes in another shell with
  559. ps -xa
  560. Revision 1.13 2001/02/20 21:36:39 peter
  561. * tasm/masm fixes merged
  562. Revision 1.12 2001/02/09 23:06:17 peter
  563. * fixed uninited var
  564. Revision 1.11 2001/02/05 20:46:59 peter
  565. * support linux unit for ver1_0 compilers
  566. Revision 1.10 2001/01/21 20:32:45 marco
  567. * Renamefest. Compiler part. Not that hard.
  568. Revision 1.9 2001/01/12 19:19:44 peter
  569. * fixed searching for utils
  570. Revision 1.8 2000/12/25 00:07:25 peter
  571. + new tlinkedlist class (merge of old tstringqueue,tcontainer and
  572. tlinkedlist objects)
  573. Revision 1.7 2000/11/13 15:26:12 marco
  574. * Renamefest
  575. Revision 1.6 2000/10/01 19:48:23 peter
  576. * lot of compile updates for cg11
  577. Revision 1.5 2000/09/24 15:06:11 peter
  578. * use defines.inc
  579. Revision 1.4 2000/08/27 16:11:49 peter
  580. * moved some util functions from globals,cobjects to cutils
  581. * splitted files into finput,fmodule
  582. Revision 1.3 2000/07/13 12:08:24 michael
  583. + patched to 1.1.0 with former 1.09patch from peter
  584. Revision 1.2 2000/07/13 11:32:32 michael
  585. + removed logs
  586. }