assemble.pas 58 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803
  1. {
  2. Copyright (c) 1998-2004 by Peter Vreman
  3. This unit handles the assemblerfile write and assembler calls of FPC
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program; if not, write to the Free Software
  14. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  15. ****************************************************************************
  16. }
  17. {# @abstract(This unit handles the assembler file write and assembler calls of FPC)
  18. Handles the calls to the actual external assemblers, as well as the generation
  19. of object files for smart linking. Also contains the base class for writing
  20. the assembler statements to file.
  21. }
  22. unit assemble;
  23. {$i fpcdefs.inc}
  24. interface
  25. uses
  26. SysUtils,
  27. systems,globtype,globals,aasmbase,aasmtai,aasmdata,ogbase,finput;
  28. const
  29. { maximum of aasmoutput lists there will be }
  30. maxoutputlists = ord(high(tasmlisttype))+1;
  31. { buffer size for writing the .s file }
  32. AsmOutSize=32768*4;
  33. type
  34. TAssembler=class(TObject)
  35. public
  36. {filenames}
  37. path : TPathStr;
  38. name : string;
  39. AsmFileName, { current .s and .o file }
  40. ObjFileName,
  41. ppufilename : TPathStr;
  42. asmprefix : string;
  43. SmartAsm : boolean;
  44. SmartFilesCount,
  45. SmartHeaderCount : longint;
  46. Constructor Create(smart:boolean);virtual;
  47. Destructor Destroy;override;
  48. procedure NextSmartName(place:tcutplace);
  49. procedure MakeObject;virtual;abstract;
  50. end;
  51. {# This is the base class which should be overridden for each each
  52. assembler writer. It is used to actually assembler a file,
  53. and write the output to the assembler file.
  54. }
  55. TExternalAssembler=class(TAssembler)
  56. private
  57. procedure CreateSmartLinkPath(const s:TPathStr);
  58. protected
  59. {outfile}
  60. AsmSize,
  61. AsmStartSize,
  62. outcnt : longint;
  63. outbuf : array[0..AsmOutSize-1] of char;
  64. outfile : file;
  65. ioerror : boolean;
  66. {input source info}
  67. lastfileinfo : tfileposinfo;
  68. infile,
  69. lastinfile : tinputfile;
  70. {last section type written}
  71. lastsectype : TAsmSectionType;
  72. procedure WriteSourceLine(hp: tailineinfo);
  73. procedure WriteTempalloc(hp: tai_tempalloc);
  74. public
  75. {# Returns the complete path and executable name of the assembler
  76. program.
  77. It first tries looking in the UTIL directory if specified,
  78. otherwise it searches in the free pascal binary directory, in
  79. the current working directory and then in the directories
  80. in the $PATH environment.}
  81. Function FindAssembler:string;
  82. {# Actually does the call to the assembler file. Returns false
  83. if the assembling of the file failed.}
  84. Function CallAssembler(const command:string; const para:TCmdStr):Boolean;
  85. Function DoAssemble:boolean;virtual;
  86. Procedure RemoveAsm;virtual;
  87. Procedure AsmFlush;
  88. Procedure AsmClear;
  89. {# Write a string to the assembler file }
  90. Procedure AsmWrite(const c:char);
  91. Procedure AsmWrite(const s:string);
  92. Procedure AsmWrite(const s:ansistring);
  93. {# Write a string to the assembler file }
  94. Procedure AsmWritePChar(p:pchar);
  95. {# Write a string to the assembler file followed by a new line }
  96. Procedure AsmWriteLn(const c:char);
  97. Procedure AsmWriteLn(const s:string);
  98. Procedure AsmWriteLn(const s:ansistring);
  99. {# Write a new line to the assembler file }
  100. Procedure AsmLn;
  101. procedure AsmCreate(Aplace:tcutplace);
  102. procedure AsmClose;
  103. {# This routine should be overridden for each assembler, it is used
  104. to actually write the abstract assembler stream to file.}
  105. procedure WriteTree(p:TAsmList);virtual;
  106. {# This routine should be overridden for each assembler, it is used
  107. to actually write all the different abstract assembler streams
  108. by calling for each stream type, the @var(WriteTree) method.}
  109. procedure WriteAsmList;virtual;
  110. {# Constructs the command line for calling the assembler }
  111. function MakeCmdLine: TCmdStr; virtual;
  112. public
  113. Constructor Create(smart:boolean);override;
  114. procedure MakeObject;override;
  115. end;
  116. { TInternalAssembler }
  117. TInternalAssembler=class(TAssembler)
  118. private
  119. FCObjOutput : TObjOutputclass;
  120. { the aasmoutput lists that need to be processed }
  121. lists : byte;
  122. list : array[1..maxoutputlists] of TAsmList;
  123. { current processing }
  124. currlistidx : byte;
  125. currlist : TAsmList;
  126. procedure WriteStab(p:pchar);
  127. function MaybeNextList(var hp:Tai):boolean;
  128. function SetIndirectToSymbol(hp: Tai; const indirectname: string): Boolean;
  129. function TreePass0(hp:Tai):Tai;
  130. function TreePass1(hp:Tai):Tai;
  131. function TreePass2(hp:Tai):Tai;
  132. procedure writetree;
  133. procedure writetreesmart;
  134. protected
  135. ObjData : TObjData;
  136. ObjOutput : tObjOutput;
  137. property CObjOutput:TObjOutputclass read FCObjOutput write FCObjOutput;
  138. public
  139. constructor create(smart:boolean);override;
  140. destructor destroy;override;
  141. procedure MakeObject;override;
  142. end;
  143. TAssemblerClass = class of TAssembler;
  144. Procedure GenerateAsm(smart:boolean);
  145. Procedure OnlyAsm;
  146. procedure RegisterAssembler(const r:tasminfo;c:TAssemblerClass);
  147. Implementation
  148. uses
  149. {$ifdef hasunix}
  150. unix,
  151. {$endif}
  152. cutils,cfileutl,
  153. {$ifdef memdebug}
  154. cclasses,
  155. {$endif memdebug}
  156. script,fmodule,verbose,
  157. {$if defined(m68k) or defined(arm)}
  158. cpuinfo,
  159. {$endif m68k or arm}
  160. aasmcpu,
  161. owbase,owar
  162. ;
  163. var
  164. CAssembler : array[tasm] of TAssemblerClass;
  165. function fixline(s:string):string;
  166. {
  167. return s with all leading and ending spaces and tabs removed
  168. }
  169. var
  170. i,j,k : integer;
  171. begin
  172. i:=length(s);
  173. while (i>0) and (s[i] in [#9,' ']) do
  174. dec(i);
  175. j:=1;
  176. while (j<i) and (s[j] in [#9,' ']) do
  177. inc(j);
  178. for k:=j to i do
  179. if s[k] in [#0..#31,#127..#255] then
  180. s[k]:='.';
  181. fixline:=Copy(s,j,i-j+1);
  182. end;
  183. {*****************************************************************************
  184. TAssembler
  185. *****************************************************************************}
  186. Constructor TAssembler.Create(smart:boolean);
  187. begin
  188. { load start values }
  189. AsmFileName:=current_module.AsmFilename;
  190. ObjFileName:=current_module.ObjFileName;
  191. name:=Lower(current_module.modulename^);
  192. path:=current_module.outputpath;
  193. asmprefix := current_module.asmprefix^;
  194. if current_module.outputpath = '' then
  195. ppufilename := ''
  196. else
  197. ppufilename := current_module.ppufilename;
  198. SmartAsm:=smart;
  199. SmartFilesCount:=0;
  200. SmartHeaderCount:=0;
  201. SmartLinkOFiles.Clear;
  202. end;
  203. Destructor TAssembler.Destroy;
  204. begin
  205. end;
  206. procedure TAssembler.NextSmartName(place:tcutplace);
  207. var
  208. s : string;
  209. begin
  210. inc(SmartFilesCount);
  211. if SmartFilesCount>999999 then
  212. Message(asmw_f_too_many_asm_files);
  213. case place of
  214. cut_begin :
  215. begin
  216. inc(SmartHeaderCount);
  217. s:=asmprefix+tostr(SmartHeaderCount)+'h';
  218. end;
  219. cut_normal :
  220. s:=asmprefix+tostr(SmartHeaderCount)+'s';
  221. cut_end :
  222. s:=asmprefix+tostr(SmartHeaderCount)+'t';
  223. end;
  224. AsmFileName:=Path+FixFileName(s+tostr(SmartFilesCount)+target_info.asmext);
  225. ObjFileName:=Path+FixFileName(s+tostr(SmartFilesCount)+target_info.objext);
  226. { insert in container so it can be cleared after the linking }
  227. SmartLinkOFiles.Insert(ObjFileName);
  228. end;
  229. {*****************************************************************************
  230. TExternalAssembler
  231. *****************************************************************************}
  232. Function DoPipe:boolean;
  233. begin
  234. DoPipe:=(cs_asm_pipe in current_settings.globalswitches) and
  235. (([cs_asm_extern,cs_asm_leave,cs_link_on_target] * current_settings.globalswitches) = []) and
  236. ((target_asm.id in [as_gas,as_ggas,as_darwin,as_powerpc_xcoff,as_clang]));
  237. end;
  238. Constructor TExternalAssembler.Create(smart:boolean);
  239. begin
  240. inherited Create(smart);
  241. if SmartAsm then
  242. begin
  243. path:=FixPath(ChangeFileExt(AsmFileName,target_info.smartext),false);
  244. CreateSmartLinkPath(path);
  245. end;
  246. Outcnt:=0;
  247. end;
  248. procedure TExternalAssembler.CreateSmartLinkPath(const s:TPathStr);
  249. procedure DeleteFilesWithExt(const AExt:string);
  250. var
  251. dir : TRawByteSearchRec;
  252. begin
  253. if findfirst(FixPath(s,false)+'*'+AExt,faAnyFile,dir) = 0 then
  254. begin
  255. repeat
  256. DeleteFile(s+source_info.dirsep+dir.name);
  257. until findnext(dir) <> 0;
  258. end;
  259. findclose(dir);
  260. end;
  261. var
  262. hs : TPathStr;
  263. begin
  264. if PathExists(s,false) then
  265. begin
  266. { the path exists, now we clean only all the .o and .s files }
  267. DeleteFilesWithExt(target_info.objext);
  268. DeleteFilesWithExt(target_info.asmext);
  269. end
  270. else
  271. begin
  272. hs:=s;
  273. if hs[length(hs)] in ['/','\'] then
  274. delete(hs,length(hs),1);
  275. {$push} {$I-}
  276. mkdir(hs);
  277. {$pop}
  278. if ioresult<>0 then;
  279. end;
  280. end;
  281. const
  282. lastas : byte=255;
  283. var
  284. LastASBin : TCmdStr;
  285. Function TExternalAssembler.FindAssembler:string;
  286. var
  287. asfound : boolean;
  288. UtilExe : string;
  289. begin
  290. asfound:=false;
  291. if cs_link_on_target in current_settings.globalswitches then
  292. begin
  293. { If linking on target, don't add any path PM }
  294. FindAssembler:=utilsprefix+ChangeFileExt(target_asm.asmbin,target_info.exeext);
  295. exit;
  296. end
  297. else
  298. UtilExe:=utilsprefix+ChangeFileExt(target_asm.asmbin,source_info.exeext);
  299. if lastas<>ord(target_asm.id) then
  300. begin
  301. lastas:=ord(target_asm.id);
  302. { is an assembler passed ? }
  303. if utilsdirectory<>'' then
  304. asfound:=FindFile(UtilExe,utilsdirectory,false,LastASBin);
  305. if not AsFound then
  306. asfound:=FindExe(UtilExe,false,LastASBin);
  307. if (not asfound) and not(cs_asm_extern in current_settings.globalswitches) then
  308. begin
  309. Message1(exec_e_assembler_not_found,LastASBin);
  310. current_settings.globalswitches:=current_settings.globalswitches+[cs_asm_extern];
  311. end;
  312. if asfound then
  313. Message1(exec_t_using_assembler,LastASBin);
  314. end;
  315. FindAssembler:=LastASBin;
  316. end;
  317. Function TExternalAssembler.CallAssembler(const command:string; const para:TCmdStr):Boolean;
  318. var
  319. DosExitCode : Integer;
  320. begin
  321. result:=true;
  322. if (cs_asm_extern in current_settings.globalswitches) then
  323. begin
  324. if SmartAsm then
  325. AsmRes.AddAsmCommand(command,para,Name+'('+TosTr(SmartFilesCount)+')')
  326. else
  327. AsmRes.AddAsmCommand(command,para,name);
  328. exit;
  329. end;
  330. try
  331. FlushOutput;
  332. DosExitCode:=RequotedExecuteProcess(command,para);
  333. if DosExitCode<>0
  334. then begin
  335. Message1(exec_e_error_while_assembling,tostr(dosexitcode));
  336. result:=false;
  337. end;
  338. except on E:EOSError do
  339. begin
  340. Message1(exec_e_cant_call_assembler,tostr(E.ErrorCode));
  341. current_settings.globalswitches:=current_settings.globalswitches+[cs_asm_extern];
  342. result:=false;
  343. end;
  344. end;
  345. end;
  346. procedure TExternalAssembler.RemoveAsm;
  347. var
  348. g : file;
  349. begin
  350. if cs_asm_leave in current_settings.globalswitches then
  351. exit;
  352. if cs_asm_extern in current_settings.globalswitches then
  353. AsmRes.AddDeleteCommand(AsmFileName)
  354. else
  355. begin
  356. assign(g,AsmFileName);
  357. {$push} {$I-}
  358. erase(g);
  359. {$pop}
  360. if ioresult<>0 then;
  361. end;
  362. end;
  363. Function TExternalAssembler.DoAssemble:boolean;
  364. begin
  365. DoAssemble:=true;
  366. if DoPipe then
  367. exit;
  368. if not(cs_asm_extern in current_settings.globalswitches) then
  369. begin
  370. if SmartAsm then
  371. begin
  372. if (SmartFilesCount<=1) then
  373. Message1(exec_i_assembling_smart,name);
  374. end
  375. else
  376. Message1(exec_i_assembling,name);
  377. end;
  378. if CallAssembler(FindAssembler,MakeCmdLine) then
  379. RemoveAsm
  380. else
  381. begin
  382. DoAssemble:=false;
  383. GenerateError;
  384. end;
  385. end;
  386. Procedure TExternalAssembler.AsmFlush;
  387. begin
  388. if outcnt>0 then
  389. begin
  390. { suppress i/o error }
  391. {$push} {$I-}
  392. BlockWrite(outfile,outbuf,outcnt);
  393. {$pop}
  394. ioerror:=ioerror or (ioresult<>0);
  395. outcnt:=0;
  396. end;
  397. end;
  398. Procedure TExternalAssembler.AsmClear;
  399. begin
  400. outcnt:=0;
  401. end;
  402. Procedure TExternalAssembler.AsmWrite(const c: char);
  403. begin
  404. if OutCnt+1>=AsmOutSize then
  405. AsmFlush;
  406. OutBuf[OutCnt]:=c;
  407. inc(OutCnt);
  408. inc(AsmSize);
  409. end;
  410. Procedure TExternalAssembler.AsmWrite(const s:string);
  411. begin
  412. if OutCnt+length(s)>=AsmOutSize then
  413. AsmFlush;
  414. Move(s[1],OutBuf[OutCnt],length(s));
  415. inc(OutCnt,length(s));
  416. inc(AsmSize,length(s));
  417. end;
  418. Procedure TExternalAssembler.AsmWrite(const s:ansistring);
  419. var
  420. StartIndex, ToWrite: longint;
  421. begin
  422. if s='' then
  423. exit;
  424. if OutCnt+length(s)>=AsmOutSize then
  425. AsmFlush;
  426. StartIndex:=1;
  427. ToWrite:=length(s);
  428. while ToWrite>AsmOutSize do
  429. begin
  430. Move(s[StartIndex],OutBuf[OutCnt],AsmOutSize);
  431. inc(OutCnt,AsmOutSize);
  432. inc(AsmSize,AsmOutSize);
  433. AsmFlush;
  434. inc(StartIndex,AsmOutSize);
  435. dec(ToWrite,AsmOutSize);
  436. end;
  437. Move(s[StartIndex],OutBuf[OutCnt],ToWrite);
  438. inc(OutCnt,ToWrite);
  439. inc(AsmSize,ToWrite);
  440. end;
  441. procedure TExternalAssembler.AsmWriteLn(const c: char);
  442. begin
  443. AsmWrite(c);
  444. AsmLn;
  445. end;
  446. Procedure TExternalAssembler.AsmWriteLn(const s:string);
  447. begin
  448. AsmWrite(s);
  449. AsmLn;
  450. end;
  451. Procedure TExternalAssembler.AsmWriteLn(const s: ansistring);
  452. begin
  453. AsmWrite(s);
  454. AsmLn;
  455. end;
  456. Procedure TExternalAssembler.AsmWritePChar(p:pchar);
  457. var
  458. i,j : longint;
  459. begin
  460. i:=StrLen(p);
  461. j:=i;
  462. while j>0 do
  463. begin
  464. i:=min(j,AsmOutSize);
  465. if OutCnt+i>=AsmOutSize then
  466. AsmFlush;
  467. Move(p[0],OutBuf[OutCnt],i);
  468. inc(OutCnt,i);
  469. inc(AsmSize,i);
  470. dec(j,i);
  471. p:=pchar(@p[i]);
  472. end;
  473. end;
  474. Procedure TExternalAssembler.AsmLn;
  475. begin
  476. if OutCnt>=AsmOutSize-2 then
  477. AsmFlush;
  478. if (cs_link_on_target in current_settings.globalswitches) then
  479. begin
  480. OutBuf[OutCnt]:=target_info.newline[1];
  481. inc(OutCnt);
  482. inc(AsmSize);
  483. if length(target_info.newline)>1 then
  484. begin
  485. OutBuf[OutCnt]:=target_info.newline[2];
  486. inc(OutCnt);
  487. inc(AsmSize);
  488. end;
  489. end
  490. else
  491. begin
  492. OutBuf[OutCnt]:=source_info.newline[1];
  493. inc(OutCnt);
  494. inc(AsmSize);
  495. if length(source_info.newline)>1 then
  496. begin
  497. OutBuf[OutCnt]:=source_info.newline[2];
  498. inc(OutCnt);
  499. inc(AsmSize);
  500. end;
  501. end;
  502. end;
  503. function TExternalAssembler.MakeCmdLine: TCmdStr;
  504. begin
  505. result:=target_asm.asmcmd;
  506. { for Xcode 7.x and later }
  507. if MacOSXVersionMin<>'' then
  508. Replace(result,'$DARWINVERSION','-mmacosx-version-min='+MacOSXVersionMin)
  509. else if iPhoneOSVersionMin<>'' then
  510. Replace(result,'$DARWINVERSION','-miphoneos-version-min='+iPhoneOSVersionMin)
  511. else
  512. Replace(result,'$DARWINVERSION','');
  513. {$ifdef arm}
  514. if (target_info.system=system_arm_darwin) then
  515. Replace(result,'$ARCH',lower(cputypestr[current_settings.cputype]));
  516. {$endif arm}
  517. if (cs_link_on_target in current_settings.globalswitches) then
  518. begin
  519. Replace(result,'$ASM',maybequoted(ScriptFixFileName(AsmFileName)));
  520. Replace(result,'$OBJ',maybequoted(ScriptFixFileName(ObjFileName)));
  521. end
  522. else
  523. begin
  524. {$ifdef hasunix}
  525. if DoPipe then
  526. if target_asm.id<>as_clang then
  527. Replace(result,'$ASM','')
  528. else
  529. Replace(result,'$ASM','-')
  530. else
  531. {$endif}
  532. Replace(result,'$ASM',maybequoted(AsmFileName));
  533. Replace(result,'$OBJ',maybequoted(ObjFileName));
  534. end;
  535. if (cs_create_pic in current_settings.moduleswitches) then
  536. Replace(result,'$PIC','-KPIC')
  537. else
  538. Replace(result,'$PIC','');
  539. if (cs_asm_source in current_settings.globalswitches) then
  540. Replace(result,'$NOWARN','')
  541. else
  542. Replace(result,'$NOWARN','-W');
  543. Replace(result,'$EXTRAOPT',asmextraopt);
  544. end;
  545. procedure TExternalAssembler.AsmCreate(Aplace:tcutplace);
  546. {$ifdef hasamiga}
  547. var
  548. tempFileName: TPathStr;
  549. {$endif}
  550. begin
  551. if SmartAsm then
  552. NextSmartName(Aplace);
  553. {$ifdef hasamiga}
  554. { on Amiga/MorphOS try to redirect .s files to the T: assign, which is
  555. for temp files, and usually (default setting) located in the RAM: drive.
  556. This highly improves assembling speed for complex projects like the
  557. compiler itself, especially on hardware with slow disk I/O.
  558. Consider this as a poor man's pipe on Amiga, because real pipe handling
  559. would be much more complex and error prone to implement. (KB) }
  560. if (([cs_asm_extern,cs_asm_leave,cs_link_on_target] * current_settings.globalswitches) = []) then
  561. begin
  562. { try to have an unique name for the .s file }
  563. tempFileName:=HexStr(GetProcessID shr 4,7)+ExtractFileName(AsmFileName);
  564. {$ifndef morphos}
  565. { old Amiga RAM: handler only allows filenames up to 30 char }
  566. if Length(tempFileName) < 30 then
  567. {$endif}
  568. AsmFileName:='T:'+tempFileName;
  569. end;
  570. {$endif}
  571. {$ifdef hasunix}
  572. if DoPipe then
  573. begin
  574. if SmartAsm then
  575. begin
  576. if (SmartFilesCount<=1) then
  577. Message1(exec_i_assembling_smart,name);
  578. end
  579. else
  580. Message1(exec_i_assembling_pipe,AsmFileName);
  581. POpen(outfile,maybequoted(FindAssembler)+' '+MakeCmdLine,'W');
  582. end
  583. else
  584. {$endif}
  585. begin
  586. Assign(outfile,AsmFileName);
  587. {$push} {$I-}
  588. Rewrite(outfile,1);
  589. {$pop}
  590. if ioresult<>0 then
  591. begin
  592. ioerror:=true;
  593. Message1(exec_d_cant_create_asmfile,AsmFileName);
  594. end;
  595. end;
  596. outcnt:=0;
  597. AsmSize:=0;
  598. AsmStartSize:=0;
  599. end;
  600. procedure TExternalAssembler.AsmClose;
  601. var
  602. f : file;
  603. FileAge : longint;
  604. begin
  605. AsmFlush;
  606. {$ifdef hasunix}
  607. if DoPipe then
  608. begin
  609. if PClose(outfile) <> 0 then
  610. GenerateError;
  611. end
  612. else
  613. {$endif}
  614. begin
  615. {Touch Assembler time to ppu time is there is a ppufilename}
  616. if ppufilename<>'' then
  617. begin
  618. Assign(f,ppufilename);
  619. {$push} {$I-}
  620. reset(f,1);
  621. {$pop}
  622. if ioresult=0 then
  623. begin
  624. FileAge := FileGetDate(GetFileHandle(f));
  625. close(f);
  626. reset(outfile,1);
  627. FileSetDate(GetFileHandle(outFile),FileAge);
  628. end;
  629. end;
  630. close(outfile);
  631. end;
  632. end;
  633. procedure TExternalAssembler.WriteSourceLine(hp: tailineinfo);
  634. var
  635. module : tmodule;
  636. begin
  637. { load infile }
  638. if (lastfileinfo.moduleindex<>hp.fileinfo.moduleindex) or
  639. (lastfileinfo.fileindex<>hp.fileinfo.fileindex) then
  640. begin
  641. { in case of a generic the module can be different }
  642. if current_module.unit_index=hp.fileinfo.moduleindex then
  643. module:=current_module
  644. else
  645. module:=get_module(hp.fileinfo.moduleindex);
  646. { during the compilation of the system unit there are cases when
  647. the fileinfo contains just zeros => invalid }
  648. if assigned(module) then
  649. infile:=module.sourcefiles.get_file(hp.fileinfo.fileindex)
  650. else
  651. infile:=nil;
  652. if assigned(infile) then
  653. begin
  654. { open only if needed !! }
  655. if (cs_asm_source in current_settings.globalswitches) then
  656. infile.open;
  657. end;
  658. { avoid unnecessary reopens of the same file !! }
  659. lastfileinfo.fileindex:=hp.fileinfo.fileindex;
  660. lastfileinfo.moduleindex:=hp.fileinfo.moduleindex;
  661. { be sure to change line !! }
  662. lastfileinfo.line:=-1;
  663. end;
  664. { write source }
  665. if (cs_asm_source in current_settings.globalswitches) and
  666. assigned(infile) then
  667. begin
  668. if (infile<>lastinfile) then
  669. begin
  670. AsmWriteLn(target_asm.comment+'['+infile.name+']');
  671. if assigned(lastinfile) then
  672. lastinfile.close;
  673. end;
  674. if (hp.fileinfo.line<>lastfileinfo.line) and
  675. (hp.fileinfo.line<infile.maxlinebuf) then
  676. begin
  677. if (hp.fileinfo.line<>0) and
  678. (infile.linebuf^[hp.fileinfo.line]>=0) then
  679. AsmWriteLn(target_asm.comment+'['+tostr(hp.fileinfo.line)+'] '+
  680. fixline(infile.GetLineStr(hp.fileinfo.line)));
  681. { set it to a negative value !
  682. to make that is has been read already !! PM }
  683. if (infile.linebuf^[hp.fileinfo.line]>=0) then
  684. infile.linebuf^[hp.fileinfo.line]:=-infile.linebuf^[hp.fileinfo.line]-1;
  685. end;
  686. end;
  687. lastfileinfo:=hp.fileinfo;
  688. lastinfile:=infile;
  689. end;
  690. procedure TExternalAssembler.WriteTempalloc(hp: tai_tempalloc);
  691. begin
  692. {$ifdef EXTDEBUG}
  693. if assigned(hp.problem) then
  694. AsmWriteLn(target_asm.comment+'Temp '+tostr(hp.temppos)+','+
  695. tostr(hp.tempsize)+' '+hp.problem^)
  696. else
  697. {$endif EXTDEBUG}
  698. AsmWriteLn(target_asm.comment+'Temp '+tostr(hp.temppos)+','+
  699. tostr(hp.tempsize)+' '+tempallocstr[hp.allocation]);
  700. end;
  701. procedure TExternalAssembler.WriteTree(p:TAsmList);
  702. begin
  703. end;
  704. procedure TExternalAssembler.WriteAsmList;
  705. begin
  706. end;
  707. procedure TExternalAssembler.MakeObject;
  708. begin
  709. AsmCreate(cut_normal);
  710. FillChar(lastfileinfo, sizeof(lastfileinfo), 0);
  711. lastfileinfo.line := -1;
  712. lastinfile := nil;
  713. lastsectype := sec_none;
  714. WriteAsmList;
  715. AsmClose;
  716. if not(ioerror) then
  717. DoAssemble;
  718. end;
  719. {*****************************************************************************
  720. TInternalAssembler
  721. *****************************************************************************}
  722. constructor TInternalAssembler.create(smart:boolean);
  723. begin
  724. inherited create(smart);
  725. ObjOutput:=nil;
  726. ObjData:=nil;
  727. SmartAsm:=smart;
  728. end;
  729. destructor TInternalAssembler.destroy;
  730. begin
  731. if assigned(ObjData) then
  732. ObjData.free;
  733. if assigned(ObjOutput) then
  734. ObjOutput.free;
  735. end;
  736. procedure TInternalAssembler.WriteStab(p:pchar);
  737. function consumecomma(var p:pchar):boolean;
  738. begin
  739. while (p^=' ') do
  740. inc(p);
  741. result:=(p^=',');
  742. inc(p);
  743. end;
  744. function consumenumber(var p:pchar;out value:longint):boolean;
  745. var
  746. hs : string;
  747. len,
  748. code : integer;
  749. begin
  750. value:=0;
  751. while (p^=' ') do
  752. inc(p);
  753. len:=0;
  754. while (p^ in ['0'..'9']) do
  755. begin
  756. inc(len);
  757. hs[len]:=p^;
  758. inc(p);
  759. end;
  760. if len>0 then
  761. begin
  762. hs[0]:=chr(len);
  763. val(hs,value,code);
  764. end
  765. else
  766. code:=-1;
  767. result:=(code=0);
  768. end;
  769. function consumeoffset(var p:pchar;out relocsym:tobjsymbol;out value:longint):boolean;
  770. var
  771. hs : string;
  772. len,
  773. code : integer;
  774. pstart : pchar;
  775. sym : tobjsymbol;
  776. exprvalue : longint;
  777. gotmin,
  778. have_first_symbol,
  779. have_second_symbol,
  780. dosub : boolean;
  781. begin
  782. result:=false;
  783. value:=0;
  784. relocsym:=nil;
  785. gotmin:=false;
  786. have_first_symbol:=false;
  787. have_second_symbol:=false;
  788. repeat
  789. dosub:=false;
  790. exprvalue:=0;
  791. if gotmin then
  792. begin
  793. dosub:=true;
  794. gotmin:=false;
  795. end;
  796. while (p^=' ') do
  797. inc(p);
  798. case p^ of
  799. #0 :
  800. break;
  801. ' ' :
  802. inc(p);
  803. '0'..'9' :
  804. begin
  805. len:=0;
  806. while (p^ in ['0'..'9']) do
  807. begin
  808. inc(len);
  809. hs[len]:=p^;
  810. inc(p);
  811. end;
  812. hs[0]:=chr(len);
  813. val(hs,exprvalue,code);
  814. if code<>0 then
  815. internalerror(200702251);
  816. end;
  817. '.','_',
  818. 'A'..'Z',
  819. 'a'..'z' :
  820. begin
  821. pstart:=p;
  822. while not(p^ in [#0,' ','-','+']) do
  823. inc(p);
  824. len:=p-pstart;
  825. if len>255 then
  826. internalerror(200509187);
  827. move(pstart^,hs[1],len);
  828. hs[0]:=chr(len);
  829. sym:=objdata.symbolref(hs);
  830. { Second symbol? }
  831. if assigned(relocsym) then
  832. begin
  833. if have_second_symbol then
  834. internalerror(2007032201);
  835. have_second_symbol:=true;
  836. if not have_first_symbol then
  837. internalerror(2007032202);
  838. { second symbol should substracted to first }
  839. if not dosub then
  840. internalerror(2007032203);
  841. if (relocsym.objsection<>sym.objsection) then
  842. internalerror(2005091810);
  843. exprvalue:=relocsym.address-sym.address;
  844. relocsym:=nil;
  845. dosub:=false;
  846. end
  847. else
  848. begin
  849. relocsym:=sym;
  850. if assigned(sym.objsection) then
  851. begin
  852. { first symbol should be + }
  853. if not have_first_symbol and dosub then
  854. internalerror(2007032204);
  855. have_first_symbol:=true;
  856. end;
  857. end;
  858. end;
  859. '+' :
  860. begin
  861. { nothing, by default addition is done }
  862. inc(p);
  863. end;
  864. '-' :
  865. begin
  866. gotmin:=true;
  867. inc(p);
  868. end;
  869. else
  870. internalerror(200509189);
  871. end;
  872. if dosub then
  873. dec(value,exprvalue)
  874. else
  875. inc(value,exprvalue);
  876. until false;
  877. result:=true;
  878. end;
  879. var
  880. stabstrlen,
  881. ofs,
  882. nline,
  883. nidx,
  884. nother,
  885. i : longint;
  886. stab : TObjStabEntry;
  887. relocsym : TObjSymbol;
  888. pstr,
  889. pcurr,
  890. pendquote : pchar;
  891. oldsec : TObjSection;
  892. begin
  893. pcurr:=nil;
  894. pstr:=nil;
  895. pendquote:=nil;
  896. relocsym:=nil;
  897. ofs:=0;
  898. { Parse string part }
  899. if (p[0]='"') then
  900. begin
  901. pstr:=@p[1];
  902. { Ignore \" inside the string }
  903. i:=1;
  904. while not((p[i]='"') and (p[i-1]<>'\')) and
  905. (p[i]<>#0) do
  906. inc(i);
  907. pendquote:=@p[i];
  908. pendquote^:=#0;
  909. pcurr:=@p[i+1];
  910. if not consumecomma(pcurr) then
  911. internalerror(200509181);
  912. end
  913. else
  914. pcurr:=p;
  915. { When in pass 1 then only alloc and leave }
  916. if ObjData.currpass=1 then
  917. begin
  918. ObjData.StabsSec.Alloc(sizeof(TObjStabEntry));
  919. if assigned(pstr) and (pstr[0]<>#0) then
  920. ObjData.StabStrSec.Alloc(strlen(pstr)+1);
  921. end
  922. else
  923. begin
  924. { Stabs format: nidx,nother,nline[,offset] }
  925. if not consumenumber(pcurr,nidx) then
  926. internalerror(200509182);
  927. if not consumecomma(pcurr) then
  928. internalerror(200509183);
  929. if not consumenumber(pcurr,nother) then
  930. internalerror(200509184);
  931. if not consumecomma(pcurr) then
  932. internalerror(200509185);
  933. if not consumenumber(pcurr,nline) then
  934. internalerror(200509186);
  935. if consumecomma(pcurr) then
  936. consumeoffset(pcurr,relocsym,ofs);
  937. { Generate stab entry }
  938. if assigned(pstr) and (pstr[0]<>#0) then
  939. begin
  940. stabstrlen:=strlen(pstr);
  941. {$ifdef optimizestabs}
  942. StabStrEntry:=nil;
  943. if (nidx=N_SourceFile) or (nidx=N_IncludeFile) then
  944. begin
  945. hs:=strpas(pstr);
  946. StabstrEntry:=StabStrDict.Find(hs);
  947. if not assigned(StabstrEntry) then
  948. begin
  949. StabstrEntry:=TStabStrEntry.Create(hs);
  950. StabstrEntry:=StabStrSec.Size;
  951. StabStrDict.Insert(StabstrEntry);
  952. { generate new stab }
  953. StabstrEntry:=nil;
  954. end;
  955. end;
  956. if assigned(StabstrEntry) then
  957. stab.strpos:=StabstrEntry.strpos
  958. else
  959. {$endif optimizestabs}
  960. begin
  961. stab.strpos:=ObjData.StabStrSec.Size;
  962. ObjData.StabStrSec.write(pstr^,stabstrlen+1);
  963. end;
  964. end
  965. else
  966. stab.strpos:=0;
  967. stab.ntype:=byte(nidx);
  968. stab.ndesc:=word(nline);
  969. stab.nother:=byte(nother);
  970. stab.nvalue:=ofs;
  971. { Write the stab first without the value field. Then
  972. write a the value field with relocation }
  973. oldsec:=ObjData.CurrObjSec;
  974. ObjData.SetSection(ObjData.StabsSec);
  975. ObjData.Writebytes(stab,sizeof(TObjStabEntry)-4);
  976. ObjData.Writereloc(stab.nvalue,4,relocsym,RELOC_ABSOLUTE32);
  977. ObjData.setsection(oldsec);
  978. end;
  979. if assigned(pendquote) then
  980. pendquote^:='"';
  981. end;
  982. function TInternalAssembler.MaybeNextList(var hp:Tai):boolean;
  983. begin
  984. { maybe end of list }
  985. while not assigned(hp) do
  986. begin
  987. if currlistidx<lists then
  988. begin
  989. inc(currlistidx);
  990. currlist:=list[currlistidx];
  991. hp:=Tai(currList.first);
  992. end
  993. else
  994. begin
  995. MaybeNextList:=false;
  996. exit;
  997. end;
  998. end;
  999. MaybeNextList:=true;
  1000. end;
  1001. function TInternalAssembler.SetIndirectToSymbol(hp: Tai; const indirectname: string): Boolean;
  1002. var
  1003. objsym : TObjSymbol;
  1004. indsym : TObjSymbol;
  1005. begin
  1006. Result:=
  1007. Assigned(hp) and
  1008. (hp.typ=ait_symbol);
  1009. if not Result then
  1010. Exit;
  1011. objsym:=Objdata.SymbolRef(tai_symbol(hp).sym);
  1012. objsym.size:=0;
  1013. indsym := TObjSymbol(ObjData.ObjSymbolList.Find(indirectname));
  1014. if not Assigned(indsym) then
  1015. begin
  1016. { it's possible that indirect symbol is not present in the list,
  1017. so we must create it as undefined }
  1018. indsym:=TObjSymbol.Create(ObjData.ObjSymbolList, indirectname);
  1019. indsym.typ:=AT_NONE;
  1020. indsym.bind:=AB_NONE;
  1021. end;
  1022. objsym.indsymbol:=indsym;
  1023. Result:=true;
  1024. end;
  1025. function TInternalAssembler.TreePass0(hp:Tai):Tai;
  1026. var
  1027. objsym,
  1028. objsymend : TObjSymbol;
  1029. begin
  1030. while assigned(hp) do
  1031. begin
  1032. case hp.typ of
  1033. ait_align :
  1034. begin
  1035. if tai_align_abstract(hp).aligntype>1 then
  1036. begin
  1037. { always use the maximum fillsize in this pass to avoid possible
  1038. short jumps to become out of range }
  1039. Tai_align_abstract(hp).fillsize:=Tai_align_abstract(hp).aligntype;
  1040. ObjData.alloc(Tai_align_abstract(hp).fillsize);
  1041. { may need to increase alignment of section }
  1042. if tai_align_abstract(hp).aligntype>ObjData.CurrObjSec.secalign then
  1043. ObjData.CurrObjSec.secalign:=tai_align_abstract(hp).aligntype;
  1044. end
  1045. else
  1046. Tai_align_abstract(hp).fillsize:=0;
  1047. end;
  1048. ait_datablock :
  1049. begin
  1050. {$ifdef USE_COMM_IN_BSS}
  1051. if writingpackages and
  1052. Tai_datablock(hp).is_global then
  1053. ObjData.SymbolDefine(Tai_datablock(hp).sym)
  1054. else
  1055. {$endif USE_COMM_IN_BSS}
  1056. begin
  1057. ObjData.allocalign(used_align(size_2_align(Tai_datablock(hp).size),0,ObjData.CurrObjSec.secalign));
  1058. ObjData.SymbolDefine(Tai_datablock(hp).sym);
  1059. ObjData.alloc(Tai_datablock(hp).size);
  1060. end;
  1061. end;
  1062. ait_real_80bit :
  1063. ObjData.alloc(tai_real_80bit(hp).savesize);
  1064. ait_real_64bit :
  1065. ObjData.alloc(8);
  1066. ait_real_32bit :
  1067. ObjData.alloc(4);
  1068. ait_comp_64bit :
  1069. ObjData.alloc(8);
  1070. ait_const:
  1071. begin
  1072. { if symbols are provided we can calculate the value for relative symbols.
  1073. This is required for length calculation of leb128 constants }
  1074. if assigned(tai_const(hp).sym) then
  1075. begin
  1076. objsym:=Objdata.SymbolRef(tai_const(hp).sym);
  1077. { objsym already defined and there is endsym? }
  1078. if assigned(objsym.objsection) and assigned(tai_const(hp).endsym) then
  1079. begin
  1080. objsymend:=Objdata.SymbolRef(tai_const(hp).endsym);
  1081. { objsymend already defined? }
  1082. if assigned(objsymend.objsection) then
  1083. begin
  1084. if objsymend.objsection<>objsym.objsection then
  1085. begin
  1086. { leb128 relative constants are not relocatable, but other types are,
  1087. given that objsym belongs to the current section. }
  1088. if (Tai_const(hp).consttype in [aitconst_uleb128bit,aitconst_sleb128bit]) or
  1089. (objsym.objsection<>ObjData.CurrObjSec) then
  1090. InternalError(200404124);
  1091. end
  1092. else
  1093. Tai_const(hp).value:=objsymend.address-objsym.address+Tai_const(hp).symofs;
  1094. end;
  1095. end;
  1096. end;
  1097. ObjData.alloc(tai_const(hp).size);
  1098. end;
  1099. ait_directive:
  1100. begin
  1101. case tai_directive(hp).directive of
  1102. asd_indirect_symbol:
  1103. { handled in TreePass1 }
  1104. ;
  1105. asd_lazy_reference:
  1106. begin
  1107. if tai_directive(hp).name='' then
  1108. Internalerror(2009112101);
  1109. objsym:=ObjData.symbolref(tai_directive(hp).name);
  1110. objsym.bind:=AB_LAZY;
  1111. end;
  1112. asd_reference:
  1113. { ignore for now, but should be added}
  1114. ;
  1115. else
  1116. internalerror(2010011101);
  1117. end;
  1118. end;
  1119. ait_section:
  1120. begin
  1121. ObjData.CreateSection(Tai_section(hp).sectype,Tai_section(hp).name^,Tai_section(hp).secorder);
  1122. Tai_section(hp).sec:=ObjData.CurrObjSec;
  1123. end;
  1124. ait_symbol :
  1125. begin
  1126. { needs extra support in the internal assembler }
  1127. { the value is just ignored }
  1128. {if tai_symbol(hp).has_value then
  1129. internalerror(2009090804); ;}
  1130. ObjData.SymbolDefine(Tai_symbol(hp).sym);
  1131. end;
  1132. ait_label :
  1133. ObjData.SymbolDefine(Tai_label(hp).labsym);
  1134. ait_string :
  1135. ObjData.alloc(Tai_string(hp).len);
  1136. ait_instruction :
  1137. begin
  1138. { reset instructions which could change in pass 2 }
  1139. Taicpu(hp).resetpass2;
  1140. ObjData.alloc(Taicpu(hp).Pass1(ObjData));
  1141. end;
  1142. ait_cutobject :
  1143. if SmartAsm then
  1144. break;
  1145. end;
  1146. hp:=Tai(hp.next);
  1147. end;
  1148. TreePass0:=hp;
  1149. end;
  1150. function TInternalAssembler.TreePass1(hp:Tai):Tai;
  1151. var
  1152. objsym,
  1153. objsymend : TObjSymbol;
  1154. begin
  1155. while assigned(hp) do
  1156. begin
  1157. case hp.typ of
  1158. ait_align :
  1159. begin
  1160. if tai_align_abstract(hp).aligntype>1 then
  1161. begin
  1162. { here we must determine the fillsize which is used in pass2 }
  1163. Tai_align_abstract(hp).fillsize:=align(ObjData.CurrObjSec.Size,Tai_align_abstract(hp).aligntype)-
  1164. ObjData.CurrObjSec.Size;
  1165. ObjData.alloc(Tai_align_abstract(hp).fillsize);
  1166. end;
  1167. end;
  1168. ait_datablock :
  1169. begin
  1170. if (oso_data in ObjData.CurrObjSec.secoptions) then
  1171. Message(asmw_e_alloc_data_only_in_bss);
  1172. {$ifdef USE_COMM_IN_BSS}
  1173. if writingpackages and
  1174. Tai_datablock(hp).is_global then
  1175. begin
  1176. objsym:=ObjData.SymbolDefine(Tai_datablock(hp).sym);
  1177. objsym.size:=Tai_datablock(hp).size;
  1178. objsym.bind:=AB_COMMON;
  1179. objsym.alignment:=needtowritealignmentalsoforELF;
  1180. end
  1181. else
  1182. {$endif USE_COMM_IN_BSS}
  1183. begin
  1184. ObjData.allocalign(used_align(size_2_align(Tai_datablock(hp).size),0,ObjData.CurrObjSec.secalign));
  1185. objsym:=ObjData.SymbolDefine(Tai_datablock(hp).sym);
  1186. objsym.size:=Tai_datablock(hp).size;
  1187. ObjData.alloc(Tai_datablock(hp).size);
  1188. end;
  1189. end;
  1190. ait_real_80bit :
  1191. ObjData.alloc(tai_real_80bit(hp).savesize);
  1192. ait_real_64bit :
  1193. ObjData.alloc(8);
  1194. ait_real_32bit :
  1195. ObjData.alloc(4);
  1196. ait_comp_64bit :
  1197. ObjData.alloc(8);
  1198. ait_const:
  1199. begin
  1200. { Recalculate relative symbols }
  1201. if assigned(tai_const(hp).sym) and
  1202. assigned(tai_const(hp).endsym) then
  1203. begin
  1204. objsym:=Objdata.SymbolRef(tai_const(hp).sym);
  1205. objsymend:=Objdata.SymbolRef(tai_const(hp).endsym);
  1206. if objsymend.objsection<>objsym.objsection then
  1207. begin
  1208. if (Tai_const(hp).consttype in [aitconst_uleb128bit,aitconst_sleb128bit]) or
  1209. (objsym.objsection<>ObjData.CurrObjSec) then
  1210. internalerror(200905042);
  1211. end
  1212. else
  1213. Tai_const(hp).value:=objsymend.address-objsym.address+Tai_const(hp).symofs;
  1214. end;
  1215. ObjData.alloc(tai_const(hp).size);
  1216. end;
  1217. ait_section:
  1218. begin
  1219. { use cached value }
  1220. ObjData.setsection(Tai_section(hp).sec);
  1221. end;
  1222. ait_stab :
  1223. begin
  1224. if assigned(Tai_stab(hp).str) then
  1225. WriteStab(Tai_stab(hp).str);
  1226. end;
  1227. ait_symbol :
  1228. ObjData.SymbolDefine(Tai_symbol(hp).sym);
  1229. ait_symbol_end :
  1230. begin
  1231. objsym:=ObjData.SymbolRef(Tai_symbol_end(hp).sym);
  1232. objsym.size:=ObjData.CurrObjSec.Size-objsym.offset;
  1233. end;
  1234. ait_label :
  1235. ObjData.SymbolDefine(Tai_label(hp).labsym);
  1236. ait_string :
  1237. ObjData.alloc(Tai_string(hp).len);
  1238. ait_instruction :
  1239. ObjData.alloc(Taicpu(hp).Pass1(ObjData));
  1240. ait_cutobject :
  1241. if SmartAsm then
  1242. break;
  1243. ait_directive :
  1244. begin
  1245. case tai_directive(hp).directive of
  1246. asd_indirect_symbol:
  1247. if tai_directive(hp).name='' then
  1248. Internalerror(2009101103)
  1249. else if not SetIndirectToSymbol(Tai(hp.Previous), tai_directive(hp).name) then
  1250. Internalerror(2009101102);
  1251. asd_lazy_reference:
  1252. { handled in TreePass0 }
  1253. ;
  1254. asd_reference:
  1255. { ignore for now, but should be added}
  1256. ;
  1257. else
  1258. internalerror(2010011102);
  1259. end;
  1260. end;
  1261. end;
  1262. hp:=Tai(hp.next);
  1263. end;
  1264. TreePass1:=hp;
  1265. end;
  1266. function TInternalAssembler.TreePass2(hp:Tai):Tai;
  1267. var
  1268. fillbuffer : tfillbuffer;
  1269. {$ifdef x86}
  1270. co : comp;
  1271. {$endif x86}
  1272. leblen : byte;
  1273. lebbuf : array[0..63] of byte;
  1274. objsym,
  1275. objsymend : TObjSymbol;
  1276. zerobuf : array[0..63] of byte;
  1277. relative_reloc: boolean;
  1278. begin
  1279. fillchar(zerobuf,sizeof(zerobuf),0);
  1280. fillchar(objsym,sizeof(objsym),0);
  1281. fillchar(objsymend,sizeof(objsymend),0);
  1282. { main loop }
  1283. while assigned(hp) do
  1284. begin
  1285. case hp.typ of
  1286. ait_align :
  1287. begin
  1288. if tai_align_abstract(hp).aligntype>ObjData.CurrObjSec.secalign then
  1289. InternalError(2012072301);
  1290. if oso_data in ObjData.CurrObjSec.secoptions then
  1291. ObjData.writebytes(Tai_align_abstract(hp).calculatefillbuf(fillbuffer,oso_executable in ObjData.CurrObjSec.secoptions)^,
  1292. Tai_align_abstract(hp).fillsize)
  1293. else
  1294. ObjData.alloc(Tai_align_abstract(hp).fillsize);
  1295. end;
  1296. ait_section :
  1297. begin
  1298. { use cached value }
  1299. ObjData.setsection(Tai_section(hp).sec);
  1300. end;
  1301. ait_symbol :
  1302. begin
  1303. ObjOutput.exportsymbol(ObjData.SymbolRef(Tai_symbol(hp).sym));
  1304. end;
  1305. ait_symbol_end :
  1306. begin
  1307. { recalculate size, as some preceding instructions
  1308. could have been changed to smaller size }
  1309. objsym:=ObjData.SymbolRef(Tai_symbol_end(hp).sym);
  1310. objsym.size:=ObjData.CurrObjSec.Size-objsym.offset;
  1311. end;
  1312. ait_datablock :
  1313. begin
  1314. ObjOutput.exportsymbol(ObjData.SymbolRef(Tai_datablock(hp).sym));
  1315. {$ifdef USE_COMM_IN_BSS}
  1316. if not(writingpackages and
  1317. Tai_datablock(hp).is_global) then
  1318. {$endif USE_COMM_IN_BSS}
  1319. begin
  1320. ObjData.allocalign(used_align(size_2_align(Tai_datablock(hp).size),0,ObjData.CurrObjSec.secalign));
  1321. ObjData.alloc(Tai_datablock(hp).size);
  1322. end;
  1323. end;
  1324. ait_real_80bit :
  1325. begin
  1326. ObjData.writebytes(Tai_real_80bit(hp).value,10);
  1327. ObjData.writebytes(zerobuf,Tai_real_80bit(hp).savesize-10);
  1328. end;
  1329. ait_real_64bit :
  1330. ObjData.writebytes(Tai_real_64bit(hp).value,8);
  1331. ait_real_32bit :
  1332. ObjData.writebytes(Tai_real_32bit(hp).value,4);
  1333. ait_comp_64bit :
  1334. begin
  1335. {$ifdef x86}
  1336. co:=comp(Tai_comp_64bit(hp).value);
  1337. ObjData.writebytes(co,8);
  1338. {$endif x86}
  1339. end;
  1340. ait_string :
  1341. ObjData.writebytes(Tai_string(hp).str^,Tai_string(hp).len);
  1342. ait_const :
  1343. begin
  1344. { Recalculate relative symbols, addresses of forward references
  1345. can be changed in treepass1 }
  1346. relative_reloc:=false;
  1347. if assigned(tai_const(hp).sym) and
  1348. assigned(tai_const(hp).endsym) then
  1349. begin
  1350. objsym:=Objdata.SymbolRef(tai_const(hp).sym);
  1351. objsymend:=Objdata.SymbolRef(tai_const(hp).endsym);
  1352. relative_reloc:=(objsym.objsection<>objsymend.objsection);
  1353. Tai_const(hp).value:=objsymend.address-objsym.address+Tai_const(hp).symofs;
  1354. end;
  1355. case tai_const(hp).consttype of
  1356. aitconst_64bit,
  1357. aitconst_32bit,
  1358. aitconst_16bit,
  1359. aitconst_64bit_unaligned,
  1360. aitconst_32bit_unaligned,
  1361. aitconst_16bit_unaligned,
  1362. aitconst_8bit :
  1363. begin
  1364. if assigned(tai_const(hp).sym) and
  1365. not assigned(tai_const(hp).endsym) then
  1366. ObjData.writereloc(Tai_const(hp).symofs,tai_const(hp).size,Objdata.SymbolRef(tai_const(hp).sym),RELOC_ABSOLUTE)
  1367. else if relative_reloc then
  1368. ObjData.writereloc(ObjData.CurrObjSec.size+tai_const(hp).size-objsym.address+tai_const(hp).symofs,tai_const(hp).size,objsymend,RELOC_RELATIVE)
  1369. else
  1370. ObjData.writebytes(Tai_const(hp).value,tai_const(hp).size);
  1371. end;
  1372. aitconst_rva_symbol :
  1373. begin
  1374. { PE32+? }
  1375. if target_info.system=system_x86_64_win64 then
  1376. ObjData.writereloc(Tai_const(hp).symofs,sizeof(longint),Objdata.SymbolRef(tai_const(hp).sym),RELOC_RVA)
  1377. else
  1378. ObjData.writereloc(Tai_const(hp).symofs,sizeof(pint),Objdata.SymbolRef(tai_const(hp).sym),RELOC_RVA);
  1379. end;
  1380. aitconst_secrel32_symbol :
  1381. begin
  1382. { Required for DWARF2 support under Windows }
  1383. ObjData.writereloc(Tai_const(hp).symofs,sizeof(longint),Objdata.SymbolRef(tai_const(hp).sym),RELOC_SECREL32);
  1384. end;
  1385. aitconst_gotoff_symbol:
  1386. ObjData.writereloc(Tai_const(hp).symofs,sizeof(longint),Objdata.SymbolRef(tai_const(hp).sym),RELOC_GOTOFF);
  1387. aitconst_uleb128bit,
  1388. aitconst_sleb128bit :
  1389. begin
  1390. if tai_const(hp).consttype=aitconst_uleb128bit then
  1391. leblen:=EncodeUleb128(qword(Tai_const(hp).value),lebbuf)
  1392. else
  1393. leblen:=EncodeSleb128(Tai_const(hp).value,lebbuf);
  1394. if leblen<>tai_const(hp).size then
  1395. internalerror(200709271);
  1396. ObjData.writebytes(lebbuf,leblen);
  1397. end;
  1398. aitconst_darwin_dwarf_delta32,
  1399. aitconst_darwin_dwarf_delta64:
  1400. ObjData.writebytes(Tai_const(hp).value,tai_const(hp).size);
  1401. else
  1402. internalerror(200603254);
  1403. end;
  1404. end;
  1405. ait_label :
  1406. begin
  1407. { exporting shouldn't be necessary as labels are local,
  1408. but it's better to be on the safe side (PFV) }
  1409. ObjOutput.exportsymbol(ObjData.SymbolRef(Tai_label(hp).labsym));
  1410. end;
  1411. ait_instruction :
  1412. Taicpu(hp).Pass2(ObjData);
  1413. ait_stab :
  1414. WriteStab(Tai_stab(hp).str);
  1415. ait_function_name,
  1416. ait_force_line : ;
  1417. ait_cutobject :
  1418. if SmartAsm then
  1419. break;
  1420. {$ifndef DISABLE_WIN64_SEH}
  1421. ait_seh_directive :
  1422. tai_seh_directive(hp).generate_code(objdata);
  1423. {$endif DISABLE_WIN64_SEH}
  1424. end;
  1425. hp:=Tai(hp.next);
  1426. end;
  1427. TreePass2:=hp;
  1428. end;
  1429. procedure TInternalAssembler.writetree;
  1430. label
  1431. doexit;
  1432. var
  1433. hp : Tai;
  1434. ObjWriter : TObjectWriter;
  1435. begin
  1436. ObjWriter:=TObjectwriter.create;
  1437. ObjOutput:=CObjOutput.Create(ObjWriter);
  1438. ObjData:=ObjOutput.newObjData(ObjFileName);
  1439. { Pass 0 }
  1440. ObjData.currpass:=0;
  1441. ObjData.createsection(sec_code);
  1442. ObjData.beforealloc;
  1443. { start with list 1 }
  1444. currlistidx:=1;
  1445. currlist:=list[currlistidx];
  1446. hp:=Tai(currList.first);
  1447. while assigned(hp) do
  1448. begin
  1449. hp:=TreePass0(hp);
  1450. MaybeNextList(hp);
  1451. end;
  1452. ObjData.afteralloc;
  1453. { leave if errors have occured }
  1454. if errorcount>0 then
  1455. goto doexit;
  1456. { Pass 1 }
  1457. ObjData.currpass:=1;
  1458. ObjData.resetsections;
  1459. ObjData.beforealloc;
  1460. ObjData.createsection(sec_code);
  1461. { start with list 1 }
  1462. currlistidx:=1;
  1463. currlist:=list[currlistidx];
  1464. hp:=Tai(currList.first);
  1465. while assigned(hp) do
  1466. begin
  1467. hp:=TreePass1(hp);
  1468. MaybeNextList(hp);
  1469. end;
  1470. ObjData.createsection(sec_code);
  1471. ObjData.afteralloc;
  1472. { leave if errors have occured }
  1473. if errorcount>0 then
  1474. goto doexit;
  1475. { Pass 2 }
  1476. ObjData.currpass:=2;
  1477. ObjData.resetsections;
  1478. ObjData.beforewrite;
  1479. ObjData.createsection(sec_code);
  1480. { start with list 1 }
  1481. currlistidx:=1;
  1482. currlist:=list[currlistidx];
  1483. hp:=Tai(currList.first);
  1484. while assigned(hp) do
  1485. begin
  1486. hp:=TreePass2(hp);
  1487. MaybeNextList(hp);
  1488. end;
  1489. ObjData.createsection(sec_code);
  1490. ObjData.afterwrite;
  1491. { don't write the .o file if errors have occured }
  1492. if errorcount=0 then
  1493. begin
  1494. { write objectfile }
  1495. ObjOutput.startobjectfile(ObjFileName);
  1496. ObjOutput.writeobjectfile(ObjData);
  1497. end;
  1498. doexit:
  1499. { Cleanup }
  1500. ObjData.free;
  1501. ObjData:=nil;
  1502. ObjWriter.free;
  1503. end;
  1504. procedure TInternalAssembler.writetreesmart;
  1505. var
  1506. hp : Tai;
  1507. startsectype : TAsmSectiontype;
  1508. place: tcutplace;
  1509. ObjWriter : TObjectWriter;
  1510. begin
  1511. if not(cs_asm_leave in current_settings.globalswitches) then
  1512. ObjWriter:=TARObjectWriter.create(current_module.staticlibfilename)
  1513. else
  1514. ObjWriter:=TObjectwriter.create;
  1515. NextSmartName(cut_normal);
  1516. ObjOutput:=CObjOutput.Create(ObjWriter);
  1517. startsectype:=sec_code;
  1518. { start with list 1 }
  1519. currlistidx:=1;
  1520. currlist:=list[currlistidx];
  1521. hp:=Tai(currList.first);
  1522. while assigned(hp) do
  1523. begin
  1524. ObjData:=ObjOutput.newObjData(ObjFileName);
  1525. { Pass 0 }
  1526. ObjData.currpass:=0;
  1527. ObjData.resetsections;
  1528. ObjData.beforealloc;
  1529. ObjData.createsection(startsectype);
  1530. TreePass0(hp);
  1531. ObjData.afteralloc;
  1532. { leave if errors have occured }
  1533. if errorcount>0 then
  1534. break;
  1535. { Pass 1 }
  1536. ObjData.currpass:=1;
  1537. ObjData.resetsections;
  1538. ObjData.beforealloc;
  1539. ObjData.createsection(startsectype);
  1540. TreePass1(hp);
  1541. ObjData.afteralloc;
  1542. { leave if errors have occured }
  1543. if errorcount>0 then
  1544. break;
  1545. { Pass 2 }
  1546. ObjData.currpass:=2;
  1547. ObjOutput.startobjectfile(ObjFileName);
  1548. ObjData.resetsections;
  1549. ObjData.beforewrite;
  1550. ObjData.createsection(startsectype);
  1551. hp:=TreePass2(hp);
  1552. ObjData.afterwrite;
  1553. { leave if errors have occured }
  1554. if errorcount>0 then
  1555. break;
  1556. { write the current objectfile }
  1557. ObjOutput.writeobjectfile(ObjData);
  1558. ObjData.free;
  1559. ObjData:=nil;
  1560. { end of lists? }
  1561. if not MaybeNextList(hp) then
  1562. break;
  1563. { we will start a new objectfile so reset everything }
  1564. { The place can still change in the next while loop, so don't init }
  1565. { the writer yet (JM) }
  1566. if (hp.typ=ait_cutobject) then
  1567. place := Tai_cutobject(hp).place
  1568. else
  1569. place := cut_normal;
  1570. { avoid empty files }
  1571. startsectype:=sec_code;
  1572. while assigned(hp) and
  1573. (Tai(hp).typ in [ait_marker,ait_comment,ait_section,ait_cutobject]) do
  1574. begin
  1575. if Tai(hp).typ=ait_section then
  1576. startsectype:=Tai_section(hp).sectype;
  1577. if (Tai(hp).typ=ait_cutobject) then
  1578. place:=Tai_cutobject(hp).place;
  1579. hp:=Tai(hp.next);
  1580. end;
  1581. if not MaybeNextList(hp) then
  1582. break;
  1583. { start next objectfile }
  1584. NextSmartName(place);
  1585. end;
  1586. ObjData.free;
  1587. ObjData:=nil;
  1588. ObjWriter.free;
  1589. end;
  1590. procedure TInternalAssembler.MakeObject;
  1591. var to_do:set of TasmlistType;
  1592. i:TasmlistType;
  1593. procedure addlist(p:TAsmList);
  1594. begin
  1595. inc(lists);
  1596. list[lists]:=p;
  1597. end;
  1598. begin
  1599. to_do:=[low(Tasmlisttype)..high(Tasmlisttype)];
  1600. if usedeffileforexports then
  1601. exclude(to_do,al_exports);
  1602. if not(tf_section_threadvars in target_info.flags) then
  1603. exclude(to_do,al_threadvars);
  1604. for i:=low(TasmlistType) to high(TasmlistType) do
  1605. if (i in to_do) and (current_asmdata.asmlists[i]<>nil) and
  1606. (not current_asmdata.asmlists[i].empty) then
  1607. addlist(current_asmdata.asmlists[i]);
  1608. if SmartAsm then
  1609. writetreesmart
  1610. else
  1611. writetree;
  1612. end;
  1613. {*****************************************************************************
  1614. Generate Assembler Files Main Procedure
  1615. *****************************************************************************}
  1616. Procedure GenerateAsm(smart:boolean);
  1617. var
  1618. a : TAssembler;
  1619. begin
  1620. if not assigned(CAssembler[target_asm.id]) then
  1621. Message(asmw_f_assembler_output_not_supported);
  1622. a:=CAssembler[target_asm.id].Create(smart);
  1623. a.MakeObject;
  1624. a.Free;
  1625. end;
  1626. Procedure OnlyAsm;
  1627. var
  1628. a : TExternalAssembler;
  1629. begin
  1630. a:=TExternalAssembler.Create(false);
  1631. a.DoAssemble;
  1632. a.Free;
  1633. end;
  1634. {*****************************************************************************
  1635. Init/Done
  1636. *****************************************************************************}
  1637. procedure RegisterAssembler(const r:tasminfo;c:TAssemblerClass);
  1638. var
  1639. t : tasm;
  1640. begin
  1641. t:=r.id;
  1642. if assigned(asminfos[t]) then
  1643. writeln('Warning: Assembler is already registered!')
  1644. else
  1645. Getmem(asminfos[t],sizeof(tasminfo));
  1646. asminfos[t]^:=r;
  1647. CAssembler[t]:=c;
  1648. end;
  1649. end.