assemble.pas 14 KB

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