assemble.pas 14 KB

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