og386cff.pas 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044
  1. {
  2. $Id$
  3. Copyright (c) 1998-2000 by Peter Vreman and Pierre Muller
  4. Contains the 386 binary coff writer
  5. * This code was inspired by the NASM sources
  6. The Netwide Assembler is copyright (C) 1996 Simon Tatham and
  7. Julian Hall. All rights reserved.
  8. This program is free software; you can redistribute it and/or modify
  9. it under the terms of the GNU General Public License as published by
  10. the Free Software Foundation; either version 2 of the License, or
  11. (at your option) any later version.
  12. This program is distributed in the hope that it will be useful,
  13. but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. GNU General Public License for more details.
  16. You should have received a copy of the GNU General Public License
  17. along with this program; if not, write to the Free Software
  18. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  19. ****************************************************************************
  20. }
  21. unit og386cff;
  22. {
  23. Notes on COFF:
  24. (0) When I say `standard COFF' below, I mean `COFF as output and
  25. used by DJGPP'. I assume DJGPP gets it right.
  26. (1) Win32 appears to interpret the term `relative relocation'
  27. differently from standard COFF. Standard COFF understands a
  28. relative relocation to mean that during relocation you add the
  29. address of the symbol you're referencing, and subtract the base
  30. address of the section you're in. Win32 COFF, by contrast, seems
  31. to add the address of the symbol and then subtract the address
  32. of THE BYTE AFTER THE RELOCATED DWORD. Hence the two formats are
  33. subtly incompatible.
  34. (2) Win32 doesn't bother putting any flags in the header flags
  35. field (at offset 0x12 into the file).
  36. (3) Win32 uses some extra flags into the section header table:
  37. it defines flags 0x80000000 (writable), 0x40000000 (readable)
  38. and 0x20000000 (executable), and uses them in the expected
  39. combinations. It also defines 0x00100000 through 0x00700000 for
  40. section alignments of 1 through 64 bytes.
  41. (4) Both standard COFF and Win32 COFF seem to use the DWORD
  42. field directly after the section name in the section header
  43. table for something strange: they store what the address of the
  44. section start point _would_ be, if you laid all the sections end
  45. to end starting at zero. Dunno why. Microsoft's documentation
  46. lists this field as "Virtual Size of Section", which doesn't
  47. seem to fit at all. In fact, Win32 even includes non-linked
  48. sections such as .drectve in this calculation.
  49. (5) Standard COFF does something very strange to common
  50. variables: the relocation point for a common variable is as far
  51. _before_ the variable as its size stretches out _after_ it. So
  52. we must fix up common variable references. Win32 seems to be
  53. sensible on this one.
  54. }
  55. interface
  56. uses
  57. cobjects,
  58. systems,cpubase,aasm,og386;
  59. type
  60. preloc = ^treloc;
  61. treloc = packed record
  62. next : preloc;
  63. address : longint;
  64. symbol : pasmsymbol;
  65. section : tsection; { only used if symbol=nil }
  66. relative : relative_type;
  67. end;
  68. psymbol = ^tsymbol;
  69. tsymbol = packed record
  70. name : string[8];
  71. strpos : longint;
  72. section : tsection;
  73. value : longint;
  74. typ : TAsmsymtype;
  75. end;
  76. pcoffsection = ^tcoffsection;
  77. tcoffsection = object
  78. index : tsection;
  79. secidx : longint;
  80. data : PDynamicArray;
  81. size,
  82. fillsize,
  83. mempos,
  84. len,
  85. datapos,
  86. relocpos,
  87. nrelocs,
  88. align,
  89. flags : longint;
  90. relochead : PReloc;
  91. reloctail : ^PReloc;
  92. constructor init(sec:TSection;Aflags:longint);
  93. destructor done;
  94. procedure write(var d;l:longint);
  95. procedure alloc(l:longint);
  96. procedure addsymreloc(ofs:longint;p:pasmsymbol;relative:relative_type);
  97. procedure addsectionreloc(ofs:longint;sec:tsection;relative:relative_type);
  98. end;
  99. pgenericcoffoutput = ^tgenericcoffoutput;
  100. tgenericcoffoutput = object(tobjectoutput)
  101. win32 : boolean;
  102. sects : array[TSection] of PCoffSection;
  103. strs,
  104. syms : Pdynamicarray;
  105. initsym : longint;
  106. constructor init(smart:boolean);
  107. destructor done;virtual;
  108. procedure initwriting(Aplace:tcutplace);virtual;
  109. procedure donewriting;virtual;
  110. procedure setsectionsizes(var s:tsecsize);virtual;
  111. procedure writebytes(var data;len:longint);virtual;
  112. procedure writealloc(len:longint);virtual;
  113. procedure writealign(len:longint);virtual;
  114. procedure writereloc(data,len:longint;p:pasmsymbol;relative:relative_type);virtual;
  115. procedure writesymbol(p:pasmsymbol);virtual;
  116. procedure writestabs(section:tsection;offset:longint;p:pchar;nidx,nother,line:longint;reloc:boolean);virtual;
  117. procedure writesymstabs(section:tsection;offset:longint;p:pchar;ps:pasmsymbol;
  118. nidx,nother,line:longint;reloc:boolean);virtual;
  119. function text_flags : longint;virtual;
  120. function data_flags : longint;virtual;
  121. function bss_flags : longint;virtual;
  122. function idata_flags : longint;virtual;
  123. function edata_flags : longint;virtual;
  124. private
  125. procedure createsection(sec:tsection);
  126. procedure write_relocs(s:pcoffsection);
  127. procedure write_symbol(const name:string;strpos,value,section,typ,aux:longint);
  128. procedure write_symbols;
  129. procedure writetodisk;
  130. end;
  131. pdjgppcoffoutput = ^tdjgppcoffoutput;
  132. tdjgppcoffoutput = object(tgenericcoffoutput)
  133. constructor init(smart:boolean);
  134. function text_flags : longint;virtual;
  135. function data_flags : longint;virtual;
  136. function bss_flags : longint;virtual;
  137. end;
  138. pwin32coffoutput = ^twin32coffoutput;
  139. twin32coffoutput = object(tgenericcoffoutput)
  140. constructor init(smart:boolean);
  141. function text_flags : longint;virtual;
  142. function data_flags : longint;virtual;
  143. function bss_flags : longint;virtual;
  144. function idata_flags : longint;virtual;
  145. function edata_flags : longint;virtual;
  146. end;
  147. implementation
  148. uses
  149. strings,verbose,
  150. globtype,globals,files;
  151. type
  152. { Structures which are written directly to the output file }
  153. coffheader=packed record
  154. mach : word;
  155. nsects : word;
  156. time : longint;
  157. sympos : longint;
  158. syms : longint;
  159. opthdr : word;
  160. flag : word;
  161. end;
  162. coffsechdr=packed record
  163. name : array[0..7] of char;
  164. vsize : longint;
  165. rvaofs : longint;
  166. datalen : longint;
  167. datapos : longint;
  168. relocpos : longint;
  169. lineno1 : longint;
  170. nrelocs : word;
  171. lineno2 : word;
  172. flags : longint;
  173. end;
  174. coffsectionrec=packed record
  175. len : longint;
  176. nrelocs : word;
  177. empty : array[0..11] of char;
  178. end;
  179. coffreloc=packed record
  180. address : longint;
  181. sym : longint;
  182. relative : word;
  183. end;
  184. coffsymbol=packed record
  185. name : array[0..3] of char; { real is [0..7], which overlaps the strpos ! }
  186. strpos : longint;
  187. value : longint;
  188. section : integer;
  189. empty : integer;
  190. typ : byte;
  191. aux : byte;
  192. end;
  193. pcoffstab=^coffstab;
  194. coffstab=packed record
  195. strpos : longint;
  196. ntype : byte;
  197. nother : byte;
  198. ndesc : word;
  199. nvalue : longint;
  200. end;
  201. {****************************************************************************
  202. TSection
  203. ****************************************************************************}
  204. constructor tcoffsection.init(sec:TSection;Aflags:longint);
  205. begin
  206. index:=sec;
  207. secidx:=0;
  208. flags:=AFlags;
  209. { alignment after section }
  210. case sec of
  211. sec_code,
  212. sec_data,
  213. sec_bss :
  214. align:=4;
  215. else
  216. align:=1;
  217. end;
  218. { filled after pass 1 }
  219. size:=0;
  220. fillsize:=0;
  221. mempos:=0;
  222. { pass 2 data }
  223. relocHead:=nil;
  224. relocTail:=@relocHead;
  225. Len:=0;
  226. NRelocs:=0;
  227. if sec=sec_bss then
  228. data:=nil
  229. else
  230. new(Data,Init(1,8192));
  231. end;
  232. destructor tcoffsection.done;
  233. begin
  234. if assigned(Data) then
  235. dispose(Data,done);
  236. end;
  237. procedure tcoffsection.write(var d;l:longint);
  238. begin
  239. if not assigned(Data) then
  240. Internalerror(3334441);
  241. Data^.write(d,l);
  242. inc(len,l);
  243. end;
  244. procedure tcoffsection.alloc(l:longint);
  245. begin
  246. if assigned(Data) then
  247. Internalerror(3334442);
  248. inc(len,l);
  249. end;
  250. procedure tcoffsection.addsymreloc(ofs:longint;p:pasmsymbol;relative:relative_type);
  251. var
  252. r : PReloc;
  253. begin
  254. new(r);
  255. reloctail^:=r;
  256. reloctail:=@r^.next;
  257. r^.next:=nil;
  258. r^.address:=ofs+mempos;
  259. r^.symbol:=p;
  260. r^.section:=sec_none;
  261. r^.relative:=relative;
  262. inc(nrelocs);
  263. end;
  264. procedure tcoffsection.addsectionreloc(ofs:longint;sec:tsection;relative:relative_type);
  265. var
  266. r : PReloc;
  267. begin
  268. new(r);
  269. reloctail^:=r;
  270. reloctail:=@r^.next;
  271. r^.next:=nil;
  272. r^.address:=ofs+mempos;
  273. r^.symbol:=nil;
  274. r^.section:=sec;
  275. r^.relative:=relative;
  276. inc(nrelocs);
  277. end;
  278. {****************************************************************************
  279. Genericcoffoutput
  280. ****************************************************************************}
  281. const
  282. {$ifdef TP}
  283. symbolresize = 50;
  284. strsresize = 200;
  285. {$else}
  286. symbolresize = 200;
  287. strsresize = 8192;
  288. {$endif}
  289. constructor tgenericcoffoutput.init(smart:boolean);
  290. begin
  291. inherited init(smart);
  292. end;
  293. destructor tgenericcoffoutput.done;
  294. begin
  295. inherited done;
  296. end;
  297. procedure tgenericcoffoutput.initwriting(Aplace:tcutplace);
  298. var
  299. s : string;
  300. begin
  301. inherited initwriting(Aplace);
  302. { reset }
  303. initsym:=0;
  304. new(syms,init(sizeof(TSymbol),symbolresize));
  305. new(strs,init(1,strsresize));
  306. FillChar(Sects,sizeof(Sects),0);
  307. { we need at least the following 3 sections }
  308. createsection(sec_code);
  309. createsection(sec_data);
  310. createsection(sec_bss);
  311. if (cs_debuginfo in aktmoduleswitches) then
  312. begin
  313. createsection(sec_stab);
  314. createsection(sec_stabstr);
  315. writestabs(sec_none,0,nil,0,0,0,false);
  316. { write zero pchar and name together (PM) }
  317. s:=#0+SplitFileName(current_module^.mainsource^)+#0;
  318. sects[sec_stabstr]^.write(s[1],length(s));
  319. end;
  320. end;
  321. procedure tgenericcoffoutput.donewriting;
  322. var
  323. sec : tsection;
  324. begin
  325. { Only write the .o if there are no errors }
  326. if errorcount=0 then
  327. writetodisk;
  328. dispose(syms,done);
  329. dispose(strs,done);
  330. for sec:=low(tsection) to high(tsection) do
  331. if assigned(sects[sec]) then
  332. dispose(sects[sec],done);
  333. inherited donewriting;
  334. end;
  335. function tgenericcoffoutput.text_flags : longint;
  336. begin
  337. text_flags:=0;
  338. end;
  339. function tgenericcoffoutput.data_flags : longint;
  340. begin
  341. data_flags:=0;
  342. end;
  343. function tgenericcoffoutput.bss_flags : longint;
  344. begin
  345. bss_flags:=0;
  346. end;
  347. function tgenericcoffoutput.edata_flags : longint;
  348. begin
  349. edata_flags:=0;
  350. end;
  351. function tgenericcoffoutput.idata_flags : longint;
  352. begin
  353. idata_flags:=0;
  354. end;
  355. procedure tgenericcoffoutput.createsection(sec:TSection);
  356. var
  357. Aflags : longint;
  358. begin
  359. Aflags:=0;
  360. case sec of
  361. sec_code :
  362. Aflags:=text_flags;
  363. sec_data :
  364. Aflags:=data_flags;
  365. sec_bss :
  366. Aflags:=bss_flags;
  367. sec_idata2,
  368. sec_idata4,
  369. sec_idata5,
  370. sec_idata6,
  371. sec_idata7 :
  372. Aflags:=idata_flags;
  373. sec_edata :
  374. Aflags:=edata_flags;
  375. else
  376. Aflags:=0;
  377. end;
  378. sects[sec]:=new(PcoffSection,init(Sec,Aflags));
  379. end;
  380. procedure tgenericcoffoutput.writesymbol(p:pasmsymbol);
  381. var
  382. pos : longint;
  383. sym : tsymbol;
  384. s : string;
  385. begin
  386. { already written ? }
  387. if p^.idx<>-1 then
  388. exit;
  389. { be sure that the section will exists }
  390. if (p^.section<>sec_none) and not(assigned(sects[p^.section])) then
  391. createsection(p^.section);
  392. { symbolname }
  393. pos:=strs^.usedsize+4;
  394. s:=p^.name;
  395. if length(s)>8 then
  396. begin
  397. s:=s+#0;
  398. strs^.write(s[1],length(s));
  399. end
  400. else
  401. pos:=-1;
  402. FillChar(sym,sizeof(sym),0);
  403. sym.strpos:=pos;
  404. if pos=-1 then
  405. sym.name:=s;
  406. sym.value:=p^.size;
  407. sym.typ:=p^.typ;
  408. { if local of global then set the section value to the address
  409. of the symbol }
  410. if p^.typ in [AS_LOCAL,AS_GLOBAL] then
  411. begin
  412. sym.section:=p^.section;
  413. sym.value:=p^.address+sects[p^.section]^.mempos;
  414. end;
  415. { update the asmsymbol index }
  416. p^.idx:=syms^.count;
  417. { store the symbol, but not the local ones (PM) }
  418. if (p^.typ<>AS_LOCAL) or ((copy(s,1,2)<>'.L') and
  419. ((copy(s,1,1)<>'L') or not win32)) then
  420. syms^.write(sym,1);
  421. { make the exported syms known to the objectwriter
  422. (needed for .a generation) }
  423. if (p^.typ=AS_GLOBAL) or
  424. ((p^.typ=AS_EXTERNAL) and (sym.value=p^.size) and (sym.value>0)) then
  425. writer^.writesym(p^.name);
  426. end;
  427. procedure tgenericcoffoutput.writebytes(var data;len:longint);
  428. begin
  429. if not assigned(sects[currsec]) then
  430. createsection(currsec);
  431. sects[currsec]^.write(data,len);
  432. end;
  433. procedure tgenericcoffoutput.writealloc(len:longint);
  434. begin
  435. if not assigned(sects[currsec]) then
  436. createsection(currsec);
  437. sects[currsec]^.alloc(len);
  438. end;
  439. procedure tgenericcoffoutput.writealign(len:longint);
  440. var modulo : longint;
  441. begin
  442. if not assigned(sects[currsec]) then
  443. createsection(currsec);
  444. modulo:=sects[currsec]^.len mod len;
  445. if modulo > 0 then
  446. sects[currsec]^.alloc(len-modulo);
  447. end;
  448. procedure tgenericcoffoutput.writereloc(data,len:longint;p:pasmsymbol;relative:relative_type);
  449. var
  450. symaddr : longint;
  451. begin
  452. if not assigned(sects[currsec]) then
  453. createsection(currsec);
  454. if assigned(p) then
  455. begin
  456. { real address of the symbol }
  457. symaddr:=p^.address;
  458. if p^.section<>sec_none then
  459. inc(symaddr,sects[p^.section]^.mempos);
  460. { no symbol relocation need inside a section }
  461. if p^.section=currsec then
  462. begin
  463. case relative of
  464. relative_false :
  465. begin
  466. sects[currsec]^.addsectionreloc(sects[currsec]^.len,currsec,relative_false);
  467. inc(data,symaddr);
  468. end;
  469. relative_true :
  470. begin
  471. inc(data,symaddr-len-sects[currsec]^.len);
  472. end;
  473. relative_rva :
  474. begin
  475. { don't know if this can happens !! }
  476. { does this work ?? }
  477. sects[currsec]^.addsectionreloc(sects[currsec]^.len,currsec,relative_rva);
  478. inc(data,symaddr);
  479. end;
  480. end;
  481. end
  482. else
  483. begin
  484. writesymbol(p);
  485. if (p^.section<>sec_none) and (relative<>relative_true) then
  486. sects[currsec]^.addsectionreloc(sects[currsec]^.len,p^.section,relative)
  487. else
  488. sects[currsec]^.addsymreloc(sects[currsec]^.len,p,relative);
  489. if not win32 then {seems wrong to me (PM) }
  490. inc(data,symaddr)
  491. else
  492. if (relative<>relative_true) and (p^.section<>sec_none) then
  493. inc(data,symaddr);
  494. if relative=relative_true then
  495. begin
  496. if win32 then
  497. dec(data,len-4)
  498. else
  499. dec(data,len+sects[currsec]^.len);
  500. end;
  501. end;
  502. end;
  503. sects[currsec]^.write(data,len);
  504. end;
  505. procedure tgenericcoffoutput.writestabs(section:tsection;offset:longint;p:pchar;nidx,nother,line:longint;reloc : boolean);
  506. var
  507. stab : coffstab;
  508. s : tsection;
  509. begin
  510. { This is wrong because
  511. sec_none is used only for external bss
  512. if section=sec_none then
  513. s:=currsec
  514. else }
  515. s:=section;
  516. { local var can be at offset -1 !! PM }
  517. if reloc then
  518. begin
  519. if (offset=-1) then
  520. begin
  521. if s=sec_none then
  522. offset:=0
  523. else
  524. offset:=sects[s]^.len;
  525. end;
  526. if (s<>sec_none) then
  527. inc(offset,sects[s]^.mempos);
  528. end;
  529. fillchar(stab,sizeof(coffstab),0);
  530. if assigned(p) and (p[0]<>#0) then
  531. begin
  532. stab.strpos:=sects[sec_stabstr]^.len;
  533. sects[sec_stabstr]^.write(p^,strlen(p)+1);
  534. end;
  535. stab.ntype:=nidx;
  536. stab.ndesc:=line;
  537. stab.nother:=nother;
  538. stab.nvalue:=offset;
  539. sects[sec_stab]^.write(stab,sizeof(stab));
  540. { when the offset is not 0 then write a relocation, take also the
  541. hdrstab into account with the offset }
  542. if reloc then
  543. if DLLSource and RelocSection then
  544. { avoid relocation in the .stab section
  545. because it ends up in the .reloc section instead }
  546. sects[sec_stab]^.addsectionreloc(sects[sec_stab]^.len-4,s,relative_rva)
  547. else
  548. sects[sec_stab]^.addsectionreloc(sects[sec_stab]^.len-4,s,relative_false);
  549. end;
  550. procedure tgenericcoffoutput.writesymstabs(section:tsection;offset:longint;p:pchar;ps:pasmsymbol;
  551. nidx,nother,line:longint;reloc:boolean);
  552. var
  553. stab : coffstab;
  554. s : tsection;
  555. begin
  556. { This is wrong because
  557. sec_none is used only for external bss
  558. if section=sec_none then
  559. s:=currsec
  560. else }
  561. s:=section;
  562. { do not use the size stored in offset field
  563. this is DJGPP specific ! PM }
  564. if win32 then
  565. offset:=0;
  566. { local var can be at offset -1 !! PM }
  567. if reloc then
  568. begin
  569. if (offset=-1) then
  570. begin
  571. if s=sec_none then
  572. offset:=0
  573. else
  574. offset:=sects[s]^.len;
  575. end;
  576. if (s<>sec_none) then
  577. inc(offset,sects[s]^.mempos);
  578. end;
  579. fillchar(stab,sizeof(coffstab),0);
  580. if assigned(p) and (p[0]<>#0) then
  581. begin
  582. stab.strpos:=sects[sec_stabstr]^.len;
  583. sects[sec_stabstr]^.write(p^,strlen(p)+1);
  584. end;
  585. stab.ntype:=nidx;
  586. stab.ndesc:=line;
  587. stab.nother:=nother;
  588. stab.nvalue:=offset;
  589. sects[sec_stab]^.write(stab,sizeof(stab));
  590. { when the offset is not 0 then write a relocation, take also the
  591. hdrstab into account with the offset }
  592. if reloc then
  593. if DLLSource and RelocSection then
  594. { avoid relocation in the .stab section
  595. because it ends up in the .reloc section instead }
  596. sects[sec_stab]^.addsymreloc(sects[sec_stab]^.len-4,ps,relative_rva)
  597. else
  598. sects[sec_stab]^.addsymreloc(sects[sec_stab]^.len-4,ps,relative_false);
  599. end;
  600. procedure tgenericcoffoutput.write_relocs(s:pcoffsection);
  601. var
  602. rel : coffreloc;
  603. hr,r : preloc;
  604. begin
  605. r:=s^.relochead;
  606. while assigned(r) do
  607. begin
  608. rel.address:=r^.address;
  609. if assigned(r^.symbol) then
  610. begin
  611. if (r^.symbol^.typ=AS_LOCAL) then
  612. rel.sym:=2*sects[r^.symbol^.section]^.secidx
  613. else
  614. begin
  615. if r^.symbol^.idx=-1 then
  616. internalerror(4321);
  617. rel.sym:=r^.symbol^.idx+initsym;
  618. end;
  619. end
  620. else if r^.section<>sec_none then
  621. rel.sym:=2*sects[r^.section]^.secidx
  622. else
  623. rel.sym:=0;
  624. case r^.relative of
  625. relative_true : rel.relative:=$14;
  626. relative_false : rel.relative:=$6;
  627. relative_rva : rel.relative:=$7;
  628. end;
  629. writer^.write(rel,sizeof(rel));
  630. { goto next and dispose this reloc }
  631. hr:=r;
  632. r:=r^.next;
  633. dispose(hr);
  634. end;
  635. end;
  636. procedure tgenericcoffoutput.write_symbol(const name:string;strpos,value,section,typ,aux:longint);
  637. var
  638. sym : coffsymbol;
  639. begin
  640. FillChar(sym,sizeof(sym),0);
  641. if strpos=-1 then
  642. move(name[1],sym.name,length(name))
  643. else
  644. sym.strpos:=strpos;
  645. sym.value:=value;
  646. sym.section:=section;
  647. sym.typ:=typ;
  648. sym.aux:=aux;
  649. writer^.write(sym,sizeof(sym));
  650. end;
  651. procedure tgenericcoffoutput.write_symbols;
  652. var
  653. filename : string[18];
  654. sec : tsection;
  655. sectionval,
  656. i : longint;
  657. globalval : byte;
  658. secrec : coffsectionrec;
  659. sym : tsymbol;
  660. begin
  661. { The `.file' record, and the file name auxiliary record. }
  662. write_symbol ('.file', -1, 0, -2, $67, 1);
  663. fillchar(filename,sizeof(filename),0);
  664. filename:=SplitFileName(current_module^.mainsource^);
  665. writer^.write(filename[1],sizeof(filename)-1);
  666. { The section records, with their auxiliaries, also store the
  667. symbol index }
  668. for sec:=low(tsection) to high(tsection) do
  669. if assigned(sects[sec]) then
  670. begin
  671. write_symbol(target_asm.secnames[sec],-1,sects[sec]^.mempos,sects[sec]^.secidx,3,1);
  672. fillchar(secrec,sizeof(secrec),0);
  673. secrec.len:=sects[sec]^.len;
  674. secrec.nrelocs:=sects[sec]^.nrelocs;
  675. writer^.write(secrec,sizeof(secrec));
  676. end;
  677. { The real symbols. }
  678. syms^.seek(0);
  679. for i:=1 to syms^.count do
  680. begin
  681. syms^.read(sym,1);
  682. if sym.typ=AS_LOCAL then
  683. globalval:=3
  684. else
  685. globalval:=2;
  686. if assigned(sects[sym.section]) then
  687. sectionval:=sects[sym.section]^.secidx
  688. else
  689. sectionval:=0;
  690. write_symbol(sym.name,sym.strpos,sym.value,sectionval,globalval,0);
  691. end;
  692. end;
  693. procedure tgenericcoffoutput.setsectionsizes(var s:tsecsize);
  694. var
  695. align,
  696. mempos : longint;
  697. sec : tsection;
  698. begin
  699. { multiply stab with real size }
  700. s[sec_stab]:=s[sec_stab]*sizeof(coffstab);
  701. { if debug then also count header stab }
  702. if (cs_debuginfo in aktmoduleswitches) then
  703. begin
  704. inc(s[sec_stab],sizeof(coffstab));
  705. inc(s[sec_stabstr],length(SplitFileName(current_module^.mainsource^))+2);
  706. end;
  707. { fix all section }
  708. mempos:=0;
  709. for sec:=low(tsection) to high(tsection) do
  710. begin
  711. if (s[sec]>0) and (not assigned(sects[sec])) then
  712. createsection(sec);
  713. if assigned(sects[sec]) then
  714. begin
  715. sects[sec]^.size:=s[sec];
  716. sects[sec]^.mempos:=mempos;
  717. { calculate the alignment }
  718. align:=sects[sec]^.align;
  719. sects[sec]^.fillsize:=align-(sects[sec]^.size and (align-1));
  720. if sects[sec]^.fillsize=align then
  721. sects[sec]^.fillsize:=0;
  722. { next section position, not for win32 which uses
  723. relative addresses }
  724. if not win32 then
  725. inc(mempos,sects[sec]^.size+sects[sec]^.fillsize);
  726. end;
  727. end;
  728. end;
  729. procedure tgenericcoffoutput.writetodisk;
  730. var
  731. datapos,secidx,
  732. nsects,sympos,i : longint;
  733. gotreloc : boolean;
  734. sec : tsection;
  735. header : coffheader;
  736. sechdr : coffsechdr;
  737. empty : array[0..15] of byte;
  738. begin
  739. { calc amount of sections we have and align sections at 4 bytes }
  740. fillchar(empty,sizeof(empty),0);
  741. nsects:=0;
  742. for sec:=low(tsection) to high(tsection) do
  743. if assigned(sects[sec]) then
  744. begin
  745. {$ifdef EXTDEBUG}
  746. { check if the section is still the same size }
  747. if (sects[sec]^.len<>sects[sec]^.size) then
  748. Comment(V_Warning,'Size of section changed '+
  749. tostr(sects[sec]^.size)+'->'+tostr(sects[sec]^.len)+
  750. ' ['+target_asm.secnames[sec]+']');
  751. {$endif EXTDEBUG}
  752. { fill with zero }
  753. if sects[sec]^.fillsize>0 then
  754. begin
  755. if assigned(sects[sec]^.data) then
  756. sects[sec]^.write(empty,sects[sec]^.fillsize)
  757. else
  758. sects[sec]^.alloc(sects[sec]^.fillsize);
  759. end;
  760. inc(nsects);
  761. end;
  762. { Calculate the filepositions }
  763. datapos:=sizeof(coffheader)+sizeof(coffsechdr)*nsects;
  764. initsym:=2; { 2 for the file }
  765. { sections first }
  766. secidx:=0;
  767. for sec:=low(tsection) to high(tsection) do
  768. if assigned(sects[sec]) then
  769. begin
  770. inc(secidx);
  771. sects[sec]^.secidx:=secidx;
  772. sects[sec]^.datapos:=datapos;
  773. if assigned(sects[sec]^.data) then
  774. inc(datapos,sects[sec]^.len);
  775. inc(initsym,2); { 2 for each section }
  776. end;
  777. { relocs }
  778. gotreloc:=false;
  779. for sec:=low(tsection) to high(tsection) do
  780. if assigned(sects[sec]) then
  781. begin
  782. sects[sec]^.relocpos:=datapos;
  783. inc(datapos,10*sects[sec]^.nrelocs);
  784. if (not gotreloc) and (sects[sec]^.nrelocs>0) then
  785. gotreloc:=true;
  786. end;
  787. { symbols }
  788. sympos:=datapos;
  789. { COFF header }
  790. fillchar(header,sizeof(coffheader),0);
  791. header.mach:=$14c;
  792. header.nsects:=nsects;
  793. header.sympos:=sympos;
  794. header.syms:=syms^.count+initsym;
  795. if gotreloc then
  796. header.flag:=$104
  797. else
  798. header.flag:=$105;
  799. writer^.write(header,sizeof(header));
  800. { Section headers }
  801. for sec:=low(tsection) to high(tsection) do
  802. if assigned(sects[sec]) then
  803. begin
  804. fillchar(sechdr,sizeof(sechdr),0);
  805. move(target_asm.secnames[sec][1],sechdr.name,length(target_asm.secnames[sec]));
  806. if not win32 then
  807. begin
  808. sechdr.rvaofs:=sects[sec]^.mempos;
  809. sechdr.vsize:=sects[sec]^.mempos;
  810. end
  811. else
  812. begin
  813. if sec=sec_bss then
  814. sechdr.vsize:=sects[sec]^.len;
  815. end;
  816. sechdr.datalen:=sects[sec]^.len;
  817. if (sects[sec]^.len>0) and assigned(sects[sec]^.data) then
  818. sechdr.datapos:=sects[sec]^.datapos;
  819. sechdr.relocpos:=sects[sec]^.relocpos;
  820. sechdr.nrelocs:=sects[sec]^.nrelocs;
  821. sechdr.flags:=sects[sec]^.flags;
  822. writer^.write(sechdr,sizeof(sechdr));
  823. end;
  824. { Sections }
  825. for sec:=low(tsection) to high(tsection) do
  826. if assigned(sects[sec]) and
  827. assigned(sects[sec]^.data) then
  828. begin
  829. { For the stab section we need an HdrSym which can now be
  830. calculated more easily }
  831. if sec=sec_stab then
  832. begin
  833. pcoffstab(sects[sec_stab]^.data^.data)^.nvalue:=sects[sec_stabstr]^.len;
  834. pcoffstab(sects[sec_stab]^.data^.data)^.strpos:=1;
  835. pcoffstab(sects[sec_stab]^.data^.data)^.ndesc:=
  836. (sects[sec_stab]^.len div sizeof(coffstab))-1{+1 according to gas output PM};
  837. end;
  838. writer^.write(sects[sec]^.data^.data^,sects[sec]^.data^.usedsize);
  839. end;
  840. { Relocs }
  841. for sec:=low(tsection) to high(tsection) do
  842. if assigned(sects[sec]) then
  843. write_relocs(sects[sec]);
  844. { Symbols }
  845. write_symbols;
  846. { Strings }
  847. i:=strs^.usedsize+4;
  848. writer^.write(i,4);
  849. writer^.write(strs^.data^,strs^.usedsize);
  850. end;
  851. {****************************************************************************
  852. DJGppcoffoutput
  853. ****************************************************************************}
  854. constructor tdjgppcoffoutput.init(smart:boolean);
  855. begin
  856. inherited init(smart);
  857. win32:=false;
  858. end;
  859. function tdjgppcoffoutput.text_flags : longint;
  860. begin
  861. text_flags:=$20;
  862. end;
  863. function tdjgppcoffoutput.data_flags : longint;
  864. begin
  865. data_flags:=$40;
  866. end;
  867. function tdjgppcoffoutput.bss_flags : longint;
  868. begin
  869. bss_flags:=$80;
  870. end;
  871. {****************************************************************************
  872. Win32coffoutput
  873. ****************************************************************************}
  874. constructor twin32coffoutput.init(smart:boolean);
  875. begin
  876. inherited init(smart);
  877. win32:=true;
  878. end;
  879. function twin32coffoutput.text_flags : longint;
  880. begin
  881. text_flags:=$60000020; { same as as 2.9.1 }
  882. end;
  883. function twin32coffoutput.data_flags : longint;
  884. begin
  885. data_flags:=$c0300040;
  886. end;
  887. function twin32coffoutput.bss_flags : longint;
  888. begin
  889. bss_flags:=$c0300080;
  890. end;
  891. function twin32coffoutput.edata_flags : longint;
  892. begin
  893. edata_flags:=$c0300040;
  894. end;
  895. function twin32coffoutput.idata_flags : longint;
  896. begin
  897. idata_flags:=$40000000;
  898. end;
  899. end.
  900. {
  901. $Log$
  902. Revision 1.22 2000-03-10 16:05:28 pierre
  903. * check that symbol is in object
  904. Revision 1.21 2000/03/10 09:15:54 pierre
  905. * rva relocation bug fixed
  906. Revision 1.20 2000/03/09 14:29:47 pierre
  907. * fix for the stab section size changes with smartlinking
  908. Revision 1.19 2000/02/09 13:22:54 peter
  909. * log truncated
  910. Revision 1.18 2000/01/12 10:38:18 peter
  911. * smartlinking fixes for binary writer
  912. * release alignreg code and moved instruction writing align to cpuasm,
  913. but it doesn't use the specified register yet
  914. Revision 1.17 2000/01/07 01:14:27 peter
  915. * updated copyright to 2000
  916. Revision 1.16 1999/12/20 22:29:26 pierre
  917. * relocation with debug info in rva (only with internal compiler)
  918. Revision 1.15 1999/11/30 10:40:43 peter
  919. + ttype, tsymlist
  920. Revision 1.14 1999/11/06 14:34:21 peter
  921. * truncated log to 20 revs
  922. Revision 1.13 1999/11/02 15:06:57 peter
  923. * import library fixes for win32
  924. * alignment works again
  925. Revision 1.12 1999/08/16 15:35:25 pierre
  926. * fix for DLL relocation problems
  927. * external bss vars had wrong stabs for pecoff
  928. + -WB11000000 to specify default image base, allows to
  929. load several DLLs with debugging info included
  930. (relocatable DLL are stripped because the relocation
  931. of the .Stab section is misplaced by ldw)
  932. Revision 1.11 1999/08/11 17:17:38 peter
  933. * fixed rva writting for section relocs
  934. * fixed section flags for edata and idata
  935. Revision 1.10 1999/08/04 00:23:05 florian
  936. * renamed i386asm and i386base to cpuasm and cpubase
  937. }