ogbase.pas 18 KB

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