assemble.pas 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619
  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. unit assemble;
  18. interface
  19. uses
  20. {$ifdef Delphi}
  21. dmisc,
  22. {$else Delphi}
  23. dos,
  24. {$endif Delphi}
  25. cobjects,globtype,globals,aasm;
  26. const
  27. {$ifdef tp}
  28. AsmOutSize=1024;
  29. {$else}
  30. AsmOutSize=32768;
  31. {$endif}
  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. smarthcount : longint;
  46. place : TCutPlace; { special 'end' file for import dir ? }
  47. {outfile}
  48. AsmSize,
  49. AsmStartSize,
  50. outcnt : longint;
  51. outbuf : array[0..AsmOutSize-1] of char;
  52. outfile : file;
  53. Constructor Init(smart:boolean);
  54. Destructor Done;
  55. Function FindAssembler:string;
  56. Function CallAssembler(const command,para:string):Boolean;
  57. Function DoAssemble:boolean;
  58. Procedure RemoveAsm;
  59. procedure NextSmartName;
  60. Procedure AsmFlush;
  61. Procedure AsmClear;
  62. Procedure AsmWrite(const s:string);
  63. Procedure AsmWritePChar(p:pchar);
  64. Procedure AsmWriteLn(const s:string);
  65. Procedure AsmLn;
  66. procedure AsmCreate(Aplace:tcutplace);
  67. procedure AsmClose;
  68. procedure Synchronize;
  69. procedure WriteTree(p:paasmoutput);virtual;
  70. procedure WriteAsmList;virtual;
  71. end;
  72. var
  73. SmartLinkFilesCnt : longint;
  74. Procedure GenerateAsm(smart:boolean);
  75. Procedure OnlyAsm;
  76. Implementation
  77. uses
  78. cutils,script,fmodule,systems,verbose
  79. {$ifdef linux}
  80. ,linux
  81. {$endif}
  82. ,strings
  83. {$ifdef i386}
  84. {$ifndef NoAg386Bin}
  85. ,ag386bin
  86. {$endif}
  87. {$ifndef NoAg386Att}
  88. ,ag386att
  89. {$endif NoAg386Att}
  90. {$ifndef NoAg386Nsm}
  91. ,ag386nsm
  92. {$endif NoAg386Nsm}
  93. {$ifndef NoAg386Int}
  94. ,ag386int
  95. {$endif NoAg386Int}
  96. {$ifdef Ag386Cof}
  97. ,ag386cof
  98. {$endif Ag386Cof}
  99. {$endif}
  100. {$ifdef m68k}
  101. {$ifndef NoAg68kGas}
  102. ,ag68kgas
  103. {$endif NoAg68kGas}
  104. {$ifndef NoAg68kMot}
  105. ,ag68kmot
  106. {$endif NoAg68kMot}
  107. {$ifndef NoAg68kMit}
  108. ,ag68kmit
  109. {$endif NoAg68kMit}
  110. {$ifndef NoAg68kMpw}
  111. ,ag68kmpw
  112. {$endif NoAg68kMpw}
  113. {$endif}
  114. ;
  115. {*****************************************************************************
  116. TAsmList
  117. *****************************************************************************}
  118. Function DoPipe:boolean;
  119. begin
  120. DoPipe:=(cs_asm_pipe in aktglobalswitches) and
  121. not(cs_asm_leave in aktglobalswitches)
  122. {$ifdef i386}
  123. and (aktoutputformat=as_i386_as)
  124. {$endif i386}
  125. {$ifdef m68k}
  126. and (aktoutputformat=as_m68k_as);
  127. {$endif m68k}
  128. end;
  129. const
  130. lastas : byte=255;
  131. var
  132. LastASBin : pathstr;
  133. Function TAsmList.FindAssembler:string;
  134. var
  135. asfound : boolean;
  136. begin
  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(target_asm.asmbin+source_os.exeext,utilsdirectory,asfound)+
  143. target_asm.asmbin+source_os.exeext;
  144. if LastASBin='' then
  145. LastASBin:=FindExe(target_asm.asmbin,asfound);
  146. if (not asfound) and not(cs_asm_extern in aktglobalswitches) then
  147. begin
  148. Message1(exec_w_assembler_not_found,LastASBin);
  149. aktglobalswitches:=aktglobalswitches+[cs_asm_extern];
  150. end;
  151. if asfound then
  152. Message1(exec_t_using_assembler,LastASBin);
  153. end;
  154. FindAssembler:=LastASBin;
  155. end;
  156. Function TAsmList.CallAssembler(const command,para:string):Boolean;
  157. begin
  158. callassembler:=true;
  159. if not(cs_asm_extern in aktglobalswitches) then
  160. begin
  161. swapvectors;
  162. exec(command,para);
  163. swapvectors;
  164. if (doserror<>0) then
  165. begin
  166. Message1(exec_w_cant_call_assembler,tostr(doserror));
  167. aktglobalswitches:=aktglobalswitches+[cs_asm_extern];
  168. callassembler:=false;
  169. end
  170. else
  171. if (dosexitcode<>0) then
  172. begin
  173. Message1(exec_w_error_while_assembling,tostr(dosexitcode));
  174. callassembler:=false;
  175. end;
  176. end
  177. else
  178. AsmRes.AddAsmCommand(command,para,name);
  179. end;
  180. procedure TAsmList.RemoveAsm;
  181. var
  182. g : file;
  183. begin
  184. if cs_asm_leave in aktglobalswitches then
  185. exit;
  186. if cs_asm_extern in aktglobalswitches then
  187. AsmRes.AddDeleteCommand(AsmFile)
  188. else
  189. begin
  190. assign(g,AsmFile);
  191. {$I-}
  192. erase(g);
  193. {$I+}
  194. if ioresult<>0 then;
  195. end;
  196. end;
  197. Function TAsmList.DoAssemble:boolean;
  198. var
  199. s : string;
  200. begin
  201. DoAssemble:=true;
  202. if DoPipe then
  203. exit;
  204. if not(cs_asm_extern in aktglobalswitches) then
  205. begin
  206. if SmartAsm then
  207. begin
  208. if (SmartLinkFilesCnt<=1) then
  209. Message1(exec_i_assembling_smart,name);
  210. end
  211. else
  212. Message1(exec_i_assembling,name);
  213. end;
  214. s:=target_asm.asmcmd;
  215. Replace(s,'$ASM',AsmFile);
  216. Replace(s,'$OBJ',ObjFile);
  217. if CallAssembler(FindAssembler,s) then
  218. RemoveAsm
  219. else
  220. begin
  221. DoAssemble:=false;
  222. GenerateError;
  223. end;
  224. end;
  225. procedure TAsmList.NextSmartName;
  226. var
  227. s : string;
  228. begin
  229. inc(SmartLinkFilesCnt);
  230. if SmartLinkFilesCnt>999999 then
  231. Message(asmw_f_too_many_asm_files);
  232. case place of
  233. cut_begin :
  234. begin
  235. inc(smarthcount);
  236. s:=current_module^.asmprefix^+tostr(smarthcount)+'h';
  237. end;
  238. cut_normal :
  239. s:=current_module^.asmprefix^+tostr(smarthcount)+'s';
  240. cut_end :
  241. s:=current_module^.asmprefix^+tostr(smarthcount)+'t';
  242. end;
  243. AsmFile:=Path+FixFileName(s+tostr(SmartLinkFilesCnt)+target_info.asmext);
  244. ObjFile:=Path+FixFileName(s+tostr(SmartLinkFilesCnt)+target_info.objext);
  245. { insert in container so it can be cleared after the linking }
  246. SmartLinkOFiles.Insert(Objfile);
  247. end;
  248. {*****************************************************************************
  249. TAsmList AsmFile Writing
  250. *****************************************************************************}
  251. Procedure TAsmList.AsmFlush;
  252. begin
  253. if outcnt>0 then
  254. begin
  255. BlockWrite(outfile,outbuf,outcnt);
  256. outcnt:=0;
  257. end;
  258. end;
  259. Procedure TAsmList.AsmClear;
  260. begin
  261. outcnt:=0;
  262. end;
  263. Procedure TAsmList.AsmWrite(const s:string);
  264. begin
  265. if OutCnt+length(s)>=AsmOutSize then
  266. AsmFlush;
  267. Move(s[1],OutBuf[OutCnt],length(s));
  268. inc(OutCnt,length(s));
  269. inc(AsmSize,length(s));
  270. end;
  271. Procedure TAsmList.AsmWriteLn(const s:string);
  272. begin
  273. AsmWrite(s);
  274. AsmLn;
  275. end;
  276. Procedure TAsmList.AsmWritePChar(p:pchar);
  277. var
  278. i,j : longint;
  279. begin
  280. i:=StrLen(p);
  281. j:=i;
  282. while j>0 do
  283. begin
  284. i:=min(j,AsmOutSize);
  285. if OutCnt+i>=AsmOutSize then
  286. AsmFlush;
  287. Move(p[0],OutBuf[OutCnt],i);
  288. inc(OutCnt,i);
  289. inc(AsmSize,i);
  290. dec(j,i);
  291. p:=pchar(@p[i]);
  292. end;
  293. end;
  294. Procedure TAsmList.AsmLn;
  295. begin
  296. if OutCnt>=AsmOutSize-2 then
  297. AsmFlush;
  298. OutBuf[OutCnt]:=target_os.newline[1];
  299. inc(OutCnt);
  300. inc(AsmSize);
  301. if length(target_os.newline)>1 then
  302. begin
  303. OutBuf[OutCnt]:=target_os.newline[2];
  304. inc(OutCnt);
  305. inc(AsmSize);
  306. end;
  307. end;
  308. procedure TAsmList.AsmCreate(Aplace:tcutplace);
  309. begin
  310. place:=Aplace;
  311. if SmartAsm then
  312. NextSmartName;
  313. {$ifdef linux}
  314. if DoPipe then
  315. begin
  316. Message1(exec_i_assembling_pipe,asmfile);
  317. POpen(outfile,'as -o '+objfile,'W');
  318. end
  319. else
  320. {$endif}
  321. begin
  322. Assign(outfile,asmfile);
  323. {$I-}
  324. Rewrite(outfile,1);
  325. {$I+}
  326. if ioresult<>0 then
  327. Message1(exec_d_cant_create_asmfile,asmfile);
  328. end;
  329. outcnt:=0;
  330. AsmSize:=0;
  331. AsmStartSize:=0;
  332. end;
  333. procedure TAsmList.AsmClose;
  334. var
  335. f : file;
  336. l : longint;
  337. begin
  338. AsmFlush;
  339. {$ifdef linux}
  340. if DoPipe then
  341. Close(outfile)
  342. else
  343. {$endif}
  344. begin
  345. {Touch Assembler time to ppu time is there is a ppufilename}
  346. if Assigned(current_module^.ppufilename) then
  347. begin
  348. Assign(f,current_module^.ppufilename^);
  349. {$I-}
  350. reset(f,1);
  351. {$I+}
  352. if ioresult=0 then
  353. begin
  354. getftime(f,l);
  355. close(f);
  356. reset(outfile,1);
  357. setftime(outfile,l);
  358. end;
  359. end;
  360. close(outfile);
  361. end;
  362. end;
  363. {Touch Assembler and object time to ppu time is there is a ppufilename}
  364. procedure TAsmList.Synchronize;
  365. begin
  366. {Touch Assembler time to ppu time is there is a ppufilename}
  367. if Assigned(current_module^.ppufilename) then
  368. begin
  369. SynchronizeFileTime(current_module^.ppufilename^,asmfile);
  370. if not(cs_asm_extern in aktglobalswitches) then
  371. SynchronizeFileTime(current_module^.ppufilename^,objfile);
  372. end;
  373. end;
  374. procedure TAsmList.WriteTree(p:paasmoutput);
  375. begin
  376. end;
  377. procedure TAsmList.WriteAsmList;
  378. begin
  379. end;
  380. procedure TAsmList.CreateSmartLinkPath(const s:string);
  381. var
  382. dir : searchrec;
  383. begin
  384. if PathExists(s) then
  385. begin
  386. { the path exists, now we clean only all the .o and .s files }
  387. { .o files }
  388. findfirst(s+dirsep+'*'+target_info.objext,anyfile,dir);
  389. while (doserror=0) do
  390. begin
  391. RemoveFile(s+dirsep+dir.name);
  392. findnext(dir);
  393. end;
  394. {$ifdef fpc}
  395. findclose(dir);
  396. {$endif}
  397. { .s files }
  398. findfirst(s+dirsep+'*'+target_info.asmext,anyfile,dir);
  399. while (doserror=0) do
  400. begin
  401. RemoveFile(s+dirsep+dir.name);
  402. findnext(dir);
  403. end;
  404. {$ifdef fpc}
  405. findclose(dir);
  406. {$endif}
  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. SmartLinkFilesCnt:=0;
  424. SmartLinkOFiles.Clear;
  425. place:=cut_normal;
  426. SmartAsm:=smart;
  427. SmartHCount:=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_tasm :
  499. a:=new(pi386intasmlist,Init(smart));
  500. {$endif NoAg386Int}
  501. {$endif}
  502. {$ifdef m68k}
  503. {$ifndef NoAg68kGas}
  504. as_m68k_as,
  505. as_m68k_gas :
  506. a:=new(pm68kgasasmlist,Init(smart));
  507. {$endif NoAg86KGas}
  508. {$ifndef NoAg68kMot}
  509. as_m68k_mot :
  510. a:=new(pm68kmotasmlist,Init(smart));
  511. {$endif NoAg86kMot}
  512. {$ifndef NoAg68kMit}
  513. as_m68k_mit :
  514. a:=new(pm68kmitasmlist,Init(smart));
  515. {$endif NoAg86KMot}
  516. {$ifndef NoAg68kMpw}
  517. as_m68k_mpw :
  518. a:=new(pm68kmpwasmlist,Init(smart));
  519. {$endif NoAg68kMpw}
  520. {$endif}
  521. else
  522. {$ifdef TP}
  523. exit;
  524. {$else}
  525. Message(asmw_f_assembler_output_not_supported);
  526. {$endif}
  527. end;
  528. a^.AsmCreate(cut_normal);
  529. a^.WriteAsmList;
  530. a^.AsmClose;
  531. a^.DoAssemble;
  532. a^.synchronize;
  533. dispose(a,Done);
  534. end;
  535. Procedure OnlyAsm;
  536. var
  537. a : PAsmList;
  538. begin
  539. a:=new(pasmlist,Init(false));
  540. a^.DoAssemble;
  541. dispose(a,Done);
  542. end;
  543. end.
  544. {
  545. $Log$
  546. Revision 1.4 2000-08-27 16:11:49 peter
  547. * moved some util functions from globals,cobjects to cutils
  548. * splitted files into finput,fmodule
  549. Revision 1.3 2000/07/13 12:08:24 michael
  550. + patched to 1.1.0 with former 1.09patch from peter
  551. Revision 1.2 2000/07/13 11:32:32 michael
  552. + removed logs
  553. }