assemble.pas 76 KB

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