assemble.pas 79 KB

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