assemble.pas 59 KB

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