assemble.pas 58 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807
  1. {
  2. Copyright (c) 1998-2004 by Peter Vreman
  3. This unit handles the assemblerfile write and assembler calls of FPC
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program; if not, write to the Free Software
  14. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  15. ****************************************************************************
  16. }
  17. {# @abstract(This unit handles the assembler file write and assembler calls of FPC)
  18. Handles the calls to the actual external assemblers, as well as the generation
  19. of object files for smart linking. Also contains the base class for writing
  20. the assembler statements to file.
  21. }
  22. unit assemble;
  23. {$i fpcdefs.inc}
  24. interface
  25. uses
  26. SysUtils,
  27. systems,globtype,globals,aasmbase,aasmtai,aasmdata,ogbase,finput;
  28. const
  29. { maximum of aasmoutput lists there will be }
  30. maxoutputlists = ord(high(tasmlisttype))+1;
  31. { buffer size for writing the .s file }
  32. AsmOutSize=32768*4;
  33. type
  34. TAssembler=class(TObject)
  35. public
  36. {filenames}
  37. path : TPathStr;
  38. name : string;
  39. AsmFileName, { current .s and .o file }
  40. ObjFileName,
  41. ppufilename : TPathStr;
  42. asmprefix : string;
  43. SmartAsm : boolean;
  44. SmartFilesCount,
  45. SmartHeaderCount : longint;
  46. Constructor Create(smart:boolean);virtual;
  47. Destructor Destroy;override;
  48. procedure NextSmartName(place:tcutplace);
  49. procedure MakeObject;virtual;abstract;
  50. end;
  51. {# This is the base class which should be overridden for each each
  52. assembler writer. It is used to actually assembler a file,
  53. and write the output to the assembler file.
  54. }
  55. TExternalAssembler=class(TAssembler)
  56. private
  57. procedure CreateSmartLinkPath(const s:TPathStr);
  58. protected
  59. {outfile}
  60. AsmSize,
  61. AsmStartSize,
  62. outcnt : longint;
  63. outbuf : array[0..AsmOutSize-1] of char;
  64. outfile : file;
  65. ioerror : boolean;
  66. {input source info}
  67. lastfileinfo : tfileposinfo;
  68. infile,
  69. lastinfile : tinputfile;
  70. {last section type written}
  71. lastsectype : TAsmSectionType;
  72. procedure WriteSourceLine(hp: tailineinfo);
  73. procedure WriteTempalloc(hp: tai_tempalloc);
  74. Function DoPipe:boolean;
  75. public
  76. {# Returns the complete path and executable name of the assembler
  77. program.
  78. It first tries looking in the UTIL directory if specified,
  79. otherwise it searches in the free pascal binary directory, in
  80. the current working directory and then in the directories
  81. in the $PATH environment.}
  82. Function FindAssembler:string;
  83. {# Actually does the call to the assembler file. Returns false
  84. if the assembling of the file failed.}
  85. Function CallAssembler(const command:string; const para:TCmdStr):Boolean;
  86. Function DoAssemble:boolean;virtual;
  87. Procedure RemoveAsm;virtual;
  88. Procedure AsmFlush;
  89. Procedure AsmClear;
  90. {# Write a string to the assembler file }
  91. Procedure AsmWrite(const c:char);
  92. Procedure AsmWrite(const s:string);
  93. Procedure AsmWrite(const s:ansistring);
  94. {# Write a string to the assembler file }
  95. Procedure AsmWritePChar(p:pchar);
  96. {# Write a string to the assembler file followed by a new line }
  97. Procedure AsmWriteLn(const c:char);
  98. Procedure AsmWriteLn(const s:string);
  99. Procedure AsmWriteLn(const s:ansistring);
  100. {# Write a new line to the assembler file }
  101. Procedure AsmLn;
  102. procedure AsmCreate(Aplace:tcutplace);
  103. procedure AsmClose;
  104. {# This routine should be overridden for each assembler, it is used
  105. to actually write the abstract assembler stream to file.}
  106. procedure WriteTree(p:TAsmList);virtual;
  107. {# This routine should be overridden for each assembler, it is used
  108. to actually write all the different abstract assembler streams
  109. by calling for each stream type, the @var(WriteTree) method.}
  110. procedure WriteAsmList;virtual;
  111. {# Constructs the command line for calling the assembler }
  112. function MakeCmdLine: TCmdStr; virtual;
  113. public
  114. Constructor Create(smart:boolean);override;
  115. procedure MakeObject;override;
  116. end;
  117. { TInternalAssembler }
  118. TInternalAssembler=class(TAssembler)
  119. private
  120. FCObjOutput : TObjOutputclass;
  121. { the aasmoutput lists that need to be processed }
  122. lists : byte;
  123. list : array[1..maxoutputlists] of TAsmList;
  124. { current processing }
  125. currlistidx : byte;
  126. currlist : TAsmList;
  127. procedure WriteStab(p:pchar);
  128. function MaybeNextList(var hp:Tai):boolean;
  129. function SetIndirectToSymbol(hp: Tai; const indirectname: string): Boolean;
  130. function TreePass0(hp:Tai):Tai;
  131. function TreePass1(hp:Tai):Tai;
  132. function TreePass2(hp:Tai):Tai;
  133. procedure writetree;
  134. procedure writetreesmart;
  135. protected
  136. ObjData : TObjData;
  137. ObjOutput : tObjOutput;
  138. property CObjOutput:TObjOutputclass read FCObjOutput write FCObjOutput;
  139. public
  140. constructor create(smart:boolean);override;
  141. destructor destroy;override;
  142. procedure MakeObject;override;
  143. end;
  144. TAssemblerClass = class of TAssembler;
  145. Procedure GenerateAsm(smart:boolean);
  146. Procedure OnlyAsm;
  147. procedure RegisterAssembler(const r:tasminfo;c:TAssemblerClass);
  148. Implementation
  149. uses
  150. {$ifdef hasunix}
  151. unix,
  152. {$endif}
  153. cutils,cfileutl,
  154. {$ifdef memdebug}
  155. cclasses,
  156. {$endif memdebug}
  157. script,fmodule,verbose,
  158. {$if defined(m68k) or defined(arm)}
  159. cpuinfo,
  160. {$endif m68k or arm}
  161. aasmcpu,
  162. owbase,owar
  163. ;
  164. var
  165. CAssembler : array[tasm] of TAssemblerClass;
  166. function fixline(s:string):string;
  167. {
  168. return s with all leading and ending spaces and tabs removed
  169. }
  170. var
  171. i,j,k : integer;
  172. begin
  173. i:=length(s);
  174. while (i>0) and (s[i] in [#9,' ']) do
  175. dec(i);
  176. j:=1;
  177. while (j<i) and (s[j] in [#9,' ']) do
  178. inc(j);
  179. for k:=j to i do
  180. if s[k] in [#0..#31,#127..#255] then
  181. s[k]:='.';
  182. fixline:=Copy(s,j,i-j+1);
  183. end;
  184. {*****************************************************************************
  185. TAssembler
  186. *****************************************************************************}
  187. Constructor TAssembler.Create(smart:boolean);
  188. begin
  189. { load start values }
  190. AsmFileName:=current_module.AsmFilename;
  191. ObjFileName:=current_module.ObjFileName;
  192. name:=Lower(current_module.modulename^);
  193. path:=current_module.outputpath;
  194. asmprefix := current_module.asmprefix^;
  195. if current_module.outputpath = '' then
  196. ppufilename := ''
  197. else
  198. ppufilename := current_module.ppufilename;
  199. SmartAsm:=smart;
  200. SmartFilesCount:=0;
  201. SmartHeaderCount:=0;
  202. SmartLinkOFiles.Clear;
  203. end;
  204. Destructor TAssembler.Destroy;
  205. begin
  206. end;
  207. procedure TAssembler.NextSmartName(place:tcutplace);
  208. var
  209. s : string;
  210. begin
  211. inc(SmartFilesCount);
  212. if SmartFilesCount>999999 then
  213. Message(asmw_f_too_many_asm_files);
  214. case place of
  215. cut_begin :
  216. begin
  217. inc(SmartHeaderCount);
  218. s:=asmprefix+tostr(SmartHeaderCount)+'h';
  219. end;
  220. cut_normal :
  221. s:=asmprefix+tostr(SmartHeaderCount)+'s';
  222. cut_end :
  223. s:=asmprefix+tostr(SmartHeaderCount)+'t';
  224. end;
  225. AsmFileName:=Path+FixFileName(s+tostr(SmartFilesCount)+target_info.asmext);
  226. ObjFileName:=Path+FixFileName(s+tostr(SmartFilesCount)+target_info.objext);
  227. { insert in container so it can be cleared after the linking }
  228. SmartLinkOFiles.Insert(ObjFileName);
  229. end;
  230. {*****************************************************************************
  231. TExternalAssembler
  232. *****************************************************************************}
  233. Function TExternalAssembler.DoPipe:boolean;
  234. begin
  235. DoPipe:=(cs_asm_pipe in current_settings.globalswitches) and
  236. (([cs_asm_extern,cs_asm_leave,cs_link_on_target] * current_settings.globalswitches) = []) and
  237. ((target_asm.id in [as_gas,as_ggas,as_darwin,as_powerpc_xcoff]));
  238. end;
  239. Constructor TExternalAssembler.Create(smart:boolean);
  240. begin
  241. inherited Create(smart);
  242. if SmartAsm then
  243. begin
  244. path:=FixPath(ChangeFileExt(AsmFileName,target_info.smartext),false);
  245. CreateSmartLinkPath(path);
  246. end;
  247. Outcnt:=0;
  248. end;
  249. procedure TExternalAssembler.CreateSmartLinkPath(const s:TPathStr);
  250. procedure DeleteFilesWithExt(const AExt:string);
  251. var
  252. dir : TRawByteSearchRec;
  253. begin
  254. if findfirst(FixPath(s,false)+'*'+AExt,faAnyFile,dir) = 0 then
  255. begin
  256. repeat
  257. DeleteFile(s+source_info.dirsep+dir.name);
  258. until findnext(dir) <> 0;
  259. end;
  260. findclose(dir);
  261. end;
  262. var
  263. hs : TPathStr;
  264. begin
  265. if PathExists(s,false) then
  266. begin
  267. { the path exists, now we clean only all the .o and .s files }
  268. DeleteFilesWithExt(target_info.objext);
  269. DeleteFilesWithExt(target_info.asmext);
  270. end
  271. else
  272. begin
  273. hs:=s;
  274. if hs[length(hs)] in ['/','\'] then
  275. delete(hs,length(hs),1);
  276. {$push} {$I-}
  277. mkdir(hs);
  278. {$pop}
  279. if ioresult<>0 then;
  280. end;
  281. end;
  282. const
  283. lastas : byte=255;
  284. var
  285. LastASBin : TCmdStr;
  286. Function TExternalAssembler.FindAssembler:string;
  287. var
  288. asfound : boolean;
  289. UtilExe : string;
  290. begin
  291. asfound:=false;
  292. if cs_link_on_target in current_settings.globalswitches then
  293. begin
  294. { If linking on target, don't add any path PM }
  295. FindAssembler:=utilsprefix+ChangeFileExt(target_asm.asmbin,target_info.exeext);
  296. exit;
  297. end
  298. else
  299. UtilExe:=utilsprefix+ChangeFileExt(target_asm.asmbin,source_info.exeext);
  300. if lastas<>ord(target_asm.id) then
  301. begin
  302. lastas:=ord(target_asm.id);
  303. { is an assembler passed ? }
  304. if utilsdirectory<>'' then
  305. asfound:=FindFile(UtilExe,utilsdirectory,false,LastASBin);
  306. if not AsFound then
  307. asfound:=FindExe(UtilExe,false,LastASBin);
  308. if (not asfound) and not(cs_asm_extern in current_settings.globalswitches) then
  309. begin
  310. Message1(exec_e_assembler_not_found,LastASBin);
  311. current_settings.globalswitches:=current_settings.globalswitches+[cs_asm_extern];
  312. end;
  313. if asfound then
  314. Message1(exec_t_using_assembler,LastASBin);
  315. end;
  316. FindAssembler:=LastASBin;
  317. end;
  318. Function TExternalAssembler.CallAssembler(const command:string; const para:TCmdStr):Boolean;
  319. var
  320. DosExitCode : Integer;
  321. begin
  322. result:=true;
  323. if (cs_asm_extern in current_settings.globalswitches) then
  324. begin
  325. if SmartAsm then
  326. AsmRes.AddAsmCommand(command,para,Name+'('+TosTr(SmartFilesCount)+')')
  327. else
  328. AsmRes.AddAsmCommand(command,para,name);
  329. exit;
  330. end;
  331. try
  332. FlushOutput;
  333. DosExitCode:=RequotedExecuteProcess(command,para);
  334. if DosExitCode<>0
  335. then begin
  336. Message1(exec_e_error_while_assembling,tostr(dosexitcode));
  337. result:=false;
  338. end;
  339. except on E:EOSError do
  340. begin
  341. Message1(exec_e_cant_call_assembler,tostr(E.ErrorCode));
  342. current_settings.globalswitches:=current_settings.globalswitches+[cs_asm_extern];
  343. result:=false;
  344. end;
  345. end;
  346. end;
  347. procedure TExternalAssembler.RemoveAsm;
  348. var
  349. g : file;
  350. begin
  351. if cs_asm_leave in current_settings.globalswitches then
  352. exit;
  353. if cs_asm_extern in current_settings.globalswitches then
  354. AsmRes.AddDeleteCommand(AsmFileName)
  355. else
  356. begin
  357. assign(g,AsmFileName);
  358. {$push} {$I-}
  359. erase(g);
  360. {$pop}
  361. if ioresult<>0 then;
  362. end;
  363. end;
  364. Function TExternalAssembler.DoAssemble:boolean;
  365. begin
  366. DoAssemble:=true;
  367. if DoPipe then
  368. exit;
  369. if not(cs_asm_extern in current_settings.globalswitches) then
  370. begin
  371. if SmartAsm then
  372. begin
  373. if (SmartFilesCount<=1) then
  374. Message1(exec_i_assembling_smart,name);
  375. end
  376. else
  377. Message1(exec_i_assembling,name);
  378. end;
  379. if CallAssembler(FindAssembler,MakeCmdLine) then
  380. RemoveAsm
  381. else
  382. begin
  383. DoAssemble:=false;
  384. GenerateError;
  385. end;
  386. end;
  387. Procedure TExternalAssembler.AsmFlush;
  388. begin
  389. if outcnt>0 then
  390. begin
  391. { suppress i/o error }
  392. {$push} {$I-}
  393. BlockWrite(outfile,outbuf,outcnt);
  394. {$pop}
  395. ioerror:=ioerror or (ioresult<>0);
  396. outcnt:=0;
  397. end;
  398. end;
  399. Procedure TExternalAssembler.AsmClear;
  400. begin
  401. outcnt:=0;
  402. end;
  403. Procedure TExternalAssembler.AsmWrite(const c: char);
  404. begin
  405. if OutCnt+1>=AsmOutSize then
  406. AsmFlush;
  407. OutBuf[OutCnt]:=c;
  408. inc(OutCnt);
  409. inc(AsmSize);
  410. end;
  411. Procedure TExternalAssembler.AsmWrite(const s:string);
  412. begin
  413. if OutCnt+length(s)>=AsmOutSize then
  414. AsmFlush;
  415. Move(s[1],OutBuf[OutCnt],length(s));
  416. inc(OutCnt,length(s));
  417. inc(AsmSize,length(s));
  418. end;
  419. Procedure TExternalAssembler.AsmWrite(const s:ansistring);
  420. var
  421. StartIndex, ToWrite: longint;
  422. begin
  423. if s='' then
  424. exit;
  425. if OutCnt+length(s)>=AsmOutSize then
  426. AsmFlush;
  427. StartIndex:=1;
  428. ToWrite:=length(s);
  429. while ToWrite>AsmOutSize do
  430. begin
  431. Move(s[StartIndex],OutBuf[OutCnt],AsmOutSize);
  432. inc(OutCnt,AsmOutSize);
  433. inc(AsmSize,AsmOutSize);
  434. AsmFlush;
  435. inc(StartIndex,AsmOutSize);
  436. dec(ToWrite,AsmOutSize);
  437. end;
  438. Move(s[StartIndex],OutBuf[OutCnt],ToWrite);
  439. inc(OutCnt,ToWrite);
  440. inc(AsmSize,ToWrite);
  441. end;
  442. procedure TExternalAssembler.AsmWriteLn(const c: char);
  443. begin
  444. AsmWrite(c);
  445. AsmLn;
  446. end;
  447. Procedure TExternalAssembler.AsmWriteLn(const s:string);
  448. begin
  449. AsmWrite(s);
  450. AsmLn;
  451. end;
  452. Procedure TExternalAssembler.AsmWriteLn(const s: ansistring);
  453. begin
  454. AsmWrite(s);
  455. AsmLn;
  456. end;
  457. Procedure TExternalAssembler.AsmWritePChar(p:pchar);
  458. var
  459. i,j : longint;
  460. begin
  461. i:=StrLen(p);
  462. j:=i;
  463. while j>0 do
  464. begin
  465. i:=min(j,AsmOutSize);
  466. if OutCnt+i>=AsmOutSize then
  467. AsmFlush;
  468. Move(p[0],OutBuf[OutCnt],i);
  469. inc(OutCnt,i);
  470. inc(AsmSize,i);
  471. dec(j,i);
  472. p:=pchar(@p[i]);
  473. end;
  474. end;
  475. Procedure TExternalAssembler.AsmLn;
  476. begin
  477. if OutCnt>=AsmOutSize-2 then
  478. AsmFlush;
  479. if (cs_link_on_target in current_settings.globalswitches) then
  480. begin
  481. OutBuf[OutCnt]:=target_info.newline[1];
  482. inc(OutCnt);
  483. inc(AsmSize);
  484. if length(target_info.newline)>1 then
  485. begin
  486. OutBuf[OutCnt]:=target_info.newline[2];
  487. inc(OutCnt);
  488. inc(AsmSize);
  489. end;
  490. end
  491. else
  492. begin
  493. OutBuf[OutCnt]:=source_info.newline[1];
  494. inc(OutCnt);
  495. inc(AsmSize);
  496. if length(source_info.newline)>1 then
  497. begin
  498. OutBuf[OutCnt]:=source_info.newline[2];
  499. inc(OutCnt);
  500. inc(AsmSize);
  501. end;
  502. end;
  503. end;
  504. function TExternalAssembler.MakeCmdLine: TCmdStr;
  505. begin
  506. result:=target_asm.asmcmd;
  507. {$ifdef arm}
  508. if (target_info.system=system_arm_darwin) then
  509. Replace(result,'$ARCH',lower(cputypestr[current_settings.cputype]));
  510. {$endif arm}
  511. if (cs_link_on_target in current_settings.globalswitches) then
  512. begin
  513. Replace(result,'$ASM',maybequoted(ScriptFixFileName(AsmFileName)));
  514. Replace(result,'$OBJ',maybequoted(ScriptFixFileName(ObjFileName)));
  515. end
  516. else
  517. begin
  518. {$ifdef hasunix}
  519. if DoPipe then
  520. Replace(result,'$ASM','')
  521. else
  522. {$endif}
  523. Replace(result,'$ASM',maybequoted(AsmFileName));
  524. Replace(result,'$OBJ',maybequoted(ObjFileName));
  525. end;
  526. if (cs_create_pic in current_settings.moduleswitches) then
  527. Replace(result,'$PIC','-KPIC')
  528. else
  529. Replace(result,'$PIC','');
  530. if (cs_asm_source in current_settings.globalswitches) then
  531. Replace(result,'$NOWARN','')
  532. else
  533. Replace(result,'$NOWARN','-W');
  534. Replace(result,'$EXTRAOPT',asmextraopt);
  535. end;
  536. procedure TExternalAssembler.AsmCreate(Aplace:tcutplace);
  537. {$ifdef hasamiga}
  538. var
  539. tempFileName: TPathStr;
  540. {$endif}
  541. begin
  542. if SmartAsm then
  543. NextSmartName(Aplace);
  544. {$ifdef hasamiga}
  545. { on Amiga/MorphOS try to redirect .s files to the T: assign, which is
  546. for temp files, and usually (default setting) located in the RAM: drive.
  547. This highly improves assembling speed for complex projects like the
  548. compiler itself, especially on hardware with slow disk I/O.
  549. Consider this as a poor man's pipe on Amiga, because real pipe handling
  550. would be much more complex and error prone to implement. (KB) }
  551. if (([cs_asm_extern,cs_asm_leave,cs_link_on_target] * current_settings.globalswitches) = []) then
  552. begin
  553. { try to have an unique name for the .s file }
  554. tempFileName:=HexStr(GetProcessID shr 4,7)+ExtractFileName(AsmFileName);
  555. {$ifndef morphos}
  556. { old Amiga RAM: handler only allows filenames up to 30 char }
  557. if Length(tempFileName) < 30 then
  558. {$endif}
  559. AsmFileName:='T:'+tempFileName;
  560. end;
  561. {$endif}
  562. {$ifdef hasunix}
  563. if DoPipe then
  564. begin
  565. if SmartAsm then
  566. begin
  567. if (SmartFilesCount<=1) then
  568. Message1(exec_i_assembling_smart,name);
  569. end
  570. else
  571. Message1(exec_i_assembling_pipe,AsmFileName);
  572. POpen(outfile,maybequoted(FindAssembler)+' '+MakeCmdLine,'W');
  573. end
  574. else
  575. {$endif}
  576. begin
  577. Assign(outfile,AsmFileName);
  578. {$push} {$I-}
  579. Rewrite(outfile,1);
  580. {$pop}
  581. if ioresult<>0 then
  582. begin
  583. ioerror:=true;
  584. Message1(exec_d_cant_create_asmfile,AsmFileName);
  585. end;
  586. end;
  587. outcnt:=0;
  588. AsmSize:=0;
  589. AsmStartSize:=0;
  590. end;
  591. procedure TExternalAssembler.AsmClose;
  592. var
  593. f : file;
  594. FileAge : longint;
  595. begin
  596. AsmFlush;
  597. {$ifdef hasunix}
  598. if DoPipe then
  599. begin
  600. if PClose(outfile) <> 0 then
  601. GenerateError;
  602. end
  603. else
  604. {$endif}
  605. begin
  606. {Touch Assembler time to ppu time is there is a ppufilename}
  607. if ppufilename<>'' then
  608. begin
  609. Assign(f,ppufilename);
  610. {$push} {$I-}
  611. reset(f,1);
  612. {$pop}
  613. if ioresult=0 then
  614. begin
  615. FileAge := FileGetDate(GetFileHandle(f));
  616. close(f);
  617. reset(outfile,1);
  618. FileSetDate(GetFileHandle(outFile),FileAge);
  619. end;
  620. end;
  621. close(outfile);
  622. end;
  623. end;
  624. procedure TExternalAssembler.WriteSourceLine(hp: tailineinfo);
  625. var
  626. module : tmodule;
  627. begin
  628. { load infile }
  629. if (lastfileinfo.moduleindex<>hp.fileinfo.moduleindex) or
  630. (lastfileinfo.fileindex<>hp.fileinfo.fileindex) then
  631. begin
  632. { in case of a generic the module can be different }
  633. if current_module.unit_index=hp.fileinfo.moduleindex then
  634. module:=current_module
  635. else
  636. module:=get_module(hp.fileinfo.moduleindex);
  637. { during the compilation of the system unit there are cases when
  638. the fileinfo contains just zeros => invalid }
  639. if assigned(module) then
  640. infile:=module.sourcefiles.get_file(hp.fileinfo.fileindex)
  641. else
  642. infile:=nil;
  643. if assigned(infile) then
  644. begin
  645. { open only if needed !! }
  646. if (cs_asm_source in current_settings.globalswitches) then
  647. infile.open;
  648. end;
  649. { avoid unnecessary reopens of the same file !! }
  650. lastfileinfo.fileindex:=hp.fileinfo.fileindex;
  651. lastfileinfo.moduleindex:=hp.fileinfo.moduleindex;
  652. { be sure to change line !! }
  653. lastfileinfo.line:=-1;
  654. end;
  655. { write source }
  656. if (cs_asm_source in current_settings.globalswitches) and
  657. assigned(infile) then
  658. begin
  659. if (infile<>lastinfile) then
  660. begin
  661. AsmWriteLn(target_asm.comment+'['+infile.name+']');
  662. if assigned(lastinfile) then
  663. lastinfile.close;
  664. end;
  665. if (hp.fileinfo.line<>lastfileinfo.line) and
  666. (hp.fileinfo.line<infile.maxlinebuf) then
  667. begin
  668. if (hp.fileinfo.line<>0) and
  669. (infile.linebuf^[hp.fileinfo.line]>=0) then
  670. AsmWriteLn(target_asm.comment+'['+tostr(hp.fileinfo.line)+'] '+
  671. fixline(infile.GetLineStr(hp.fileinfo.line)));
  672. { set it to a negative value !
  673. to make that is has been read already !! PM }
  674. if (infile.linebuf^[hp.fileinfo.line]>=0) then
  675. infile.linebuf^[hp.fileinfo.line]:=-infile.linebuf^[hp.fileinfo.line]-1;
  676. end;
  677. end;
  678. lastfileinfo:=hp.fileinfo;
  679. lastinfile:=infile;
  680. end;
  681. procedure TExternalAssembler.WriteTempalloc(hp: tai_tempalloc);
  682. begin
  683. {$ifdef EXTDEBUG}
  684. if assigned(hp.problem) then
  685. AsmWriteLn(target_asm.comment+'Temp '+tostr(hp.temppos)+','+
  686. tostr(hp.tempsize)+' '+hp.problem^)
  687. else
  688. {$endif EXTDEBUG}
  689. AsmWriteLn(target_asm.comment+'Temp '+tostr(hp.temppos)+','+
  690. tostr(hp.tempsize)+' '+tempallocstr[hp.allocation]);
  691. end;
  692. procedure TExternalAssembler.WriteTree(p:TAsmList);
  693. begin
  694. end;
  695. procedure TExternalAssembler.WriteAsmList;
  696. begin
  697. end;
  698. procedure TExternalAssembler.MakeObject;
  699. begin
  700. AsmCreate(cut_normal);
  701. FillChar(lastfileinfo, sizeof(lastfileinfo), 0);
  702. lastfileinfo.line := -1;
  703. lastinfile := nil;
  704. lastsectype := sec_none;
  705. WriteAsmList;
  706. AsmClose;
  707. if not(ioerror) then
  708. DoAssemble;
  709. end;
  710. {*****************************************************************************
  711. TInternalAssembler
  712. *****************************************************************************}
  713. constructor TInternalAssembler.create(smart:boolean);
  714. begin
  715. inherited create(smart);
  716. ObjOutput:=nil;
  717. ObjData:=nil;
  718. SmartAsm:=smart;
  719. end;
  720. destructor TInternalAssembler.destroy;
  721. begin
  722. if assigned(ObjData) then
  723. ObjData.free;
  724. if assigned(ObjOutput) then
  725. ObjOutput.free;
  726. end;
  727. procedure TInternalAssembler.WriteStab(p:pchar);
  728. function consumecomma(var p:pchar):boolean;
  729. begin
  730. while (p^=' ') do
  731. inc(p);
  732. result:=(p^=',');
  733. inc(p);
  734. end;
  735. function consumenumber(var p:pchar;out value:longint):boolean;
  736. var
  737. hs : string;
  738. len,
  739. code : integer;
  740. begin
  741. value:=0;
  742. while (p^=' ') do
  743. inc(p);
  744. len:=0;
  745. while (p^ in ['0'..'9']) do
  746. begin
  747. inc(len);
  748. hs[len]:=p^;
  749. inc(p);
  750. end;
  751. if len>0 then
  752. begin
  753. hs[0]:=chr(len);
  754. val(hs,value,code);
  755. end
  756. else
  757. code:=-1;
  758. result:=(code=0);
  759. end;
  760. function consumeoffset(var p:pchar;out relocsym:tobjsymbol;out value:longint):boolean;
  761. var
  762. hs : string;
  763. len,
  764. code : integer;
  765. pstart : pchar;
  766. sym : tobjsymbol;
  767. exprvalue : longint;
  768. gotmin,
  769. have_first_symbol,
  770. have_second_symbol,
  771. dosub : boolean;
  772. begin
  773. result:=false;
  774. value:=0;
  775. relocsym:=nil;
  776. gotmin:=false;
  777. have_first_symbol:=false;
  778. have_second_symbol:=false;
  779. repeat
  780. dosub:=false;
  781. exprvalue:=0;
  782. if gotmin then
  783. begin
  784. dosub:=true;
  785. gotmin:=false;
  786. end;
  787. while (p^=' ') do
  788. inc(p);
  789. case p^ of
  790. #0 :
  791. break;
  792. ' ' :
  793. inc(p);
  794. '0'..'9' :
  795. begin
  796. len:=0;
  797. while (p^ in ['0'..'9']) do
  798. begin
  799. inc(len);
  800. hs[len]:=p^;
  801. inc(p);
  802. end;
  803. hs[0]:=chr(len);
  804. val(hs,exprvalue,code);
  805. if code<>0 then
  806. internalerror(200702251);
  807. end;
  808. '.','_',
  809. 'A'..'Z',
  810. 'a'..'z' :
  811. begin
  812. pstart:=p;
  813. while not(p^ in [#0,' ','-','+']) do
  814. inc(p);
  815. len:=p-pstart;
  816. if len>255 then
  817. internalerror(200509187);
  818. move(pstart^,hs[1],len);
  819. hs[0]:=chr(len);
  820. sym:=objdata.symbolref(hs);
  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. {$ifdef ARM}
  1107. asd_thumb_func:
  1108. ObjData.ThumbFunc:=true;
  1109. {$endif ARM}
  1110. else
  1111. internalerror(2010011101);
  1112. end;
  1113. end;
  1114. ait_section:
  1115. begin
  1116. ObjData.CreateSection(Tai_section(hp).sectype,Tai_section(hp).name^,Tai_section(hp).secorder);
  1117. Tai_section(hp).sec:=ObjData.CurrObjSec;
  1118. end;
  1119. ait_symbol :
  1120. begin
  1121. { needs extra support in the internal assembler }
  1122. { the value is just ignored }
  1123. {if tai_symbol(hp).has_value then
  1124. internalerror(2009090804); ;}
  1125. ObjData.SymbolDefine(Tai_symbol(hp).sym);
  1126. end;
  1127. ait_label :
  1128. ObjData.SymbolDefine(Tai_label(hp).labsym);
  1129. ait_string :
  1130. ObjData.alloc(Tai_string(hp).len);
  1131. ait_instruction :
  1132. begin
  1133. { reset instructions which could change in pass 2 }
  1134. Taicpu(hp).resetpass2;
  1135. ObjData.alloc(Taicpu(hp).Pass1(ObjData));
  1136. end;
  1137. ait_cutobject :
  1138. if SmartAsm then
  1139. break;
  1140. end;
  1141. hp:=Tai(hp.next);
  1142. end;
  1143. TreePass0:=hp;
  1144. end;
  1145. function TInternalAssembler.TreePass1(hp:Tai):Tai;
  1146. var
  1147. objsym,
  1148. objsymend : TObjSymbol;
  1149. begin
  1150. while assigned(hp) do
  1151. begin
  1152. case hp.typ of
  1153. ait_align :
  1154. begin
  1155. if tai_align_abstract(hp).aligntype>1 then
  1156. begin
  1157. { here we must determine the fillsize which is used in pass2 }
  1158. Tai_align_abstract(hp).fillsize:=align(ObjData.CurrObjSec.Size,Tai_align_abstract(hp).aligntype)-
  1159. ObjData.CurrObjSec.Size;
  1160. ObjData.alloc(Tai_align_abstract(hp).fillsize);
  1161. end;
  1162. end;
  1163. ait_datablock :
  1164. begin
  1165. if (oso_data in ObjData.CurrObjSec.secoptions) then
  1166. Message(asmw_e_alloc_data_only_in_bss);
  1167. {$ifdef USE_COMM_IN_BSS}
  1168. if writingpackages and
  1169. Tai_datablock(hp).is_global then
  1170. begin
  1171. objsym:=ObjData.SymbolDefine(Tai_datablock(hp).sym);
  1172. objsym.size:=Tai_datablock(hp).size;
  1173. objsym.bind:=AB_COMMON;
  1174. objsym.alignment:=needtowritealignmentalsoforELF;
  1175. end
  1176. else
  1177. {$endif USE_COMM_IN_BSS}
  1178. begin
  1179. ObjData.allocalign(used_align(size_2_align(Tai_datablock(hp).size),0,ObjData.CurrObjSec.secalign));
  1180. objsym:=ObjData.SymbolDefine(Tai_datablock(hp).sym);
  1181. objsym.size:=Tai_datablock(hp).size;
  1182. ObjData.alloc(Tai_datablock(hp).size);
  1183. end;
  1184. end;
  1185. ait_real_80bit :
  1186. ObjData.alloc(tai_real_80bit(hp).savesize);
  1187. ait_real_64bit :
  1188. ObjData.alloc(8);
  1189. ait_real_32bit :
  1190. ObjData.alloc(4);
  1191. ait_comp_64bit :
  1192. ObjData.alloc(8);
  1193. ait_const:
  1194. begin
  1195. { Recalculate relative symbols }
  1196. if assigned(tai_const(hp).sym) and
  1197. assigned(tai_const(hp).endsym) then
  1198. begin
  1199. objsym:=Objdata.SymbolRef(tai_const(hp).sym);
  1200. objsymend:=Objdata.SymbolRef(tai_const(hp).endsym);
  1201. if objsymend.objsection<>objsym.objsection then
  1202. begin
  1203. if (Tai_const(hp).consttype in [aitconst_uleb128bit,aitconst_sleb128bit]) or
  1204. (objsym.objsection<>ObjData.CurrObjSec) then
  1205. internalerror(200905042);
  1206. end
  1207. else
  1208. Tai_const(hp).value:=objsymend.address-objsym.address+Tai_const(hp).symofs;
  1209. end;
  1210. ObjData.alloc(tai_const(hp).size);
  1211. end;
  1212. ait_section:
  1213. begin
  1214. { use cached value }
  1215. ObjData.setsection(Tai_section(hp).sec);
  1216. end;
  1217. ait_stab :
  1218. begin
  1219. if assigned(Tai_stab(hp).str) then
  1220. WriteStab(Tai_stab(hp).str);
  1221. end;
  1222. ait_symbol :
  1223. ObjData.SymbolDefine(Tai_symbol(hp).sym);
  1224. ait_symbol_end :
  1225. begin
  1226. objsym:=ObjData.SymbolRef(Tai_symbol_end(hp).sym);
  1227. objsym.size:=ObjData.CurrObjSec.Size-objsym.offset;
  1228. end;
  1229. ait_label :
  1230. ObjData.SymbolDefine(Tai_label(hp).labsym);
  1231. ait_string :
  1232. ObjData.alloc(Tai_string(hp).len);
  1233. ait_instruction :
  1234. ObjData.alloc(Taicpu(hp).Pass1(ObjData));
  1235. ait_cutobject :
  1236. if SmartAsm then
  1237. break;
  1238. ait_directive :
  1239. begin
  1240. case tai_directive(hp).directive of
  1241. asd_indirect_symbol:
  1242. if tai_directive(hp).name='' then
  1243. Internalerror(2009101103)
  1244. else if not SetIndirectToSymbol(Tai(hp.Previous), tai_directive(hp).name) then
  1245. Internalerror(2009101102);
  1246. asd_lazy_reference:
  1247. { handled in TreePass0 }
  1248. ;
  1249. asd_reference:
  1250. { ignore for now, but should be added}
  1251. ;
  1252. asd_thumb_func:
  1253. { ignore for now, but should be added}
  1254. ;
  1255. else
  1256. internalerror(2010011102);
  1257. end;
  1258. end;
  1259. end;
  1260. hp:=Tai(hp.next);
  1261. end;
  1262. TreePass1:=hp;
  1263. end;
  1264. function TInternalAssembler.TreePass2(hp:Tai):Tai;
  1265. var
  1266. fillbuffer : tfillbuffer;
  1267. {$ifdef x86}
  1268. co : comp;
  1269. {$endif x86}
  1270. leblen : byte;
  1271. lebbuf : array[0..63] of byte;
  1272. objsym,
  1273. objsymend : TObjSymbol;
  1274. zerobuf : array[0..63] of byte;
  1275. relative_reloc: boolean;
  1276. tmp : word;
  1277. begin
  1278. fillchar(zerobuf,sizeof(zerobuf),0);
  1279. fillchar(objsym,sizeof(objsym),0);
  1280. fillchar(objsymend,sizeof(objsymend),0);
  1281. { main loop }
  1282. while assigned(hp) do
  1283. begin
  1284. case hp.typ of
  1285. ait_align :
  1286. begin
  1287. if tai_align_abstract(hp).aligntype>ObjData.CurrObjSec.secalign then
  1288. InternalError(2012072301);
  1289. if oso_data in ObjData.CurrObjSec.secoptions then
  1290. ObjData.writebytes(Tai_align_abstract(hp).calculatefillbuf(fillbuffer,oso_executable in ObjData.CurrObjSec.secoptions)^,
  1291. Tai_align_abstract(hp).fillsize)
  1292. else
  1293. ObjData.alloc(Tai_align_abstract(hp).fillsize);
  1294. end;
  1295. ait_section :
  1296. begin
  1297. { use cached value }
  1298. ObjData.setsection(Tai_section(hp).sec);
  1299. end;
  1300. ait_symbol :
  1301. begin
  1302. ObjOutput.exportsymbol(ObjData.SymbolRef(Tai_symbol(hp).sym));
  1303. end;
  1304. ait_symbol_end :
  1305. begin
  1306. { recalculate size, as some preceding instructions
  1307. could have been changed to smaller size }
  1308. objsym:=ObjData.SymbolRef(Tai_symbol_end(hp).sym);
  1309. objsym.size:=ObjData.CurrObjSec.Size-objsym.offset;
  1310. end;
  1311. ait_datablock :
  1312. begin
  1313. ObjOutput.exportsymbol(ObjData.SymbolRef(Tai_datablock(hp).sym));
  1314. {$ifdef USE_COMM_IN_BSS}
  1315. if not(writingpackages and
  1316. Tai_datablock(hp).is_global) then
  1317. {$endif USE_COMM_IN_BSS}
  1318. begin
  1319. ObjData.allocalign(used_align(size_2_align(Tai_datablock(hp).size),0,ObjData.CurrObjSec.secalign));
  1320. ObjData.alloc(Tai_datablock(hp).size);
  1321. end;
  1322. end;
  1323. ait_real_80bit :
  1324. begin
  1325. ObjData.writebytes(Tai_real_80bit(hp).value,10);
  1326. ObjData.writebytes(zerobuf,Tai_real_80bit(hp).savesize-10);
  1327. end;
  1328. ait_real_64bit :
  1329. ObjData.writebytes(Tai_real_64bit(hp).value,8);
  1330. ait_real_32bit :
  1331. ObjData.writebytes(Tai_real_32bit(hp).value,4);
  1332. ait_comp_64bit :
  1333. begin
  1334. {$ifdef x86}
  1335. co:=comp(Tai_comp_64bit(hp).value);
  1336. ObjData.writebytes(co,8);
  1337. {$endif x86}
  1338. end;
  1339. ait_string :
  1340. ObjData.writebytes(Tai_string(hp).str^,Tai_string(hp).len);
  1341. ait_const :
  1342. begin
  1343. { Recalculate relative symbols, addresses of forward references
  1344. can be changed in treepass1 }
  1345. relative_reloc:=false;
  1346. if assigned(tai_const(hp).sym) and
  1347. assigned(tai_const(hp).endsym) then
  1348. begin
  1349. objsym:=Objdata.SymbolRef(tai_const(hp).sym);
  1350. objsymend:=Objdata.SymbolRef(tai_const(hp).endsym);
  1351. relative_reloc:=(objsym.objsection<>objsymend.objsection);
  1352. Tai_const(hp).value:=objsymend.address-objsym.address+Tai_const(hp).symofs;
  1353. end;
  1354. case tai_const(hp).consttype of
  1355. aitconst_64bit,
  1356. aitconst_32bit,
  1357. aitconst_16bit,
  1358. aitconst_64bit_unaligned,
  1359. aitconst_32bit_unaligned,
  1360. aitconst_16bit_unaligned,
  1361. aitconst_8bit :
  1362. begin
  1363. if assigned(tai_const(hp).sym) and
  1364. not assigned(tai_const(hp).endsym) then
  1365. ObjData.writereloc(Tai_const(hp).symofs,tai_const(hp).size,Objdata.SymbolRef(tai_const(hp).sym),RELOC_ABSOLUTE)
  1366. else if relative_reloc then
  1367. ObjData.writereloc(ObjData.CurrObjSec.size+tai_const(hp).size-objsym.address+tai_const(hp).symofs,tai_const(hp).size,objsymend,RELOC_RELATIVE)
  1368. else
  1369. ObjData.writebytes(Tai_const(hp).value,tai_const(hp).size);
  1370. end;
  1371. aitconst_rva_symbol :
  1372. begin
  1373. { PE32+? }
  1374. if target_info.system=system_x86_64_win64 then
  1375. ObjData.writereloc(Tai_const(hp).symofs,sizeof(longint),Objdata.SymbolRef(tai_const(hp).sym),RELOC_RVA)
  1376. else
  1377. ObjData.writereloc(Tai_const(hp).symofs,sizeof(pint),Objdata.SymbolRef(tai_const(hp).sym),RELOC_RVA);
  1378. end;
  1379. aitconst_secrel32_symbol :
  1380. begin
  1381. { Required for DWARF2 support under Windows }
  1382. ObjData.writereloc(Tai_const(hp).symofs,sizeof(longint),Objdata.SymbolRef(tai_const(hp).sym),RELOC_SECREL32);
  1383. end;
  1384. aitconst_gotoff_symbol:
  1385. ObjData.writereloc(Tai_const(hp).symofs,sizeof(longint),Objdata.SymbolRef(tai_const(hp).sym),RELOC_GOTOFF);
  1386. aitconst_uleb128bit,
  1387. aitconst_sleb128bit :
  1388. begin
  1389. if tai_const(hp).consttype=aitconst_uleb128bit then
  1390. leblen:=EncodeUleb128(qword(Tai_const(hp).value),lebbuf)
  1391. else
  1392. leblen:=EncodeSleb128(Tai_const(hp).value,lebbuf);
  1393. if leblen<>tai_const(hp).size then
  1394. internalerror(200709271);
  1395. ObjData.writebytes(lebbuf,leblen);
  1396. end;
  1397. aitconst_darwin_dwarf_delta32,
  1398. aitconst_darwin_dwarf_delta64:
  1399. ObjData.writebytes(Tai_const(hp).value,tai_const(hp).size);
  1400. aitconst_half16bit:
  1401. begin
  1402. tmp:=Tai_const(hp).value div 2;
  1403. ObjData.writebytes(tmp,2);
  1404. end
  1405. else
  1406. internalerror(200603254);
  1407. end;
  1408. end;
  1409. ait_label :
  1410. begin
  1411. { exporting shouldn't be necessary as labels are local,
  1412. but it's better to be on the safe side (PFV) }
  1413. ObjOutput.exportsymbol(ObjData.SymbolRef(Tai_label(hp).labsym));
  1414. end;
  1415. ait_instruction :
  1416. Taicpu(hp).Pass2(ObjData);
  1417. ait_stab :
  1418. WriteStab(Tai_stab(hp).str);
  1419. ait_function_name,
  1420. ait_force_line : ;
  1421. ait_cutobject :
  1422. if SmartAsm then
  1423. break;
  1424. {$ifndef DISABLE_WIN64_SEH}
  1425. ait_seh_directive :
  1426. tai_seh_directive(hp).generate_code(objdata);
  1427. {$endif DISABLE_WIN64_SEH}
  1428. end;
  1429. hp:=Tai(hp.next);
  1430. end;
  1431. TreePass2:=hp;
  1432. end;
  1433. procedure TInternalAssembler.writetree;
  1434. label
  1435. doexit;
  1436. var
  1437. hp : Tai;
  1438. ObjWriter : TObjectWriter;
  1439. begin
  1440. ObjWriter:=TObjectwriter.create;
  1441. ObjOutput:=CObjOutput.Create(ObjWriter);
  1442. ObjData:=ObjOutput.newObjData(ObjFileName);
  1443. { Pass 0 }
  1444. ObjData.currpass:=0;
  1445. ObjData.createsection(sec_code);
  1446. ObjData.beforealloc;
  1447. { start with list 1 }
  1448. currlistidx:=1;
  1449. currlist:=list[currlistidx];
  1450. hp:=Tai(currList.first);
  1451. while assigned(hp) do
  1452. begin
  1453. hp:=TreePass0(hp);
  1454. MaybeNextList(hp);
  1455. end;
  1456. ObjData.afteralloc;
  1457. { leave if errors have occured }
  1458. if errorcount>0 then
  1459. goto doexit;
  1460. { Pass 1 }
  1461. ObjData.currpass:=1;
  1462. ObjData.resetsections;
  1463. ObjData.beforealloc;
  1464. ObjData.createsection(sec_code);
  1465. { start with list 1 }
  1466. currlistidx:=1;
  1467. currlist:=list[currlistidx];
  1468. hp:=Tai(currList.first);
  1469. while assigned(hp) do
  1470. begin
  1471. hp:=TreePass1(hp);
  1472. MaybeNextList(hp);
  1473. end;
  1474. ObjData.createsection(sec_code);
  1475. ObjData.afteralloc;
  1476. { leave if errors have occured }
  1477. if errorcount>0 then
  1478. goto doexit;
  1479. { Pass 2 }
  1480. ObjData.currpass:=2;
  1481. ObjData.resetsections;
  1482. ObjData.beforewrite;
  1483. ObjData.createsection(sec_code);
  1484. { start with list 1 }
  1485. currlistidx:=1;
  1486. currlist:=list[currlistidx];
  1487. hp:=Tai(currList.first);
  1488. while assigned(hp) do
  1489. begin
  1490. hp:=TreePass2(hp);
  1491. MaybeNextList(hp);
  1492. end;
  1493. ObjData.createsection(sec_code);
  1494. ObjData.afterwrite;
  1495. { don't write the .o file if errors have occured }
  1496. if errorcount=0 then
  1497. begin
  1498. { write objectfile }
  1499. ObjOutput.startobjectfile(ObjFileName);
  1500. ObjOutput.writeobjectfile(ObjData);
  1501. end;
  1502. doexit:
  1503. { Cleanup }
  1504. ObjData.free;
  1505. ObjData:=nil;
  1506. ObjWriter.free;
  1507. end;
  1508. procedure TInternalAssembler.writetreesmart;
  1509. var
  1510. hp : Tai;
  1511. startsectype : TAsmSectiontype;
  1512. place: tcutplace;
  1513. ObjWriter : TObjectWriter;
  1514. begin
  1515. if not(cs_asm_leave in current_settings.globalswitches) then
  1516. ObjWriter:=TARObjectWriter.create(current_module.staticlibfilename)
  1517. else
  1518. ObjWriter:=TObjectwriter.create;
  1519. NextSmartName(cut_normal);
  1520. ObjOutput:=CObjOutput.Create(ObjWriter);
  1521. startsectype:=sec_code;
  1522. { start with list 1 }
  1523. currlistidx:=1;
  1524. currlist:=list[currlistidx];
  1525. hp:=Tai(currList.first);
  1526. while assigned(hp) do
  1527. begin
  1528. ObjData:=ObjOutput.newObjData(ObjFileName);
  1529. { Pass 0 }
  1530. ObjData.currpass:=0;
  1531. ObjData.resetsections;
  1532. ObjData.beforealloc;
  1533. ObjData.createsection(startsectype);
  1534. TreePass0(hp);
  1535. ObjData.afteralloc;
  1536. { leave if errors have occured }
  1537. if errorcount>0 then
  1538. break;
  1539. { Pass 1 }
  1540. ObjData.currpass:=1;
  1541. ObjData.resetsections;
  1542. ObjData.beforealloc;
  1543. ObjData.createsection(startsectype);
  1544. TreePass1(hp);
  1545. ObjData.afteralloc;
  1546. { leave if errors have occured }
  1547. if errorcount>0 then
  1548. break;
  1549. { Pass 2 }
  1550. ObjData.currpass:=2;
  1551. ObjOutput.startobjectfile(ObjFileName);
  1552. ObjData.resetsections;
  1553. ObjData.beforewrite;
  1554. ObjData.createsection(startsectype);
  1555. hp:=TreePass2(hp);
  1556. ObjData.afterwrite;
  1557. { leave if errors have occured }
  1558. if errorcount>0 then
  1559. break;
  1560. { write the current objectfile }
  1561. ObjOutput.writeobjectfile(ObjData);
  1562. ObjData.free;
  1563. ObjData:=nil;
  1564. { end of lists? }
  1565. if not MaybeNextList(hp) then
  1566. break;
  1567. { we will start a new objectfile so reset everything }
  1568. { The place can still change in the next while loop, so don't init }
  1569. { the writer yet (JM) }
  1570. if (hp.typ=ait_cutobject) then
  1571. place := Tai_cutobject(hp).place
  1572. else
  1573. place := cut_normal;
  1574. { avoid empty files }
  1575. startsectype:=sec_code;
  1576. while assigned(hp) and
  1577. (Tai(hp).typ in [ait_marker,ait_comment,ait_section,ait_cutobject]) do
  1578. begin
  1579. if Tai(hp).typ=ait_section then
  1580. startsectype:=Tai_section(hp).sectype;
  1581. if (Tai(hp).typ=ait_cutobject) then
  1582. place:=Tai_cutobject(hp).place;
  1583. hp:=Tai(hp.next);
  1584. end;
  1585. if not MaybeNextList(hp) then
  1586. break;
  1587. { start next objectfile }
  1588. NextSmartName(place);
  1589. end;
  1590. ObjData.free;
  1591. ObjData:=nil;
  1592. ObjWriter.free;
  1593. end;
  1594. procedure TInternalAssembler.MakeObject;
  1595. var to_do:set of TasmlistType;
  1596. i:TasmlistType;
  1597. procedure addlist(p:TAsmList);
  1598. begin
  1599. inc(lists);
  1600. list[lists]:=p;
  1601. end;
  1602. begin
  1603. to_do:=[low(Tasmlisttype)..high(Tasmlisttype)];
  1604. if usedeffileforexports then
  1605. exclude(to_do,al_exports);
  1606. if not(tf_section_threadvars in target_info.flags) then
  1607. exclude(to_do,al_threadvars);
  1608. for i:=low(TasmlistType) to high(TasmlistType) do
  1609. if (i in to_do) and (current_asmdata.asmlists[i]<>nil) and
  1610. (not current_asmdata.asmlists[i].empty) then
  1611. addlist(current_asmdata.asmlists[i]);
  1612. if SmartAsm then
  1613. writetreesmart
  1614. else
  1615. writetree;
  1616. end;
  1617. {*****************************************************************************
  1618. Generate Assembler Files Main Procedure
  1619. *****************************************************************************}
  1620. Procedure GenerateAsm(smart:boolean);
  1621. var
  1622. a : TAssembler;
  1623. begin
  1624. if not assigned(CAssembler[target_asm.id]) then
  1625. Message(asmw_f_assembler_output_not_supported);
  1626. a:=CAssembler[target_asm.id].Create(smart);
  1627. a.MakeObject;
  1628. a.Free;
  1629. end;
  1630. Procedure OnlyAsm;
  1631. var
  1632. a : TExternalAssembler;
  1633. begin
  1634. a:=TExternalAssembler.Create(false);
  1635. a.DoAssemble;
  1636. a.Free;
  1637. end;
  1638. {*****************************************************************************
  1639. Init/Done
  1640. *****************************************************************************}
  1641. procedure RegisterAssembler(const r:tasminfo;c:TAssemblerClass);
  1642. var
  1643. t : tasm;
  1644. begin
  1645. t:=r.id;
  1646. if assigned(asminfos[t]) then
  1647. writeln('Warning: Assembler is already registered!')
  1648. else
  1649. Getmem(asminfos[t],sizeof(tasminfo));
  1650. asminfos[t]^:=r;
  1651. CAssembler[t]:=c;
  1652. end;
  1653. end.