ogrel.pas 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904
  1. {
  2. Copyright (c) 2020 by Nikolay Nikolov
  3. Contains the ASCII relocatable object file format (*.rel) reader and writer
  4. This is the object format used on the Z80 platforms.
  5. This program is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 2 of the License, or
  8. (at your option) any later version.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with this program; if not, write to the Free Software
  15. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  16. ****************************************************************************
  17. }
  18. unit ogrel;
  19. {$i fpcdefs.inc}
  20. interface
  21. uses
  22. { common }
  23. cclasses,globtype,
  24. { target }
  25. systems,
  26. { assembler }
  27. cpuinfo,cpubase,aasmbase,assemble,link,
  28. { output }
  29. ogbase,
  30. owbase;
  31. type
  32. TRelRelocationFlag=(
  33. rrfByte, { bit 0 }
  34. rrfSymbol, { bit 1 }
  35. rrfPcRelative, { bit 2 }
  36. rrfTwoByteObjectFormatForByteData, { bit 3 }
  37. rrfUnsignedByteData, { bit 4 }
  38. rrfPage0Reference, { bit 5 }
  39. rrfPageNNNReference, { bit 6 }
  40. rrfMSBWith2ByteMode, { bit 7 }
  41. rrfThreeByteObjectFormatForByteData, { bit 8 }
  42. rrfRealMSBForThreeByteMode, { bit 9 }
  43. rrfReserved10, { bit 10 }
  44. rrfReserved11); { bit 11 }
  45. TRelRelocationFlags=set of TRelRelocationFlag;
  46. { TRelRelocation }
  47. TRelRelocation = class(TObjRelocation)
  48. private
  49. function GetSecOrSymIdx: longint;
  50. public
  51. RelFlags: TRelRelocationFlags;
  52. HiByte: Byte;
  53. constructor CreateSymbol(ADataOffset:TObjSectionOfs;s:TObjSymbol;Atyp:TObjRelocationType);
  54. constructor CreateSection(ADataOffset:TObjSectionOfs;aobjsec:TObjSection;Atyp:TObjRelocationType);
  55. function EncodeFlags: string;
  56. property SecOrSymIdx: longint read GetSecOrSymIdx;
  57. end;
  58. { TRelObjData }
  59. TRelObjData = class(TObjData)
  60. public
  61. function sectionname(atype:TAsmSectiontype;const aname:string;aorder:TAsmSectionOrder):string;override;
  62. function sectiontype2align(atype:TAsmSectiontype):longint;override;
  63. procedure writeReloc(Data:TRelocDataInt;len:aword;p:TObjSymbol;Reloctype:TObjRelocationType);override;
  64. end;
  65. { TRelObjOutput }
  66. TRelObjOutput = class(tObjOutput)
  67. private
  68. procedure writeString(const S: ansistring);
  69. procedure writeLine(const S: ansistring);
  70. procedure WriteAreaContentAndRelocations(sec: TObjSection);
  71. protected
  72. function writeData(Data:TObjData):boolean;override;
  73. public
  74. constructor create(AWriter:TObjectWriter);override;
  75. end;
  76. { TRelAssembler }
  77. TRelAssembler = class(tinternalassembler)
  78. constructor create(info: pasminfo; smart:boolean);override;
  79. end;
  80. { TRelObjInput }
  81. TRelObjInput = class(TObjInput)
  82. private const
  83. MaxBufSize=512;
  84. private
  85. FBuf: array [0..MaxBufSize-1] of Char;
  86. FBufSize: Integer;
  87. FBufPos: Integer;
  88. function FillBuf: boolean;
  89. function AtEndOfBuf: boolean;
  90. function AtEoF: boolean;
  91. function ReadChar(out c: char): boolean;
  92. function PeekChar(out c: char): boolean;
  93. function ReadLine(out s: string): boolean;
  94. public
  95. constructor create;override;
  96. function ReadObjData(AReader:TObjectreader;out Data:TObjData):boolean;override;
  97. class function CanReadObjData(AReader:TObjectreader):boolean;override;
  98. end;
  99. { TIntelHexExeOutput }
  100. TIntelHexExeOutput = class(TExeOutput)
  101. protected
  102. function writeData:boolean;override;
  103. procedure DoRelocationFixup(objsec:TObjSection);override;
  104. public
  105. constructor create;override;
  106. end;
  107. implementation
  108. uses
  109. SysUtils,
  110. cutils,verbose,globals,
  111. fmodule,aasmtai,aasmdata,
  112. ogmap,owar,
  113. version
  114. ;
  115. function tohex(q: qword): string;
  116. begin
  117. result:=HexStr(q,16);
  118. while (Length(result)>1) and (result[1]='0') do
  119. delete(result,1,1);
  120. end;
  121. {*****************************************************************************
  122. TRelRelocation
  123. *****************************************************************************}
  124. function TRelRelocation.GetSecOrSymIdx: longint;
  125. begin
  126. if assigned(symbol) then
  127. result:=symbol.symidx
  128. else if assigned(objsection) then
  129. result:=objsection.SecSymIdx
  130. else
  131. internalerror(2020050502);
  132. end;
  133. constructor TRelRelocation.CreateSymbol(ADataOffset: TObjSectionOfs; s: TObjSymbol; Atyp: TObjRelocationType);
  134. begin
  135. inherited;
  136. case Atyp of
  137. RELOC_ABSOLUTE_HI8:
  138. begin
  139. size:=1;
  140. RelFlags:=[rrfSymbol,rrfByte,rrfTwoByteObjectFormatForByteData,rrfMSBWith2ByteMode];
  141. end;
  142. RELOC_ABSOLUTE_LO8:
  143. begin
  144. size:=1;
  145. RelFlags:=[rrfSymbol,rrfByte,rrfTwoByteObjectFormatForByteData];
  146. end;
  147. RELOC_ABSOLUTE:
  148. begin
  149. size:=2;
  150. RelFlags:=[rrfSymbol];
  151. end;
  152. else
  153. internalerror(2020050601);
  154. end;
  155. end;
  156. constructor TRelRelocation.CreateSection(ADataOffset: TObjSectionOfs; aobjsec: TObjSection; Atyp: TObjRelocationType);
  157. begin
  158. inherited;
  159. case Atyp of
  160. RELOC_ABSOLUTE_HI8:
  161. begin
  162. size:=1;
  163. RelFlags:=[rrfByte,rrfTwoByteObjectFormatForByteData,rrfMSBWith2ByteMode];
  164. end;
  165. RELOC_ABSOLUTE_LO8:
  166. begin
  167. size:=1;
  168. RelFlags:=[rrfByte,rrfTwoByteObjectFormatForByteData];
  169. end;
  170. RELOC_ABSOLUTE:
  171. begin
  172. size:=2;
  173. RelFlags:=[];
  174. end;
  175. else
  176. internalerror(2020050601);
  177. end;
  178. end;
  179. function TRelRelocation.EncodeFlags: string;
  180. var
  181. FlagsWord: Word;
  182. begin
  183. FlagsWord:=0;
  184. if rrfByte in RelFlags then
  185. Inc(FlagsWord,1);
  186. if rrfSymbol in RelFlags then
  187. Inc(FlagsWord,2);
  188. if rrfPcRelative in RelFlags then
  189. Inc(FlagsWord,4);
  190. if rrfTwoByteObjectFormatForByteData in RelFlags then
  191. Inc(FlagsWord,8);
  192. if rrfUnsignedByteData in RelFlags then
  193. Inc(FlagsWord,16);
  194. if rrfPage0Reference in RelFlags then
  195. Inc(FlagsWord,32);
  196. if rrfPageNNNReference in RelFlags then
  197. Inc(FlagsWord,64);
  198. if rrfMSBWith2ByteMode in RelFlags then
  199. Inc(FlagsWord,128);
  200. if rrfThreeByteObjectFormatForByteData in RelFlags then
  201. Inc(FlagsWord,256);
  202. if rrfRealMSBForThreeByteMode in RelFlags then
  203. Inc(FlagsWord,512);
  204. if rrfReserved10 in RelFlags then
  205. Inc(FlagsWord,1024);
  206. if rrfReserved11 in RelFlags then
  207. Inc(FlagsWord,2048);
  208. if (FlagsWord<=255) and ((FlagsWord and $F0)<>$F0) then
  209. Result:=HexStr(FlagsWord,2)
  210. else
  211. Result:=HexStr($F0 or Byte(FlagsWord shr 8),2)+' '+HexStr(Byte(FlagsWord),2);
  212. end;
  213. {*****************************************************************************
  214. TRelObjData
  215. *****************************************************************************}
  216. function TRelObjData.sectionname(atype: TAsmSectiontype; const aname: string; aorder: TAsmSectionOrder): string;
  217. const
  218. secnames : array[TAsmSectiontype] of string[length('__DATA, __datacoal_nt,coalesced')] = ('','',
  219. '_CODE',
  220. '_DATA',
  221. '_DATA',
  222. '.rodata',
  223. '.bss',
  224. '.threadvar',
  225. '.pdata',
  226. '', { stubs }
  227. '__DATA,__nl_symbol_ptr',
  228. '__DATA,__la_symbol_ptr',
  229. '__DATA,__mod_init_func',
  230. '__DATA,__mod_term_func',
  231. '.stab',
  232. '.stabstr',
  233. '.idata$2','.idata$4','.idata$5','.idata$6','.idata$7','.edata',
  234. '.eh_frame',
  235. '.debug_frame','.debug_info','.debug_line','.debug_abbrev','.debug_aranges','.debug_ranges',
  236. '.fpc',
  237. '.toc',
  238. '.init',
  239. '.fini',
  240. '.objc_class',
  241. '.objc_meta_class',
  242. '.objc_cat_cls_meth',
  243. '.objc_cat_inst_meth',
  244. '.objc_protocol',
  245. '.objc_string_object',
  246. '.objc_cls_meth',
  247. '.objc_inst_meth',
  248. '.objc_cls_refs',
  249. '.objc_message_refs',
  250. '.objc_symbols',
  251. '.objc_category',
  252. '.objc_class_vars',
  253. '.objc_instance_vars',
  254. '.objc_module_info',
  255. '.objc_class_names',
  256. '.objc_meth_var_types',
  257. '.objc_meth_var_names',
  258. '.objc_selector_strs',
  259. '.objc_protocol_ext',
  260. '.objc_class_ext',
  261. '.objc_property',
  262. '.objc_image_info',
  263. '.objc_cstring_object',
  264. '.objc_sel_fixup',
  265. '__DATA,__objc_data',
  266. '__DATA,__objc_const',
  267. '.objc_superrefs',
  268. '__DATA, __datacoal_nt,coalesced',
  269. '.objc_classlist',
  270. '.objc_nlclasslist',
  271. '.objc_catlist',
  272. '.obcj_nlcatlist',
  273. '.objc_protolist',
  274. '.stack',
  275. '.heap',
  276. '.gcc_except_table',
  277. '.ARM.attributes'
  278. );
  279. begin
  280. result:=secnames[atype];
  281. end;
  282. function TRelObjData.sectiontype2align(atype:TAsmSectiontype):longint;
  283. begin
  284. result:=1;
  285. end;
  286. procedure TRelObjData.writeReloc(Data: TRelocDataInt; len: aword; p: TObjSymbol; Reloctype: TObjRelocationType);
  287. var
  288. bytes: array [0..1] of Byte;
  289. symaddr: QWord;
  290. objreloc: TRelRelocation;
  291. begin
  292. if CurrObjSec=nil then
  293. internalerror(200403072);
  294. objreloc:=nil;
  295. if assigned(p) then
  296. begin
  297. { real address of the symbol }
  298. symaddr:=p.address;
  299. if p.bind=AB_EXTERNAL then
  300. begin
  301. objreloc:=TRelRelocation.CreateSymbol(CurrObjSec.Size,p,Reloctype);
  302. if Reloctype in [RELOC_ABSOLUTE_HI8,RELOC_ABSOLUTE_LO8] then
  303. objreloc.HiByte:=Byte(Data shr 8);
  304. CurrObjSec.ObjRelocations.Add(objreloc);
  305. end
  306. { relative relocations within the same section can be calculated directly,
  307. without the need to emit a relocation entry }
  308. else if (p.objsection=CurrObjSec) and
  309. (p.bind<>AB_COMMON) and
  310. (Reloctype=RELOC_RELATIVE) then
  311. begin
  312. data:=data+symaddr-len-CurrObjSec.Size;
  313. end
  314. else
  315. begin
  316. objreloc:=TRelRelocation.CreateSection(CurrObjSec.Size,p.objsection,Reloctype);
  317. inc(data,symaddr);
  318. if Reloctype in [RELOC_ABSOLUTE_HI8,RELOC_ABSOLUTE_LO8] then
  319. objreloc.HiByte:=Byte(Data shr 8);
  320. CurrObjSec.ObjRelocations.Add(objreloc);
  321. end;
  322. end;
  323. case len of
  324. 2:
  325. begin
  326. bytes[0]:=Byte(Data);
  327. bytes[1]:=Byte(Data shr 8);
  328. writebytes(bytes,2);
  329. end;
  330. 1:
  331. begin
  332. bytes[0]:=Byte(Data);
  333. writebytes(bytes,1);
  334. end;
  335. else
  336. internalerror(2020050423);
  337. end;
  338. end;
  339. {*****************************************************************************
  340. TRelObjOutput
  341. *****************************************************************************}
  342. procedure TRelObjOutput.writeString(const S: ansistring);
  343. begin
  344. FWriter.write(S[1],Length(S));
  345. end;
  346. procedure TRelObjOutput.writeLine(const S: ansistring);
  347. begin
  348. writeString(S+#10)
  349. end;
  350. procedure TRelObjOutput.WriteAreaContentAndRelocations(sec: TObjSection);
  351. const
  352. MaxChunkSize={14}7;
  353. var
  354. ChunkStart,ChunkLen, i: LongWord;
  355. ChunkFixupStart,ChunkFixupEnd, j, st_ofs: Integer;
  356. st,sr: ansistring;
  357. buf: array [0..MaxChunkSize-1] of Byte;
  358. reloc: TRelRelocation;
  359. begin
  360. if (oso_data in sec.SecOptions) and (sec.Data=nil) then
  361. internalerror(200403073);
  362. if assigned(sec.data) then
  363. sec.data.seek(0);
  364. ChunkFixupStart:=0;
  365. ChunkFixupEnd:=-1;
  366. ChunkStart:=0;
  367. ChunkLen:=Min(MaxChunkSize, sec.size-ChunkStart);
  368. while ChunkLen>0 do
  369. begin
  370. { find last fixup in the chunk }
  371. while (ChunkFixupEnd<(sec.ObjRelocations.Count-1)) and
  372. (TRelRelocation(sec.ObjRelocations[ChunkFixupEnd+1]).DataOffset<(ChunkStart+ChunkLen)) do
  373. inc(ChunkFixupEnd);
  374. { check if last chunk is crossing the chunk boundary, and trim ChunkLen if necessary }
  375. if (ChunkFixupEnd>=ChunkFixupStart) and
  376. ((TRelRelocation(sec.ObjRelocations[ChunkFixupEnd]).DataOffset+
  377. TRelRelocation(sec.ObjRelocations[ChunkFixupEnd]).size)>(ChunkStart+ChunkLen)) then
  378. begin
  379. ChunkLen:=TRelRelocation(sec.ObjRelocations[ChunkFixupEnd]).DataOffset-ChunkStart;
  380. Dec(ChunkFixupEnd);
  381. end;
  382. if ChunkLen>SizeOf(buf) then
  383. internalerror(2020050501);
  384. st:='T '+HexStr(Byte(ChunkStart),2)+' '+HexStr(Byte(ChunkStart shr 8),2);
  385. sr:='R 00 00 '+HexStr(Byte(sec.SecSymIdx),2)+' '+HexStr(Byte(sec.SecSymIdx shr 8),2);
  386. if assigned(sec.Data) then
  387. sec.Data.read(buf,ChunkLen)
  388. else
  389. FillChar(buf,ChunkLen,0);
  390. st_ofs:=1;
  391. { relocations present in the current chunk? }
  392. if ChunkFixupEnd>=ChunkFixupStart then
  393. begin
  394. j:=ChunkFixupStart;
  395. reloc:=TRelRelocation(sec.ObjRelocations[j]);
  396. end
  397. else
  398. begin
  399. j:=-1;
  400. reloc:=nil;
  401. end;
  402. for i:=0 to ChunkLen-1 do
  403. begin
  404. st:=st+' '+HexStr(buf[i],2);
  405. Inc(st_ofs);
  406. if assigned(reloc) then
  407. begin
  408. { advance to the current relocation }
  409. while (reloc.DataOffset<(ChunkStart+i)) and (j<ChunkFixupEnd) do
  410. begin
  411. Inc(j);
  412. reloc:=TRelRelocation(sec.ObjRelocations[j]);
  413. end;
  414. { is there a relocation at the current position? }
  415. if reloc.DataOffset=(ChunkStart+i) then
  416. begin
  417. sr:=sr+' '+reloc.EncodeFlags+' '+HexStr(st_ofs,2)+' '+HexStr(Byte(reloc.SecOrSymIdx),2)+' '+HexStr(Byte(reloc.SecOrSymIdx shr 8),2);
  418. if reloc.typ in [RELOC_ABSOLUTE_HI8,RELOC_ABSOLUTE_LO8] then
  419. begin
  420. st:=st+' '+HexStr(reloc.HiByte,2);
  421. Inc(st_ofs);
  422. end;
  423. end;
  424. end;
  425. end;
  426. writeLine(st);
  427. writeLine(sr);
  428. { prepare next chunk }
  429. Inc(ChunkStart, ChunkLen);
  430. ChunkLen:=Min(MaxChunkSize, sec.size-ChunkStart);
  431. ChunkFixupStart:=ChunkFixupEnd+1;
  432. end;
  433. end;
  434. function TRelObjOutput.writeData(Data: TObjData): boolean;
  435. var
  436. global_symbols_count: Integer = 0;
  437. secidx, idx, i, j: Integer;
  438. objsym: TObjSymbol;
  439. objsec: TObjSection;
  440. begin
  441. global_symbols_count:=0;
  442. for i:=0 to Data.ObjSymbolList.Count-1 do
  443. begin
  444. objsym:=TObjSymbol(Data.ObjSymbolList[i]);
  445. if objsym.bind in [AB_EXTERNAL,AB_GLOBAL] then
  446. Inc(global_symbols_count);
  447. end;
  448. writeLine('XL2');
  449. writeLine('H '+tohex(data.ObjSectionList.Count)+' areas '+tohex(global_symbols_count)+' global symbols');
  450. idx:=0;
  451. for i:=0 to Data.ObjSymbolList.Count-1 do
  452. begin
  453. objsym:=TObjSymbol(Data.ObjSymbolList[i]);
  454. if objsym.bind=AB_EXTERNAL then
  455. begin
  456. writeLine('S '+ApplyAsmSymbolRestrictions(objsym.Name)+' Ref0000');
  457. objsym.symidx:=idx;
  458. Inc(idx);
  459. end;
  460. end;
  461. secidx:=0;
  462. for i:=0 to Data.ObjSectionList.Count-1 do
  463. begin
  464. objsec:=TObjSection(Data.ObjSectionList[i]);
  465. writeLine('A '+objsec.Name+' size '+tohex(objsec.Size)+' flags 0 addr 0');
  466. objsec.SecSymIdx:=secidx;
  467. Inc(secidx);
  468. for j:=0 to Data.ObjSymbolList.Count-1 do
  469. begin
  470. objsym:=TObjSymbol(Data.ObjSymbolList[j]);
  471. if (objsym.bind=AB_GLOBAL) and (objsym.objsection=objsec) then
  472. begin
  473. writeLine('S '+ApplyAsmSymbolRestrictions(objsym.Name)+' Def'+HexStr(objsym.offset,4));
  474. objsym.symidx:=idx;
  475. Inc(idx);
  476. end;
  477. end;
  478. end;
  479. for i:=0 to Data.ObjSectionList.Count-1 do
  480. begin
  481. objsec:=TObjSection(Data.ObjSectionList[i]);
  482. WriteAreaContentAndRelocations(objsec);
  483. end;
  484. result:=true;
  485. end;
  486. constructor TRelObjOutput.create(AWriter: TObjectWriter);
  487. begin
  488. inherited;
  489. cobjdata:=TRelObjData;
  490. end;
  491. {*****************************************************************************
  492. TRelAssembler
  493. *****************************************************************************}
  494. constructor TRelAssembler.create(info: pasminfo; smart: boolean);
  495. begin
  496. inherited;
  497. CObjOutput:=TRelObjOutput;
  498. CInternalAr:=tarobjectwriter;
  499. end;
  500. {*****************************************************************************
  501. TRelObjInput
  502. *****************************************************************************}
  503. function TRelObjInput.FillBuf: boolean;
  504. begin
  505. FBufPos:=0;
  506. FBufSize:=min(FReader.size-FReader.Pos,MaxBufSize);
  507. if FBufSize>0 then
  508. result:=FReader.read(FBuf,FBufSize)
  509. else
  510. result:=true;
  511. end;
  512. function TRelObjInput.AtEndOfBuf: boolean;
  513. begin
  514. result:=FBufPos=FBufSize;
  515. end;
  516. function TRelObjInput.AtEoF: boolean;
  517. begin
  518. result:=AtEndOfBuf and (FReader.Pos=FReader.size);
  519. end;
  520. function TRelObjInput.ReadChar(out c: char): boolean;
  521. begin
  522. c:=#0;
  523. if AtEndOfBuf then
  524. begin
  525. result:=FillBuf;
  526. if not result then
  527. exit;
  528. end;
  529. if not AtEndOfBuf then
  530. begin
  531. c:=FBuf[FBufPos];
  532. Inc(FBufPos);
  533. result:=true;
  534. end
  535. else
  536. result:=false;
  537. end;
  538. function TRelObjInput.PeekChar(out c: char): boolean;
  539. begin
  540. c:=#0;
  541. if AtEndOfBuf then
  542. begin
  543. result:=FillBuf;
  544. if not result then
  545. exit;
  546. end;
  547. if not AtEndOfBuf then
  548. begin
  549. c:=FBuf[FBufPos];
  550. result:=true;
  551. end
  552. else
  553. result:=false;
  554. end;
  555. function TRelObjInput.ReadLine(out s: string): boolean;
  556. var
  557. c: Char;
  558. begin
  559. s:='';
  560. if AtEoF then
  561. begin
  562. result:=false;
  563. exit;
  564. end;
  565. repeat
  566. if not AtEoF then
  567. begin
  568. if not ReadChar(c) then
  569. begin
  570. result:=false;
  571. exit;
  572. end;
  573. if not (c in [#13,#10]) then
  574. s:=s+c;
  575. end;
  576. until (c in [#13,#10]) or AtEoF;
  577. if (c=#13) and not AtEoF then
  578. begin
  579. if not PeekChar(c) then
  580. begin
  581. result:=false;
  582. exit;
  583. end;
  584. if c=#10 then
  585. begin
  586. if not ReadChar(c) then
  587. begin
  588. result:=false;
  589. exit;
  590. end;
  591. end;
  592. end;
  593. result:=true;
  594. end;
  595. constructor TRelObjInput.create;
  596. begin
  597. inherited create;
  598. cobjdata:=TRelObjData;
  599. FBufSize:=0;
  600. FBufPos:=0;
  601. end;
  602. function TRelObjInput.ReadObjData(AReader: TObjectreader; out Data: TObjData): boolean;
  603. const
  604. GenericRelErrMsg='Error reading REL file';
  605. var
  606. s, AreaName: string;
  607. RecType: Char;
  608. HeaderFound: Boolean=false;
  609. ExpectedAreas,ExpectedSymbols,AreaSize,AreaFlags,AreaAddr: LongInt;
  610. tmpint: SizeInt;
  611. CurrSec: TObjSection=nil;
  612. begin
  613. FReader:=AReader;
  614. InputFileName:=AReader.FileName;
  615. Data:=CObjData.Create(InputFileName);
  616. result:=false;
  617. s:='';
  618. repeat
  619. if AtEoF or not ReadLine(s) then
  620. begin
  621. InputError(GenericRelErrMsg);
  622. exit;
  623. end;
  624. s:=Trim(s);
  625. until s<>'';
  626. if s<>'XL2' then
  627. begin
  628. InputError('Invalid or unsupported REL format identifier');
  629. exit;
  630. end;
  631. while not AtEoF do
  632. begin
  633. if not ReadLine(s) then
  634. begin
  635. InputError(GenericRelErrMsg);
  636. exit;
  637. end;
  638. s:=Trim(s);
  639. if s<>'' then
  640. begin
  641. RecType:=s[1];
  642. if (length(s)<3) or (s[2]<>' ') then
  643. begin
  644. InputError('Invalid or unsupported REL record');
  645. exit;
  646. end;
  647. delete(s,1,2);
  648. case RecType of
  649. 'H': { header }
  650. begin
  651. if HeaderFound then
  652. begin
  653. InputError('Duplicated header');
  654. exit;
  655. end;
  656. HeaderFound:=true;
  657. tmpint:=Pos(' ',s);
  658. if not TryStrToInt('$'+Copy(s,1,tmpint-1),ExpectedAreas) then
  659. begin
  660. InputError('Invalid area count in header');
  661. exit;
  662. end;
  663. delete(s,1,tmpint);
  664. if copy(s,1,6)<>'areas ' then
  665. begin
  666. InputError('Invalid header');
  667. exit;
  668. end;
  669. delete(s,1,6);
  670. tmpint:=Pos(' ',s);
  671. if not TryStrToInt('$'+Copy(s,1,tmpint-1),ExpectedSymbols) then
  672. begin
  673. InputError('Invalid symbol count in header');
  674. exit;
  675. end;
  676. delete(s,1,tmpint);
  677. if s<>'global symbols' then
  678. begin
  679. InputError('Invalid header');
  680. exit;
  681. end;
  682. end;
  683. 'M': { module }
  684. begin
  685. { we ignore this for now }
  686. end;
  687. 'S': { symbol }
  688. begin
  689. { todo: implement }
  690. end;
  691. 'A': { area }
  692. begin
  693. if not HeaderFound then
  694. begin
  695. InputError('Area record encountered before header');
  696. exit;
  697. end;
  698. tmpint:=Pos(' ',s);
  699. if tmpint<=1 then
  700. begin
  701. InputError('Invalid area record');
  702. exit;
  703. end;
  704. AreaName:=copy(s,1,tmpint-1);
  705. delete(s,1,tmpint);
  706. if copy(s,1,5)<>'size ' then
  707. begin
  708. InputError('Invalid area record');
  709. exit;
  710. end;
  711. delete(s,1,5);
  712. tmpint:=Pos(' ',s);
  713. if not TryStrToInt('$'+Copy(s,1,tmpint-1),AreaSize) then
  714. begin
  715. InputError('Invalid area size');
  716. exit;
  717. end;
  718. delete(s,1,tmpint);
  719. if copy(s,1,6)<>'flags ' then
  720. begin
  721. InputError('Invalid area record');
  722. exit;
  723. end;
  724. delete(s,1,6);
  725. tmpint:=Pos(' ',s);
  726. if not TryStrToInt('$'+Copy(s,1,tmpint-1),AreaFlags) then
  727. begin
  728. InputError('Invalid area flags');
  729. exit;
  730. end;
  731. delete(s,1,tmpint);
  732. if copy(s,1,5)<>'addr ' then
  733. begin
  734. InputError('Invalid area record');
  735. exit;
  736. end;
  737. delete(s,1,5);
  738. if not TryStrToInt('$'+Copy(s,1,tmpint-1),AreaAddr) then
  739. begin
  740. InputError('Invalid area address');
  741. exit;
  742. end;
  743. if AreaFlags<>0 then
  744. begin
  745. InputError('Unsupported area flags ('+tostr(AreaFlags)+')');
  746. exit;
  747. end;
  748. if AreaAddr<>0 then
  749. begin
  750. InputError('Area address<>0 not supported');
  751. exit;
  752. end;
  753. CurrSec:=Data.createsection(AreaName,1,[],false);
  754. CurrSec.alloc(AreaSize);
  755. if Data.ObjSectionList.Count>ExpectedAreas then
  756. begin
  757. InputError('Number of areas exceeds the number, declared in header');
  758. exit;
  759. end;
  760. end;
  761. 'T': { T line () }
  762. begin
  763. { todo: implement }
  764. end;
  765. 'R': { R line (relocation information) }
  766. begin
  767. { todo: implement }
  768. end;
  769. 'P': { P line (paging information) }
  770. begin
  771. InputError('P line records are not supported');
  772. exit;
  773. end;
  774. else
  775. begin
  776. InputError('Unsupported REL record type: #'+tostr(Ord(RecType)));
  777. exit;
  778. end;
  779. end;
  780. end;
  781. end;
  782. end;
  783. class function TRelObjInput.CanReadObjData(AReader: TObjectreader): boolean;
  784. var
  785. s: string;
  786. instance: TRelObjInput;
  787. begin
  788. result:=false;
  789. instance:=TRelObjInput.Create;
  790. instance.FReader:=AReader;
  791. with instance do
  792. while not AtEoF do
  793. begin
  794. if not ReadLine(s) then
  795. exit;
  796. s:=Trim(s);
  797. if s<>'' then
  798. begin
  799. result:=s='XL2';
  800. break;
  801. end;
  802. end;
  803. instance.Free;
  804. end;
  805. {*****************************************************************************
  806. TIntelHexExeOutput
  807. *****************************************************************************}
  808. function TIntelHexExeOutput.writeData: boolean;
  809. begin
  810. result:=false;
  811. end;
  812. procedure TIntelHexExeOutput.DoRelocationFixup(objsec: TObjSection);
  813. begin
  814. end;
  815. constructor TIntelHexExeOutput.create;
  816. begin
  817. inherited create;
  818. CObjData:=TRelObjData;
  819. end;
  820. {*****************************************************************************
  821. Initialize
  822. *****************************************************************************}
  823. const
  824. as_z80_rel_info : tasminfo =
  825. (
  826. id : as_z80_rel;
  827. idtxt : 'REL';
  828. asmbin : '';
  829. asmcmd : '';
  830. supported_targets : [system_z80_embedded,system_z80_zxspectrum];
  831. flags : [af_outputbinary,af_smartlink_sections];
  832. labelprefix : '..@';
  833. labelmaxlen : 79;
  834. comment : '; ';
  835. dollarsign: '$';
  836. );
  837. initialization
  838. RegisterAssembler(as_z80_rel_info,TRelAssembler);
  839. end.