ogbase.pas 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639
  1. {
  2. $Id$
  3. Copyright (c) 1998-2002 by Peter Vreman
  4. Contains the base stuff for binary object file writers
  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 ogbase;
  19. {$i fpcdefs.inc}
  20. interface
  21. uses
  22. {$ifdef Delphi}
  23. sysutils,
  24. dmisc,
  25. {$else Delphi}
  26. strings,
  27. dos,
  28. {$endif Delphi}
  29. { common }
  30. cclasses,
  31. { targets }
  32. systems,
  33. { outputwriters }
  34. owbase,owar,
  35. { assembler }
  36. cpubase,aasmbase,aasmtai;
  37. type
  38. tobjectoutput = class
  39. protected
  40. { writer }
  41. FWriter : tobjectwriter;
  42. function writedata(data:TAsmObjectData):boolean;virtual;abstract;
  43. public
  44. constructor create(smart:boolean);
  45. destructor destroy;override;
  46. function newobjectdata(const n:string):TAsmObjectData;virtual;
  47. function startobjectfile(const fn:string):boolean;
  48. function writeobjectfile(data:TAsmObjectData):boolean;
  49. procedure exportsymbol(p:tasmsymbol);
  50. property Writer:TObjectWriter read FWriter;
  51. end;
  52. tobjectinput = class
  53. protected
  54. { reader }
  55. FReader : tobjectreader;
  56. protected
  57. function str2sec(const s:string):TSection;
  58. function readobjectdata(data:TAsmObjectData):boolean;virtual;abstract;
  59. public
  60. constructor create;
  61. destructor destroy;override;
  62. function newobjectdata(const n:string):TAsmObjectData;virtual;
  63. function readobjectfile(const fn:string;data:TAsmObjectData):boolean;virtual;
  64. property Reader:TObjectReader read FReader;
  65. end;
  66. texesection = class
  67. public
  68. name : string[32];
  69. available : boolean;
  70. secsymidx,
  71. datasize,
  72. datapos,
  73. memsize,
  74. mempos : longint;
  75. flags : cardinal;
  76. DataList : TLinkedList;
  77. constructor create(const n:string);
  78. destructor destroy;override;
  79. end;
  80. texeoutput = class
  81. protected
  82. { writer }
  83. FWriter : tobjectwriter;
  84. procedure WriteZeros(l:longint);
  85. procedure MapObjectdata(var datapos:longint;var mempos:longint);
  86. function writedata:boolean;virtual;abstract;
  87. public
  88. { info for each section }
  89. sections : array[TSection] of texesection;
  90. { global symbols }
  91. externalsyms : tsinglelist;
  92. commonsyms : tsinglelist;
  93. globalsyms : tdictionary;
  94. { list of all data of the object files to link }
  95. objdatalist : tlinkedlist;
  96. constructor create;
  97. destructor destroy;override;
  98. function newobjectinput:tobjectinput;virtual;
  99. procedure GenerateExecutable(const fn:string);virtual;abstract;
  100. function writeexefile(const fn:string):boolean;
  101. function CalculateSymbols:boolean;
  102. procedure CalculateMemoryMap;virtual;abstract;
  103. procedure addobjdata(objdata:TAsmObjectData);
  104. procedure FixUpSymbols;
  105. procedure FixUpRelocations;
  106. procedure addglobalsym(const name:string;ofs:longint);
  107. property Writer:TObjectWriter read FWriter;
  108. end;
  109. var
  110. exeoutput : texeoutput;
  111. implementation
  112. uses
  113. cutils,globtype,globals,verbose,fmodule,ogmap;
  114. {****************************************************************************
  115. tobjectoutput
  116. ****************************************************************************}
  117. constructor tobjectoutput.create(smart:boolean);
  118. begin
  119. { init writer }
  120. if smart and
  121. not(cs_asm_leave in aktglobalswitches) then
  122. FWriter:=tarobjectwriter.create(current_module.staticlibfilename^)
  123. else
  124. FWriter:=tobjectwriter.create;
  125. end;
  126. destructor tobjectoutput.destroy;
  127. begin
  128. FWriter.free;
  129. end;
  130. function tobjectoutput.newobjectdata(const n:string):TAsmObjectData;
  131. begin
  132. result:=TAsmObjectData.create(n);
  133. end;
  134. function tobjectoutput.startobjectfile(const fn:string):boolean;
  135. begin
  136. result:=false;
  137. { start the writer already, so the .a generation can initialize
  138. the position of the current objectfile }
  139. if not FWriter.createfile(fn) then
  140. Comment(V_Fatal,'Can''t create object '+fn);
  141. result:=true;
  142. end;
  143. function tobjectoutput.writeobjectfile(data:TAsmObjectData):boolean;
  144. begin
  145. if errorcount=0 then
  146. result:=writedata(data)
  147. else
  148. result:=true;
  149. { close the writer }
  150. FWriter.closefile;
  151. end;
  152. procedure tobjectoutput.exportsymbol(p:tasmsymbol);
  153. begin
  154. { export globals and common symbols, this is needed
  155. for .a files }
  156. if p.currbind in [AB_GLOBAL,AB_COMMON] then
  157. FWriter.writesym(p.name);
  158. end;
  159. {****************************************************************************
  160. texesection
  161. ****************************************************************************}
  162. constructor texesection.create(const n:string);
  163. begin
  164. name:=n;
  165. mempos:=0;
  166. memsize:=0;
  167. datapos:=0;
  168. datasize:=0;
  169. secsymidx:=0;
  170. available:=false;
  171. flags:=0;
  172. datalist:=TLinkedList.Create;
  173. end;
  174. destructor texesection.destroy;
  175. begin
  176. end;
  177. {****************************************************************************
  178. texeoutput
  179. ****************************************************************************}
  180. constructor texeoutput.create;
  181. var
  182. sec : TSection;
  183. begin
  184. { init writer }
  185. FWriter:=tobjectwriter.create;
  186. { object files }
  187. objdatalist:=tlinkedlist.create;
  188. { symbols }
  189. globalsyms:=tdictionary.create;
  190. globalsyms.usehash;
  191. globalsyms.noclear:=true;
  192. externalsyms:=tsinglelist.create;
  193. commonsyms:=tsinglelist.create;
  194. { sections }
  195. for sec:=low(TSection) to high(TSection) do
  196. sections[sec]:=texesection.create(target_asm.secnames[sec]);
  197. end;
  198. destructor texeoutput.destroy;
  199. var
  200. sec : TSection;
  201. begin
  202. for sec:=low(TSection) to high(TSection) do
  203. sections[sec].free;
  204. globalsyms.free;
  205. externalsyms.free;
  206. commonsyms.free;
  207. objdatalist.free;
  208. FWriter.free;
  209. end;
  210. function texeoutput.newobjectinput:tobjectinput;
  211. begin
  212. result:=tobjectinput.create;
  213. end;
  214. function texeoutput.writeexefile(const fn:string):boolean;
  215. begin
  216. result:=false;
  217. if FWriter.createfile(fn) then
  218. begin
  219. { Only write the .o if there are no errors }
  220. if errorcount=0 then
  221. result:=writedata
  222. else
  223. result:=true;
  224. { close the writer }
  225. FWriter.closefile;
  226. end
  227. else
  228. Comment(V_Fatal,'Can''t create executable '+fn);
  229. end;
  230. procedure texeoutput.addobjdata(objdata:TAsmObjectData);
  231. var
  232. sec : TSection;
  233. begin
  234. objdatalist.concat(objdata);
  235. { check which sections are available }
  236. for sec:=low(TSection) to high(TSection) do
  237. begin
  238. if assigned(objdata.sects[sec]) then
  239. begin
  240. sections[sec].available:=true;
  241. sections[sec].flags:=objdata.sects[sec].flags;
  242. end;
  243. end;
  244. end;
  245. procedure texeoutput.MapObjectdata(var datapos:longint;var mempos:longint);
  246. var
  247. sec : TSection;
  248. s : TAsmSection;
  249. alignedpos : longint;
  250. objdata : TAsmObjectData;
  251. begin
  252. { calculate offsets of each objdata }
  253. for sec:=low(TSection) to high(TSection) do
  254. begin
  255. if sections[sec].available then
  256. begin
  257. { set start position of section }
  258. sections[sec].datapos:=datapos;
  259. sections[sec].mempos:=mempos;
  260. { update objectfiles }
  261. objdata:=TAsmObjectData(objdatalist.first);
  262. while assigned(objdata) do
  263. begin
  264. s:=objdata.sects[sec];
  265. if assigned(s) then
  266. begin
  267. { align section }
  268. mempos:=align(mempos,$10);
  269. if assigned(s.data) then
  270. begin
  271. alignedpos:=align(datapos,$10);
  272. s.dataalignbytes:=alignedpos-datapos;
  273. datapos:=alignedpos;
  274. end;
  275. { set position and size of this objectfile }
  276. s.mempos:=mempos;
  277. s.datapos:=datapos;
  278. inc(mempos,s.datasize);
  279. if assigned(s.data) then
  280. inc(datapos,s.datasize);
  281. end;
  282. objdata:=TAsmObjectData(objdata.next);
  283. end;
  284. { calculate size of the section }
  285. sections[sec].datasize:=datapos-sections[sec].datapos;
  286. sections[sec].memsize:=mempos-sections[sec].mempos;
  287. end;
  288. end;
  289. end;
  290. procedure texeoutput.WriteZeros(l:longint);
  291. var
  292. empty : array[0..63] of char;
  293. begin
  294. if l>0 then
  295. begin
  296. fillchar(empty,l,0);
  297. FWriter.Write(empty,l);
  298. end;
  299. end;
  300. procedure texeoutput.FixUpSymbols;
  301. var
  302. sec : TSection;
  303. objdata : TAsmObjectData;
  304. sym,
  305. hsym : tasmsymbol;
  306. begin
  307. {
  308. Fixing up symbols is done in the following steps:
  309. 1. Update addresses
  310. 2. Update common references
  311. 3. Update external references
  312. }
  313. { Step 1, Update addresses }
  314. if assigned(exemap) then
  315. exemap.AddMemoryMapHeader;
  316. for sec:=low(TSection) to high(TSection) do
  317. if sections[sec].available then
  318. begin
  319. if assigned(exemap) then
  320. exemap.AddMemoryMapSection(sections[sec]);
  321. objdata:=TAsmObjectData(objdatalist.first);
  322. while assigned(objdata) do
  323. begin
  324. if assigned(objdata.sects[sec]) then
  325. begin
  326. if assigned(exemap) then
  327. exemap.AddMemoryMapObjectData(objdata,sec);
  328. hsym:=tasmsymbol(objdata.symbols.first);
  329. while assigned(hsym) do
  330. begin
  331. { process only the symbols that are defined in this section
  332. and are located in this module }
  333. if ((hsym.section=sec) or
  334. ((sec=sec_bss) and (hsym.section=sec_common))) then
  335. begin
  336. if hsym.currbind=AB_EXTERNAL then
  337. internalerror(200206303);
  338. inc(hsym.address,TAsmObjectData(hsym.objectdata).sects[sec].mempos);
  339. if assigned(exemap) then
  340. exemap.AddMemoryMapSymbol(hsym);
  341. end;
  342. hsym:=tasmsymbol(hsym.indexnext);
  343. end;
  344. end;
  345. objdata:=TAsmObjectData(objdata.next);
  346. end;
  347. end;
  348. { Step 2, Update commons }
  349. sym:=tasmsymbol(commonsyms.first);
  350. while assigned(sym) do
  351. begin
  352. if sym.currbind=AB_COMMON then
  353. begin
  354. { update this symbol }
  355. sym.currbind:=sym.altsymbol.currbind;
  356. sym.address:=sym.altsymbol.address;
  357. sym.size:=sym.altsymbol.size;
  358. sym.section:=sym.altsymbol.section;
  359. sym.typ:=sym.altsymbol.typ;
  360. sym.objectdata:=sym.altsymbol.objectdata;
  361. end;
  362. sym:=tasmsymbol(sym.listnext);
  363. end;
  364. { Step 3, Update externals }
  365. sym:=tasmsymbol(externalsyms.first);
  366. while assigned(sym) do
  367. begin
  368. if sym.currbind=AB_EXTERNAL then
  369. begin
  370. { update this symbol }
  371. sym.currbind:=sym.altsymbol.currbind;
  372. sym.address:=sym.altsymbol.address;
  373. sym.size:=sym.altsymbol.size;
  374. sym.section:=sym.altsymbol.section;
  375. sym.typ:=sym.altsymbol.typ;
  376. sym.objectdata:=sym.altsymbol.objectdata;
  377. end;
  378. sym:=tasmsymbol(sym.listnext);
  379. end;
  380. end;
  381. procedure texeoutput.FixUpRelocations;
  382. var
  383. objdata : TAsmObjectData;
  384. begin
  385. objdata:=TAsmObjectData(objdatalist.first);
  386. while assigned(objdata) do
  387. begin
  388. objdata.fixuprelocs;
  389. objdata:=TAsmObjectData(objdata.next);
  390. end;
  391. end;
  392. procedure texeoutput.addglobalsym(const name:string;ofs:longint);
  393. var
  394. sym : tasmsymbol;
  395. begin
  396. sym:=tasmsymbol(globalsyms.search(name));
  397. if not assigned(sym) then
  398. begin
  399. sym:=tasmsymbol.create(name,AB_GLOBAL,AT_FUNCTION);
  400. globalsyms.insert(sym);
  401. end;
  402. sym.currbind:=AB_GLOBAL;
  403. sym.address:=ofs;
  404. end;
  405. function TExeOutput.CalculateSymbols:boolean;
  406. var
  407. commonobjdata,
  408. objdata : TAsmObjectData;
  409. s : TAsmSection;
  410. sym,p : tasmsymbol;
  411. begin
  412. commonobjdata:=nil;
  413. CalculateSymbols:=true;
  414. {
  415. The symbol calculation is done in 3 steps:
  416. 1. register globals
  417. register externals
  418. register commons
  419. 2. try to find commons, if not found then
  420. add to the globals (so externals can be resolved)
  421. 3. try to find externals
  422. }
  423. { Step 1, Register symbols }
  424. objdata:=TAsmObjectData(objdatalist.first);
  425. while assigned(objdata) do
  426. begin
  427. sym:=tasmsymbol(objdata.symbols.first);
  428. while assigned(sym) do
  429. begin
  430. if not assigned(sym.objectdata) then
  431. internalerror(200206302);
  432. case sym.currbind of
  433. AB_GLOBAL :
  434. begin
  435. p:=tasmsymbol(globalsyms.search(sym.name));
  436. if not assigned(p) then
  437. globalsyms.insert(sym)
  438. else
  439. begin
  440. Comment(V_Error,'Multiple defined symbol '+sym.name);
  441. CalculateSymbols:=false;
  442. end;
  443. end;
  444. AB_EXTERNAL :
  445. externalsyms.insert(sym);
  446. AB_COMMON :
  447. commonsyms.insert(sym);
  448. end;
  449. sym:=tasmsymbol(sym.indexnext);
  450. end;
  451. objdata:=TAsmObjectData(objdata.next);
  452. end;
  453. { Step 2, Match common symbols or add to the globals }
  454. sym:=tasmsymbol(commonsyms.first);
  455. while assigned(sym) do
  456. begin
  457. if sym.currbind=AB_COMMON then
  458. begin
  459. p:=tasmsymbol(globalsyms.search(sym.name));
  460. if assigned(p) then
  461. begin
  462. if p.size<>sym.size then
  463. internalerror(200206301);
  464. end
  465. else
  466. begin
  467. { allocate new symbol in .bss and store it in the
  468. *COMMON* module }
  469. if not assigned(commonobjdata) then
  470. begin
  471. if assigned(exemap) then
  472. exemap.AddCommonSymbolsHeader;
  473. { create .bss section and add to list }
  474. s:=TAsmSection.create(target_asm.secnames[sec_common],0,true);
  475. commonobjdata:=TAsmObjectData.create('*COMMON*');
  476. commonobjdata.sects[sec_bss]:=s;
  477. addobjdata(commonobjdata);
  478. end;
  479. p:=TAsmSymbol.Create(sym.name,AB_GLOBAL,AT_FUNCTION);
  480. p.SetAddress(0,sec_common,s.datasize,sym.size);
  481. p.objectdata:=commonobjdata;
  482. commonobjdata.sects[sec_bss].alloc(sym.size);
  483. commonobjdata.symbols.insert(p);
  484. { update this symbol }
  485. if assigned(exemap) then
  486. exemap.AddCommonSymbol(p);
  487. { make this symbol available as a global }
  488. globalsyms.insert(p);
  489. end;
  490. sym.altsymbol:=p;
  491. end;
  492. sym:=tasmsymbol(sym.listnext);
  493. end;
  494. { Step 3 }
  495. sym:=tasmsymbol(externalsyms.first);
  496. while assigned(sym) do
  497. begin
  498. if sym.currbind=AB_EXTERNAL then
  499. begin
  500. p:=tasmsymbol(globalsyms.search(sym.name));
  501. if assigned(p) then
  502. begin
  503. sym.altsymbol:=p;
  504. end
  505. else
  506. begin
  507. Comment(V_Error,'Undefined symbol: '+sym.name);
  508. CalculateSymbols:=false;
  509. end;
  510. end;
  511. sym:=tasmsymbol(sym.listnext);
  512. end;
  513. end;
  514. {****************************************************************************
  515. tobjectinput
  516. ****************************************************************************}
  517. constructor tobjectinput.create;
  518. begin
  519. { init reader }
  520. FReader:=tobjectreader.create;
  521. end;
  522. destructor tobjectinput.destroy;
  523. begin
  524. FReader.free;
  525. end;
  526. function tobjectinput.newobjectdata(const n:string):TAsmObjectData;
  527. begin
  528. result:=TAsmObjectData.create(n);
  529. end;
  530. function tobjectinput.readobjectfile(const fn:string;data:TAsmObjectData):boolean;
  531. begin
  532. result:=false;
  533. { start the reader }
  534. if FReader.openfile(fn) then
  535. begin
  536. result:=readobjectdata(data);
  537. FReader.closefile;
  538. end;
  539. end;
  540. function tobjectinput.str2sec(const s:string):TSection;
  541. var
  542. t : TSection;
  543. begin
  544. for t:=low(TSection) to high(TSection) do
  545. begin
  546. if (s=target_asm.secnames[t]) then
  547. begin
  548. str2sec:=t;
  549. exit;
  550. end;
  551. end;
  552. str2sec:=sec_none;
  553. end;
  554. end.
  555. {
  556. $Log$
  557. Revision 1.13 2003-04-22 14:33:38 peter
  558. * removed some notes/hints
  559. Revision 1.12 2002/07/01 18:46:24 peter
  560. * internal linker
  561. * reorganized aasm layer
  562. Revision 1.11 2002/05/18 13:34:10 peter
  563. * readded missing revisions
  564. Revision 1.9 2002/05/14 19:34:43 peter
  565. * removed old logs and updated copyright year
  566. }