assemble.pas 75 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279
  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. public
  134. {# Returns the complete path and executable name of the assembler
  135. program.
  136. It first tries looking in the UTIL directory if specified,
  137. otherwise it searches in the free pascal binary directory, in
  138. the current working directory and then in the directories
  139. in the $PATH environment.}
  140. Function FindAssembler:string;
  141. {# Actually does the call to the assembler file. Returns false
  142. if the assembling of the file failed.}
  143. Function CallAssembler(const command:string; const para:TCmdStr):Boolean;
  144. Function DoAssemble:boolean;virtual;
  145. {# This routine should be overridden for each assembler, it is used
  146. to actually write the abstract assembler stream to file.}
  147. procedure WriteTree(p:TAsmList);virtual;
  148. {# This routine should be overridden for each assembler, it is used
  149. to actually write all the different abstract assembler streams
  150. by calling for each stream type, the @var(WriteTree) method.}
  151. procedure WriteAsmList;virtual;
  152. {# Constructs the command line for calling the assembler }
  153. function MakeCmdLine: TCmdStr; virtual;
  154. public
  155. Constructor Create(info: pasminfo; smart: boolean);override;
  156. Constructor CreateWithWriter(info: pasminfo; wr: TExternalAssemblerOutputFile; freewriter, smart: boolean);
  157. procedure MakeObject;override;
  158. destructor Destroy; override;
  159. property writer: TExternalAssemblerOutputFile read fwriter;
  160. end;
  161. TExternalAssemblerClass = class of TExternalAssembler;
  162. { TInternalAssembler }
  163. TInternalAssembler=class(TAssembler)
  164. private
  165. FCObjOutput : TObjOutputclass;
  166. FCInternalAr : TObjectWriterClass;
  167. { the aasmoutput lists that need to be processed }
  168. lists : byte;
  169. list : array[1..maxoutputlists] of TAsmList;
  170. { current processing }
  171. currlistidx : byte;
  172. currlist : TAsmList;
  173. procedure WriteStab(p:pchar);
  174. function MaybeNextList(var hp:Tai):boolean;
  175. function SetIndirectToSymbol(hp: Tai; const indirectname: string): Boolean;
  176. function TreePass0(hp:Tai):Tai;
  177. function TreePass1(hp:Tai):Tai;
  178. function TreePass2(hp:Tai):Tai;
  179. procedure writetree;
  180. procedure writetreesmart;
  181. protected
  182. ObjData : TObjData;
  183. ObjOutput : tObjOutput;
  184. property CObjOutput:TObjOutputclass read FCObjOutput write FCObjOutput;
  185. property CInternalAr : TObjectWriterClass read FCInternalAr write FCInternalAr;
  186. public
  187. constructor Create(info: pasminfo; smart: boolean);override;
  188. destructor destroy;override;
  189. procedure MakeObject;override;
  190. end;
  191. TAssemblerClass = class of TAssembler;
  192. Procedure GenerateAsm(smart:boolean);
  193. { get an instance of an external GNU-style assembler that is compatible
  194. with the current target, reusing an existing writer. Used by the LLVM
  195. target to write inline assembler }
  196. function GetExternalGnuAssemblerWithAsmInfoWriter(info: pasminfo; wr: TExternalAssemblerOutputFile): TExternalAssembler;
  197. procedure RegisterAssembler(const r:tasminfo;c:TAssemblerClass);
  198. Implementation
  199. uses
  200. {$ifdef hasunix}
  201. unix,
  202. {$endif}
  203. cutils,cfileutl,
  204. {$ifdef memdebug}
  205. cclasses,
  206. {$endif memdebug}
  207. script,fmodule,verbose,
  208. cpuinfo,
  209. aasmcpu,
  210. owar,owomflib
  211. ;
  212. var
  213. CAssembler : array[tasm] of TAssemblerClass;
  214. function fixline(s:string):string;
  215. {
  216. return s with all leading and ending spaces and tabs removed
  217. }
  218. var
  219. i,j,k : integer;
  220. begin
  221. i:=length(s);
  222. while (i>0) and (s[i] in [#9,' ']) do
  223. dec(i);
  224. j:=1;
  225. while (j<i) and (s[j] in [#9,' ']) do
  226. inc(j);
  227. for k:=j to i do
  228. if s[k] in [#0..#31,#127..#255] then
  229. s[k]:='.';
  230. fixline:=Copy(s,j,i-j+1);
  231. end;
  232. {*****************************************************************************
  233. TAssembler
  234. *****************************************************************************}
  235. Constructor TAssembler.Create(info: pasminfo; smart: boolean);
  236. begin
  237. asminfo:=info;
  238. { load start values }
  239. AsmFileName:=current_module.AsmFilename;
  240. ObjFileName:=current_module.ObjFileName;
  241. name:=Lower(current_module.modulename^);
  242. path:=current_module.outputpath;
  243. asmprefix := current_module.asmprefix^;
  244. if current_module.outputpath = '' then
  245. ppufilename := ''
  246. else
  247. ppufilename := current_module.ppufilename;
  248. SmartAsm:=smart;
  249. SmartFilesCount:=0;
  250. SmartHeaderCount:=0;
  251. SmartLinkOFiles.Clear;
  252. end;
  253. Destructor TAssembler.Destroy;
  254. begin
  255. end;
  256. procedure TAssembler.NextSmartName(place:tcutplace);
  257. var
  258. s : string;
  259. begin
  260. inc(SmartFilesCount);
  261. if SmartFilesCount>999999 then
  262. Message(asmw_f_too_many_asm_files);
  263. case place of
  264. cut_begin :
  265. begin
  266. inc(SmartHeaderCount);
  267. s:=asmprefix+tostr(SmartHeaderCount)+'h';
  268. end;
  269. cut_normal :
  270. s:=asmprefix+tostr(SmartHeaderCount)+'s';
  271. cut_end :
  272. s:=asmprefix+tostr(SmartHeaderCount)+'t';
  273. end;
  274. AsmFileName:=Path+FixFileName(s+tostr(SmartFilesCount)+target_info.asmext);
  275. ObjFileName:=Path+FixFileName(s+tostr(SmartFilesCount)+target_info.objext);
  276. { insert in container so it can be cleared after the linking }
  277. SmartLinkOFiles.Insert(ObjFileName);
  278. end;
  279. {*****************************************************************************
  280. TAssemblerOutputFile
  281. *****************************************************************************}
  282. procedure TExternalAssemblerOutputFile.RemoveAsm;
  283. var
  284. g : file;
  285. begin
  286. if cs_asm_leave in current_settings.globalswitches then
  287. exit;
  288. if cs_asm_extern in current_settings.globalswitches then
  289. AsmRes.AddDeleteCommand(owner.AsmFileName)
  290. else
  291. begin
  292. assign(g,owner.AsmFileName);
  293. {$push} {$I-}
  294. erase(g);
  295. {$pop}
  296. if ioresult<>0 then;
  297. end;
  298. end;
  299. Procedure TExternalAssemblerOutputFile.AsmFlush;
  300. begin
  301. if outcnt>0 then
  302. begin
  303. { suppress i/o error }
  304. {$push} {$I-}
  305. BlockWrite(outfile,outbuf,outcnt);
  306. {$pop}
  307. fioerror:=fioerror or (ioresult<>0);
  308. outcnt:=0;
  309. end;
  310. end;
  311. procedure TExternalAssemblerOutputFile.MarkEmpty;
  312. begin
  313. AsmStartSize:=AsmSize
  314. end;
  315. function TExternalAssemblerOutputFile.ClearIfEmpty: boolean;
  316. begin
  317. result:=AsmSize=AsmStartSize;
  318. if result then
  319. AsmClear;
  320. end;
  321. procedure TExternalAssemblerOutputFile.AsmWriteFiltered(const c: char);
  322. begin
  323. MaybeAddLinePrefix;
  324. AsmWriteAnsiStringUnfiltered(decorator.LineFilter(c));
  325. end;
  326. procedure TExternalAssemblerOutputFile.AsmWriteFiltered(const s: string);
  327. begin
  328. MaybeAddLinePrefix;
  329. AsmWriteAnsiStringUnfiltered(decorator.LineFilter(s));
  330. end;
  331. procedure TExternalAssemblerOutputFile.AsmWriteFiltered(const s: ansistring);
  332. begin
  333. MaybeAddLinePrefix;
  334. AsmWriteAnsiStringUnfiltered(decorator.LineFilter(s));
  335. end;
  336. procedure TExternalAssemblerOutputFile.AsmWriteFiltered(p: pchar; len: longint);
  337. var
  338. s: ansistring;
  339. begin
  340. MaybeAddLinePrefix;
  341. setlength(s,len);
  342. move(p^,s[1],len);
  343. AsmWriteAnsiStringUnfiltered(decorator.LineFilter(s));
  344. end;
  345. Procedure TExternalAssemblerOutputFile.AsmClear;
  346. begin
  347. outcnt:=0;
  348. end;
  349. procedure TExternalAssemblerOutputFile.MaybeAddLinePrefix;
  350. begin
  351. if assigned(decorator) and
  352. linestart then
  353. begin
  354. AsmWriteAnsiStringUnfiltered(decorator.LinePrefix);
  355. linestart:=false;
  356. end;
  357. end;
  358. procedure TExternalAssemblerOutputFile.MaybeAddLinePostfix;
  359. begin
  360. if assigned(decorator) and
  361. not linestart then
  362. begin
  363. AsmWriteAnsiStringUnfiltered(decorator.LinePostfix);
  364. linestart:=true;
  365. end;
  366. end;
  367. procedure TExternalAssemblerOutputFile.AsmWriteAnsiStringUnfiltered(const s: ansistring);
  368. var
  369. StartIndex, ToWrite: longint;
  370. begin
  371. if s='' then
  372. exit;
  373. if OutCnt+length(s)>=AsmOutSize then
  374. AsmFlush;
  375. StartIndex:=1;
  376. ToWrite:=length(s);
  377. while ToWrite>AsmOutSize do
  378. begin
  379. Move(s[StartIndex],OutBuf[OutCnt],AsmOutSize);
  380. inc(OutCnt,AsmOutSize);
  381. inc(AsmSize,AsmOutSize);
  382. AsmFlush;
  383. inc(StartIndex,AsmOutSize);
  384. dec(ToWrite,AsmOutSize);
  385. end;
  386. Move(s[StartIndex],OutBuf[OutCnt],ToWrite);
  387. inc(OutCnt,ToWrite);
  388. inc(AsmSize,ToWrite);
  389. end;
  390. constructor TExternalAssemblerOutputFile.Create(_owner: TExternalAssembler);
  391. begin
  392. owner:=_owner;
  393. linestart:=true;
  394. end;
  395. Procedure TExternalAssemblerOutputFile.AsmWrite(const c: char);
  396. begin
  397. if assigned(decorator) then
  398. AsmWriteFiltered(c)
  399. else
  400. begin
  401. if OutCnt+1>=AsmOutSize then
  402. AsmFlush;
  403. OutBuf[OutCnt]:=c;
  404. inc(OutCnt);
  405. inc(AsmSize);
  406. end;
  407. end;
  408. Procedure TExternalAssemblerOutputFile.AsmWrite(const s:string);
  409. begin
  410. if s='' then
  411. exit;
  412. if assigned(decorator) then
  413. AsmWriteFiltered(s)
  414. else
  415. begin
  416. if OutCnt+length(s)>=AsmOutSize then
  417. AsmFlush;
  418. Move(s[1],OutBuf[OutCnt],length(s));
  419. inc(OutCnt,length(s));
  420. inc(AsmSize,length(s));
  421. end;
  422. end;
  423. Procedure TExternalAssemblerOutputFile.AsmWrite(const s:ansistring);
  424. begin
  425. if s='' then
  426. exit;
  427. if assigned(decorator) then
  428. AsmWriteFiltered(s)
  429. else
  430. AsmWriteAnsiStringUnfiltered(s);
  431. end;
  432. procedure TExternalAssemblerOutputFile.AsmWriteLn(const c: char);
  433. begin
  434. AsmWrite(c);
  435. AsmLn;
  436. end;
  437. Procedure TExternalAssemblerOutputFile.AsmWriteLn(const s:string);
  438. begin
  439. AsmWrite(s);
  440. AsmLn;
  441. end;
  442. Procedure TExternalAssemblerOutputFile.AsmWriteLn(const s: ansistring);
  443. begin
  444. AsmWrite(s);
  445. AsmLn;
  446. end;
  447. Procedure TExternalAssemblerOutputFile.AsmWritePChar(p:pchar);
  448. var
  449. i,j : longint;
  450. begin
  451. i:=StrLen(p);
  452. if i=0 then
  453. exit;
  454. if assigned(decorator) then
  455. AsmWriteFiltered(p,i)
  456. else
  457. begin
  458. j:=i;
  459. while j>0 do
  460. begin
  461. i:=min(j,AsmOutSize);
  462. if OutCnt+i>=AsmOutSize then
  463. AsmFlush;
  464. Move(p[0],OutBuf[OutCnt],i);
  465. inc(OutCnt,i);
  466. inc(AsmSize,i);
  467. dec(j,i);
  468. p:=pchar(@p[i]);
  469. end;
  470. end;
  471. end;
  472. Procedure TExternalAssemblerOutputFile.AsmLn;
  473. begin
  474. MaybeAddLinePostfix;
  475. if OutCnt>=AsmOutSize-2 then
  476. AsmFlush;
  477. if (cs_link_on_target in current_settings.globalswitches) then
  478. begin
  479. OutBuf[OutCnt]:=target_info.newline[1];
  480. inc(OutCnt);
  481. inc(AsmSize);
  482. if length(target_info.newline)>1 then
  483. begin
  484. OutBuf[OutCnt]:=target_info.newline[2];
  485. inc(OutCnt);
  486. inc(AsmSize);
  487. end;
  488. end
  489. else
  490. begin
  491. OutBuf[OutCnt]:=source_info.newline[1];
  492. inc(OutCnt);
  493. inc(AsmSize);
  494. if length(source_info.newline)>1 then
  495. begin
  496. OutBuf[OutCnt]:=source_info.newline[2];
  497. inc(OutCnt);
  498. inc(AsmSize);
  499. end;
  500. end;
  501. end;
  502. procedure TExternalAssemblerOutputFile.AsmCreate(Aplace:tcutplace);
  503. {$ifdef hasamiga}
  504. var
  505. tempFileName: TPathStr;
  506. {$endif}
  507. begin
  508. if owner.SmartAsm then
  509. owner.NextSmartName(Aplace);
  510. {$ifdef hasamiga}
  511. { on Amiga/MorphOS try to redirect .s files to the T: assign, which is
  512. for temp files, and usually (default setting) located in the RAM: drive.
  513. This highly improves assembling speed for complex projects like the
  514. compiler itself, especially on hardware with slow disk I/O.
  515. Consider this as a poor man's pipe on Amiga, because real pipe handling
  516. would be much more complex and error prone to implement. (KB) }
  517. if (([cs_asm_extern,cs_asm_leave,cs_link_on_target] * current_settings.globalswitches) = []) then
  518. begin
  519. { try to have an unique name for the .s file }
  520. tempFileName:=HexStr(GetProcessID shr 4,7)+ExtractFileName(owner.AsmFileName);
  521. {$ifndef morphos}
  522. { old Amiga RAM: handler only allows filenames up to 30 char }
  523. if Length(tempFileName) < 30 then
  524. {$endif}
  525. owner.AsmFileName:='T:'+tempFileName;
  526. end;
  527. {$endif}
  528. {$ifdef hasunix}
  529. if owner.DoPipe then
  530. begin
  531. if owner.SmartAsm then
  532. begin
  533. if (owner.SmartFilesCount<=1) then
  534. Message1(exec_i_assembling_smart,owner.name);
  535. end
  536. else
  537. Message1(exec_i_assembling_pipe,owner.AsmFileName);
  538. if checkverbosity(V_Executable) then
  539. comment(V_Executable,'Executing "'+maybequoted(owner.FindAssembler)+'" with command line "'+
  540. owner.MakeCmdLine+'"');
  541. POpen(outfile,maybequoted(owner.FindAssembler)+' '+owner.MakeCmdLine,'W');
  542. end
  543. else
  544. {$endif}
  545. begin
  546. Assign(outfile,owner.AsmFileName);
  547. {$push} {$I-}
  548. Rewrite(outfile,1);
  549. {$pop}
  550. if ioresult<>0 then
  551. begin
  552. fioerror:=true;
  553. Message1(exec_d_cant_create_asmfile,owner.AsmFileName);
  554. end;
  555. end;
  556. outcnt:=0;
  557. AsmSize:=0;
  558. AsmStartSize:=0;
  559. end;
  560. procedure TExternalAssemblerOutputFile.AsmClose;
  561. var
  562. f : file;
  563. FileAge : longint;
  564. begin
  565. AsmFlush;
  566. {$ifdef hasunix}
  567. if owner.DoPipe then
  568. begin
  569. if PClose(outfile) <> 0 then
  570. GenerateError;
  571. end
  572. else
  573. {$endif}
  574. begin
  575. {Touch Assembler time to ppu time is there is a ppufilename}
  576. if owner.ppufilename<>'' then
  577. begin
  578. Assign(f,owner.ppufilename);
  579. {$push} {$I-}
  580. reset(f,1);
  581. {$pop}
  582. if ioresult=0 then
  583. begin
  584. FileAge := FileGetDate(GetFileHandle(f));
  585. close(f);
  586. reset(outfile,1);
  587. FileSetDate(GetFileHandle(outFile),FileAge);
  588. end;
  589. end;
  590. close(outfile);
  591. end;
  592. end;
  593. {*****************************************************************************
  594. TExternalAssembler
  595. *****************************************************************************}
  596. function TExternalAssembler.single2str(d : single) : string;
  597. var
  598. hs : string;
  599. begin
  600. str(d,hs);
  601. { replace space with + }
  602. if hs[1]=' ' then
  603. hs[1]:='+';
  604. single2str:='0d'+hs
  605. end;
  606. function TExternalAssembler.double2str(d : double) : string;
  607. var
  608. hs : string;
  609. begin
  610. str(d,hs);
  611. { replace space with + }
  612. if hs[1]=' ' then
  613. hs[1]:='+';
  614. double2str:='0d'+hs
  615. end;
  616. function TExternalAssembler.extended2str(e : extended) : string;
  617. var
  618. hs : string;
  619. begin
  620. str(e,hs);
  621. { replace space with + }
  622. if hs[1]=' ' then
  623. hs[1]:='+';
  624. extended2str:='0d'+hs
  625. end;
  626. Function TExternalAssembler.DoPipe:boolean;
  627. begin
  628. DoPipe:=(cs_asm_pipe in current_settings.globalswitches) and
  629. (([cs_asm_extern,cs_asm_leave,cs_link_on_target] * current_settings.globalswitches) = []) and
  630. ((asminfo^.id in [as_gas,as_ggas,as_darwin,as_powerpc_xcoff,as_clang,as_solaris_as]));
  631. end;
  632. Constructor TExternalAssembler.Create(info: pasminfo; smart: boolean);
  633. begin
  634. inherited;
  635. if not assigned(fwriter) then
  636. begin
  637. fwriter:=TExternalAssemblerOutputFile.Create(self);
  638. ffreewriter:=true;
  639. end;
  640. if SmartAsm then
  641. begin
  642. path:=FixPath(ChangeFileExt(AsmFileName,target_info.smartext),false);
  643. CreateSmartLinkPath(path);
  644. end;
  645. end;
  646. constructor TExternalAssembler.CreateWithWriter(info: pasminfo; wr: TExternalAssemblerOutputFile; freewriter,smart: boolean);
  647. begin
  648. fwriter:=wr;
  649. ffreewriter:=freewriter;
  650. Create(info,smart);
  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.