assemble.pas 53 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698
  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,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(TAbstractAssembler)
  35. public
  36. {filenames}
  37. path : string;
  38. name : string;
  39. AsmFileName, { current .s and .o file }
  40. ObjFileName,
  41. ppufilename : string;
  42. asmprefix : string;
  43. SmartAsm : boolean;
  44. SmartFilesCount,
  45. SmartHeaderCount : longint;
  46. Constructor Create(smart:boolean);virtual;
  47. Destructor Destroy;override;
  48. procedure NextSmartName(place:tcutplace);
  49. procedure MakeObject;virtual;abstract;
  50. end;
  51. {# This is the base class which should be overridden for each each
  52. assembler writer. It is used to actually assembler a file,
  53. and write the output to the assembler file.
  54. }
  55. TExternalAssembler=class(TAssembler)
  56. private
  57. procedure CreateSmartLinkPath(const s:string);
  58. protected
  59. {outfile}
  60. AsmSize,
  61. AsmStartSize,
  62. outcnt : longint;
  63. outbuf : array[0..AsmOutSize-1] of char;
  64. outfile : file;
  65. ioerror : boolean;
  66. {input source info}
  67. lastfileinfo : tfileposinfo;
  68. infile,
  69. lastinfile : tinputfile;
  70. {last section type written}
  71. lastsectype : TAsmSectionType;
  72. procedure WriteSourceLine(hp: tailineinfo);
  73. procedure WriteTempalloc(hp: tai_tempalloc);
  74. public
  75. {# Returns the complete path and executable name of the assembler
  76. program.
  77. It first tries looking in the UTIL directory if specified,
  78. otherwise it searches in the free pascal binary directory, in
  79. the current working directory and then in the directories
  80. in the $PATH environment.}
  81. Function FindAssembler:string;
  82. {# Actually does the call to the assembler file. Returns false
  83. if the assembling of the file failed.}
  84. Function CallAssembler(const command:string; const para:TCmdStr):Boolean;
  85. Function DoAssemble:boolean;virtual;
  86. Procedure RemoveAsm;
  87. Procedure AsmFlush;
  88. Procedure AsmClear;
  89. {# Write a string to the assembler file }
  90. Procedure AsmWrite(const c:char);
  91. Procedure AsmWrite(const s:string);
  92. Procedure AsmWrite(const s:ansistring);
  93. {# Write a string to the assembler file }
  94. Procedure AsmWritePChar(p:pchar);
  95. {# Write a string to the assembler file followed by a new line }
  96. Procedure AsmWriteLn(const c:char);
  97. Procedure AsmWriteLn(const s:string);
  98. Procedure AsmWriteLn(const s:ansistring);
  99. {# Write a new line to the assembler file }
  100. Procedure AsmLn;
  101. procedure AsmCreate(Aplace:tcutplace);
  102. procedure AsmClose;
  103. {# This routine should be overridden for each assembler, it is used
  104. to actually write the abstract assembler stream to file.}
  105. procedure WriteTree(p:TAsmList);virtual;
  106. {# This routine should be overridden for each assembler, it is used
  107. to actually write all the different abstract assembler streams
  108. by calling for each stream type, the @var(WriteTree) method.}
  109. procedure WriteAsmList;virtual;
  110. {# Constructs the command line for calling the assembler }
  111. function MakeCmdLine: TCmdStr; virtual;
  112. public
  113. Constructor Create(smart:boolean);override;
  114. procedure MakeObject;override;
  115. end;
  116. { TInternalAssembler }
  117. TInternalAssembler=class(TAssembler)
  118. private
  119. FCObjOutput : TObjOutputclass;
  120. { the aasmoutput lists that need to be processed }
  121. lists : byte;
  122. list : array[1..maxoutputlists] of TAsmList;
  123. { current processing }
  124. currlistidx : byte;
  125. currlist : TAsmList;
  126. procedure WriteStab(p:pchar);
  127. function MaybeNextList(var hp:Tai):boolean;
  128. function SetIndirectToSymbol(hp: Tai; const indirectname: string): Boolean;
  129. function TreePass0(hp:Tai):Tai;
  130. function TreePass1(hp:Tai):Tai;
  131. function TreePass2(hp:Tai):Tai;
  132. procedure writetree;
  133. procedure writetreesmart;
  134. protected
  135. ObjData : TObjData;
  136. ObjOutput : tObjOutput;
  137. property CObjOutput:TObjOutputclass read FCObjOutput write FCObjOutput;
  138. public
  139. constructor create(smart:boolean);override;
  140. destructor destroy;override;
  141. procedure MakeObject;override;
  142. end;
  143. TAssemblerClass = class of TAssembler;
  144. Procedure GenerateAsm(smart:boolean);
  145. Procedure OnlyAsm;
  146. procedure RegisterAssembler(const r:tasminfo;c:TAssemblerClass);
  147. Implementation
  148. uses
  149. {$ifdef hasunix}
  150. unix,
  151. {$endif}
  152. cutils,cfileutl,
  153. {$ifdef memdebug}
  154. cclasses,
  155. {$endif memdebug}
  156. script,fmodule,verbose,
  157. {$if defined(m68k) or defined(arm)}
  158. cpuinfo,
  159. {$endif m68k or arm}
  160. aasmcpu,
  161. owbase,owar
  162. ;
  163. var
  164. CAssembler : array[tasm] of TAssemblerClass;
  165. function fixline(s:string):string;
  166. {
  167. return s with all leading and ending spaces and tabs removed
  168. }
  169. var
  170. i,j,k : integer;
  171. begin
  172. i:=length(s);
  173. while (i>0) and (s[i] in [#9,' ']) do
  174. dec(i);
  175. j:=1;
  176. while (j<i) and (s[j] in [#9,' ']) do
  177. inc(j);
  178. for k:=j to i do
  179. if s[k] in [#0..#31,#127..#255] then
  180. s[k]:='.';
  181. fixline:=Copy(s,j,i-j+1);
  182. end;
  183. {*****************************************************************************
  184. TAssembler
  185. *****************************************************************************}
  186. Constructor TAssembler.Create(smart:boolean);
  187. begin
  188. { load start values }
  189. AsmFileName:=current_module.AsmFilename^;
  190. ObjFileName:=current_module.ObjFileName^;
  191. name:=Lower(current_module.modulename^);
  192. path:=current_module.outputpath^;
  193. asmprefix := current_module.asmprefix^;
  194. if not assigned(current_module.outputpath) then
  195. ppufilename := ''
  196. else
  197. ppufilename := current_module.ppufilename^;
  198. SmartAsm:=smart;
  199. SmartFilesCount:=0;
  200. SmartHeaderCount:=0;
  201. SmartLinkOFiles.Clear;
  202. end;
  203. Destructor TAssembler.Destroy;
  204. begin
  205. end;
  206. procedure TAssembler.NextSmartName(place:tcutplace);
  207. var
  208. s : string;
  209. begin
  210. inc(SmartFilesCount);
  211. if SmartFilesCount>999999 then
  212. Message(asmw_f_too_many_asm_files);
  213. case place of
  214. cut_begin :
  215. begin
  216. inc(SmartHeaderCount);
  217. s:=asmprefix+tostr(SmartHeaderCount)+'h';
  218. end;
  219. cut_normal :
  220. s:=asmprefix+tostr(SmartHeaderCount)+'s';
  221. cut_end :
  222. s:=asmprefix+tostr(SmartHeaderCount)+'t';
  223. end;
  224. AsmFileName:=Path+FixFileName(s+tostr(SmartFilesCount)+target_info.asmext);
  225. ObjFileName:=Path+FixFileName(s+tostr(SmartFilesCount)+target_info.objext);
  226. { insert in container so it can be cleared after the linking }
  227. SmartLinkOFiles.Insert(ObjFileName);
  228. end;
  229. {*****************************************************************************
  230. TExternalAssembler
  231. *****************************************************************************}
  232. Function DoPipe:boolean;
  233. begin
  234. DoPipe:=(cs_asm_pipe in current_settings.globalswitches) and
  235. (([cs_asm_extern,cs_asm_leave,cs_link_on_target] * current_settings.globalswitches) = []) and
  236. ((target_asm.id in [as_gas,as_ggas,as_darwin]));
  237. end;
  238. Constructor TExternalAssembler.Create(smart:boolean);
  239. begin
  240. inherited Create(smart);
  241. if SmartAsm then
  242. begin
  243. path:=FixPath(ChangeFileExt(AsmFileName,target_info.smartext),false);
  244. CreateSmartLinkPath(path);
  245. end;
  246. Outcnt:=0;
  247. end;
  248. procedure TExternalAssembler.CreateSmartLinkPath(const s:string);
  249. procedure DeleteFilesWithExt(const AExt:string);
  250. var
  251. dir : TSearchRec;
  252. begin
  253. if findfirst(s+source_info.dirsep+'*'+AExt,faAnyFile,dir) = 0 then
  254. begin
  255. repeat
  256. DeleteFile(s+source_info.dirsep+dir.name);
  257. until findnext(dir) <> 0;
  258. end;
  259. findclose(dir);
  260. end;
  261. var
  262. hs : string;
  263. begin
  264. if PathExists(s,false) then
  265. begin
  266. { the path exists, now we clean only all the .o and .s files }
  267. DeleteFilesWithExt(target_info.objext);
  268. DeleteFilesWithExt(target_info.asmext);
  269. end
  270. else
  271. begin
  272. hs:=s;
  273. if hs[length(hs)] in ['/','\'] then
  274. delete(hs,length(hs),1);
  275. {$I-}
  276. mkdir(hs);
  277. {$I+}
  278. if ioresult<>0 then;
  279. end;
  280. end;
  281. const
  282. lastas : byte=255;
  283. var
  284. LastASBin : TCmdStr;
  285. Function TExternalAssembler.FindAssembler:string;
  286. var
  287. asfound : boolean;
  288. UtilExe : string;
  289. begin
  290. asfound:=false;
  291. if cs_link_on_target in current_settings.globalswitches then
  292. begin
  293. { If linking on target, don't add any path PM }
  294. FindAssembler:=utilsprefix+ChangeFileExt(target_asm.asmbin,target_info.exeext);
  295. exit;
  296. end
  297. else
  298. UtilExe:=utilsprefix+ChangeFileExt(target_asm.asmbin,source_info.exeext);
  299. if lastas<>ord(target_asm.id) then
  300. begin
  301. lastas:=ord(target_asm.id);
  302. { is an assembler passed ? }
  303. if utilsdirectory<>'' then
  304. asfound:=FindFile(UtilExe,utilsdirectory,false,LastASBin);
  305. if not AsFound then
  306. asfound:=FindExe(UtilExe,false,LastASBin);
  307. if (not asfound) and not(cs_asm_extern in current_settings.globalswitches) then
  308. begin
  309. Message1(exec_e_assembler_not_found,LastASBin);
  310. current_settings.globalswitches:=current_settings.globalswitches+[cs_asm_extern];
  311. end;
  312. if asfound then
  313. Message1(exec_t_using_assembler,LastASBin);
  314. end;
  315. FindAssembler:=LastASBin;
  316. end;
  317. Function TExternalAssembler.CallAssembler(const command:string; const para:TCmdStr):Boolean;
  318. var
  319. DosExitCode : Integer;
  320. begin
  321. result:=true;
  322. if (cs_asm_extern in current_settings.globalswitches) then
  323. begin
  324. AsmRes.AddAsmCommand(command,para,name);
  325. exit;
  326. end;
  327. try
  328. FlushOutput;
  329. DosExitCode := ExecuteProcess(command,para);
  330. if DosExitCode <>0
  331. then begin
  332. Message1(exec_e_error_while_assembling,tostr(dosexitcode));
  333. result:=false;
  334. end;
  335. except on E:EOSError do
  336. begin
  337. Message1(exec_e_cant_call_assembler,tostr(E.ErrorCode));
  338. current_settings.globalswitches:=current_settings.globalswitches+[cs_asm_extern];
  339. result:=false;
  340. end;
  341. end;
  342. end;
  343. procedure TExternalAssembler.RemoveAsm;
  344. var
  345. g : file;
  346. begin
  347. if cs_asm_leave in current_settings.globalswitches then
  348. exit;
  349. if cs_asm_extern in current_settings.globalswitches then
  350. AsmRes.AddDeleteCommand(AsmFileName)
  351. else
  352. begin
  353. assign(g,AsmFileName);
  354. {$I-}
  355. erase(g);
  356. {$I+}
  357. if ioresult<>0 then;
  358. end;
  359. end;
  360. Function TExternalAssembler.DoAssemble:boolean;
  361. begin
  362. DoAssemble:=true;
  363. if DoPipe then
  364. exit;
  365. if not(cs_asm_extern in current_settings.globalswitches) then
  366. begin
  367. if SmartAsm then
  368. begin
  369. if (SmartFilesCount<=1) then
  370. Message1(exec_i_assembling_smart,name);
  371. end
  372. else
  373. Message1(exec_i_assembling,name);
  374. end;
  375. if CallAssembler(FindAssembler,MakeCmdLine) then
  376. RemoveAsm
  377. else
  378. begin
  379. DoAssemble:=false;
  380. GenerateError;
  381. end;
  382. end;
  383. Procedure TExternalAssembler.AsmFlush;
  384. begin
  385. if outcnt>0 then
  386. begin
  387. { suppress i/o error }
  388. {$i-}
  389. BlockWrite(outfile,outbuf,outcnt);
  390. {$i+}
  391. ioerror:=ioerror or (ioresult<>0);
  392. outcnt:=0;
  393. end;
  394. end;
  395. Procedure TExternalAssembler.AsmClear;
  396. begin
  397. outcnt:=0;
  398. end;
  399. Procedure TExternalAssembler.AsmWrite(const c: char);
  400. begin
  401. if OutCnt+1>=AsmOutSize then
  402. AsmFlush;
  403. OutBuf[OutCnt]:=c;
  404. inc(OutCnt);
  405. inc(AsmSize);
  406. end;
  407. Procedure TExternalAssembler.AsmWrite(const s:string);
  408. begin
  409. if OutCnt+length(s)>=AsmOutSize then
  410. AsmFlush;
  411. Move(s[1],OutBuf[OutCnt],length(s));
  412. inc(OutCnt,length(s));
  413. inc(AsmSize,length(s));
  414. end;
  415. Procedure TExternalAssembler.AsmWrite(const s:ansistring);
  416. begin
  417. if s='' then
  418. exit;
  419. if OutCnt+length(s)>=AsmOutSize then
  420. AsmFlush;
  421. Move(s[1],OutBuf[OutCnt],length(s));
  422. inc(OutCnt,length(s));
  423. inc(AsmSize,length(s));
  424. end;
  425. procedure TExternalAssembler.AsmWriteLn(const c: char);
  426. begin
  427. AsmWrite(c);
  428. AsmLn;
  429. end;
  430. Procedure TExternalAssembler.AsmWriteLn(const s:string);
  431. begin
  432. AsmWrite(s);
  433. AsmLn;
  434. end;
  435. Procedure TExternalAssembler.AsmWriteLn(const s: ansistring);
  436. begin
  437. AsmWrite(s);
  438. AsmLn;
  439. end;
  440. Procedure TExternalAssembler.AsmWritePChar(p:pchar);
  441. var
  442. i,j : longint;
  443. begin
  444. i:=StrLen(p);
  445. j:=i;
  446. while j>0 do
  447. begin
  448. i:=min(j,AsmOutSize);
  449. if OutCnt+i>=AsmOutSize then
  450. AsmFlush;
  451. Move(p[0],OutBuf[OutCnt],i);
  452. inc(OutCnt,i);
  453. inc(AsmSize,i);
  454. dec(j,i);
  455. p:=pchar(@p[i]);
  456. end;
  457. end;
  458. Procedure TExternalAssembler.AsmLn;
  459. begin
  460. if OutCnt>=AsmOutSize-2 then
  461. AsmFlush;
  462. if (cs_link_on_target in current_settings.globalswitches) then
  463. begin
  464. OutBuf[OutCnt]:=target_info.newline[1];
  465. inc(OutCnt);
  466. inc(AsmSize);
  467. if length(target_info.newline)>1 then
  468. begin
  469. OutBuf[OutCnt]:=target_info.newline[2];
  470. inc(OutCnt);
  471. inc(AsmSize);
  472. end;
  473. end
  474. else
  475. begin
  476. OutBuf[OutCnt]:=source_info.newline[1];
  477. inc(OutCnt);
  478. inc(AsmSize);
  479. if length(source_info.newline)>1 then
  480. begin
  481. OutBuf[OutCnt]:=source_info.newline[2];
  482. inc(OutCnt);
  483. inc(AsmSize);
  484. end;
  485. end;
  486. end;
  487. function TExternalAssembler.MakeCmdLine: TCmdStr;
  488. begin
  489. result:=target_asm.asmcmd;
  490. {$ifdef m68k}
  491. if current_settings.cputype = cpu_MC68020 then
  492. result:='-m68020 '+result
  493. else
  494. result:='-m68000 '+result;
  495. {$endif}
  496. {$ifdef arm}
  497. if (target_info.system=system_arm_darwin) then
  498. Replace(result,'$ARCH',lower(cputypestr[current_settings.cputype]));
  499. {$endif arm}
  500. if (cs_link_on_target in current_settings.globalswitches) then
  501. begin
  502. Replace(result,'$ASM',maybequoted(ScriptFixFileName(AsmFileName)));
  503. Replace(result,'$OBJ',maybequoted(ScriptFixFileName(ObjFileName)));
  504. end
  505. else
  506. begin
  507. {$ifdef hasunix}
  508. if DoPipe then
  509. Replace(result,'$ASM','')
  510. else
  511. {$endif}
  512. Replace(result,'$ASM',maybequoted(AsmFileName));
  513. Replace(result,'$OBJ',maybequoted(ObjFileName));
  514. end;
  515. end;
  516. procedure TExternalAssembler.AsmCreate(Aplace:tcutplace);
  517. begin
  518. if SmartAsm then
  519. NextSmartName(Aplace);
  520. {$ifdef hasunix}
  521. if DoPipe then
  522. begin
  523. if SmartAsm then
  524. begin
  525. if (SmartFilesCount<=1) then
  526. Message1(exec_i_assembling_smart,name);
  527. end
  528. else
  529. Message1(exec_i_assembling_pipe,AsmFileName);
  530. POpen(outfile,maybequoted(FindAssembler)+' '+MakeCmdLine,'W');
  531. end
  532. else
  533. {$endif}
  534. begin
  535. Assign(outfile,AsmFileName);
  536. {$I-}
  537. Rewrite(outfile,1);
  538. {$I+}
  539. if ioresult<>0 then
  540. begin
  541. ioerror:=true;
  542. Message1(exec_d_cant_create_asmfile,AsmFileName);
  543. end;
  544. end;
  545. outcnt:=0;
  546. AsmSize:=0;
  547. AsmStartSize:=0;
  548. end;
  549. procedure TExternalAssembler.AsmClose;
  550. var
  551. f : file;
  552. FileAge : longint;
  553. begin
  554. AsmFlush;
  555. {$ifdef hasunix}
  556. if DoPipe then
  557. begin
  558. if PClose(outfile) <> 0 then
  559. GenerateError;
  560. end
  561. else
  562. {$endif}
  563. begin
  564. {Touch Assembler time to ppu time is there is a ppufilename}
  565. if ppufilename<>'' then
  566. begin
  567. Assign(f,ppufilename);
  568. {$I-}
  569. reset(f,1);
  570. {$I+}
  571. if ioresult=0 then
  572. begin
  573. FileAge := FileGetDate(GetFileHandle(f));
  574. close(f);
  575. reset(outfile,1);
  576. FileSetDate(GetFileHandle(outFile),FileAge);
  577. end;
  578. end;
  579. close(outfile);
  580. end;
  581. end;
  582. procedure TExternalAssembler.WriteSourceLine(hp: tailineinfo);
  583. begin
  584. { load infile }
  585. if lastfileinfo.fileindex<>hp.fileinfo.fileindex then
  586. begin
  587. infile:=current_module.sourcefiles.get_file(hp.fileinfo.fileindex);
  588. if assigned(infile) then
  589. begin
  590. { open only if needed !! }
  591. if (cs_asm_source in current_settings.globalswitches) then
  592. infile.open;
  593. end;
  594. { avoid unnecessary reopens of the same file !! }
  595. lastfileinfo.fileindex:=hp.fileinfo.fileindex;
  596. { be sure to change line !! }
  597. lastfileinfo.line:=-1;
  598. end;
  599. { write source }
  600. if (cs_asm_source in current_settings.globalswitches) and
  601. assigned(infile) then
  602. begin
  603. if (infile<>lastinfile) then
  604. begin
  605. AsmWriteLn(target_asm.comment+'['+infile.name^+']');
  606. if assigned(lastinfile) then
  607. lastinfile.close;
  608. end;
  609. if (hp.fileinfo.line<>lastfileinfo.line) and
  610. (hp.fileinfo.line<infile.maxlinebuf) then
  611. begin
  612. if (hp.fileinfo.line<>0) and
  613. (infile.linebuf^[hp.fileinfo.line]>=0) then
  614. AsmWriteLn(target_asm.comment+'['+tostr(hp.fileinfo.line)+'] '+
  615. fixline(infile.GetLineStr(hp.fileinfo.line)));
  616. { set it to a negative value !
  617. to make that is has been read already !! PM }
  618. if (infile.linebuf^[hp.fileinfo.line]>=0) then
  619. infile.linebuf^[hp.fileinfo.line]:=-infile.linebuf^[hp.fileinfo.line]-1;
  620. end;
  621. end;
  622. lastfileinfo:=hp.fileinfo;
  623. lastinfile:=infile;
  624. end;
  625. procedure TExternalAssembler.WriteTempalloc(hp: tai_tempalloc);
  626. begin
  627. {$ifdef EXTDEBUG}
  628. if assigned(hp.problem) then
  629. AsmWriteLn(target_asm.comment+'Temp '+tostr(hp.temppos)+','+
  630. tostr(hp.tempsize)+' '+hp.problem^)
  631. else
  632. {$endif EXTDEBUG}
  633. AsmWriteLn(target_asm.comment+'Temp '+tostr(hp.temppos)+','+
  634. tostr(hp.tempsize)+' '+tempallocstr[hp.allocation]);
  635. end;
  636. procedure TExternalAssembler.WriteTree(p:TAsmList);
  637. begin
  638. end;
  639. procedure TExternalAssembler.WriteAsmList;
  640. begin
  641. end;
  642. procedure TExternalAssembler.MakeObject;
  643. begin
  644. AsmCreate(cut_normal);
  645. FillChar(lastfileinfo, sizeof(lastfileinfo), 0);
  646. lastfileinfo.line := -1;
  647. lastinfile := nil;
  648. lastsectype := sec_none;
  649. WriteAsmList;
  650. AsmClose;
  651. if not(ioerror) then
  652. DoAssemble;
  653. end;
  654. {*****************************************************************************
  655. TInternalAssembler
  656. *****************************************************************************}
  657. constructor TInternalAssembler.create(smart:boolean);
  658. begin
  659. inherited create(smart);
  660. ObjOutput:=nil;
  661. ObjData:=nil;
  662. SmartAsm:=smart;
  663. end;
  664. destructor TInternalAssembler.destroy;
  665. begin
  666. if assigned(ObjData) then
  667. ObjData.free;
  668. if assigned(ObjOutput) then
  669. ObjOutput.free;
  670. end;
  671. procedure TInternalAssembler.WriteStab(p:pchar);
  672. function consumecomma(var p:pchar):boolean;
  673. begin
  674. while (p^=' ') do
  675. inc(p);
  676. result:=(p^=',');
  677. inc(p);
  678. end;
  679. function consumenumber(var p:pchar;out value:longint):boolean;
  680. var
  681. hs : string;
  682. len,
  683. code : integer;
  684. begin
  685. value:=0;
  686. while (p^=' ') do
  687. inc(p);
  688. len:=0;
  689. while (p^ in ['0'..'9']) do
  690. begin
  691. inc(len);
  692. hs[len]:=p^;
  693. inc(p);
  694. end;
  695. if len>0 then
  696. begin
  697. hs[0]:=chr(len);
  698. val(hs,value,code);
  699. end
  700. else
  701. code:=-1;
  702. result:=(code=0);
  703. end;
  704. function consumeoffset(var p:pchar;out relocsym:tobjsymbol;out value:longint):boolean;
  705. var
  706. hs : string;
  707. len,
  708. code : integer;
  709. pstart : pchar;
  710. sym : tobjsymbol;
  711. exprvalue : longint;
  712. gotmin,
  713. have_first_symbol,
  714. have_second_symbol,
  715. dosub : boolean;
  716. begin
  717. result:=false;
  718. value:=0;
  719. relocsym:=nil;
  720. gotmin:=false;
  721. have_first_symbol:=false;
  722. have_second_symbol:=false;
  723. repeat
  724. dosub:=false;
  725. exprvalue:=0;
  726. if gotmin then
  727. begin
  728. dosub:=true;
  729. gotmin:=false;
  730. end;
  731. while (p^=' ') do
  732. inc(p);
  733. case p^ of
  734. #0 :
  735. break;
  736. ' ' :
  737. inc(p);
  738. '0'..'9' :
  739. begin
  740. len:=0;
  741. while (p^ in ['0'..'9']) do
  742. begin
  743. inc(len);
  744. hs[len]:=p^;
  745. inc(p);
  746. end;
  747. hs[0]:=chr(len);
  748. val(hs,exprvalue,code);
  749. if code<>0 then
  750. internalerror(200702251);
  751. end;
  752. '.','_',
  753. 'A'..'Z',
  754. 'a'..'z' :
  755. begin
  756. pstart:=p;
  757. while not(p^ in [#0,' ','-','+']) do
  758. inc(p);
  759. len:=p-pstart;
  760. if len>255 then
  761. internalerror(200509187);
  762. move(pstart^,hs[1],len);
  763. hs[0]:=chr(len);
  764. sym:=objdata.symbolref(hs);
  765. have_first_symbol:=true;
  766. { Second symbol? }
  767. if assigned(relocsym) then
  768. begin
  769. if have_second_symbol then
  770. internalerror(2007032201);
  771. have_second_symbol:=true;
  772. if not have_first_symbol then
  773. internalerror(2007032202);
  774. { second symbol should substracted to first }
  775. if not dosub then
  776. internalerror(2007032203);
  777. if (relocsym.objsection<>sym.objsection) then
  778. internalerror(2005091810);
  779. exprvalue:=relocsym.address-sym.address;
  780. relocsym:=nil;
  781. dosub:=false;
  782. end
  783. else
  784. begin
  785. relocsym:=sym;
  786. if assigned(sym.objsection) then
  787. begin
  788. { first symbol should be + }
  789. if not have_first_symbol and dosub then
  790. internalerror(2007032204);
  791. have_first_symbol:=true;
  792. end;
  793. end;
  794. end;
  795. '+' :
  796. begin
  797. { nothing, by default addition is done }
  798. inc(p);
  799. end;
  800. '-' :
  801. begin
  802. gotmin:=true;
  803. inc(p);
  804. end;
  805. else
  806. internalerror(200509189);
  807. end;
  808. if dosub then
  809. dec(value,exprvalue)
  810. else
  811. inc(value,exprvalue);
  812. until false;
  813. result:=true;
  814. end;
  815. var
  816. stabstrlen,
  817. ofs,
  818. nline,
  819. nidx,
  820. nother,
  821. i : longint;
  822. stab : TObjStabEntry;
  823. relocsym : TObjSymbol;
  824. pstr,
  825. pcurr,
  826. pendquote : pchar;
  827. oldsec : TObjSection;
  828. begin
  829. pcurr:=nil;
  830. pstr:=nil;
  831. pendquote:=nil;
  832. relocsym:=nil;
  833. ofs:=0;
  834. { Parse string part }
  835. if (p[0]='"') then
  836. begin
  837. pstr:=@p[1];
  838. { Ignore \" inside the string }
  839. i:=1;
  840. while not((p[i]='"') and (p[i-1]<>'\')) and
  841. (p[i]<>#0) do
  842. inc(i);
  843. pendquote:=@p[i];
  844. pendquote^:=#0;
  845. pcurr:=@p[i+1];
  846. if not consumecomma(pcurr) then
  847. internalerror(200509181);
  848. end
  849. else
  850. pcurr:=p;
  851. { When in pass 1 then only alloc and leave }
  852. if ObjData.currpass=1 then
  853. begin
  854. ObjData.StabsSec.Alloc(sizeof(TObjStabEntry));
  855. if assigned(pstr) and (pstr[0]<>#0) then
  856. ObjData.StabStrSec.Alloc(strlen(pstr)+1);
  857. end
  858. else
  859. begin
  860. { Stabs format: nidx,nother,nline[,offset] }
  861. if not consumenumber(pcurr,nidx) then
  862. internalerror(200509182);
  863. if not consumecomma(pcurr) then
  864. internalerror(200509183);
  865. if not consumenumber(pcurr,nother) then
  866. internalerror(200509184);
  867. if not consumecomma(pcurr) then
  868. internalerror(200509185);
  869. if not consumenumber(pcurr,nline) then
  870. internalerror(200509186);
  871. if consumecomma(pcurr) then
  872. consumeoffset(pcurr,relocsym,ofs);
  873. { Generate stab entry }
  874. if assigned(pstr) and (pstr[0]<>#0) then
  875. begin
  876. stabstrlen:=strlen(pstr);
  877. {$ifdef optimizestabs}
  878. StabStrEntry:=nil;
  879. if (nidx=N_SourceFile) or (nidx=N_IncludeFile) then
  880. begin
  881. hs:=strpas(pstr);
  882. StabstrEntry:=StabStrDict.Find(hs);
  883. if not assigned(StabstrEntry) then
  884. begin
  885. StabstrEntry:=TStabStrEntry.Create(hs);
  886. StabstrEntry:=StabStrSec.Size;
  887. StabStrDict.Insert(StabstrEntry);
  888. { generate new stab }
  889. StabstrEntry:=nil;
  890. end;
  891. end;
  892. if assigned(StabstrEntry) then
  893. stab.strpos:=StabstrEntry.strpos
  894. else
  895. {$endif optimizestabs}
  896. begin
  897. stab.strpos:=ObjData.StabStrSec.Size;
  898. ObjData.StabStrSec.write(pstr^,stabstrlen+1);
  899. end;
  900. end
  901. else
  902. stab.strpos:=0;
  903. stab.ntype:=byte(nidx);
  904. stab.ndesc:=word(nline);
  905. stab.nother:=byte(nother);
  906. stab.nvalue:=ofs;
  907. { Write the stab first without the value field. Then
  908. write a the value field with relocation }
  909. oldsec:=ObjData.CurrObjSec;
  910. ObjData.SetSection(ObjData.StabsSec);
  911. ObjData.Writebytes(stab,sizeof(TObjStabEntry)-4);
  912. ObjData.Writereloc(stab.nvalue,4,relocsym,RELOC_ABSOLUTE32);
  913. ObjData.setsection(oldsec);
  914. end;
  915. if assigned(pendquote) then
  916. pendquote^:='"';
  917. end;
  918. function TInternalAssembler.MaybeNextList(var hp:Tai):boolean;
  919. begin
  920. { maybe end of list }
  921. while not assigned(hp) do
  922. begin
  923. if currlistidx<lists then
  924. begin
  925. inc(currlistidx);
  926. currlist:=list[currlistidx];
  927. hp:=Tai(currList.first);
  928. end
  929. else
  930. begin
  931. MaybeNextList:=false;
  932. exit;
  933. end;
  934. end;
  935. MaybeNextList:=true;
  936. end;
  937. function TInternalAssembler.SetIndirectToSymbol(hp: Tai; const indirectname: string): Boolean;
  938. var
  939. objsym : TObjSymbol;
  940. indsym : TObjSymbol;
  941. begin
  942. Result:=
  943. Assigned(hp) and
  944. (hp.typ=ait_symbol);
  945. if not Result then
  946. Exit;
  947. objsym:=Objdata.SymbolRef(tai_symbol(hp).sym);
  948. objsym.size:=0;
  949. indsym := TObjSymbol(ObjData.ObjSymbolList.Find(indirectname));
  950. if not Assigned(indsym) then
  951. begin
  952. { it's possible that indirect symbol is not present in the list,
  953. so we must create it as undefined }
  954. indsym:=TObjSymbol.Create(ObjData.ObjSymbolList, indirectname);
  955. indsym.typ:=AT_NONE;
  956. indsym.bind:=AB_NONE;
  957. end;
  958. objsym.indsymbol:=indsym;
  959. Result:=true;
  960. end;
  961. function TInternalAssembler.TreePass0(hp:Tai):Tai;
  962. var
  963. objsym,
  964. objsymend : TObjSymbol;
  965. begin
  966. while assigned(hp) do
  967. begin
  968. case hp.typ of
  969. ait_align :
  970. begin
  971. if tai_align_abstract(hp).aligntype>1 then
  972. begin
  973. { always use the maximum fillsize in this pass to avoid possible
  974. short jumps to become out of range }
  975. Tai_align_abstract(hp).fillsize:=Tai_align_abstract(hp).aligntype;
  976. ObjData.alloc(Tai_align_abstract(hp).fillsize);
  977. end
  978. else
  979. Tai_align_abstract(hp).fillsize:=0;
  980. end;
  981. ait_datablock :
  982. begin
  983. {$ifdef USE_COMM_IN_BSS}
  984. if writingpackages and
  985. Tai_datablock(hp).is_global then
  986. ObjData.SymbolDefine(Tai_datablock(hp).sym)
  987. else
  988. {$endif USE_COMM_IN_BSS}
  989. begin
  990. ObjData.allocalign(used_align(size_2_align(Tai_datablock(hp).size),0,ObjData.CurrObjSec.secalign));
  991. ObjData.SymbolDefine(Tai_datablock(hp).sym);
  992. ObjData.alloc(Tai_datablock(hp).size);
  993. end;
  994. end;
  995. ait_real_80bit :
  996. ObjData.alloc(tai_real_80bit(hp).savesize);
  997. ait_real_64bit :
  998. ObjData.alloc(8);
  999. ait_real_32bit :
  1000. ObjData.alloc(4);
  1001. ait_comp_64bit :
  1002. ObjData.alloc(8);
  1003. ait_const:
  1004. begin
  1005. { if symbols are provided we can calculate the value for relative symbols.
  1006. This is required for length calculation of leb128 constants }
  1007. if assigned(tai_const(hp).sym) then
  1008. begin
  1009. objsym:=Objdata.SymbolRef(tai_const(hp).sym);
  1010. { objsym already defined and there is endsym? }
  1011. if assigned(objsym.objsection) and assigned(tai_const(hp).endsym) then
  1012. begin
  1013. objsymend:=Objdata.SymbolRef(tai_const(hp).endsym);
  1014. { objsymend already defined? }
  1015. if assigned(objsymend.objsection) then
  1016. begin
  1017. if objsymend.objsection<>objsym.objsection then
  1018. internalerror(200404124);
  1019. Tai_const(hp).value:=objsymend.address-objsym.address+Tai_const(hp).symofs;
  1020. end;
  1021. end;
  1022. end;
  1023. ObjData.alloc(tai_const(hp).size);
  1024. end;
  1025. ait_directive:
  1026. begin
  1027. case tai_directive(hp).directive of
  1028. asd_indirect_symbol:
  1029. { handled in TreePass1 }
  1030. ;
  1031. asd_lazy_reference:
  1032. begin
  1033. if tai_directive(hp).name = nil then
  1034. Internalerror(2009112101);
  1035. objsym:=ObjData.symbolref(tai_directive(hp).name^);
  1036. objsym.bind:=AB_LAZY;
  1037. end;
  1038. asd_reference:
  1039. { ignore for now, but should be added}
  1040. ;
  1041. else
  1042. internalerror(2010011101);
  1043. end;
  1044. end;
  1045. ait_section:
  1046. begin
  1047. ObjData.CreateSection(Tai_section(hp).sectype,Tai_section(hp).name^,Tai_section(hp).secorder);
  1048. Tai_section(hp).sec:=ObjData.CurrObjSec;
  1049. end;
  1050. ait_symbol :
  1051. begin
  1052. { needs extra support in the internal assembler }
  1053. { the value is just ignored }
  1054. {if tai_symbol(hp).has_value then
  1055. internalerror(2009090804); ;}
  1056. ObjData.SymbolDefine(Tai_symbol(hp).sym);
  1057. end;
  1058. ait_label :
  1059. ObjData.SymbolDefine(Tai_label(hp).labsym);
  1060. ait_string :
  1061. ObjData.alloc(Tai_string(hp).len);
  1062. ait_instruction :
  1063. begin
  1064. { reset instructions which could change in pass 2 }
  1065. Taicpu(hp).resetpass2;
  1066. ObjData.alloc(Taicpu(hp).Pass1(ObjData));
  1067. end;
  1068. ait_cutobject :
  1069. if SmartAsm then
  1070. break;
  1071. end;
  1072. hp:=Tai(hp.next);
  1073. end;
  1074. TreePass0:=hp;
  1075. end;
  1076. function TInternalAssembler.TreePass1(hp:Tai):Tai;
  1077. var
  1078. objsym,
  1079. objsymend : TObjSymbol;
  1080. begin
  1081. while assigned(hp) do
  1082. begin
  1083. case hp.typ of
  1084. ait_align :
  1085. begin
  1086. if tai_align_abstract(hp).aligntype>1 then
  1087. begin
  1088. { here we must determine the fillsize which is used in pass2 }
  1089. Tai_align_abstract(hp).fillsize:=align(ObjData.CurrObjSec.Size,Tai_align_abstract(hp).aligntype)-
  1090. ObjData.CurrObjSec.Size;
  1091. ObjData.alloc(Tai_align_abstract(hp).fillsize);
  1092. end;
  1093. end;
  1094. ait_datablock :
  1095. begin
  1096. if (oso_data in ObjData.CurrObjSec.secoptions) then
  1097. Message(asmw_e_alloc_data_only_in_bss);
  1098. {$ifdef USE_COMM_IN_BSS}
  1099. if writingpackages and
  1100. Tai_datablock(hp).is_global then
  1101. begin
  1102. objsym:=ObjData.SymbolDefine(Tai_datablock(hp).sym);
  1103. objsym.size:=Tai_datablock(hp).size;
  1104. objsym.bind:=AB_COMMON;
  1105. objsym.alignment:=needtowritealignmentalsoforELF;
  1106. end
  1107. else
  1108. {$endif USE_COMM_IN_BSS}
  1109. begin
  1110. ObjData.allocalign(used_align(size_2_align(Tai_datablock(hp).size),0,ObjData.CurrObjSec.secalign));
  1111. objsym:=ObjData.SymbolDefine(Tai_datablock(hp).sym);
  1112. objsym.size:=Tai_datablock(hp).size;
  1113. ObjData.alloc(Tai_datablock(hp).size);
  1114. end;
  1115. end;
  1116. ait_real_80bit :
  1117. ObjData.alloc(tai_real_80bit(hp).savesize);
  1118. ait_real_64bit :
  1119. ObjData.alloc(8);
  1120. ait_real_32bit :
  1121. ObjData.alloc(4);
  1122. ait_comp_64bit :
  1123. ObjData.alloc(8);
  1124. ait_const:
  1125. begin
  1126. { Recalculate relative symbols }
  1127. if assigned(tai_const(hp).sym) and
  1128. assigned(tai_const(hp).endsym) then
  1129. begin
  1130. objsym:=Objdata.SymbolRef(tai_const(hp).sym);
  1131. objsymend:=Objdata.SymbolRef(tai_const(hp).endsym);
  1132. if objsymend.objsection<>objsym.objsection then
  1133. internalerror(200905042);
  1134. Tai_const(hp).value:=objsymend.address-objsym.address+Tai_const(hp).symofs;
  1135. end;
  1136. ObjData.alloc(tai_const(hp).size);
  1137. end;
  1138. ait_section:
  1139. begin
  1140. { use cached value }
  1141. ObjData.setsection(Tai_section(hp).sec);
  1142. end;
  1143. ait_stab :
  1144. begin
  1145. if assigned(Tai_stab(hp).str) then
  1146. WriteStab(Tai_stab(hp).str);
  1147. end;
  1148. ait_symbol :
  1149. ObjData.SymbolDefine(Tai_symbol(hp).sym);
  1150. ait_symbol_end :
  1151. begin
  1152. objsym:=ObjData.SymbolRef(Tai_symbol_end(hp).sym);
  1153. objsym.size:=ObjData.CurrObjSec.Size-objsym.offset;
  1154. end;
  1155. ait_label :
  1156. ObjData.SymbolDefine(Tai_label(hp).labsym);
  1157. ait_string :
  1158. ObjData.alloc(Tai_string(hp).len);
  1159. ait_instruction :
  1160. ObjData.alloc(Taicpu(hp).Pass1(ObjData));
  1161. ait_cutobject :
  1162. if SmartAsm then
  1163. break;
  1164. ait_directive :
  1165. begin
  1166. case tai_directive(hp).directive of
  1167. asd_indirect_symbol:
  1168. if tai_directive(hp).name = nil then
  1169. Internalerror(2009101103)
  1170. else if not SetIndirectToSymbol(Tai(hp.Previous), tai_directive(hp).name^) then
  1171. Internalerror(2009101102);
  1172. asd_lazy_reference:
  1173. { handled in TreePass0 }
  1174. ;
  1175. asd_reference:
  1176. { ignore for now, but should be added}
  1177. ;
  1178. else
  1179. internalerror(2010011102);
  1180. end;
  1181. end;
  1182. end;
  1183. hp:=Tai(hp.next);
  1184. end;
  1185. TreePass1:=hp;
  1186. end;
  1187. function TInternalAssembler.TreePass2(hp:Tai):Tai;
  1188. var
  1189. fillbuffer : tfillbuffer;
  1190. {$ifdef x86}
  1191. co : comp;
  1192. {$endif x86}
  1193. leblen : byte;
  1194. lebbuf : array[0..63] of byte;
  1195. objsym,
  1196. objsymend : TObjSymbol;
  1197. zerobuf : array[0..63] of byte;
  1198. begin
  1199. fillchar(zerobuf,sizeof(zerobuf),0);
  1200. { main loop }
  1201. while assigned(hp) do
  1202. begin
  1203. case hp.typ of
  1204. ait_align :
  1205. begin
  1206. if oso_data in ObjData.CurrObjSec.secoptions then
  1207. ObjData.writebytes(Tai_align_abstract(hp).calculatefillbuf(fillbuffer,oso_executable in ObjData.CurrObjSec.secoptions)^,
  1208. Tai_align_abstract(hp).fillsize)
  1209. else
  1210. ObjData.alloc(Tai_align_abstract(hp).fillsize);
  1211. end;
  1212. ait_section :
  1213. begin
  1214. { use cached value }
  1215. ObjData.setsection(Tai_section(hp).sec);
  1216. end;
  1217. ait_symbol :
  1218. begin
  1219. ObjOutput.exportsymbol(ObjData.SymbolRef(Tai_symbol(hp).sym));
  1220. end;
  1221. ait_datablock :
  1222. begin
  1223. ObjOutput.exportsymbol(ObjData.SymbolRef(Tai_datablock(hp).sym));
  1224. {$ifdef USE_COMM_IN_BSS}
  1225. if not(writingpackages and
  1226. Tai_datablock(hp).is_global) then
  1227. {$endif USE_COMM_IN_BSS}
  1228. begin
  1229. ObjData.allocalign(used_align(size_2_align(Tai_datablock(hp).size),0,ObjData.CurrObjSec.secalign));
  1230. ObjData.alloc(Tai_datablock(hp).size);
  1231. end;
  1232. end;
  1233. ait_real_80bit :
  1234. begin
  1235. ObjData.writebytes(Tai_real_80bit(hp).value,10);
  1236. ObjData.writebytes(zerobuf,Tai_real_80bit(hp).savesize-10);
  1237. end;
  1238. ait_real_64bit :
  1239. ObjData.writebytes(Tai_real_64bit(hp).value,8);
  1240. ait_real_32bit :
  1241. ObjData.writebytes(Tai_real_32bit(hp).value,4);
  1242. ait_comp_64bit :
  1243. begin
  1244. {$ifdef x86}
  1245. co:=comp(Tai_comp_64bit(hp).value);
  1246. ObjData.writebytes(co,8);
  1247. {$endif x86}
  1248. end;
  1249. ait_string :
  1250. ObjData.writebytes(Tai_string(hp).str^,Tai_string(hp).len);
  1251. ait_const :
  1252. begin
  1253. { Recalculate relative symbols, addresses of forward references
  1254. can be changed in treepass1 }
  1255. if assigned(tai_const(hp).sym) and
  1256. assigned(tai_const(hp).endsym) then
  1257. begin
  1258. objsym:=Objdata.SymbolRef(tai_const(hp).sym);
  1259. objsymend:=Objdata.SymbolRef(tai_const(hp).endsym);
  1260. Tai_const(hp).value:=objsymend.address-objsym.address+Tai_const(hp).symofs;
  1261. end;
  1262. case tai_const(hp).consttype of
  1263. aitconst_64bit,
  1264. aitconst_32bit,
  1265. aitconst_16bit,
  1266. aitconst_8bit :
  1267. begin
  1268. if assigned(tai_const(hp).sym) and
  1269. not assigned(tai_const(hp).endsym) then
  1270. ObjData.writereloc(Tai_const(hp).symofs,tai_const(hp).size,Objdata.SymbolRef(tai_const(hp).sym),RELOC_ABSOLUTE)
  1271. else
  1272. ObjData.writebytes(Tai_const(hp).value,tai_const(hp).size);
  1273. end;
  1274. aitconst_rva_symbol :
  1275. begin
  1276. { PE32+? }
  1277. if target_info.system=system_x86_64_win64 then
  1278. ObjData.writereloc(Tai_const(hp).symofs,sizeof(longint),Objdata.SymbolRef(tai_const(hp).sym),RELOC_RVA)
  1279. else
  1280. ObjData.writereloc(Tai_const(hp).symofs,sizeof(pint),Objdata.SymbolRef(tai_const(hp).sym),RELOC_RVA);
  1281. end;
  1282. aitconst_secrel32_symbol :
  1283. begin
  1284. { Required for DWARF2 support under Windows }
  1285. ObjData.writereloc(Tai_const(hp).symofs,sizeof(longint),Objdata.SymbolRef(tai_const(hp).sym),RELOC_SECREL32);
  1286. end;
  1287. aitconst_uleb128bit,
  1288. aitconst_sleb128bit :
  1289. begin
  1290. if tai_const(hp).consttype=aitconst_uleb128bit then
  1291. leblen:=EncodeUleb128(qword(Tai_const(hp).value),lebbuf)
  1292. else
  1293. leblen:=EncodeSleb128(Tai_const(hp).value,lebbuf);
  1294. if leblen<>tai_const(hp).size then
  1295. internalerror(200709271);
  1296. ObjData.writebytes(lebbuf,leblen);
  1297. end;
  1298. aitconst_darwin_dwarf_delta32,
  1299. aitconst_darwin_dwarf_delta64:
  1300. ObjData.writebytes(Tai_const(hp).value,tai_const(hp).size);
  1301. else
  1302. internalerror(200603254);
  1303. end;
  1304. end;
  1305. ait_label :
  1306. begin
  1307. { exporting shouldn't be necessary as labels are local,
  1308. but it's better to be on the safe side (PFV) }
  1309. ObjOutput.exportsymbol(ObjData.SymbolRef(Tai_label(hp).labsym));
  1310. end;
  1311. ait_instruction :
  1312. Taicpu(hp).Pass2(ObjData);
  1313. ait_stab :
  1314. WriteStab(Tai_stab(hp).str);
  1315. ait_function_name,
  1316. ait_force_line : ;
  1317. ait_cutobject :
  1318. if SmartAsm then
  1319. break;
  1320. end;
  1321. hp:=Tai(hp.next);
  1322. end;
  1323. TreePass2:=hp;
  1324. end;
  1325. procedure TInternalAssembler.writetree;
  1326. label
  1327. doexit;
  1328. var
  1329. hp : Tai;
  1330. ObjWriter : TObjectWriter;
  1331. begin
  1332. ObjWriter:=TObjectwriter.create;
  1333. ObjOutput:=CObjOutput.Create(ObjWriter);
  1334. ObjData:=ObjOutput.newObjData(ObjFileName);
  1335. { Pass 0 }
  1336. ObjData.currpass:=0;
  1337. ObjData.createsection(sec_code);
  1338. ObjData.beforealloc;
  1339. { start with list 1 }
  1340. currlistidx:=1;
  1341. currlist:=list[currlistidx];
  1342. hp:=Tai(currList.first);
  1343. while assigned(hp) do
  1344. begin
  1345. hp:=TreePass0(hp);
  1346. MaybeNextList(hp);
  1347. end;
  1348. ObjData.afteralloc;
  1349. { leave if errors have occured }
  1350. if errorcount>0 then
  1351. goto doexit;
  1352. { Pass 1 }
  1353. ObjData.currpass:=1;
  1354. ObjData.resetsections;
  1355. ObjData.beforealloc;
  1356. ObjData.createsection(sec_code);
  1357. { start with list 1 }
  1358. currlistidx:=1;
  1359. currlist:=list[currlistidx];
  1360. hp:=Tai(currList.first);
  1361. while assigned(hp) do
  1362. begin
  1363. hp:=TreePass1(hp);
  1364. MaybeNextList(hp);
  1365. end;
  1366. ObjData.createsection(sec_code);
  1367. ObjData.afteralloc;
  1368. { leave if errors have occured }
  1369. if errorcount>0 then
  1370. goto doexit;
  1371. { Pass 2 }
  1372. ObjData.currpass:=2;
  1373. ObjData.resetsections;
  1374. ObjData.beforewrite;
  1375. ObjData.createsection(sec_code);
  1376. { start with list 1 }
  1377. currlistidx:=1;
  1378. currlist:=list[currlistidx];
  1379. hp:=Tai(currList.first);
  1380. while assigned(hp) do
  1381. begin
  1382. hp:=TreePass2(hp);
  1383. MaybeNextList(hp);
  1384. end;
  1385. ObjData.createsection(sec_code);
  1386. ObjData.afterwrite;
  1387. { don't write the .o file if errors have occured }
  1388. if errorcount=0 then
  1389. begin
  1390. { write objectfile }
  1391. ObjOutput.startobjectfile(ObjFileName);
  1392. ObjOutput.writeobjectfile(ObjData);
  1393. end;
  1394. doexit:
  1395. { Cleanup }
  1396. ObjData.free;
  1397. ObjData:=nil;
  1398. ObjWriter.free;
  1399. end;
  1400. procedure TInternalAssembler.writetreesmart;
  1401. var
  1402. hp : Tai;
  1403. startsectype : TAsmSectiontype;
  1404. place: tcutplace;
  1405. ObjWriter : TObjectWriter;
  1406. begin
  1407. if not(cs_asm_leave in current_settings.globalswitches) then
  1408. ObjWriter:=TARObjectWriter.create(current_module.staticlibfilename^)
  1409. else
  1410. ObjWriter:=TObjectwriter.create;
  1411. NextSmartName(cut_normal);
  1412. ObjOutput:=CObjOutput.Create(ObjWriter);
  1413. startsectype:=sec_code;
  1414. { start with list 1 }
  1415. currlistidx:=1;
  1416. currlist:=list[currlistidx];
  1417. hp:=Tai(currList.first);
  1418. while assigned(hp) do
  1419. begin
  1420. ObjData:=ObjOutput.newObjData(ObjFileName);
  1421. { Pass 0 }
  1422. ObjData.currpass:=0;
  1423. ObjData.resetsections;
  1424. ObjData.beforealloc;
  1425. ObjData.createsection(startsectype);
  1426. TreePass0(hp);
  1427. ObjData.afteralloc;
  1428. { leave if errors have occured }
  1429. if errorcount>0 then
  1430. break;
  1431. { Pass 1 }
  1432. ObjData.currpass:=1;
  1433. ObjData.resetsections;
  1434. ObjData.beforealloc;
  1435. ObjData.createsection(startsectype);
  1436. TreePass1(hp);
  1437. ObjData.afteralloc;
  1438. { leave if errors have occured }
  1439. if errorcount>0 then
  1440. break;
  1441. { Pass 2 }
  1442. ObjData.currpass:=2;
  1443. ObjOutput.startobjectfile(ObjFileName);
  1444. ObjData.resetsections;
  1445. ObjData.beforewrite;
  1446. ObjData.createsection(startsectype);
  1447. hp:=TreePass2(hp);
  1448. ObjData.afterwrite;
  1449. { leave if errors have occured }
  1450. if errorcount>0 then
  1451. break;
  1452. { write the current objectfile }
  1453. ObjOutput.writeobjectfile(ObjData);
  1454. ObjData.free;
  1455. ObjData:=nil;
  1456. { end of lists? }
  1457. if not MaybeNextList(hp) then
  1458. break;
  1459. { we will start a new objectfile so reset everything }
  1460. { The place can still change in the next while loop, so don't init }
  1461. { the writer yet (JM) }
  1462. if (hp.typ=ait_cutobject) then
  1463. place := Tai_cutobject(hp).place
  1464. else
  1465. place := cut_normal;
  1466. { avoid empty files }
  1467. startsectype:=sec_code;
  1468. while assigned(hp) and
  1469. (Tai(hp).typ in [ait_marker,ait_comment,ait_section,ait_cutobject]) do
  1470. begin
  1471. if Tai(hp).typ=ait_section then
  1472. startsectype:=Tai_section(hp).sectype;
  1473. if (Tai(hp).typ=ait_cutobject) then
  1474. place:=Tai_cutobject(hp).place;
  1475. hp:=Tai(hp.next);
  1476. end;
  1477. if not MaybeNextList(hp) then
  1478. break;
  1479. { start next objectfile }
  1480. NextSmartName(place);
  1481. end;
  1482. ObjData.free;
  1483. ObjData:=nil;
  1484. ObjWriter.free;
  1485. end;
  1486. procedure TInternalAssembler.MakeObject;
  1487. var to_do:set of TasmlistType;
  1488. i:TasmlistType;
  1489. procedure addlist(p:TAsmList);
  1490. begin
  1491. inc(lists);
  1492. list[lists]:=p;
  1493. end;
  1494. begin
  1495. to_do:=[low(Tasmlisttype)..high(Tasmlisttype)];
  1496. if usedeffileforexports then
  1497. exclude(to_do,al_exports);
  1498. if not(tf_section_threadvars in target_info.flags) then
  1499. exclude(to_do,al_threadvars);
  1500. for i:=low(TasmlistType) to high(TasmlistType) do
  1501. if (i in to_do) and (current_asmdata.asmlists[i]<>nil) then
  1502. addlist(current_asmdata.asmlists[i]);
  1503. if SmartAsm then
  1504. writetreesmart
  1505. else
  1506. writetree;
  1507. end;
  1508. {*****************************************************************************
  1509. Generate Assembler Files Main Procedure
  1510. *****************************************************************************}
  1511. Procedure GenerateAsm(smart:boolean);
  1512. var
  1513. a : TAssembler;
  1514. begin
  1515. if not assigned(CAssembler[target_asm.id]) then
  1516. Message(asmw_f_assembler_output_not_supported);
  1517. a:=CAssembler[target_asm.id].Create(smart);
  1518. a.MakeObject;
  1519. a.Free;
  1520. end;
  1521. Procedure OnlyAsm;
  1522. var
  1523. a : TExternalAssembler;
  1524. begin
  1525. a:=TExternalAssembler.Create(false);
  1526. a.DoAssemble;
  1527. a.Free;
  1528. end;
  1529. {*****************************************************************************
  1530. Init/Done
  1531. *****************************************************************************}
  1532. procedure RegisterAssembler(const r:tasminfo;c:TAssemblerClass);
  1533. var
  1534. t : tasm;
  1535. begin
  1536. t:=r.id;
  1537. if assigned(asminfos[t]) then
  1538. writeln('Warning: Assembler is already registered!')
  1539. else
  1540. Getmem(asminfos[t],sizeof(tasminfo));
  1541. asminfos[t]^:=r;
  1542. CAssembler[t]:=c;
  1543. end;
  1544. end.