assemble.pas 75 KB

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