assemble.pas 76 KB

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