assemble.pas 57 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765
  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(TObject)
  35. public
  36. {filenames}
  37. path : TPathStr;
  38. name : string;
  39. AsmFileName, { current .s and .o file }
  40. ObjFileName,
  41. ppufilename : TPathStr;
  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:TPathStr);
  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;virtual;
  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 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,as_powerpc_xcoff]));
  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:TPathStr);
  249. procedure DeleteFilesWithExt(const AExt:string);
  250. var
  251. dir : TRawByteSearchRec;
  252. begin
  253. if findfirst(FixPath(s,false)+'*'+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 : TPathStr;
  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. {$push} {$I-}
  276. mkdir(hs);
  277. {$pop}
  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:=RequotedExecuteProcess(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. {$push} {$I-}
  355. erase(g);
  356. {$pop}
  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. {$push} {$I-}
  389. BlockWrite(outfile,outbuf,outcnt);
  390. {$pop}
  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. var
  417. StartIndex, ToWrite: longint;
  418. begin
  419. if s='' then
  420. exit;
  421. if OutCnt+length(s)>=AsmOutSize then
  422. AsmFlush;
  423. StartIndex:=1;
  424. ToWrite:=length(s);
  425. while ToWrite>AsmOutSize do
  426. begin
  427. Move(s[StartIndex],OutBuf[OutCnt],AsmOutSize);
  428. inc(OutCnt,AsmOutSize);
  429. inc(AsmSize,AsmOutSize);
  430. AsmFlush;
  431. inc(StartIndex,AsmOutSize);
  432. dec(ToWrite,AsmOutSize);
  433. end;
  434. Move(s[StartIndex],OutBuf[OutCnt],ToWrite);
  435. inc(OutCnt,ToWrite);
  436. inc(AsmSize,ToWrite);
  437. end;
  438. procedure TExternalAssembler.AsmWriteLn(const c: char);
  439. begin
  440. AsmWrite(c);
  441. AsmLn;
  442. end;
  443. Procedure TExternalAssembler.AsmWriteLn(const s:string);
  444. begin
  445. AsmWrite(s);
  446. AsmLn;
  447. end;
  448. Procedure TExternalAssembler.AsmWriteLn(const s: ansistring);
  449. begin
  450. AsmWrite(s);
  451. AsmLn;
  452. end;
  453. Procedure TExternalAssembler.AsmWritePChar(p:pchar);
  454. var
  455. i,j : longint;
  456. begin
  457. i:=StrLen(p);
  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. Procedure TExternalAssembler.AsmLn;
  472. begin
  473. if OutCnt>=AsmOutSize-2 then
  474. AsmFlush;
  475. if (cs_link_on_target in current_settings.globalswitches) then
  476. begin
  477. OutBuf[OutCnt]:=target_info.newline[1];
  478. inc(OutCnt);
  479. inc(AsmSize);
  480. if length(target_info.newline)>1 then
  481. begin
  482. OutBuf[OutCnt]:=target_info.newline[2];
  483. inc(OutCnt);
  484. inc(AsmSize);
  485. end;
  486. end
  487. else
  488. begin
  489. OutBuf[OutCnt]:=source_info.newline[1];
  490. inc(OutCnt);
  491. inc(AsmSize);
  492. if length(source_info.newline)>1 then
  493. begin
  494. OutBuf[OutCnt]:=source_info.newline[2];
  495. inc(OutCnt);
  496. inc(AsmSize);
  497. end;
  498. end;
  499. end;
  500. function TExternalAssembler.MakeCmdLine: TCmdStr;
  501. begin
  502. result:=target_asm.asmcmd;
  503. {$ifdef arm}
  504. if (target_info.system=system_arm_darwin) then
  505. Replace(result,'$ARCH',lower(cputypestr[current_settings.cputype]));
  506. {$endif arm}
  507. if (cs_link_on_target in current_settings.globalswitches) then
  508. begin
  509. Replace(result,'$ASM',maybequoted(ScriptFixFileName(AsmFileName)));
  510. Replace(result,'$OBJ',maybequoted(ScriptFixFileName(ObjFileName)));
  511. end
  512. else
  513. begin
  514. {$ifdef hasunix}
  515. if DoPipe then
  516. Replace(result,'$ASM','')
  517. else
  518. {$endif}
  519. Replace(result,'$ASM',maybequoted(AsmFileName));
  520. Replace(result,'$OBJ',maybequoted(ObjFileName));
  521. end;
  522. if (cs_create_pic in current_settings.moduleswitches) then
  523. Replace(result,'$PIC','-KPIC')
  524. else
  525. Replace(result,'$PIC','');
  526. if (cs_asm_source in current_settings.globalswitches) then
  527. Replace(result,'$NOWARN','')
  528. else
  529. Replace(result,'$NOWARN','-W');
  530. Replace(result,'$EXTRAOPT',asmextraopt);
  531. end;
  532. procedure TExternalAssembler.AsmCreate(Aplace:tcutplace);
  533. begin
  534. if SmartAsm then
  535. NextSmartName(Aplace);
  536. {$ifdef hasunix}
  537. if DoPipe then
  538. begin
  539. if SmartAsm then
  540. begin
  541. if (SmartFilesCount<=1) then
  542. Message1(exec_i_assembling_smart,name);
  543. end
  544. else
  545. Message1(exec_i_assembling_pipe,AsmFileName);
  546. POpen(outfile,maybequoted(FindAssembler)+' '+MakeCmdLine,'W');
  547. end
  548. else
  549. {$endif}
  550. begin
  551. Assign(outfile,AsmFileName);
  552. {$push} {$I-}
  553. Rewrite(outfile,1);
  554. {$pop}
  555. if ioresult<>0 then
  556. begin
  557. ioerror:=true;
  558. Message1(exec_d_cant_create_asmfile,AsmFileName);
  559. end;
  560. end;
  561. outcnt:=0;
  562. AsmSize:=0;
  563. AsmStartSize:=0;
  564. end;
  565. procedure TExternalAssembler.AsmClose;
  566. var
  567. f : file;
  568. FileAge : longint;
  569. begin
  570. AsmFlush;
  571. {$ifdef hasunix}
  572. if DoPipe then
  573. begin
  574. if PClose(outfile) <> 0 then
  575. GenerateError;
  576. end
  577. else
  578. {$endif}
  579. begin
  580. {Touch Assembler time to ppu time is there is a ppufilename}
  581. if ppufilename<>'' then
  582. begin
  583. Assign(f,ppufilename);
  584. {$push} {$I-}
  585. reset(f,1);
  586. {$pop}
  587. if ioresult=0 then
  588. begin
  589. FileAge := FileGetDate(GetFileHandle(f));
  590. close(f);
  591. reset(outfile,1);
  592. FileSetDate(GetFileHandle(outFile),FileAge);
  593. end;
  594. end;
  595. close(outfile);
  596. end;
  597. end;
  598. procedure TExternalAssembler.WriteSourceLine(hp: tailineinfo);
  599. var
  600. module : tmodule;
  601. begin
  602. { load infile }
  603. if (lastfileinfo.moduleindex<>hp.fileinfo.moduleindex) or
  604. (lastfileinfo.fileindex<>hp.fileinfo.fileindex) then
  605. begin
  606. { in case of a generic the module can be different }
  607. if current_module.unit_index=hp.fileinfo.moduleindex then
  608. module:=current_module
  609. else
  610. module:=get_module(hp.fileinfo.moduleindex);
  611. { during the compilation of the system unit there are cases when
  612. the fileinfo contains just zeros => invalid }
  613. if assigned(module) then
  614. infile:=module.sourcefiles.get_file(hp.fileinfo.fileindex)
  615. else
  616. infile:=nil;
  617. if assigned(infile) then
  618. begin
  619. { open only if needed !! }
  620. if (cs_asm_source in current_settings.globalswitches) then
  621. infile.open;
  622. end;
  623. { avoid unnecessary reopens of the same file !! }
  624. lastfileinfo.fileindex:=hp.fileinfo.fileindex;
  625. lastfileinfo.moduleindex:=hp.fileinfo.moduleindex;
  626. { be sure to change line !! }
  627. lastfileinfo.line:=-1;
  628. end;
  629. { write source }
  630. if (cs_asm_source in current_settings.globalswitches) and
  631. assigned(infile) then
  632. begin
  633. if (infile<>lastinfile) then
  634. begin
  635. AsmWriteLn(target_asm.comment+'['+infile.name+']');
  636. if assigned(lastinfile) then
  637. lastinfile.close;
  638. end;
  639. if (hp.fileinfo.line<>lastfileinfo.line) and
  640. (hp.fileinfo.line<infile.maxlinebuf) then
  641. begin
  642. if (hp.fileinfo.line<>0) and
  643. (infile.linebuf^[hp.fileinfo.line]>=0) then
  644. AsmWriteLn(target_asm.comment+'['+tostr(hp.fileinfo.line)+'] '+
  645. fixline(infile.GetLineStr(hp.fileinfo.line)));
  646. { set it to a negative value !
  647. to make that is has been read already !! PM }
  648. if (infile.linebuf^[hp.fileinfo.line]>=0) then
  649. infile.linebuf^[hp.fileinfo.line]:=-infile.linebuf^[hp.fileinfo.line]-1;
  650. end;
  651. end;
  652. lastfileinfo:=hp.fileinfo;
  653. lastinfile:=infile;
  654. end;
  655. procedure TExternalAssembler.WriteTempalloc(hp: tai_tempalloc);
  656. begin
  657. {$ifdef EXTDEBUG}
  658. if assigned(hp.problem) then
  659. AsmWriteLn(target_asm.comment+'Temp '+tostr(hp.temppos)+','+
  660. tostr(hp.tempsize)+' '+hp.problem^)
  661. else
  662. {$endif EXTDEBUG}
  663. AsmWriteLn(target_asm.comment+'Temp '+tostr(hp.temppos)+','+
  664. tostr(hp.tempsize)+' '+tempallocstr[hp.allocation]);
  665. end;
  666. procedure TExternalAssembler.WriteTree(p:TAsmList);
  667. begin
  668. end;
  669. procedure TExternalAssembler.WriteAsmList;
  670. begin
  671. end;
  672. procedure TExternalAssembler.MakeObject;
  673. begin
  674. AsmCreate(cut_normal);
  675. FillChar(lastfileinfo, sizeof(lastfileinfo), 0);
  676. lastfileinfo.line := -1;
  677. lastinfile := nil;
  678. lastsectype := sec_none;
  679. WriteAsmList;
  680. AsmClose;
  681. if not(ioerror) then
  682. DoAssemble;
  683. end;
  684. {*****************************************************************************
  685. TInternalAssembler
  686. *****************************************************************************}
  687. constructor TInternalAssembler.create(smart:boolean);
  688. begin
  689. inherited create(smart);
  690. ObjOutput:=nil;
  691. ObjData:=nil;
  692. SmartAsm:=smart;
  693. end;
  694. destructor TInternalAssembler.destroy;
  695. begin
  696. if assigned(ObjData) then
  697. ObjData.free;
  698. if assigned(ObjOutput) then
  699. ObjOutput.free;
  700. end;
  701. procedure TInternalAssembler.WriteStab(p:pchar);
  702. function consumecomma(var p:pchar):boolean;
  703. begin
  704. while (p^=' ') do
  705. inc(p);
  706. result:=(p^=',');
  707. inc(p);
  708. end;
  709. function consumenumber(var p:pchar;out value:longint):boolean;
  710. var
  711. hs : string;
  712. len,
  713. code : integer;
  714. begin
  715. value:=0;
  716. while (p^=' ') do
  717. inc(p);
  718. len:=0;
  719. while (p^ in ['0'..'9']) do
  720. begin
  721. inc(len);
  722. hs[len]:=p^;
  723. inc(p);
  724. end;
  725. if len>0 then
  726. begin
  727. hs[0]:=chr(len);
  728. val(hs,value,code);
  729. end
  730. else
  731. code:=-1;
  732. result:=(code=0);
  733. end;
  734. function consumeoffset(var p:pchar;out relocsym:tobjsymbol;out value:longint):boolean;
  735. var
  736. hs : string;
  737. len,
  738. code : integer;
  739. pstart : pchar;
  740. sym : tobjsymbol;
  741. exprvalue : longint;
  742. gotmin,
  743. have_first_symbol,
  744. have_second_symbol,
  745. dosub : boolean;
  746. begin
  747. result:=false;
  748. value:=0;
  749. relocsym:=nil;
  750. gotmin:=false;
  751. have_first_symbol:=false;
  752. have_second_symbol:=false;
  753. repeat
  754. dosub:=false;
  755. exprvalue:=0;
  756. if gotmin then
  757. begin
  758. dosub:=true;
  759. gotmin:=false;
  760. end;
  761. while (p^=' ') do
  762. inc(p);
  763. case p^ of
  764. #0 :
  765. break;
  766. ' ' :
  767. inc(p);
  768. '0'..'9' :
  769. begin
  770. len:=0;
  771. while (p^ in ['0'..'9']) do
  772. begin
  773. inc(len);
  774. hs[len]:=p^;
  775. inc(p);
  776. end;
  777. hs[0]:=chr(len);
  778. val(hs,exprvalue,code);
  779. if code<>0 then
  780. internalerror(200702251);
  781. end;
  782. '.','_',
  783. 'A'..'Z',
  784. 'a'..'z' :
  785. begin
  786. pstart:=p;
  787. while not(p^ in [#0,' ','-','+']) do
  788. inc(p);
  789. len:=p-pstart;
  790. if len>255 then
  791. internalerror(200509187);
  792. move(pstart^,hs[1],len);
  793. hs[0]:=chr(len);
  794. sym:=objdata.symbolref(hs);
  795. { Second symbol? }
  796. if assigned(relocsym) then
  797. begin
  798. if have_second_symbol then
  799. internalerror(2007032201);
  800. have_second_symbol:=true;
  801. if not have_first_symbol then
  802. internalerror(2007032202);
  803. { second symbol should substracted to first }
  804. if not dosub then
  805. internalerror(2007032203);
  806. if (relocsym.objsection<>sym.objsection) then
  807. internalerror(2005091810);
  808. exprvalue:=relocsym.address-sym.address;
  809. relocsym:=nil;
  810. dosub:=false;
  811. end
  812. else
  813. begin
  814. relocsym:=sym;
  815. if assigned(sym.objsection) then
  816. begin
  817. { first symbol should be + }
  818. if not have_first_symbol and dosub then
  819. internalerror(2007032204);
  820. have_first_symbol:=true;
  821. end;
  822. end;
  823. end;
  824. '+' :
  825. begin
  826. { nothing, by default addition is done }
  827. inc(p);
  828. end;
  829. '-' :
  830. begin
  831. gotmin:=true;
  832. inc(p);
  833. end;
  834. else
  835. internalerror(200509189);
  836. end;
  837. if dosub then
  838. dec(value,exprvalue)
  839. else
  840. inc(value,exprvalue);
  841. until false;
  842. result:=true;
  843. end;
  844. var
  845. stabstrlen,
  846. ofs,
  847. nline,
  848. nidx,
  849. nother,
  850. i : longint;
  851. stab : TObjStabEntry;
  852. relocsym : TObjSymbol;
  853. pstr,
  854. pcurr,
  855. pendquote : pchar;
  856. oldsec : TObjSection;
  857. begin
  858. pcurr:=nil;
  859. pstr:=nil;
  860. pendquote:=nil;
  861. relocsym:=nil;
  862. ofs:=0;
  863. { Parse string part }
  864. if (p[0]='"') then
  865. begin
  866. pstr:=@p[1];
  867. { Ignore \" inside the string }
  868. i:=1;
  869. while not((p[i]='"') and (p[i-1]<>'\')) and
  870. (p[i]<>#0) do
  871. inc(i);
  872. pendquote:=@p[i];
  873. pendquote^:=#0;
  874. pcurr:=@p[i+1];
  875. if not consumecomma(pcurr) then
  876. internalerror(200509181);
  877. end
  878. else
  879. pcurr:=p;
  880. { When in pass 1 then only alloc and leave }
  881. if ObjData.currpass=1 then
  882. begin
  883. ObjData.StabsSec.Alloc(sizeof(TObjStabEntry));
  884. if assigned(pstr) and (pstr[0]<>#0) then
  885. ObjData.StabStrSec.Alloc(strlen(pstr)+1);
  886. end
  887. else
  888. begin
  889. { Stabs format: nidx,nother,nline[,offset] }
  890. if not consumenumber(pcurr,nidx) then
  891. internalerror(200509182);
  892. if not consumecomma(pcurr) then
  893. internalerror(200509183);
  894. if not consumenumber(pcurr,nother) then
  895. internalerror(200509184);
  896. if not consumecomma(pcurr) then
  897. internalerror(200509185);
  898. if not consumenumber(pcurr,nline) then
  899. internalerror(200509186);
  900. if consumecomma(pcurr) then
  901. consumeoffset(pcurr,relocsym,ofs);
  902. { Generate stab entry }
  903. if assigned(pstr) and (pstr[0]<>#0) then
  904. begin
  905. stabstrlen:=strlen(pstr);
  906. {$ifdef optimizestabs}
  907. StabStrEntry:=nil;
  908. if (nidx=N_SourceFile) or (nidx=N_IncludeFile) then
  909. begin
  910. hs:=strpas(pstr);
  911. StabstrEntry:=StabStrDict.Find(hs);
  912. if not assigned(StabstrEntry) then
  913. begin
  914. StabstrEntry:=TStabStrEntry.Create(hs);
  915. StabstrEntry:=StabStrSec.Size;
  916. StabStrDict.Insert(StabstrEntry);
  917. { generate new stab }
  918. StabstrEntry:=nil;
  919. end;
  920. end;
  921. if assigned(StabstrEntry) then
  922. stab.strpos:=StabstrEntry.strpos
  923. else
  924. {$endif optimizestabs}
  925. begin
  926. stab.strpos:=ObjData.StabStrSec.Size;
  927. ObjData.StabStrSec.write(pstr^,stabstrlen+1);
  928. end;
  929. end
  930. else
  931. stab.strpos:=0;
  932. stab.ntype:=byte(nidx);
  933. stab.ndesc:=word(nline);
  934. stab.nother:=byte(nother);
  935. stab.nvalue:=ofs;
  936. { Write the stab first without the value field. Then
  937. write a the value field with relocation }
  938. oldsec:=ObjData.CurrObjSec;
  939. ObjData.SetSection(ObjData.StabsSec);
  940. ObjData.Writebytes(stab,sizeof(TObjStabEntry)-4);
  941. ObjData.Writereloc(stab.nvalue,4,relocsym,RELOC_ABSOLUTE32);
  942. ObjData.setsection(oldsec);
  943. end;
  944. if assigned(pendquote) then
  945. pendquote^:='"';
  946. end;
  947. function TInternalAssembler.MaybeNextList(var hp:Tai):boolean;
  948. begin
  949. { maybe end of list }
  950. while not assigned(hp) do
  951. begin
  952. if currlistidx<lists then
  953. begin
  954. inc(currlistidx);
  955. currlist:=list[currlistidx];
  956. hp:=Tai(currList.first);
  957. end
  958. else
  959. begin
  960. MaybeNextList:=false;
  961. exit;
  962. end;
  963. end;
  964. MaybeNextList:=true;
  965. end;
  966. function TInternalAssembler.SetIndirectToSymbol(hp: Tai; const indirectname: string): Boolean;
  967. var
  968. objsym : TObjSymbol;
  969. indsym : TObjSymbol;
  970. begin
  971. Result:=
  972. Assigned(hp) and
  973. (hp.typ=ait_symbol);
  974. if not Result then
  975. Exit;
  976. objsym:=Objdata.SymbolRef(tai_symbol(hp).sym);
  977. objsym.size:=0;
  978. indsym := TObjSymbol(ObjData.ObjSymbolList.Find(indirectname));
  979. if not Assigned(indsym) then
  980. begin
  981. { it's possible that indirect symbol is not present in the list,
  982. so we must create it as undefined }
  983. indsym:=TObjSymbol.Create(ObjData.ObjSymbolList, indirectname);
  984. indsym.typ:=AT_NONE;
  985. indsym.bind:=AB_NONE;
  986. end;
  987. objsym.indsymbol:=indsym;
  988. Result:=true;
  989. end;
  990. function TInternalAssembler.TreePass0(hp:Tai):Tai;
  991. var
  992. objsym,
  993. objsymend : TObjSymbol;
  994. begin
  995. while assigned(hp) do
  996. begin
  997. case hp.typ of
  998. ait_align :
  999. begin
  1000. if tai_align_abstract(hp).aligntype>1 then
  1001. begin
  1002. { always use the maximum fillsize in this pass to avoid possible
  1003. short jumps to become out of range }
  1004. Tai_align_abstract(hp).fillsize:=Tai_align_abstract(hp).aligntype;
  1005. ObjData.alloc(Tai_align_abstract(hp).fillsize);
  1006. { may need to increase alignment of section }
  1007. if tai_align_abstract(hp).aligntype>ObjData.CurrObjSec.secalign then
  1008. ObjData.CurrObjSec.secalign:=tai_align_abstract(hp).aligntype;
  1009. end
  1010. else
  1011. Tai_align_abstract(hp).fillsize:=0;
  1012. end;
  1013. ait_datablock :
  1014. begin
  1015. {$ifdef USE_COMM_IN_BSS}
  1016. if writingpackages and
  1017. Tai_datablock(hp).is_global then
  1018. ObjData.SymbolDefine(Tai_datablock(hp).sym)
  1019. else
  1020. {$endif USE_COMM_IN_BSS}
  1021. begin
  1022. ObjData.allocalign(used_align(size_2_align(Tai_datablock(hp).size),0,ObjData.CurrObjSec.secalign));
  1023. ObjData.SymbolDefine(Tai_datablock(hp).sym);
  1024. ObjData.alloc(Tai_datablock(hp).size);
  1025. end;
  1026. end;
  1027. ait_real_80bit :
  1028. ObjData.alloc(tai_real_80bit(hp).savesize);
  1029. ait_real_64bit :
  1030. ObjData.alloc(8);
  1031. ait_real_32bit :
  1032. ObjData.alloc(4);
  1033. ait_comp_64bit :
  1034. ObjData.alloc(8);
  1035. ait_const:
  1036. begin
  1037. { if symbols are provided we can calculate the value for relative symbols.
  1038. This is required for length calculation of leb128 constants }
  1039. if assigned(tai_const(hp).sym) then
  1040. begin
  1041. objsym:=Objdata.SymbolRef(tai_const(hp).sym);
  1042. { objsym already defined and there is endsym? }
  1043. if assigned(objsym.objsection) and assigned(tai_const(hp).endsym) then
  1044. begin
  1045. objsymend:=Objdata.SymbolRef(tai_const(hp).endsym);
  1046. { objsymend already defined? }
  1047. if assigned(objsymend.objsection) then
  1048. begin
  1049. if objsymend.objsection<>objsym.objsection then
  1050. begin
  1051. { leb128 relative constants are not relocatable, but other types are,
  1052. given that objsym belongs to the current section. }
  1053. if (Tai_const(hp).consttype in [aitconst_uleb128bit,aitconst_sleb128bit]) or
  1054. (objsym.objsection<>ObjData.CurrObjSec) then
  1055. InternalError(200404124);
  1056. end
  1057. else
  1058. Tai_const(hp).value:=objsymend.address-objsym.address+Tai_const(hp).symofs;
  1059. end;
  1060. end;
  1061. end;
  1062. ObjData.alloc(tai_const(hp).size);
  1063. end;
  1064. ait_directive:
  1065. begin
  1066. case tai_directive(hp).directive of
  1067. asd_indirect_symbol:
  1068. { handled in TreePass1 }
  1069. ;
  1070. asd_lazy_reference:
  1071. begin
  1072. if tai_directive(hp).name='' then
  1073. Internalerror(2009112101);
  1074. objsym:=ObjData.symbolref(tai_directive(hp).name);
  1075. objsym.bind:=AB_LAZY;
  1076. end;
  1077. asd_reference:
  1078. { ignore for now, but should be added}
  1079. ;
  1080. else
  1081. internalerror(2010011101);
  1082. end;
  1083. end;
  1084. ait_section:
  1085. begin
  1086. ObjData.CreateSection(Tai_section(hp).sectype,Tai_section(hp).name^,Tai_section(hp).secorder);
  1087. Tai_section(hp).sec:=ObjData.CurrObjSec;
  1088. end;
  1089. ait_symbol :
  1090. begin
  1091. { needs extra support in the internal assembler }
  1092. { the value is just ignored }
  1093. {if tai_symbol(hp).has_value then
  1094. internalerror(2009090804); ;}
  1095. ObjData.SymbolDefine(Tai_symbol(hp).sym);
  1096. end;
  1097. ait_label :
  1098. ObjData.SymbolDefine(Tai_label(hp).labsym);
  1099. ait_string :
  1100. ObjData.alloc(Tai_string(hp).len);
  1101. ait_instruction :
  1102. begin
  1103. { reset instructions which could change in pass 2 }
  1104. Taicpu(hp).resetpass2;
  1105. ObjData.alloc(Taicpu(hp).Pass1(ObjData));
  1106. end;
  1107. ait_cutobject :
  1108. if SmartAsm then
  1109. break;
  1110. end;
  1111. hp:=Tai(hp.next);
  1112. end;
  1113. TreePass0:=hp;
  1114. end;
  1115. function TInternalAssembler.TreePass1(hp:Tai):Tai;
  1116. var
  1117. objsym,
  1118. objsymend : TObjSymbol;
  1119. begin
  1120. while assigned(hp) do
  1121. begin
  1122. case hp.typ of
  1123. ait_align :
  1124. begin
  1125. if tai_align_abstract(hp).aligntype>1 then
  1126. begin
  1127. { here we must determine the fillsize which is used in pass2 }
  1128. Tai_align_abstract(hp).fillsize:=align(ObjData.CurrObjSec.Size,Tai_align_abstract(hp).aligntype)-
  1129. ObjData.CurrObjSec.Size;
  1130. ObjData.alloc(Tai_align_abstract(hp).fillsize);
  1131. end;
  1132. end;
  1133. ait_datablock :
  1134. begin
  1135. if (oso_data in ObjData.CurrObjSec.secoptions) then
  1136. Message(asmw_e_alloc_data_only_in_bss);
  1137. {$ifdef USE_COMM_IN_BSS}
  1138. if writingpackages and
  1139. Tai_datablock(hp).is_global then
  1140. begin
  1141. objsym:=ObjData.SymbolDefine(Tai_datablock(hp).sym);
  1142. objsym.size:=Tai_datablock(hp).size;
  1143. objsym.bind:=AB_COMMON;
  1144. objsym.alignment:=needtowritealignmentalsoforELF;
  1145. end
  1146. else
  1147. {$endif USE_COMM_IN_BSS}
  1148. begin
  1149. ObjData.allocalign(used_align(size_2_align(Tai_datablock(hp).size),0,ObjData.CurrObjSec.secalign));
  1150. objsym:=ObjData.SymbolDefine(Tai_datablock(hp).sym);
  1151. objsym.size:=Tai_datablock(hp).size;
  1152. ObjData.alloc(Tai_datablock(hp).size);
  1153. end;
  1154. end;
  1155. ait_real_80bit :
  1156. ObjData.alloc(tai_real_80bit(hp).savesize);
  1157. ait_real_64bit :
  1158. ObjData.alloc(8);
  1159. ait_real_32bit :
  1160. ObjData.alloc(4);
  1161. ait_comp_64bit :
  1162. ObjData.alloc(8);
  1163. ait_const:
  1164. begin
  1165. { Recalculate relative symbols }
  1166. if assigned(tai_const(hp).sym) and
  1167. assigned(tai_const(hp).endsym) then
  1168. begin
  1169. objsym:=Objdata.SymbolRef(tai_const(hp).sym);
  1170. objsymend:=Objdata.SymbolRef(tai_const(hp).endsym);
  1171. if objsymend.objsection<>objsym.objsection then
  1172. begin
  1173. if (Tai_const(hp).consttype in [aitconst_uleb128bit,aitconst_sleb128bit]) or
  1174. (objsym.objsection<>ObjData.CurrObjSec) then
  1175. internalerror(200905042);
  1176. end
  1177. else
  1178. Tai_const(hp).value:=objsymend.address-objsym.address+Tai_const(hp).symofs;
  1179. end;
  1180. ObjData.alloc(tai_const(hp).size);
  1181. end;
  1182. ait_section:
  1183. begin
  1184. { use cached value }
  1185. ObjData.setsection(Tai_section(hp).sec);
  1186. end;
  1187. ait_stab :
  1188. begin
  1189. if assigned(Tai_stab(hp).str) then
  1190. WriteStab(Tai_stab(hp).str);
  1191. end;
  1192. ait_symbol :
  1193. ObjData.SymbolDefine(Tai_symbol(hp).sym);
  1194. ait_symbol_end :
  1195. begin
  1196. objsym:=ObjData.SymbolRef(Tai_symbol_end(hp).sym);
  1197. objsym.size:=ObjData.CurrObjSec.Size-objsym.offset;
  1198. end;
  1199. ait_label :
  1200. ObjData.SymbolDefine(Tai_label(hp).labsym);
  1201. ait_string :
  1202. ObjData.alloc(Tai_string(hp).len);
  1203. ait_instruction :
  1204. ObjData.alloc(Taicpu(hp).Pass1(ObjData));
  1205. ait_cutobject :
  1206. if SmartAsm then
  1207. break;
  1208. ait_directive :
  1209. begin
  1210. case tai_directive(hp).directive of
  1211. asd_indirect_symbol:
  1212. if tai_directive(hp).name='' then
  1213. Internalerror(2009101103)
  1214. else if not SetIndirectToSymbol(Tai(hp.Previous), tai_directive(hp).name) then
  1215. Internalerror(2009101102);
  1216. asd_lazy_reference:
  1217. { handled in TreePass0 }
  1218. ;
  1219. asd_reference:
  1220. { ignore for now, but should be added}
  1221. ;
  1222. else
  1223. internalerror(2010011102);
  1224. end;
  1225. end;
  1226. end;
  1227. hp:=Tai(hp.next);
  1228. end;
  1229. TreePass1:=hp;
  1230. end;
  1231. function TInternalAssembler.TreePass2(hp:Tai):Tai;
  1232. var
  1233. fillbuffer : tfillbuffer;
  1234. {$ifdef x86}
  1235. co : comp;
  1236. {$endif x86}
  1237. leblen : byte;
  1238. lebbuf : array[0..63] of byte;
  1239. objsym,
  1240. objsymend : TObjSymbol;
  1241. zerobuf : array[0..63] of byte;
  1242. relative_reloc: boolean;
  1243. begin
  1244. fillchar(zerobuf,sizeof(zerobuf),0);
  1245. fillchar(objsym,sizeof(objsym),0);
  1246. fillchar(objsymend,sizeof(objsymend),0);
  1247. { main loop }
  1248. while assigned(hp) do
  1249. begin
  1250. case hp.typ of
  1251. ait_align :
  1252. begin
  1253. if tai_align_abstract(hp).aligntype>ObjData.CurrObjSec.secalign then
  1254. InternalError(2012072301);
  1255. if oso_data in ObjData.CurrObjSec.secoptions then
  1256. ObjData.writebytes(Tai_align_abstract(hp).calculatefillbuf(fillbuffer,oso_executable in ObjData.CurrObjSec.secoptions)^,
  1257. Tai_align_abstract(hp).fillsize)
  1258. else
  1259. ObjData.alloc(Tai_align_abstract(hp).fillsize);
  1260. end;
  1261. ait_section :
  1262. begin
  1263. { use cached value }
  1264. ObjData.setsection(Tai_section(hp).sec);
  1265. end;
  1266. ait_symbol :
  1267. begin
  1268. ObjOutput.exportsymbol(ObjData.SymbolRef(Tai_symbol(hp).sym));
  1269. end;
  1270. ait_symbol_end :
  1271. begin
  1272. { recalculate size, as some preceding instructions
  1273. could have been changed to smaller size }
  1274. objsym:=ObjData.SymbolRef(Tai_symbol_end(hp).sym);
  1275. objsym.size:=ObjData.CurrObjSec.Size-objsym.offset;
  1276. end;
  1277. ait_datablock :
  1278. begin
  1279. ObjOutput.exportsymbol(ObjData.SymbolRef(Tai_datablock(hp).sym));
  1280. {$ifdef USE_COMM_IN_BSS}
  1281. if not(writingpackages and
  1282. Tai_datablock(hp).is_global) then
  1283. {$endif USE_COMM_IN_BSS}
  1284. begin
  1285. ObjData.allocalign(used_align(size_2_align(Tai_datablock(hp).size),0,ObjData.CurrObjSec.secalign));
  1286. ObjData.alloc(Tai_datablock(hp).size);
  1287. end;
  1288. end;
  1289. ait_real_80bit :
  1290. begin
  1291. ObjData.writebytes(Tai_real_80bit(hp).value,10);
  1292. ObjData.writebytes(zerobuf,Tai_real_80bit(hp).savesize-10);
  1293. end;
  1294. ait_real_64bit :
  1295. ObjData.writebytes(Tai_real_64bit(hp).value,8);
  1296. ait_real_32bit :
  1297. ObjData.writebytes(Tai_real_32bit(hp).value,4);
  1298. ait_comp_64bit :
  1299. begin
  1300. {$ifdef x86}
  1301. co:=comp(Tai_comp_64bit(hp).value);
  1302. ObjData.writebytes(co,8);
  1303. {$endif x86}
  1304. end;
  1305. ait_string :
  1306. ObjData.writebytes(Tai_string(hp).str^,Tai_string(hp).len);
  1307. ait_const :
  1308. begin
  1309. { Recalculate relative symbols, addresses of forward references
  1310. can be changed in treepass1 }
  1311. relative_reloc:=false;
  1312. if assigned(tai_const(hp).sym) and
  1313. assigned(tai_const(hp).endsym) then
  1314. begin
  1315. objsym:=Objdata.SymbolRef(tai_const(hp).sym);
  1316. objsymend:=Objdata.SymbolRef(tai_const(hp).endsym);
  1317. relative_reloc:=(objsym.objsection<>objsymend.objsection);
  1318. Tai_const(hp).value:=objsymend.address-objsym.address+Tai_const(hp).symofs;
  1319. end;
  1320. case tai_const(hp).consttype of
  1321. aitconst_64bit,
  1322. aitconst_32bit,
  1323. aitconst_16bit,
  1324. aitconst_64bit_unaligned,
  1325. aitconst_32bit_unaligned,
  1326. aitconst_16bit_unaligned,
  1327. aitconst_8bit :
  1328. begin
  1329. if assigned(tai_const(hp).sym) and
  1330. not assigned(tai_const(hp).endsym) then
  1331. ObjData.writereloc(Tai_const(hp).symofs,tai_const(hp).size,Objdata.SymbolRef(tai_const(hp).sym),RELOC_ABSOLUTE)
  1332. else if relative_reloc then
  1333. ObjData.writereloc(ObjData.CurrObjSec.size+tai_const(hp).size-objsym.address+tai_const(hp).symofs,tai_const(hp).size,objsymend,RELOC_RELATIVE)
  1334. else
  1335. ObjData.writebytes(Tai_const(hp).value,tai_const(hp).size);
  1336. end;
  1337. aitconst_rva_symbol :
  1338. begin
  1339. { PE32+? }
  1340. if target_info.system=system_x86_64_win64 then
  1341. ObjData.writereloc(Tai_const(hp).symofs,sizeof(longint),Objdata.SymbolRef(tai_const(hp).sym),RELOC_RVA)
  1342. else
  1343. ObjData.writereloc(Tai_const(hp).symofs,sizeof(pint),Objdata.SymbolRef(tai_const(hp).sym),RELOC_RVA);
  1344. end;
  1345. aitconst_secrel32_symbol :
  1346. begin
  1347. { Required for DWARF2 support under Windows }
  1348. ObjData.writereloc(Tai_const(hp).symofs,sizeof(longint),Objdata.SymbolRef(tai_const(hp).sym),RELOC_SECREL32);
  1349. end;
  1350. aitconst_uleb128bit,
  1351. aitconst_sleb128bit :
  1352. begin
  1353. if tai_const(hp).consttype=aitconst_uleb128bit then
  1354. leblen:=EncodeUleb128(qword(Tai_const(hp).value),lebbuf)
  1355. else
  1356. leblen:=EncodeSleb128(Tai_const(hp).value,lebbuf);
  1357. if leblen<>tai_const(hp).size then
  1358. internalerror(200709271);
  1359. ObjData.writebytes(lebbuf,leblen);
  1360. end;
  1361. aitconst_darwin_dwarf_delta32,
  1362. aitconst_darwin_dwarf_delta64:
  1363. ObjData.writebytes(Tai_const(hp).value,tai_const(hp).size);
  1364. else
  1365. internalerror(200603254);
  1366. end;
  1367. end;
  1368. ait_label :
  1369. begin
  1370. { exporting shouldn't be necessary as labels are local,
  1371. but it's better to be on the safe side (PFV) }
  1372. ObjOutput.exportsymbol(ObjData.SymbolRef(Tai_label(hp).labsym));
  1373. end;
  1374. ait_instruction :
  1375. Taicpu(hp).Pass2(ObjData);
  1376. ait_stab :
  1377. WriteStab(Tai_stab(hp).str);
  1378. ait_function_name,
  1379. ait_force_line : ;
  1380. ait_cutobject :
  1381. if SmartAsm then
  1382. break;
  1383. {$ifndef DISABLE_WIN64_SEH}
  1384. ait_seh_directive :
  1385. tai_seh_directive(hp).generate_code(objdata);
  1386. {$endif DISABLE_WIN64_SEH}
  1387. end;
  1388. hp:=Tai(hp.next);
  1389. end;
  1390. TreePass2:=hp;
  1391. end;
  1392. procedure TInternalAssembler.writetree;
  1393. label
  1394. doexit;
  1395. var
  1396. hp : Tai;
  1397. ObjWriter : TObjectWriter;
  1398. begin
  1399. ObjWriter:=TObjectwriter.create;
  1400. ObjOutput:=CObjOutput.Create(ObjWriter);
  1401. ObjData:=ObjOutput.newObjData(ObjFileName);
  1402. { Pass 0 }
  1403. ObjData.currpass:=0;
  1404. ObjData.createsection(sec_code);
  1405. ObjData.beforealloc;
  1406. { start with list 1 }
  1407. currlistidx:=1;
  1408. currlist:=list[currlistidx];
  1409. hp:=Tai(currList.first);
  1410. while assigned(hp) do
  1411. begin
  1412. hp:=TreePass0(hp);
  1413. MaybeNextList(hp);
  1414. end;
  1415. ObjData.afteralloc;
  1416. { leave if errors have occured }
  1417. if errorcount>0 then
  1418. goto doexit;
  1419. { Pass 1 }
  1420. ObjData.currpass:=1;
  1421. ObjData.resetsections;
  1422. ObjData.beforealloc;
  1423. ObjData.createsection(sec_code);
  1424. { start with list 1 }
  1425. currlistidx:=1;
  1426. currlist:=list[currlistidx];
  1427. hp:=Tai(currList.first);
  1428. while assigned(hp) do
  1429. begin
  1430. hp:=TreePass1(hp);
  1431. MaybeNextList(hp);
  1432. end;
  1433. ObjData.createsection(sec_code);
  1434. ObjData.afteralloc;
  1435. { leave if errors have occured }
  1436. if errorcount>0 then
  1437. goto doexit;
  1438. { Pass 2 }
  1439. ObjData.currpass:=2;
  1440. ObjData.resetsections;
  1441. ObjData.beforewrite;
  1442. ObjData.createsection(sec_code);
  1443. { start with list 1 }
  1444. currlistidx:=1;
  1445. currlist:=list[currlistidx];
  1446. hp:=Tai(currList.first);
  1447. while assigned(hp) do
  1448. begin
  1449. hp:=TreePass2(hp);
  1450. MaybeNextList(hp);
  1451. end;
  1452. ObjData.createsection(sec_code);
  1453. ObjData.afterwrite;
  1454. { don't write the .o file if errors have occured }
  1455. if errorcount=0 then
  1456. begin
  1457. { write objectfile }
  1458. ObjOutput.startobjectfile(ObjFileName);
  1459. ObjOutput.writeobjectfile(ObjData);
  1460. end;
  1461. doexit:
  1462. { Cleanup }
  1463. ObjData.free;
  1464. ObjData:=nil;
  1465. ObjWriter.free;
  1466. end;
  1467. procedure TInternalAssembler.writetreesmart;
  1468. var
  1469. hp : Tai;
  1470. startsectype : TAsmSectiontype;
  1471. place: tcutplace;
  1472. ObjWriter : TObjectWriter;
  1473. begin
  1474. if not(cs_asm_leave in current_settings.globalswitches) then
  1475. ObjWriter:=TARObjectWriter.create(current_module.staticlibfilename)
  1476. else
  1477. ObjWriter:=TObjectwriter.create;
  1478. NextSmartName(cut_normal);
  1479. ObjOutput:=CObjOutput.Create(ObjWriter);
  1480. startsectype:=sec_code;
  1481. { start with list 1 }
  1482. currlistidx:=1;
  1483. currlist:=list[currlistidx];
  1484. hp:=Tai(currList.first);
  1485. while assigned(hp) do
  1486. begin
  1487. ObjData:=ObjOutput.newObjData(ObjFileName);
  1488. { Pass 0 }
  1489. ObjData.currpass:=0;
  1490. ObjData.resetsections;
  1491. ObjData.beforealloc;
  1492. ObjData.createsection(startsectype);
  1493. TreePass0(hp);
  1494. ObjData.afteralloc;
  1495. { leave if errors have occured }
  1496. if errorcount>0 then
  1497. break;
  1498. { Pass 1 }
  1499. ObjData.currpass:=1;
  1500. ObjData.resetsections;
  1501. ObjData.beforealloc;
  1502. ObjData.createsection(startsectype);
  1503. TreePass1(hp);
  1504. ObjData.afteralloc;
  1505. { leave if errors have occured }
  1506. if errorcount>0 then
  1507. break;
  1508. { Pass 2 }
  1509. ObjData.currpass:=2;
  1510. ObjOutput.startobjectfile(ObjFileName);
  1511. ObjData.resetsections;
  1512. ObjData.beforewrite;
  1513. ObjData.createsection(startsectype);
  1514. hp:=TreePass2(hp);
  1515. ObjData.afterwrite;
  1516. { leave if errors have occured }
  1517. if errorcount>0 then
  1518. break;
  1519. { write the current objectfile }
  1520. ObjOutput.writeobjectfile(ObjData);
  1521. ObjData.free;
  1522. ObjData:=nil;
  1523. { end of lists? }
  1524. if not MaybeNextList(hp) then
  1525. break;
  1526. { we will start a new objectfile so reset everything }
  1527. { The place can still change in the next while loop, so don't init }
  1528. { the writer yet (JM) }
  1529. if (hp.typ=ait_cutobject) then
  1530. place := Tai_cutobject(hp).place
  1531. else
  1532. place := cut_normal;
  1533. { avoid empty files }
  1534. startsectype:=sec_code;
  1535. while assigned(hp) and
  1536. (Tai(hp).typ in [ait_marker,ait_comment,ait_section,ait_cutobject]) do
  1537. begin
  1538. if Tai(hp).typ=ait_section then
  1539. startsectype:=Tai_section(hp).sectype;
  1540. if (Tai(hp).typ=ait_cutobject) then
  1541. place:=Tai_cutobject(hp).place;
  1542. hp:=Tai(hp.next);
  1543. end;
  1544. if not MaybeNextList(hp) then
  1545. break;
  1546. { start next objectfile }
  1547. NextSmartName(place);
  1548. end;
  1549. ObjData.free;
  1550. ObjData:=nil;
  1551. ObjWriter.free;
  1552. end;
  1553. procedure TInternalAssembler.MakeObject;
  1554. var to_do:set of TasmlistType;
  1555. i:TasmlistType;
  1556. procedure addlist(p:TAsmList);
  1557. begin
  1558. inc(lists);
  1559. list[lists]:=p;
  1560. end;
  1561. begin
  1562. to_do:=[low(Tasmlisttype)..high(Tasmlisttype)];
  1563. if usedeffileforexports then
  1564. exclude(to_do,al_exports);
  1565. if not(tf_section_threadvars in target_info.flags) then
  1566. exclude(to_do,al_threadvars);
  1567. for i:=low(TasmlistType) to high(TasmlistType) do
  1568. if (i in to_do) and (current_asmdata.asmlists[i]<>nil) then
  1569. addlist(current_asmdata.asmlists[i]);
  1570. if SmartAsm then
  1571. writetreesmart
  1572. else
  1573. writetree;
  1574. end;
  1575. {*****************************************************************************
  1576. Generate Assembler Files Main Procedure
  1577. *****************************************************************************}
  1578. Procedure GenerateAsm(smart:boolean);
  1579. var
  1580. a : TAssembler;
  1581. begin
  1582. if not assigned(CAssembler[target_asm.id]) then
  1583. Message(asmw_f_assembler_output_not_supported);
  1584. a:=CAssembler[target_asm.id].Create(smart);
  1585. a.MakeObject;
  1586. a.Free;
  1587. end;
  1588. Procedure OnlyAsm;
  1589. var
  1590. a : TExternalAssembler;
  1591. begin
  1592. a:=TExternalAssembler.Create(false);
  1593. a.DoAssemble;
  1594. a.Free;
  1595. end;
  1596. {*****************************************************************************
  1597. Init/Done
  1598. *****************************************************************************}
  1599. procedure RegisterAssembler(const r:tasminfo;c:TAssemblerClass);
  1600. var
  1601. t : tasm;
  1602. begin
  1603. t:=r.id;
  1604. if assigned(asminfos[t]) then
  1605. writeln('Warning: Assembler is already registered!')
  1606. else
  1607. Getmem(asminfos[t],sizeof(tasminfo));
  1608. asminfos[t]^:=r;
  1609. CAssembler[t]:=c;
  1610. end;
  1611. end.