assemble.pas 14 KB

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