ogrel.pas 41 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221
  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. '_DATA',
  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. function DecodeRelFlags(n1: Word): TRelRelocationFlags;
  604. begin
  605. result:=[];
  606. if (n1 and (1 shl 0))<>0 then
  607. include(result,rrfByte);
  608. if (n1 and (1 shl 1))<>0 then
  609. include(result,rrfSymbol);
  610. if (n1 and (1 shl 2))<>0 then
  611. include(result,rrfPcRelative);
  612. if (n1 and (1 shl 3))<>0 then
  613. include(result,rrfTwoByteObjectFormatForByteData);
  614. if (n1 and (1 shl 4))<>0 then
  615. include(result,rrfUnsignedByteData);
  616. if (n1 and (1 shl 5))<>0 then
  617. include(result,rrfPage0Reference);
  618. if (n1 and (1 shl 6))<>0 then
  619. include(result,rrfPageNNNReference);
  620. if (n1 and (1 shl 7))<>0 then
  621. include(result,rrfMSBWith2ByteMode);
  622. if (n1 and (1 shl 8))<>0 then
  623. include(result,rrfThreeByteObjectFormatForByteData);
  624. if (n1 and (1 shl 9))<>0 then
  625. include(result,rrfRealMSBForThreeByteMode);
  626. if (n1 and (1 shl 10))<>0 then
  627. include(result,rrfReserved10);
  628. if (n1 and (1 shl 11))<>0 then
  629. include(result,rrfReserved11);
  630. end;
  631. function HandleTR(const T,R: string): boolean;
  632. const
  633. GenericTErrMsg='Invalid T record';
  634. GenericRErrMsg='Invalid R record';
  635. UnsupportedRelocationFlags=[rrfPcRelative,rrfUnsignedByteData,
  636. rrfPage0Reference,rrfPageNNNReference,rrfThreeByteObjectFormatForByteData,
  637. rrfRealMSBForThreeByteMode,rrfReserved10,rrfReserved11];
  638. var
  639. ArrT, ArrR: array of byte;
  640. ArrTIsRelocHiByte: array of boolean;
  641. tmpint: Longint;
  642. i: Integer;
  643. AreaIndex, AreaOffset: Word;
  644. LastDataOfsIndex: Integer;
  645. LastDataOfsValue: TObjSectionOfs;
  646. ObjSec: TObjSection;
  647. n1, xx_xx: Word;
  648. n1x, n2, RelHiByte: Byte;
  649. RelFlags: TRelRelocationFlags;
  650. reloc:TRelRelocation;
  651. RelocDataOffset: TObjSectionOfs;
  652. RelocTyp: TObjRelocationType;
  653. begin
  654. result:=false;
  655. if (length(T)<5) or (((length(T)-2) mod 3)<>0) then
  656. begin
  657. InputError(GenericTErrMsg);
  658. exit;
  659. end;
  660. if (length(R)<11) or (((length(R)-2) mod 3)<>0) then
  661. begin
  662. InputError(GenericRErrMsg);
  663. exit;
  664. end;
  665. SetLength(ArrT,((length(T)-2) div 3)+1);
  666. for i:=0 to length(ArrT)-1 do
  667. begin
  668. if (i>0) and (T[i*3]<>' ') then
  669. begin
  670. InputError(GenericTErrMsg);
  671. exit;
  672. end;
  673. if not TryStrToInt('$'+copy(T,1+i*3,2),tmpint) then
  674. begin
  675. InputError(GenericTErrMsg);
  676. exit;
  677. end;
  678. if (tmpint<0) or (tmpint>255) then
  679. begin
  680. InputError(GenericTErrMsg);
  681. exit;
  682. end;
  683. ArrT[i]:=tmpint;
  684. end;
  685. SetLength(ArrR,((length(R)-2) div 3)+1);
  686. for i:=0 to length(ArrR)-1 do
  687. begin
  688. if (i>0) and (R[i*3]<>' ') then
  689. begin
  690. InputError(GenericRErrMsg);
  691. exit;
  692. end;
  693. if not TryStrToInt('$'+copy(R,1+i*3,2),tmpint) then
  694. begin
  695. InputError(GenericRErrMsg);
  696. exit;
  697. end;
  698. if (tmpint<0) or (tmpint>255) then
  699. begin
  700. InputError(GenericRErrMsg);
  701. exit;
  702. end;
  703. ArrR[i]:=tmpint;
  704. end;
  705. if (length(ArrT)<2) or (length(ArrR)<4) then
  706. internalerror(2020060201);
  707. if (ArrR[0]<>0) or (ArrR[1]<>0) then
  708. begin
  709. InputError(GenericRErrMsg);
  710. exit;
  711. end;
  712. AreaIndex:=(ArrR[3] shl 8) or ArrR[2];
  713. AreaOffset:=(ArrT[1] shl 8) or ArrT[0];
  714. if AreaIndex>=Data.ObjSectionList.Count then
  715. begin
  716. InputError('Area index in R record out of bounds');
  717. exit;
  718. end;
  719. ObjSec:=TObjSection(Data.ObjSectionList[AreaIndex]);
  720. if AreaOffset>ObjSec.Size then
  721. begin
  722. InputError('Area offset in T exceeds area size');
  723. exit;
  724. end;
  725. { parse relocations }
  726. SetLength(ArrTIsRelocHiByte,Length(ArrT));
  727. LastDataOfsIndex:=2;
  728. LastDataOfsValue:=AreaOffset;
  729. i:=4;
  730. while i<length(ArrR) do
  731. begin
  732. n1:=ArrR[i];
  733. Inc(i);
  734. if (n1 and $F0)=$F0 then
  735. begin
  736. if i>=length(ArrR) then
  737. begin
  738. InputError(GenericRErrMsg);
  739. exit;
  740. end;
  741. n1x:=ArrR[i];
  742. Inc(i);
  743. n1:=((n1 and $0F) shl 8) or n1x;
  744. end;
  745. if (i+2)>=length(ArrR) then
  746. begin
  747. InputError(GenericRErrMsg);
  748. exit;
  749. end;
  750. n2:=ArrR[i];
  751. xx_xx:=ArrR[i+1] or (ArrR[i+2] shl 8);
  752. Inc(i,3);
  753. RelFlags:=DecodeRelFlags(n1);
  754. if ((RelFlags*UnsupportedRelocationFlags)<>[]) or
  755. ((rrfByte in RelFlags) xor (rrfTwoByteObjectFormatForByteData in RelFlags)) then
  756. begin
  757. InputError('Unsupported relocation flags ($'+HexStr(n1,3)+')');
  758. exit;
  759. end;
  760. if n2<=1 then
  761. begin
  762. InputError('Invalid relocation data offset');
  763. exit;
  764. end;
  765. if rrfByte in RelFlags then
  766. begin
  767. if rrfMSBWith2ByteMode in RelFlags then
  768. RelocTyp:=RELOC_ABSOLUTE_HI8
  769. else
  770. RelocTyp:=RELOC_ABSOLUTE_LO8;
  771. if (n2+1)>=length(ArrT) then
  772. begin
  773. InputError('Invalid relocation data offset');
  774. exit;
  775. end;
  776. ArrTIsRelocHiByte[n2+1]:=true;
  777. RelHiByte:=ArrT[n2+1];
  778. end
  779. else
  780. begin
  781. RelocTyp:=RELOC_ABSOLUTE;
  782. if n2>=length(ArrT) then
  783. begin
  784. InputError('Invalid relocation data offset');
  785. exit;
  786. end;
  787. RelHiByte:=0;
  788. end;
  789. while LastDataOfsIndex<n2 do
  790. begin
  791. if not ArrTIsRelocHiByte[LastDataOfsIndex] then
  792. Inc(LastDataOfsValue);
  793. Inc(LastDataOfsIndex);
  794. end;
  795. RelocDataOffset:=LastDataOfsValue;
  796. if rrfSymbol in RelFlags then
  797. begin
  798. if xx_xx>=Data.ObjSymbolList.Count then
  799. begin
  800. InputError('Relocation to symbol with invalid index');
  801. exit;
  802. end;
  803. reloc:=TRelRelocation.CreateSymbol(RelocDataOffset,TObjSymbol(Data.ObjSymbolList[xx_xx]),RelocTyp);
  804. end
  805. else
  806. begin
  807. if xx_xx>=Data.ObjSectionlist.Count then
  808. begin
  809. InputError('Relocation to area with invalid index');
  810. exit;
  811. end;
  812. reloc:=TRelRelocation.CreateSection(RelocDataOffset,TObjSection(Data.ObjSectionlist[xx_xx]),RelocTyp);
  813. end;
  814. reloc.RelFlags:=RelFlags;
  815. reloc.HiByte:=RelHiByte;
  816. objsec.ObjRelocations.Add(reloc);
  817. end;
  818. { read the data }
  819. objsec.SecOptions:=objsec.SecOptions+[oso_Data];
  820. objsec.Data.seek(AreaOffset);
  821. for i:=2 to length(ArrT)-1 do
  822. if not ArrTIsRelocHiByte[i] then
  823. objsec.Data.write(ArrT[i],1);
  824. result:=true;
  825. end;
  826. const
  827. GenericRelErrMsg='Error reading REL file';
  828. var
  829. s, AreaName, SymbolName: string;
  830. RecType: Char;
  831. HeaderFound: Boolean=false;
  832. ExpectedAreas,ExpectedSymbols,AreaSize,AreaFlags,AreaAddr,
  833. SymbolOfs: LongInt;
  834. tmpint: SizeInt;
  835. CurrSec: TObjSection=nil;
  836. objsym: TObjSymbol;
  837. LastT: string='';
  838. begin
  839. FReader:=AReader;
  840. InputFileName:=AReader.FileName;
  841. Data:=CObjData.Create(InputFileName);
  842. result:=false;
  843. s:='';
  844. repeat
  845. if AtEoF or not ReadLine(s) then
  846. begin
  847. InputError(GenericRelErrMsg);
  848. exit;
  849. end;
  850. s:=Trim(s);
  851. until s<>'';
  852. if s<>'XL2' then
  853. begin
  854. InputError('Invalid or unsupported REL format identifier');
  855. exit;
  856. end;
  857. while not AtEoF do
  858. begin
  859. if not ReadLine(s) then
  860. begin
  861. InputError(GenericRelErrMsg);
  862. exit;
  863. end;
  864. s:=Trim(s);
  865. if s<>'' then
  866. begin
  867. RecType:=s[1];
  868. if (length(s)<3) or (s[2]<>' ') then
  869. begin
  870. InputError('Invalid or unsupported REL record');
  871. exit;
  872. end;
  873. delete(s,1,2);
  874. case RecType of
  875. 'H': { header }
  876. begin
  877. if HeaderFound then
  878. begin
  879. InputError('Duplicated header');
  880. exit;
  881. end;
  882. HeaderFound:=true;
  883. tmpint:=Pos(' ',s);
  884. if not TryStrToInt('$'+Copy(s,1,tmpint-1),ExpectedAreas) then
  885. begin
  886. InputError('Invalid area count in header');
  887. exit;
  888. end;
  889. delete(s,1,tmpint);
  890. if copy(s,1,6)<>'areas ' then
  891. begin
  892. InputError('Invalid header');
  893. exit;
  894. end;
  895. delete(s,1,6);
  896. tmpint:=Pos(' ',s);
  897. if not TryStrToInt('$'+Copy(s,1,tmpint-1),ExpectedSymbols) then
  898. begin
  899. InputError('Invalid symbol count in header');
  900. exit;
  901. end;
  902. delete(s,1,tmpint);
  903. if s<>'global symbols' then
  904. begin
  905. InputError('Invalid header');
  906. exit;
  907. end;
  908. end;
  909. 'M': { module }
  910. begin
  911. { we ignore this for now }
  912. end;
  913. 'S': { symbol }
  914. begin
  915. if not HeaderFound then
  916. begin
  917. InputError('Symbol record encountered before header');
  918. exit;
  919. end;
  920. tmpint:=Pos(' ',s);
  921. if tmpint<=1 then
  922. begin
  923. InputError('Invalid symbol record');
  924. exit;
  925. end;
  926. SymbolName:=copy(s,1,tmpint-1);
  927. delete(s,1,tmpint);
  928. if Length(s)<4 then
  929. begin
  930. InputError('Invalid symbol record');
  931. exit;
  932. end;
  933. if not TryStrToInt('$'+Copy(s,4,Length(s)-4),SymbolOfs) then
  934. begin
  935. InputError('Invalid symbol offset');
  936. exit;
  937. end;
  938. case Copy(s,1,3) of
  939. 'Def':
  940. begin
  941. if CurrSec=nil then
  942. begin
  943. InputError('Public symbol defined outside any area');
  944. exit;
  945. end;
  946. if (SymbolOfs<0) or (SymbolOfs>=CurrSec.Size) then
  947. begin
  948. InputError('Public symbol offset outside the range of the current area');
  949. exit;
  950. end;
  951. objsym:=Data.CreateSymbol(SymbolName);
  952. objsym.bind:=AB_GLOBAL;
  953. objsym.typ:=AT_FUNCTION;
  954. objsym.objsection:=CurrSec;
  955. objsym.offset:=SymbolOfs;
  956. objsym.size:=0;
  957. end;
  958. 'Ref':
  959. begin
  960. if CurrSec<>nil then
  961. begin
  962. InputError('External symbols must be defined before the first area');
  963. exit;
  964. end;
  965. if SymbolOfs<>0 then
  966. begin
  967. InputError('External symbols must be declared with an offset of 0');
  968. exit;
  969. end;
  970. objsym:=Data.CreateSymbol(SymbolName);
  971. objsym.bind:=AB_EXTERNAL;
  972. objsym.typ:=AT_FUNCTION;
  973. objsym.objsection:=nil;
  974. objsym.offset:=0;
  975. objsym.size:=0;
  976. end;
  977. else
  978. begin
  979. InputError('Invalid or unsupported symbol record');
  980. exit;
  981. end;
  982. end;
  983. if Data.ObjSymbolList.Count>ExpectedSymbols then
  984. begin
  985. InputError('Number of symbols exceeds the number, declared in header');
  986. exit;
  987. end;
  988. end;
  989. 'A': { area }
  990. begin
  991. if not HeaderFound then
  992. begin
  993. InputError('Area record encountered before header');
  994. exit;
  995. end;
  996. tmpint:=Pos(' ',s);
  997. if tmpint<=1 then
  998. begin
  999. InputError('Invalid area record');
  1000. exit;
  1001. end;
  1002. AreaName:=copy(s,1,tmpint-1);
  1003. delete(s,1,tmpint);
  1004. if copy(s,1,5)<>'size ' then
  1005. begin
  1006. InputError('Invalid area record');
  1007. exit;
  1008. end;
  1009. delete(s,1,5);
  1010. tmpint:=Pos(' ',s);
  1011. if not TryStrToInt('$'+Copy(s,1,tmpint-1),AreaSize) then
  1012. begin
  1013. InputError('Invalid area size');
  1014. exit;
  1015. end;
  1016. delete(s,1,tmpint);
  1017. if copy(s,1,6)<>'flags ' then
  1018. begin
  1019. InputError('Invalid area record');
  1020. exit;
  1021. end;
  1022. delete(s,1,6);
  1023. tmpint:=Pos(' ',s);
  1024. if not TryStrToInt('$'+Copy(s,1,tmpint-1),AreaFlags) then
  1025. begin
  1026. InputError('Invalid area flags');
  1027. exit;
  1028. end;
  1029. delete(s,1,tmpint);
  1030. if copy(s,1,5)<>'addr ' then
  1031. begin
  1032. InputError('Invalid area record');
  1033. exit;
  1034. end;
  1035. delete(s,1,5);
  1036. if not TryStrToInt('$'+Copy(s,1,tmpint-1),AreaAddr) then
  1037. begin
  1038. InputError('Invalid area address');
  1039. exit;
  1040. end;
  1041. if AreaFlags<>0 then
  1042. begin
  1043. InputError('Unsupported area flags ('+tostr(AreaFlags)+')');
  1044. exit;
  1045. end;
  1046. if AreaAddr<>0 then
  1047. begin
  1048. InputError('Area address<>0 not supported');
  1049. exit;
  1050. end;
  1051. CurrSec:=Data.createsection(AreaName,1,[],false);
  1052. CurrSec.alloc(AreaSize);
  1053. if Data.ObjSectionList.Count>ExpectedAreas then
  1054. begin
  1055. InputError('Number of areas exceeds the number, declared in header');
  1056. exit;
  1057. end;
  1058. end;
  1059. 'T': { T line () }
  1060. begin
  1061. if LastT<>'' then
  1062. begin
  1063. InputError('T record not followed by R record');
  1064. exit;
  1065. end;
  1066. LastT:=s;
  1067. end;
  1068. 'R': { R line (relocation information) }
  1069. begin
  1070. if LastT='' then
  1071. begin
  1072. InputError('R record without T record');
  1073. exit;
  1074. end;
  1075. if not HandleTR(LastT,s) then
  1076. exit;
  1077. LastT:='';
  1078. end;
  1079. 'P': { P line (paging information) }
  1080. begin
  1081. InputError('P line records are not supported');
  1082. exit;
  1083. end;
  1084. else
  1085. begin
  1086. InputError('Unsupported REL record type: #'+tostr(Ord(RecType)));
  1087. exit;
  1088. end;
  1089. end;
  1090. end;
  1091. end;
  1092. result:=true;
  1093. end;
  1094. class function TRelObjInput.CanReadObjData(AReader: TObjectreader): boolean;
  1095. var
  1096. s: string;
  1097. instance: TRelObjInput;
  1098. begin
  1099. result:=false;
  1100. instance:=TRelObjInput.Create;
  1101. instance.FReader:=AReader;
  1102. with instance do
  1103. while not AtEoF do
  1104. begin
  1105. if not ReadLine(s) then
  1106. exit;
  1107. s:=Trim(s);
  1108. if s<>'' then
  1109. begin
  1110. result:=s='XL2';
  1111. break;
  1112. end;
  1113. end;
  1114. instance.Free;
  1115. end;
  1116. {*****************************************************************************
  1117. TIntelHexExeOutput
  1118. *****************************************************************************}
  1119. function TIntelHexExeOutput.writeData: boolean;
  1120. begin
  1121. result:=false;
  1122. end;
  1123. procedure TIntelHexExeOutput.DoRelocationFixup(objsec: TObjSection);
  1124. begin
  1125. end;
  1126. constructor TIntelHexExeOutput.create;
  1127. begin
  1128. inherited create;
  1129. CObjData:=TRelObjData;
  1130. MaxMemPos:=$FFFF;
  1131. end;
  1132. {*****************************************************************************
  1133. Initialize
  1134. *****************************************************************************}
  1135. const
  1136. as_z80_rel_info : tasminfo =
  1137. (
  1138. id : as_z80_rel;
  1139. idtxt : 'REL';
  1140. asmbin : '';
  1141. asmcmd : '';
  1142. supported_targets : [system_z80_embedded,system_z80_zxspectrum];
  1143. flags : [af_outputbinary,af_smartlink_sections];
  1144. labelprefix : '..@';
  1145. labelmaxlen : 79;
  1146. comment : '; ';
  1147. dollarsign: '$';
  1148. );
  1149. initialization
  1150. RegisterAssembler(as_z80_rel_info,TRelAssembler);
  1151. end.