assemble.pas 72 KB

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