ogbase.pas 17 KB

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