assemble.pas 57 KB

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