assemble.pas 14 KB

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