ogbase.pas 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637
  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. hsym : tasmsymbol;
  252. begin
  253. { calculate offsets of each objdata }
  254. for sec:=low(TSection) to high(TSection) do
  255. begin
  256. if sections[sec].available then
  257. begin
  258. { set start position of section }
  259. sections[sec].datapos:=datapos;
  260. sections[sec].mempos:=mempos;
  261. { update objectfiles }
  262. objdata:=TAsmObjectData(objdatalist.first);
  263. while assigned(objdata) do
  264. begin
  265. s:=objdata.sects[sec];
  266. if assigned(s) then
  267. begin
  268. { align section }
  269. mempos:=align(mempos,$10);
  270. if assigned(s.data) then
  271. begin
  272. alignedpos:=align(datapos,$10);
  273. s.dataalignbytes:=alignedpos-datapos;
  274. datapos:=alignedpos;
  275. end;
  276. { set position and size of this objectfile }
  277. s.mempos:=mempos;
  278. s.datapos:=datapos;
  279. inc(mempos,s.datasize);
  280. if assigned(s.data) then
  281. inc(datapos,s.datasize);
  282. end;
  283. objdata:=TAsmObjectData(objdata.next);
  284. end;
  285. { calculate size of the section }
  286. sections[sec].datasize:=datapos-sections[sec].datapos;
  287. sections[sec].memsize:=mempos-sections[sec].mempos;
  288. end;
  289. end;
  290. end;
  291. procedure texeoutput.WriteZeros(l:longint);
  292. var
  293. empty : array[0..63] of char;
  294. begin
  295. if l>0 then
  296. begin
  297. fillchar(empty,l,0);
  298. FWriter.Write(empty,l);
  299. end;
  300. end;
  301. procedure texeoutput.FixUpSymbols;
  302. var
  303. sec : TSection;
  304. objdata : TAsmObjectData;
  305. sym,
  306. hsym : tasmsymbol;
  307. begin
  308. {
  309. Fixing up symbols is done in the following steps:
  310. 1. Update addresses
  311. 2. Update common references
  312. 3. Update external references
  313. }
  314. { Step 1, Update addresses }
  315. if assigned(exemap) then
  316. exemap.AddMemoryMapHeader;
  317. for sec:=low(TSection) to high(TSection) do
  318. if sections[sec].available then
  319. begin
  320. if assigned(exemap) then
  321. exemap.AddMemoryMapSection(sections[sec]);
  322. objdata:=TAsmObjectData(objdatalist.first);
  323. while assigned(objdata) do
  324. begin
  325. if assigned(objdata.sects[sec]) then
  326. begin
  327. if assigned(exemap) then
  328. exemap.AddMemoryMapObjectData(objdata,sec);
  329. hsym:=tasmsymbol(objdata.symbols.first);
  330. while assigned(hsym) do
  331. begin
  332. { process only the symbols that are defined in this section
  333. and are located in this module }
  334. if ((hsym.section=sec) or
  335. ((sec=sec_bss) and (hsym.section=sec_common))) then
  336. begin
  337. if hsym.currbind=AB_EXTERNAL then
  338. internalerror(200206303);
  339. inc(hsym.address,TAsmObjectData(hsym.objectdata).sects[sec].mempos);
  340. if assigned(exemap) then
  341. exemap.AddMemoryMapSymbol(hsym);
  342. end;
  343. hsym:=tasmsymbol(hsym.indexnext);
  344. end;
  345. end;
  346. objdata:=TAsmObjectData(objdata.next);
  347. end;
  348. end;
  349. { Step 2, Update commons }
  350. sym:=tasmsymbol(commonsyms.first);
  351. while assigned(sym) do
  352. begin
  353. if sym.currbind=AB_COMMON then
  354. begin
  355. { update this symbol }
  356. sym.currbind:=sym.altsymbol.currbind;
  357. sym.address:=sym.altsymbol.address;
  358. sym.size:=sym.altsymbol.size;
  359. sym.section:=sym.altsymbol.section;
  360. sym.typ:=sym.altsymbol.typ;
  361. sym.objectdata:=sym.altsymbol.objectdata;
  362. end;
  363. sym:=tasmsymbol(sym.listnext);
  364. end;
  365. { Step 3, Update externals }
  366. sym:=tasmsymbol(externalsyms.first);
  367. while assigned(sym) do
  368. begin
  369. if sym.currbind=AB_EXTERNAL then
  370. begin
  371. { update this symbol }
  372. sym.currbind:=sym.altsymbol.currbind;
  373. sym.address:=sym.altsymbol.address;
  374. sym.size:=sym.altsymbol.size;
  375. sym.section:=sym.altsymbol.section;
  376. sym.typ:=sym.altsymbol.typ;
  377. sym.objectdata:=sym.altsymbol.objectdata;
  378. end;
  379. sym:=tasmsymbol(sym.listnext);
  380. end;
  381. end;
  382. procedure texeoutput.FixUpRelocations;
  383. var
  384. objdata : TAsmObjectData;
  385. begin
  386. objdata:=TAsmObjectData(objdatalist.first);
  387. while assigned(objdata) do
  388. begin
  389. objdata.fixuprelocs;
  390. objdata:=TAsmObjectData(objdata.next);
  391. end;
  392. end;
  393. procedure texeoutput.addglobalsym(const name:string;ofs:longint);
  394. var
  395. sym : tasmsymbol;
  396. begin
  397. sym:=tasmsymbol(globalsyms.search(name));
  398. if not assigned(sym) then
  399. begin
  400. sym:=tasmsymbol.create(name,AB_GLOBAL,AT_FUNCTION);
  401. globalsyms.insert(sym);
  402. end;
  403. sym.currbind:=AB_GLOBAL;
  404. sym.address:=ofs;
  405. end;
  406. function TExeOutput.CalculateSymbols:boolean;
  407. var
  408. commonobjdata,
  409. objdata : TAsmObjectData;
  410. s : TAsmSection;
  411. sym,p : tasmsymbol;
  412. begin
  413. commonobjdata:=nil;
  414. CalculateSymbols:=true;
  415. {
  416. The symbol calculation is done in 3 steps:
  417. 1. register globals
  418. register externals
  419. register commons
  420. 2. try to find commons, if not found then
  421. add to the globals (so externals can be resolved)
  422. 3. try to find externals
  423. }
  424. { Step 1, Register symbols }
  425. objdata:=TAsmObjectData(objdatalist.first);
  426. while assigned(objdata) do
  427. begin
  428. sym:=tasmsymbol(objdata.symbols.first);
  429. while assigned(sym) do
  430. begin
  431. if not assigned(sym.objectdata) then
  432. internalerror(200206302);
  433. case sym.currbind of
  434. AB_GLOBAL :
  435. begin
  436. p:=tasmsymbol(globalsyms.search(sym.name));
  437. if not assigned(p) then
  438. globalsyms.insert(sym)
  439. else
  440. begin
  441. Comment(V_Error,'Multiple defined symbol '+sym.name);
  442. CalculateSymbols:=false;
  443. end;
  444. end;
  445. AB_EXTERNAL :
  446. externalsyms.insert(sym);
  447. AB_COMMON :
  448. commonsyms.insert(sym);
  449. end;
  450. sym:=tasmsymbol(sym.indexnext);
  451. end;
  452. objdata:=TAsmObjectData(objdata.next);
  453. end;
  454. { Step 2, Match common symbols or add to the globals }
  455. sym:=tasmsymbol(commonsyms.first);
  456. while assigned(sym) do
  457. begin
  458. if sym.currbind=AB_COMMON then
  459. begin
  460. p:=tasmsymbol(globalsyms.search(sym.name));
  461. if assigned(p) then
  462. begin
  463. if p.size<>sym.size then
  464. internalerror(200206301);
  465. end
  466. else
  467. begin
  468. { allocate new symbol in .bss and store it in the
  469. *COMMON* module }
  470. if not assigned(commonobjdata) then
  471. begin
  472. if assigned(exemap) then
  473. exemap.AddCommonSymbolsHeader;
  474. { create .bss section and add to list }
  475. s:=TAsmSection.create(target_asm.secnames[sec_common],0,true);
  476. commonobjdata:=TAsmObjectData.create('*COMMON*');
  477. commonobjdata.sects[sec_bss]:=s;
  478. addobjdata(commonobjdata);
  479. end;
  480. p:=TAsmSymbol.Create(sym.name,AB_GLOBAL,AT_FUNCTION);
  481. p.SetAddress(0,sec_common,s.datasize,sym.size);
  482. p.objectdata:=commonobjdata;
  483. commonobjdata.sects[sec_bss].alloc(sym.size);
  484. commonobjdata.symbols.insert(p);
  485. { update this symbol }
  486. if assigned(exemap) then
  487. exemap.AddCommonSymbol(p);
  488. { make this symbol available as a global }
  489. globalsyms.insert(p);
  490. end;
  491. sym.altsymbol:=p;
  492. end;
  493. sym:=tasmsymbol(sym.listnext);
  494. end;
  495. { Step 3 }
  496. sym:=tasmsymbol(externalsyms.first);
  497. while assigned(sym) do
  498. begin
  499. if sym.currbind=AB_EXTERNAL then
  500. begin
  501. p:=tasmsymbol(globalsyms.search(sym.name));
  502. if assigned(p) then
  503. begin
  504. sym.altsymbol:=p;
  505. end
  506. else
  507. begin
  508. Comment(V_Error,'Undefined symbol: '+sym.name);
  509. CalculateSymbols:=false;
  510. end;
  511. end;
  512. sym:=tasmsymbol(sym.listnext);
  513. end;
  514. end;
  515. {****************************************************************************
  516. tobjectinput
  517. ****************************************************************************}
  518. constructor tobjectinput.create;
  519. begin
  520. { init reader }
  521. FReader:=tobjectreader.create;
  522. end;
  523. destructor tobjectinput.destroy;
  524. begin
  525. FReader.free;
  526. end;
  527. function tobjectinput.newobjectdata(const n:string):TAsmObjectData;
  528. begin
  529. result:=TAsmObjectData.create(n);
  530. end;
  531. function tobjectinput.readobjectfile(const fn:string;data:TAsmObjectData):boolean;
  532. begin
  533. result:=false;
  534. { start the reader }
  535. if FReader.openfile(fn) then
  536. begin
  537. result:=readobjectdata(data);
  538. FReader.closefile;
  539. end;
  540. end;
  541. function tobjectinput.str2sec(const s:string):TSection;
  542. var
  543. t : TSection;
  544. begin
  545. for t:=low(TSection) to high(TSection) do
  546. begin
  547. if (s=target_asm.secnames[t]) then
  548. begin
  549. str2sec:=t;
  550. exit;
  551. end;
  552. end;
  553. str2sec:=sec_none;
  554. end;
  555. end.
  556. {
  557. $Log$
  558. Revision 1.12 2002-07-01 18:46:24 peter
  559. * internal linker
  560. * reorganized aasm layer
  561. Revision 1.11 2002/05/18 13:34:10 peter
  562. * readded missing revisions
  563. Revision 1.9 2002/05/14 19:34:43 peter
  564. * removed old logs and updated copyright year
  565. }