assemble.pas 76 KB

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