assemble.pas 57 KB

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