assemble.pas 52 KB

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