assemble.pas 62 KB

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