assemble.pas 14 KB

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