assemble.pas 58 KB

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