ogbase.pas 18 KB

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