ogelf.pas 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907
  1. {
  2. Copyright (c) 1998-2002 by Peter Vreman
  3. Contains the binary elf writer
  4. * This code was inspired by the NASM sources
  5. The Netwide Assembler is Copyright (c) 1996 Simon Tatham and
  6. Julian Hall. All rights reserved.
  7. This program is free software; you can redistribute it and/or modify
  8. it under the terms of the GNU General Public License as published by
  9. the Free Software Foundation; either version 2 of the License, or
  10. (at your option) any later version.
  11. This program is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. GNU General Public License for more details.
  15. You should have received a copy of the GNU General Public License
  16. along with this program; if not, write to the Free Software
  17. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  18. ****************************************************************************
  19. }
  20. unit ogelf;
  21. {$i fpcdefs.inc}
  22. interface
  23. uses
  24. { common }
  25. cclasses,globtype,
  26. { target }
  27. systems,
  28. { assembler }
  29. cpuinfo,cpubase,aasmbase,aasmtai,assemble,
  30. { output }
  31. ogbase;
  32. type
  33. telf32section = class(TAsmSection)
  34. public
  35. secshidx : longint; { index for the section in symtab }
  36. shstridx,
  37. shtype,
  38. shflags,
  39. shlink,
  40. shinfo,
  41. entsize : longint;
  42. { relocation }
  43. relocsect : telf32Section;
  44. constructor create(const Aname:string;Atype:TAsmSectionType;Aalign:longint;Aoptions:TAsmSectionOptions);override;
  45. constructor create_ext(const Aname:string;Atype:TAsmSectionType;Ashtype,Ashflags,Ashlink,Ashinfo,Aalign,Aentsize:longint);
  46. destructor destroy;override;
  47. end;
  48. telf32objectdata = class(TAsmObjectData)
  49. public
  50. symtabsect,
  51. strtabsect,
  52. shstrtabsect,
  53. gotpcsect,
  54. gotoffsect,
  55. goTSect,
  56. plTSect,
  57. symsect : telf32Section;
  58. syms : Tdynamicarray;
  59. constructor create(const n:string);
  60. destructor destroy;override;
  61. function sectionname(atype:tasmsectiontype;const aname:string):string;override;
  62. procedure writereloc(data,len:aint;p:tasmsymbol;relative:TAsmRelocationType);override;
  63. procedure writesymbol(p:tasmsymbol);override;
  64. procedure writestabs(offset:aint;p:pchar;nidx,nother,line:longint;reloc:boolean);override;
  65. procedure writesymstabs(offset:aint;p:pchar;ps:tasmsymbol;nidx,nother,line:longint;reloc:boolean);override;
  66. procedure beforealloc;override;
  67. procedure beforewrite;override;
  68. end;
  69. telf32objectoutput = class(tobjectoutput)
  70. private
  71. elf32data : telf32objectdata;
  72. initsym : longint;
  73. procedure createrelocsection(s:telf32section);
  74. procedure createshstrtab;
  75. procedure createsymtab;
  76. procedure writesectionheader(s:telf32section);
  77. procedure writesectiondata(s:telf32section);
  78. procedure section_write_symbol(p:tnamedindexitem;arg:pointer);
  79. procedure section_write_sh_string(p:tnamedindexitem;arg:pointer);
  80. procedure section_number_symbol(p:tnamedindexitem;arg:pointer);
  81. procedure section_count_sects(p:tnamedindexitem;arg:pointer);
  82. procedure section_create_relocsec(p:tnamedindexitem;arg:pointer);
  83. procedure section_set_datapos(p:tnamedindexitem;arg:pointer);
  84. procedure section_relocsec_set_datapos(p:tnamedindexitem;arg:pointer);
  85. procedure section_write_data(p:tnamedindexitem;arg:pointer);
  86. procedure section_write_sechdr(p:tnamedindexitem;arg:pointer);
  87. procedure section_write_relocsec(p:tnamedindexitem;arg:pointer);
  88. protected
  89. function writedata(data:TAsmObjectData):boolean;override;
  90. public
  91. function newobjectdata(const n:string):TAsmObjectData;override;
  92. end;
  93. telf32assembler = class(tinternalassembler)
  94. constructor create(smart:boolean);override;
  95. end;
  96. implementation
  97. uses
  98. strings,
  99. verbose,
  100. cutils,globals,fmodule;
  101. const
  102. symbolresize = 200*18;
  103. const
  104. R_386_32 = 1; { ordinary absolute relocation }
  105. R_386_PC32 = 2; { PC-relative relocation }
  106. R_386_GOT32 = 3; { an offset into GOT }
  107. R_386_PLT32 = 4; { a PC-relative offset into PLT }
  108. R_386_GOTOFF = 9; { an offset from GOT base }
  109. R_386_GOTPC = 10; { a PC-relative offset _to_ GOT }
  110. SHN_UNDEF = 0;
  111. SHN_ABS = $fff1;
  112. SHN_COMMON = $fff2;
  113. SHT_NULL = 0;
  114. SHT_PROGBITS = 1;
  115. SHT_SYMTAB = 2;
  116. SHT_STRTAB = 3;
  117. SHT_RELA = 4;
  118. SHT_HASH = 5;
  119. SHT_DYNAMIC = 6;
  120. SHT_NOTE = 7;
  121. SHT_NOBITS = 8;
  122. SHT_REL = 9;
  123. SHT_SHLIB = 10;
  124. SHT_DYNSYM = 11;
  125. SHF_WRITE = 1;
  126. SHF_ALLOC = 2;
  127. SHF_EXECINSTR = 4;
  128. STB_LOCAL = 0;
  129. STB_GLOBAL = 1;
  130. STB_WEAK = 2;
  131. STT_NOTYPE = 0;
  132. STT_OBJECT = 1;
  133. STT_FUNC = 2;
  134. STT_SECTION = 3;
  135. STT_FILE = 4;
  136. type
  137. { Structures which are written directly to the output file }
  138. telf32header=packed record
  139. magic0123 : longint;
  140. file_class : byte;
  141. data_encoding : byte;
  142. file_version : byte;
  143. padding : array[$07..$0f] of byte;
  144. e_type : word;
  145. e_machine : word;
  146. e_version : longint;
  147. e_entry : longint; { entrypoint }
  148. e_phoff : longint; { program header offset }
  149. e_shoff : longint; { sections header offset }
  150. e_flags : longint;
  151. e_ehsize : word; { elf header size in bytes }
  152. e_phentsize : word; { size of an entry in the program header array }
  153. e_phnum : word; { 0..e_phnum-1 of entrys }
  154. e_shentsize : word; { size of an entry in sections header array }
  155. e_shnum : word; { 0..e_shnum-1 of entrys }
  156. e_shstrndx : word; { index of string section header }
  157. end;
  158. telf32sechdr=packed record
  159. sh_name : longint;
  160. sh_type : longint;
  161. sh_flags : longint;
  162. sh_addr : longint;
  163. sh_offset : longint;
  164. sh_size : longint;
  165. sh_link : longint;
  166. sh_info : longint;
  167. sh_addralign : longint;
  168. sh_entsize : longint;
  169. end;
  170. telf32reloc=packed record
  171. address : longint;
  172. info : longint; { bit 0-7: type, 8-31: symbol }
  173. end;
  174. telf32symbol=packed record
  175. st_name : longint;
  176. st_value : longint;
  177. st_size : longint;
  178. st_info : byte; { bit 0-3: type, 4-7: bind }
  179. st_other : byte;
  180. st_shndx : word;
  181. end;
  182. telf32stab=packed record
  183. strpos : longint;
  184. ntype : byte;
  185. nother : byte;
  186. ndesc : word;
  187. nvalue : longint;
  188. end;
  189. {****************************************************************************
  190. TSection
  191. ****************************************************************************}
  192. constructor telf32section.create(const Aname:string;Atype:TAsmSectionType;Aalign:longint;Aoptions:TAsmSectionOptions);
  193. var
  194. Ashflags,Ashtype,Aentsize : longint;
  195. begin
  196. Ashflags:=0;
  197. Ashtype:=0;
  198. Aentsize:=0;
  199. case Atype of
  200. sec_code :
  201. begin
  202. Ashflags:=SHF_ALLOC or SHF_EXECINSTR;
  203. AshType:=SHT_PROGBITS;
  204. AAlign:=max(sizeof(aint),AAlign);
  205. end;
  206. sec_data :
  207. begin
  208. Ashflags:=SHF_ALLOC or SHF_WRITE;
  209. AshType:=SHT_PROGBITS;
  210. AAlign:=max(sizeof(aint),AAlign);
  211. end;
  212. sec_bss :
  213. begin
  214. Ashflags:=SHF_ALLOC or SHF_WRITE;
  215. AshType:=SHT_NOBITS;
  216. AAlign:=max(sizeof(aint),AAlign);
  217. end;
  218. sec_stab :
  219. begin
  220. AshType:=SHT_PROGBITS;
  221. AAlign:=max(sizeof(aint),AAlign);
  222. Aentsize:=sizeof(telf32stab);
  223. end;
  224. sec_stabstr :
  225. begin
  226. AshType:=SHT_STRTAB;
  227. AAlign:=1;
  228. end;
  229. sec_fpc :
  230. begin
  231. AshFlags:=SHF_ALLOC;
  232. AshType:=SHT_PROGBITS ;
  233. AAlign:=4;// max(sizeof(aint),AAlign);
  234. end;
  235. end;
  236. create_ext(Aname,Atype,Ashtype,Ashflags,0,0,Aalign,Aentsize);
  237. end;
  238. constructor telf32section.create_ext(const Aname:string;Atype:TAsmSectionType;Ashtype,Ashflags,Ashlink,Ashinfo,Aalign,Aentsize:longint);
  239. var
  240. aoptions : TAsmSectionOptions;
  241. begin
  242. aoptions:=[];
  243. if (AshType=SHT_NOBITS) then
  244. include(aoptions,aso_alloconly);
  245. inherited create(Aname,Atype,Aalign,aoptions);
  246. secshidx:=0;
  247. shstridx:=0;
  248. shtype:=AshType;
  249. shflags:=AshFlags;
  250. shlink:=Ashlink;
  251. shinfo:=Ashinfo;
  252. entsize:=Aentsize;
  253. relocsect:=nil;
  254. end;
  255. destructor telf32section.destroy;
  256. begin
  257. if assigned(relocsect) then
  258. relocsect.free;
  259. inherited destroy;
  260. end;
  261. {****************************************************************************
  262. telf32objectdata
  263. ****************************************************************************}
  264. constructor telf32objectdata.create(const n:string);
  265. var
  266. s : string;
  267. begin
  268. inherited create(n);
  269. CAsmSection:=TElf32Section;
  270. { reset }
  271. Syms:=TDynamicArray.Create(symbolresize);
  272. { default sections }
  273. symtabsect:=telf32section.create_ext('.symtab',sec_custom,2,0,0,0,4,16);
  274. strtabsect:=telf32section.create_ext('.strtab',sec_custom,3,0,0,0,1,0);
  275. shstrtabsect:=telf32section.create_ext('.shstrtab',sec_custom,3,0,0,0,1,0);
  276. { insert the empty and filename as first in strtab }
  277. strtabsect.writestr(#0);
  278. strtabsect.writestr(SplitFileName(current_module.mainsource^)+#0);
  279. { we need at least the following sections }
  280. createsection(sec_code,'',0,[]);
  281. createsection(sec_data,'',0,[]);
  282. createsection(sec_bss,'',0,[]);
  283. { create stabs sections if debugging }
  284. if (cs_debuginfo in aktmoduleswitches) then
  285. begin
  286. stabssec:=createsection(sec_stab,'',0,[]);
  287. stabstrsec:=createsection(sec_stabstr,'',0,[]);
  288. end;
  289. end;
  290. destructor telf32objectdata.destroy;
  291. begin
  292. Syms.Free;
  293. symtabsect.free;
  294. strtabsect.free;
  295. shstrtabsect.free;
  296. inherited destroy;
  297. end;
  298. function telf32objectdata.sectionname(atype:tasmsectiontype;const aname:string):string;
  299. const
  300. secnames : array[tasmsectiontype] of string[12] = ('',
  301. {$ifdef userodata}
  302. '.text','.data','.rodata','.bss',
  303. {$else userodata}
  304. '.text','.data','.data','.bss',
  305. {$endif userodata}
  306. 'common',
  307. '.note',
  308. '.stab','.stabstr',
  309. '.idata$2','.idata$4','.idata$5','.idata$6','.idata$7','.edata',
  310. '.eh_frame',
  311. '.debug_frame',
  312. 'fpc.resptrs'
  313. );
  314. begin
  315. if use_smartlink_section and
  316. (atype<>sec_bss) and
  317. (aname<>'') then
  318. result:='.gnu.linkonce'+copy(secnames[atype],1,2)+'.'+aname
  319. else
  320. result:=secnames[atype];
  321. end;
  322. procedure telf32objectdata.writesymbol(p:tasmsymbol);
  323. begin
  324. if currsec=nil then
  325. internalerror(200403291);
  326. { already written ? }
  327. if p.indexnr<>-1 then
  328. exit;
  329. { calculate symbol index }
  330. if (p.currbind<>AB_LOCAL) then
  331. begin
  332. { insert the symbol in the local index, the indexarray
  333. will take care of the numbering }
  334. symbols.insert(p);
  335. end
  336. else
  337. p.indexnr:=-2; { local }
  338. end;
  339. procedure telf32objectdata.writereloc(data,len:aint;p:tasmsymbol;relative:TAsmRelocationType);
  340. var
  341. symaddr : longint;
  342. begin
  343. if currsec=nil then
  344. internalerror(200403292);
  345. {$ifdef userodata}
  346. if currsec.sectype in [sec_rodata,sec_bss] then
  347. internalerror(200408252);
  348. {$endif userodata}
  349. if assigned(p) then
  350. begin
  351. { real address of the symbol }
  352. symaddr:=p.address;
  353. { Local symbols can be resolved already or need a section reloc }
  354. if (p.currbind=AB_LOCAL) then
  355. begin
  356. { For a relative relocation in the same section the
  357. value can be calculated }
  358. if (p.section=currsec) and
  359. (relative=RELOC_RELATIVE) then
  360. inc(data,symaddr-len-currsec.datasize)
  361. else
  362. begin
  363. currsec.addsectionreloc(currsec.datasize,p.section,relative);
  364. inc(data,symaddr);
  365. end;
  366. end
  367. else
  368. begin
  369. writesymbol(p);
  370. currsec.addsymreloc(currsec.datasize,p,relative);
  371. if relative=RELOC_RELATIVE then
  372. dec(data,len);
  373. end;
  374. end;
  375. currsec.write(data,len);
  376. end;
  377. procedure telf32objectdata.writestabs(offset:aint;p:pchar;nidx,nother,line:longint;reloc : boolean);
  378. var
  379. stab : telf32stab;
  380. begin
  381. if reloc then
  382. begin
  383. if (offset=-1) then
  384. begin
  385. if currsec=nil then
  386. offset:=0
  387. else
  388. offset:=currsec.datasize;
  389. end;
  390. end;
  391. fillchar(stab,sizeof(telf32stab),0);
  392. if assigned(p) and (p[0]<>#0) then
  393. begin
  394. stab.strpos:=stabstrsec.datasize;
  395. stabstrsec.write(p^,strlen(p)+1);
  396. end;
  397. stab.ntype:=nidx;
  398. stab.ndesc:=line;
  399. stab.nother:=nother;
  400. stab.nvalue:=offset;
  401. stabssec.write(stab,sizeof(stab));
  402. { when the offset is not 0 then write a relocation, take also the
  403. hdrstab into account with the offset }
  404. if reloc then
  405. stabssec.addsectionreloc(stabssec.datasize-4,currsec,RELOC_ABSOLUTE);
  406. end;
  407. procedure telf32objectdata.writesymstabs(offset:aint;p:pchar;ps:tasmsymbol;nidx,nother,line:longint;reloc:boolean);
  408. var
  409. stab : telf32stab;
  410. begin
  411. fillchar(stab,sizeof(telf32stab),0);
  412. if assigned(p) and (p[0]<>#0) then
  413. begin
  414. stab.strpos:=stabstrsec.datasize;
  415. stabstrsec.write(p^,strlen(p)+1);
  416. end;
  417. stab.ntype:=nidx;
  418. stab.ndesc:=line;
  419. stab.nother:=nother;
  420. stab.nvalue:=0;
  421. stabssec.write(stab,sizeof(stab));
  422. { when the offset is not 0 then write a relocation, take also the
  423. hdrstab into account with the offset }
  424. if reloc then
  425. stabssec.addsymreloc(stabssec.datasize-4,ps,RELOC_ABSOLUTE);
  426. end;
  427. procedure telf32objectdata.beforealloc;
  428. begin
  429. { create stabs sections if debugging }
  430. if (cs_debuginfo in aktmoduleswitches) then
  431. begin
  432. StabsSec.Alloc(sizeof(telf32stab));
  433. StabStrSec.Alloc(length(SplitFileName(current_module.mainsource^))+2);
  434. end;
  435. end;
  436. procedure telf32objectdata.beforewrite;
  437. var
  438. s : string;
  439. begin
  440. { create stabs sections if debugging }
  441. if (cs_debuginfo in aktmoduleswitches) then
  442. begin
  443. writestabs(0,nil,0,0,0,false);
  444. { write zero pchar and name together (PM) }
  445. s:=#0+SplitFileName(current_module.mainsource^)+#0;
  446. stabstrsec.write(s[1],length(s));
  447. end;
  448. end;
  449. {****************************************************************************
  450. telf32objectoutput
  451. ****************************************************************************}
  452. function telf32objectoutput.newobjectdata(const n:string):TAsmObjectData;
  453. begin
  454. result:=telf32objectdata.create(n);
  455. end;
  456. procedure telf32objectoutput.createrelocsection(s:telf32section);
  457. var
  458. rel : telf32reloc;
  459. r : tasmrelocation;
  460. relsym,reltyp : longint;
  461. begin
  462. with elf32data do
  463. begin
  464. {$ifdef userodata}
  465. { rodata can't have relocations }
  466. if s.sectype=sec_rodata then
  467. begin
  468. if assigned(s.relocations.first) then
  469. internalerror(200408251);
  470. exit;
  471. end;
  472. {$endif userodata}
  473. { create the reloc section }
  474. s.relocsect:=telf32section.create_ext('.rel'+s.name,sec_custom,9,0,symtabsect.secshidx,s.secshidx,4,8);
  475. { add the relocations }
  476. r:=TasmRelocation(s.relocations.first);
  477. while assigned(r) do
  478. begin
  479. rel.address:=r.address;
  480. if assigned(r.symbol) then
  481. begin
  482. if (r.symbol.currbind=AB_LOCAL) then
  483. relsym:=r.symbol.section.secsymidx
  484. else
  485. begin
  486. if r.symbol.indexnr=-1 then
  487. internalerror(4321);
  488. { indexnr starts with 1, ELF starts with 0 }
  489. relsym:=r.symbol.indexnr+initsym-1;
  490. end;
  491. end
  492. else
  493. if r.section<>nil then
  494. relsym:=r.section.secsymidx
  495. else
  496. relsym:=SHN_UNDEF;
  497. case r.typ of
  498. RELOC_RELATIVE :
  499. reltyp:=R_386_PC32;
  500. RELOC_ABSOLUTE :
  501. reltyp:=R_386_32;
  502. end;
  503. rel.info:=(relsym shl 8) or reltyp;
  504. { write reloc }
  505. s.relocsect.write(rel,sizeof(rel));
  506. r:=TAsmRelocation(r.next);
  507. end;
  508. end;
  509. end;
  510. procedure telf32objectoutput.section_write_symbol(p:tnamedindexitem;arg:pointer);
  511. var
  512. elfsym : telf32symbol;
  513. begin
  514. fillchar(elfsym,sizeof(elfsym),0);
  515. elfsym.st_name:=telf32section(p).shstridx;
  516. elfsym.st_info:=STT_SECTION;
  517. elfsym.st_shndx:=telf32section(p).secshidx;
  518. elf32data.symtabsect.write(elfsym,sizeof(elfsym));
  519. { increase locals count }
  520. inc(plongint(arg)^);
  521. end;
  522. procedure telf32objectoutput.createsymtab;
  523. var
  524. elfsym : telf32symbol;
  525. locals : longint;
  526. sym : tasmsymbol;
  527. begin
  528. with elf32data do
  529. begin
  530. locals:=2;
  531. { empty entry }
  532. fillchar(elfsym,sizeof(elfsym),0);
  533. symtabsect.write(elfsym,sizeof(elfsym));
  534. { filename entry }
  535. elfsym.st_name:=1;
  536. elfsym.st_info:=STT_FILE;
  537. elfsym.st_shndx:=SHN_ABS;
  538. symtabsect.write(elfsym,sizeof(elfsym));
  539. { section }
  540. sects.foreach(@section_write_symbol,@locals);
  541. { symbols }
  542. sym:=Tasmsymbol(symbols.First);
  543. while assigned(sym) do
  544. begin
  545. fillchar(elfsym,sizeof(elfsym),0);
  546. { symbolname, write the #0 separate to overcome 255+1 char not possible }
  547. elfsym.st_name:=strtabsect.datasize;
  548. strtabsect.writestr(sym.name);
  549. strtabsect.writestr(#0);
  550. case sym.currbind of
  551. AB_LOCAL,
  552. AB_GLOBAL :
  553. elfsym.st_value:=sym.address;
  554. AB_COMMON :
  555. elfsym.st_value:=$10;
  556. end;
  557. elfsym.st_size:=sym.size;
  558. case sym.currbind of
  559. AB_LOCAL :
  560. begin
  561. elfsym.st_info:=STB_LOCAL shl 4;
  562. inc(locals);
  563. end;
  564. AB_COMMON,
  565. AB_EXTERNAL,
  566. AB_GLOBAL :
  567. elfsym.st_info:=STB_GLOBAL shl 4;
  568. end;
  569. if sym.currbind<>AB_EXTERNAL then
  570. begin
  571. case sym.typ of
  572. AT_FUNCTION :
  573. elfsym.st_info:=elfsym.st_info or STT_FUNC;
  574. AT_DATA :
  575. elfsym.st_info:=elfsym.st_info or STT_OBJECT;
  576. end;
  577. end;
  578. if sym.currbind=AB_COMMON then
  579. elfsym.st_shndx:=SHN_COMMON
  580. else
  581. if assigned(sym.section) then
  582. elfsym.st_shndx:=telf32section(sym.section).secshidx
  583. else
  584. elfsym.st_shndx:=SHN_UNDEF;
  585. symtabsect.write(elfsym,sizeof(elfsym));
  586. sym:=tasmsymbol(sym.indexnext);
  587. end;
  588. { update the .symtab section header }
  589. symtabsect.shlink:=strtabsect.secshidx;
  590. symtabsect.shinfo:=locals;
  591. end;
  592. end;
  593. procedure telf32objectoutput.section_write_sh_string(p:tnamedindexitem;arg:pointer);
  594. begin
  595. telf32section(p).shstridx:=elf32data.shstrtabsect.writestr(tasmsection(p).name+#0);
  596. if assigned(telf32section(p).relocsect) then
  597. telf32section(p).relocsect.shstridx:=elf32data.shstrtabsect.writestr(telf32section(p).relocsect.name+#0);
  598. end;
  599. procedure telf32objectoutput.createshstrtab;
  600. begin
  601. with elf32data do
  602. begin
  603. with shstrtabsect do
  604. begin
  605. writestr(#0);
  606. symtabsect.shstridx:=writestr('.symtab'#0);
  607. strtabsect.shstridx:=writestr('.strtab'#0);
  608. shstrtabsect.shstridx:=writestr('.shstrtab'#0);
  609. sects.foreach(@section_write_sh_string,nil);
  610. end;
  611. end;
  612. end;
  613. procedure telf32objectoutput.writesectionheader(s:telf32section);
  614. var
  615. sechdr : telf32sechdr;
  616. begin
  617. fillchar(sechdr,sizeof(sechdr),0);
  618. sechdr.sh_name:=s.shstridx;
  619. sechdr.sh_type:=s.shtype;
  620. sechdr.sh_flags:=s.shflags;
  621. sechdr.sh_offset:=s.datapos;
  622. sechdr.sh_size:=s.datasize;
  623. sechdr.sh_link:=s.shlink;
  624. sechdr.sh_info:=s.shinfo;
  625. sechdr.sh_addralign:=s.addralign;
  626. sechdr.sh_entsize:=s.entsize;
  627. writer.write(sechdr,sizeof(sechdr));
  628. end;
  629. procedure telf32objectoutput.writesectiondata(s:telf32section);
  630. var
  631. hp : pdynamicblock;
  632. begin
  633. FWriter.writezeros(s.dataalignbytes);
  634. s.alignsection;
  635. hp:=s.data.firstblock;
  636. while assigned(hp) do
  637. begin
  638. FWriter.write(hp^.data,hp^.used);
  639. hp:=hp^.next;
  640. end;
  641. end;
  642. procedure telf32objectoutput.section_number_symbol(p:tnamedindexitem;arg:pointer);
  643. begin
  644. tasmsection(p).secsymidx:=plongint(arg)^;
  645. inc(plongint(arg)^);
  646. end;
  647. procedure telf32objectoutput.section_count_sects(p:tnamedindexitem;arg:pointer);
  648. begin
  649. telf32section(p).secshidx:=plongint(arg)^;
  650. inc(plongint(arg)^);
  651. if telf32section(p).relocations.count>0 then
  652. inc(plongint(arg)^);
  653. end;
  654. procedure telf32objectoutput.section_create_relocsec(p:tnamedindexitem;arg:pointer);
  655. begin
  656. if (telf32section(p).relocations.count>0) then
  657. createrelocsection(telf32section(p));
  658. end;
  659. procedure telf32objectoutput.section_set_datapos(p:tnamedindexitem;arg:pointer);
  660. begin
  661. if (aso_alloconly in tasmsection(p).secoptions) then
  662. tasmsection(p).datapos:=paint(arg)^
  663. else
  664. tasmsection(p).setdatapos(paint(arg)^);
  665. end;
  666. procedure telf32objectoutput.section_relocsec_set_datapos(p:tnamedindexitem;arg:pointer);
  667. begin
  668. if assigned(telf32section(p).relocsect) then
  669. telf32section(p).relocsect.setdatapos(paint(arg)^);
  670. end;
  671. procedure telf32objectoutput.section_write_data(p:tnamedindexitem;arg:pointer);
  672. begin
  673. if (aso_alloconly in tasmsection(p).secoptions) then
  674. exit;
  675. if tasmsection(p).data=nil then
  676. internalerror(200403073);
  677. writesectiondata(telf32section(p));
  678. end;
  679. procedure telf32objectoutput.section_write_sechdr(p:tnamedindexitem;arg:pointer);
  680. begin
  681. writesectionheader(telf32section(p));
  682. if assigned(telf32section(p).relocsect) then
  683. writesectionheader(telf32section(p).relocsect);
  684. end;
  685. procedure telf32objectoutput.section_write_relocsec(p:tnamedindexitem;arg:pointer);
  686. begin
  687. if assigned(telf32section(p).relocsect) then
  688. writesectiondata(telf32section(p).relocsect);
  689. end;
  690. function telf32objectoutput.writedata(data:TAsmObjectData):boolean;
  691. var
  692. header : telf32header;
  693. datapos : aint;
  694. shoffset,
  695. nsects : longint;
  696. hstab : telf32stab;
  697. empty : array[0..63] of byte;
  698. begin
  699. result:=false;
  700. elf32data:=telf32objectdata(data);
  701. with elf32data do
  702. begin
  703. { calc amount of sections we have }
  704. initsym:=2;
  705. nsects:=1;
  706. fillchar(empty,sizeof(empty),0);
  707. { each section requires a symbol for relocation }
  708. sects.foreach(@section_number_symbol,@initsym);
  709. { also create the index in the section header table }
  710. sects.foreach(@section_count_sects,@nsects);
  711. { add default sections follows }
  712. shstrtabsect.secshidx:=nsects;
  713. inc(nsects);
  714. symtabsect.secshidx:=nsects;
  715. inc(nsects);
  716. strtabsect.secshidx:=nsects;
  717. inc(nsects);
  718. { For the stab section we need an HdrSym which can now be
  719. calculated more easily }
  720. if assigned(stabssec) then
  721. begin
  722. hstab.strpos:=1;
  723. hstab.ntype:=0;
  724. hstab.nother:=0;
  725. hstab.ndesc:=(stabssec.datasize div sizeof(telf32stab))-1{+1 according to gas output PM};
  726. hstab.nvalue:=stabstrsec.datasize;
  727. stabssec.Data.seek(0);
  728. stabssec.Data.write(hstab,sizeof(hstab));
  729. end;
  730. { Create the relocation sections }
  731. sects.foreach(@section_create_relocsec,nil);
  732. { create .symtab and .strtab }
  733. createsymtab;
  734. { create .shstrtab }
  735. createshstrtab;
  736. { Calculate the filepositions }
  737. datapos:=$40; { elfheader + alignment }
  738. { sections first }
  739. sects.foreach(@section_set_datapos,@datapos);
  740. { shstrtab }
  741. shstrtabsect.setdatapos(datapos);
  742. { section headers }
  743. shoffset:=datapos;
  744. inc(datapos,nsects*sizeof(telf32sechdr));
  745. { symtab }
  746. symtabsect.setdatapos(datapos);
  747. { strtab }
  748. strtabsect.setdatapos(datapos);
  749. { .rel sections }
  750. sects.foreach(@section_relocsec_set_datapos,@datapos);
  751. { Write ELF Header }
  752. fillchar(header,sizeof(header),0);
  753. header.magic0123:=$464c457f; { = #127'ELF' }
  754. header.file_class:=1;
  755. header.data_encoding:=1;
  756. header.file_version:=1;
  757. header.e_type:=1;
  758. header.e_machine:=3;
  759. header.e_version:=1;
  760. header.e_shoff:=shoffset;
  761. header.e_shstrndx:=shstrtabsect.secshidx;
  762. header.e_shnum:=nsects;
  763. header.e_ehsize:=sizeof(telf32header);
  764. header.e_shentsize:=sizeof(telf32sechdr);
  765. writer.write(header,sizeof(header));
  766. writer.write(empty,$40-sizeof(header)); { align }
  767. { Sections }
  768. sects.foreach(@section_write_data,nil);
  769. { .shstrtab }
  770. writesectiondata(shstrtabsect);
  771. { section headers, start with an empty header for sh_undef }
  772. writer.write(empty,sizeof(telf32sechdr));
  773. sects.foreach(@section_write_sechdr,nil);
  774. writesectionheader(shstrtabsect);
  775. writesectionheader(symtabsect);
  776. writesectionheader(strtabsect);
  777. { .symtab }
  778. writesectiondata(symtabsect);
  779. { .strtab }
  780. writesectiondata(strtabsect);
  781. { .rel sections }
  782. sects.foreach(@section_write_relocsec,nil);
  783. end;
  784. result:=true;
  785. end;
  786. {****************************************************************************
  787. TELFAssembler
  788. ****************************************************************************}
  789. constructor TELF32Assembler.Create(smart:boolean);
  790. begin
  791. inherited Create(smart);
  792. objectoutput:=telf32objectoutput.create(smart);
  793. end;
  794. {*****************************************************************************
  795. Initialize
  796. *****************************************************************************}
  797. const
  798. as_i386_elf32_info : tasminfo =
  799. (
  800. id : as_i386_elf32;
  801. idtxt : 'ELF';
  802. asmbin : '';
  803. asmcmd : '';
  804. supported_target : system_any; //target_i386_linux;
  805. // flags : [af_outputbinary,af_smartlink_sections];
  806. flags : [af_outputbinary];
  807. labelprefix : '.L';
  808. comment : '';
  809. );
  810. initialization
  811. RegisterAssembler(as_i386_elf32_info,TElf32Assembler);
  812. end.