assemble.pas 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679
  1. {
  2. $Id$
  3. Copyright (c) 1998 by the FPC development team
  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. dos,cobjects,globtype,globals,aasm;
  21. const
  22. {$ifdef tp}
  23. AsmOutSize=1024;
  24. {$else}
  25. AsmOutSize=32768;
  26. {$endif}
  27. type
  28. PAsmList=^TAsmList;
  29. TAsmList=object
  30. {filenames}
  31. path : pathstr;
  32. name : namestr;
  33. asmfile, { current .s and .o file }
  34. objfile,
  35. as_bin : string;
  36. IsEndFile : boolean; { special 'end' file for import dir ? }
  37. {outfile}
  38. AsmSize,
  39. AsmStartSize,
  40. outcnt : longint;
  41. outbuf : array[0..AsmOutSize-1] of char;
  42. outfile : file;
  43. Constructor Init;
  44. Destructor Done;
  45. Function FindAssembler:string;
  46. Function CallAssembler(const command,para:string):Boolean;
  47. Function DoAssemble:boolean;
  48. Procedure RemoveAsm;
  49. procedure NextSmartName;
  50. Procedure AsmFlush;
  51. Procedure AsmClear;
  52. Procedure AsmWrite(const s:string);
  53. Procedure AsmWritePChar(p:pchar);
  54. Procedure AsmWriteLn(const s:string);
  55. Procedure AsmLn;
  56. procedure AsmCreate;
  57. procedure AsmClose;
  58. procedure Synchronize;
  59. procedure WriteTree(p:paasmoutput);virtual;
  60. procedure WriteAsmList;virtual;
  61. end;
  62. Procedure GenerateAsm;
  63. Procedure OnlyAsm;
  64. var
  65. SmartLinkFilesCnt : longint;
  66. Implementation
  67. uses
  68. script,files,systems,verbose,comphook
  69. {$ifdef linux}
  70. ,linux
  71. {$endif}
  72. ,strings
  73. {$ifdef i386}
  74. {$ifndef NoAg386Att}
  75. ,ag386att
  76. {$endif NoAg386Att}
  77. {$ifndef NoAg386Nsm}
  78. ,ag386nsm
  79. {$endif NoAg386Nsm}
  80. {$ifndef NoAg386Int}
  81. ,ag386int
  82. {$endif NoAg386Int}
  83. {$endif}
  84. {$ifdef m68k}
  85. {$ifndef NoAg68kGas}
  86. ,ag68kgas
  87. {$endif NoAg68kGas}
  88. {$ifndef NoAg68kMot}
  89. ,ag68kmot
  90. {$endif NoAg68kMot}
  91. {$ifndef NoAg68kMit}
  92. ,ag68kmit
  93. {$endif NoAg68kMit}
  94. {$ifndef NoAg68kMpw}
  95. ,ag68kmpw
  96. {$endif NoAg68kMpw}
  97. {$endif}
  98. ;
  99. {*****************************************************************************
  100. TAsmList
  101. *****************************************************************************}
  102. Function DoPipe:boolean;
  103. begin
  104. DoPipe:=(cs_asm_pipe in aktglobalswitches) and
  105. not(cs_asm_leave in aktglobalswitches)
  106. {$ifdef i386}
  107. and (aktoutputformat=as_i386_o)
  108. {$endif i386}
  109. {$ifdef m68k}
  110. and (aktoutputformat=as_m68k_o);
  111. {$endif m68k}
  112. end;
  113. const
  114. lastas : byte=255;
  115. var
  116. LastASBin : string;
  117. Function TAsmList.FindAssembler:string;
  118. var
  119. asfound : boolean;
  120. begin
  121. if lastas<>ord(target_asm.id) then
  122. begin
  123. lastas:=ord(target_asm.id);
  124. { is an assembler passed ? }
  125. if utilsdirectory<>'' then
  126. begin
  127. LastASBin:=Search(target_asm.asmbin+source_os.exeext,
  128. utilsdirectory,asfound)+target_asm.asmbin+source_os.exeext;
  129. end
  130. else
  131. LastASBin:=FindExe(target_asm.asmbin,asfound);
  132. if (not asfound) and not(cs_asm_extern in aktglobalswitches) then
  133. begin
  134. Message1(exec_w_assembler_not_found,LastASBin);
  135. aktglobalswitches:=aktglobalswitches+[cs_asm_extern];
  136. end;
  137. if asfound then
  138. Message1(exec_t_using_assembler,LastASBin);
  139. end;
  140. FindAssembler:=LastASBin;
  141. end;
  142. Function TAsmList.CallAssembler(const command,para:string):Boolean;
  143. begin
  144. callassembler:=true;
  145. if not(cs_asm_extern in aktglobalswitches) then
  146. begin
  147. swapvectors;
  148. exec(command,para);
  149. swapvectors;
  150. if (doserror<>0) then
  151. begin
  152. Message1(exec_w_cant_call_assembler,tostr(doserror));
  153. aktglobalswitches:=aktglobalswitches+[cs_asm_extern];
  154. callassembler:=false;
  155. end
  156. else
  157. if (dosexitcode<>0) then
  158. begin
  159. Message1(exec_w_error_while_assembling,tostr(dosexitcode));
  160. callassembler:=false;
  161. end;
  162. end
  163. else
  164. AsmRes.AddAsmCommand(command,para,name);
  165. end;
  166. procedure TAsmList.RemoveAsm;
  167. var
  168. g : file;
  169. i : word;
  170. begin
  171. if cs_asm_leave in aktglobalswitches then
  172. exit;
  173. if cs_asm_extern in aktglobalswitches then
  174. AsmRes.AddDeleteCommand(AsmFile)
  175. else
  176. begin
  177. assign(g,AsmFile);
  178. {$I-}
  179. erase(g);
  180. {$I+}
  181. i:=ioresult;
  182. end;
  183. end;
  184. Function TAsmList.DoAssemble:boolean;
  185. var
  186. s : string;
  187. begin
  188. DoAssemble:=true;
  189. if DoPipe then
  190. exit;
  191. if (SmartLinkFilesCnt<=1) and not(cs_asm_extern in aktglobalswitches) then
  192. Message1(exec_i_assembling,name);
  193. s:=target_asm.asmcmd;
  194. Replace(s,'$ASM',AsmFile);
  195. Replace(s,'$OBJ',ObjFile);
  196. if CallAssembler(FindAssembler,s) then
  197. RemoveAsm
  198. else
  199. begin
  200. DoAssemble:=false;
  201. inc(status.errorcount);
  202. end;
  203. end;
  204. procedure TAsmList.NextSmartName;
  205. var
  206. s : string;
  207. begin
  208. inc(SmartLinkFilesCnt);
  209. if SmartLinkFilesCnt>999999 then
  210. Message(assem_f_too_many_asm_files);
  211. if IsEndFile then
  212. begin
  213. s:=current_module^.asmprefix^+'e';
  214. IsEndFile:=false;
  215. end
  216. else
  217. s:=current_module^.asmprefix^;
  218. AsmFile:=Path+FixFileName(s+tostr(SmartLinkFilesCnt)+target_info.asmext);
  219. ObjFile:=Path+FixFileName(s+tostr(SmartLinkFilesCnt)+target_info.objext);
  220. end;
  221. {*****************************************************************************
  222. TAsmList AsmFile Writing
  223. *****************************************************************************}
  224. Procedure TAsmList.AsmFlush;
  225. begin
  226. if outcnt>0 then
  227. begin
  228. BlockWrite(outfile,outbuf,outcnt);
  229. outcnt:=0;
  230. end;
  231. end;
  232. Procedure TAsmList.AsmClear;
  233. begin
  234. outcnt:=0;
  235. end;
  236. Procedure TAsmList.AsmWrite(const s:string);
  237. begin
  238. if OutCnt+length(s)>=AsmOutSize then
  239. AsmFlush;
  240. Move(s[1],OutBuf[OutCnt],length(s));
  241. inc(OutCnt,length(s));
  242. inc(AsmSize,length(s));
  243. end;
  244. Procedure TAsmList.AsmWriteLn(const s:string);
  245. begin
  246. AsmWrite(s);
  247. AsmLn;
  248. end;
  249. Procedure TAsmList.AsmWritePChar(p:pchar);
  250. var
  251. i,j : longint;
  252. begin
  253. i:=StrLen(p);
  254. j:=i;
  255. while j>0 do
  256. begin
  257. i:=min(j,AsmOutSize);
  258. if OutCnt+i>=AsmOutSize then
  259. AsmFlush;
  260. Move(p[0],OutBuf[OutCnt],i);
  261. inc(OutCnt,i);
  262. inc(AsmSize,i);
  263. dec(j,i);
  264. p:=pchar(@p[i]);
  265. end;
  266. end;
  267. Procedure TAsmList.AsmLn;
  268. begin
  269. if OutCnt>=AsmOutSize-2 then
  270. AsmFlush;
  271. OutBuf[OutCnt]:=target_os.newline[1];
  272. inc(OutCnt);
  273. inc(AsmSize);
  274. if length(target_os.newline)>1 then
  275. begin
  276. OutBuf[OutCnt]:=target_os.newline[2];
  277. inc(OutCnt);
  278. inc(AsmSize);
  279. end;
  280. end;
  281. procedure TAsmList.AsmCreate;
  282. begin
  283. if (cs_smartlink in aktmoduleswitches) then
  284. NextSmartName;
  285. {$ifdef linux}
  286. if DoPipe then
  287. begin
  288. Message1(exec_i_assembling_pipe,asmfile);
  289. POpen(outfile,'as -o '+objfile,'W');
  290. end
  291. else
  292. {$endif}
  293. begin
  294. Assign(outfile,asmfile);
  295. {$I-}
  296. Rewrite(outfile,1);
  297. {$I+}
  298. if ioresult<>0 then
  299. Message1(exec_d_cant_create_asmfile,asmfile);
  300. end;
  301. outcnt:=0;
  302. AsmSize:=0;
  303. AsmStartSize:=0;
  304. end;
  305. procedure TAsmList.AsmClose;
  306. var
  307. f : file;
  308. l : longint;
  309. begin
  310. AsmFlush;
  311. {$ifdef linux}
  312. if DoPipe then
  313. Close(outfile)
  314. else
  315. {$endif}
  316. begin
  317. {Touch Assembler time to ppu time is there is a ppufilename}
  318. if Assigned(current_module^.ppufilename) then
  319. begin
  320. Assign(f,current_module^.ppufilename^);
  321. {$I-}
  322. reset(f,1);
  323. {$I+}
  324. if ioresult=0 then
  325. begin
  326. getftime(f,l);
  327. close(f);
  328. reset(outfile,1);
  329. setftime(outfile,l);
  330. end;
  331. end;
  332. close(outfile);
  333. end;
  334. end;
  335. {Touch Assembler and object time to ppu time is there is a ppufilename}
  336. procedure TAsmList.Synchronize;
  337. var
  338. f : file;
  339. l : longint;
  340. begin
  341. {Touch Assembler time to ppu time is there is a ppufilename}
  342. if Assigned(current_module^.ppufilename) then
  343. begin
  344. Assign(f,current_module^.ppufilename^);
  345. {$I-}
  346. reset(f,1);
  347. {$I+}
  348. if ioresult=0 then
  349. begin
  350. getftime(f,l);
  351. close(f);
  352. assign(f,asmfile);
  353. {$I-}
  354. reset(f,1);
  355. {$I+}
  356. if ioresult=0 then
  357. begin
  358. setftime(f,l);
  359. close(f);
  360. end;
  361. if not(cs_asm_extern in aktglobalswitches) then
  362. begin
  363. assign(f,objfile);
  364. {$I-}
  365. reset(f,1);
  366. {$I+}
  367. if ioresult=0 then
  368. begin
  369. setftime(f,l);
  370. close(f);
  371. end;
  372. end;
  373. end;
  374. end;
  375. end;
  376. procedure TAsmList.WriteTree(p:paasmoutput);
  377. begin
  378. end;
  379. procedure TAsmList.WriteAsmList;
  380. begin
  381. end;
  382. Constructor TAsmList.Init;
  383. var
  384. i : word;
  385. begin
  386. { load start values }
  387. asmfile:=current_module^.asmfilename^;
  388. objfile:=current_module^.objfilename^;
  389. name:=FixFileName(current_module^.modulename^);
  390. OutCnt:=0;
  391. SmartLinkFilesCnt:=0;
  392. IsEndFile:=false;
  393. { Which path will be used ? }
  394. if (cs_smartlink in aktmoduleswitches) then
  395. begin
  396. path:=current_module^.path^+FixFileName(current_module^.modulename^)+target_info.smartext;
  397. {$I-}
  398. mkdir(path);
  399. {$I+}
  400. i:=ioresult;
  401. path:=FixPath(path,false);
  402. end
  403. else
  404. path:=current_module^.path^;
  405. end;
  406. Destructor TAsmList.Done;
  407. begin
  408. end;
  409. {*****************************************************************************
  410. Generate Assembler Files Main Procedure
  411. *****************************************************************************}
  412. Procedure GenerateAsm;
  413. var
  414. a : PAsmList;
  415. begin
  416. case aktoutputformat of
  417. {$ifdef i386}
  418. {$ifndef NoAg386Att}
  419. as_i386_o,
  420. as_i386_o_aout,
  421. as_i386_asw :
  422. a:=new(pi386attasmlist,Init);
  423. {$endif NoAg386Att}
  424. {$ifndef NoAg386Nsm}
  425. as_i386_nasmcoff,
  426. as_i386_nasmelf,
  427. as_i386_nasmobj :
  428. a:=new(pi386nasmasmlist,Init);
  429. {$endif NoAg386Nsm}
  430. {$ifndef NoAg386Int}
  431. as_i386_tasm :
  432. a:=new(pi386intasmlist,Init);
  433. {$endif NoAg386Int}
  434. {$endif}
  435. {$ifdef m68k}
  436. {$ifndef NoAg68kGas}
  437. as_m68k_o,
  438. as_m68k_gas :
  439. a:=new(pm68kgasasmlist,Init);
  440. {$endif NoAg86KGas}
  441. {$ifndef NoAg68kMot}
  442. as_m68k_mot :
  443. a:=new(pm68kmotasmlist,Init);
  444. {$endif NoAg86kMot}
  445. {$ifndef NoAg68kMit}
  446. as_m68k_mit :
  447. a:=new(pm68kmitasmlist,Init);
  448. {$endif NoAg86KMot}
  449. {$ifndef NoAg68kMpw}
  450. as_m68k_mpw :
  451. a:=new(pm68kmpwasmlist,Init);
  452. {$endif NoAg68kMpw}
  453. {$endif}
  454. else
  455. Message(assem_f_assembler_output_not_supported);
  456. end;
  457. a^.AsmCreate;
  458. a^.WriteAsmList;
  459. a^.AsmClose;
  460. a^.DoAssemble;
  461. a^.synchronize;
  462. dispose(a,Done);
  463. end;
  464. Procedure OnlyAsm;
  465. var
  466. a : PAsmList;
  467. begin
  468. a:=new(pasmlist,Init);
  469. a^.DoAssemble;
  470. dispose(a,Done);
  471. end;
  472. end.
  473. {
  474. $Log$
  475. Revision 1.33 1998-12-11 00:02:45 peter
  476. + globtype,tokens,version unit splitted from globals
  477. Revision 1.32 1998/11/06 09:46:46 pierre
  478. * assemble failure increments status errorcount again !!
  479. Revision 1.31 1998/10/26 22:23:28 peter
  480. + fixpath() has an extra option to allow a ./ as path
  481. Revision 1.30 1998/10/16 13:37:14 florian
  482. + switch -FD added to specify the path for utilities
  483. Revision 1.29 1998/10/15 16:19:42 peter
  484. * fixed asmsynchronize
  485. Revision 1.28 1998/10/14 15:56:43 pierre
  486. * all references to comp suppressed for m68k
  487. Revision 1.27 1998/10/13 16:50:01 pierre
  488. * undid some changes of Peter that made the compiler wrong
  489. for m68k (I had to reinsert some ifdefs)
  490. * removed several memory leaks under m68k
  491. * removed the meory leaks for assembler readers
  492. * cross compiling shoud work again better
  493. ( crosscompiling sysamiga works
  494. but as68k still complain about some code !)
  495. Revision 1.26 1998/10/13 13:10:11 peter
  496. * new style for m68k/i386 infos and enums
  497. Revision 1.25 1998/10/13 08:19:24 pierre
  498. + source_os is now set correctly for cross-processor compilers
  499. (tos contains all target_infos and
  500. we use CPU86 and CPU68 conditionnals to
  501. get the source operating system
  502. this only works if you do not undefine
  503. the source target !!)
  504. * several cg68k memory leaks fixed
  505. + started to change the code so that it should be possible to have
  506. a complete compiler (both for m68k and i386 !!)
  507. Revision 1.24 1998/10/08 23:28:50 peter
  508. * -vu shows unit info, -vt shows tried/used files
  509. Revision 1.23 1998/10/07 04:27:37 carl
  510. + MPW support
  511. Revision 1.22 1998/09/16 16:41:39 peter
  512. * merged fixes
  513. Revision 1.21.2.1 1998/09/16 16:11:38 peter
  514. * missing isendfile reset in .init
  515. Revision 1.21 1998/09/07 18:33:32 peter
  516. + smartlinking for win95 imports
  517. Revision 1.20 1998/09/04 17:34:20 pierre
  518. * bug with datalabel corrected
  519. + assembler errors better commented
  520. * one nested record crash removed
  521. Revision 1.19 1998/08/26 10:06:34 peter
  522. * reduce amount of asmfiles generated
  523. * no stabs are written in writefilelineinfo when debuginfo is off
  524. Revision 1.18 1998/08/21 14:08:39 pierre
  525. + TEST_FUNCRET now default (old code removed)
  526. works also for m68k (at least compiles)
  527. Revision 1.17 1998/08/17 09:17:43 peter
  528. * static/shared linking updates
  529. Revision 1.16 1998/08/14 21:56:30 peter
  530. * setting the outputfile using -o works now to create static libs
  531. Revision 1.15 1998/08/14 18:16:09 peter
  532. * return after a failed call will now add it to ppas
  533. Revision 1.14 1998/08/10 14:49:41 peter
  534. + localswitches, moduleswitches, globalswitches splitting
  535. Revision 1.13 1998/07/14 21:46:40 peter
  536. * updated messages file
  537. Revision 1.12 1998/07/08 14:58:34 daniel
  538. * First check if call to assembler is succesfull, then check it's exit code.
  539. This is more logical than first checking the exit code. For some mysterious
  540. reason this did not give problems on DOS & Linux. On OS/2 it did.
  541. Revision 1.11 1998/06/08 22:59:43 peter
  542. * smartlinking works for win32
  543. * some defines to exclude some compiler parts
  544. Revision 1.10 1998/06/04 23:51:33 peter
  545. * m68k compiles
  546. + .def file creation moved to gendef.pas so it could also be used
  547. for win32
  548. Revision 1.9 1998/05/23 01:21:01 peter
  549. + aktasmmode, aktoptprocessor, aktoutputformat
  550. + smartlink per module $SMARTLINK-/+ (like MMX) and moved to aktswitches
  551. + $LIBNAME to set the library name where the unit will be put in
  552. * splitted cgi386 a bit (codeseg to large for bp7)
  553. * nasm, tasm works again. nasm moved to ag386nsm.pas
  554. Revision 1.8 1998/05/11 13:07:53 peter
  555. + $ifdef NEWPPU for the new ppuformat
  556. + $define GDB not longer required
  557. * removed all warnings and stripped some log comments
  558. * no findfirst/findnext anymore to remove smartlink *.o files
  559. Revision 1.7 1998/05/07 00:17:00 peter
  560. * smartlinking for sets
  561. + consts labels are now concated/generated in hcodegen
  562. * moved some cpu code to cga and some none cpu depended code from cga
  563. to tree and hcodegen and cleanup of hcodegen
  564. * assembling .. output reduced for smartlinking ;)
  565. Revision 1.6 1998/05/04 17:54:24 peter
  566. + smartlinking works (only case jumptable left todo)
  567. * redesign of systems.pas to support assemblers and linkers
  568. + Unitname is now also in the PPU-file, increased version to 14
  569. Revision 1.5 1998/04/29 10:33:44 pierre
  570. + added some code for ansistring (not complete nor working yet)
  571. * corrected operator overloading
  572. * corrected nasm output
  573. + started inline procedures
  574. + added starstarn : use ** for exponentiation (^ gave problems)
  575. + started UseTokenInfo cond to get accurate positions
  576. Revision 1.4 1998/04/27 23:10:27 peter
  577. + new scanner
  578. * $makelib -> if smartlink
  579. * small filename fixes pmodule.setfilename
  580. * moved import from files.pas -> import.pas
  581. Revision 1.3 1998/04/10 14:41:43 peter
  582. * removed some Hints
  583. * small speed optimization for AsmLn
  584. Revision 1.2 1998/04/08 11:34:18 peter
  585. * nasm works (linux only tested)
  586. }