ogelf.pas 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919
  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_rodata :
  213. begin
  214. {$warning TODO Remove rodata hack}
  215. Ashflags:=SHF_ALLOC or SHF_WRITE;
  216. AshType:=SHT_PROGBITS;
  217. AAlign:=max(sizeof(aint),AAlign);
  218. end;
  219. sec_bss,sec_threadvar :
  220. begin
  221. Ashflags:=SHF_ALLOC or SHF_WRITE;
  222. AshType:=SHT_NOBITS;
  223. AAlign:=max(sizeof(aint),AAlign);
  224. end;
  225. sec_stab :
  226. begin
  227. AshType:=SHT_PROGBITS;
  228. AAlign:=max(sizeof(aint),AAlign);
  229. Aentsize:=sizeof(telf32stab);
  230. end;
  231. sec_stabstr :
  232. begin
  233. AshType:=SHT_STRTAB;
  234. AAlign:=1;
  235. end;
  236. sec_fpc :
  237. begin
  238. AshFlags:=SHF_ALLOC;
  239. AshType:=SHT_PROGBITS ;
  240. AAlign:=4;// max(sizeof(aint),AAlign);
  241. end;
  242. else
  243. internalerror(200509122);
  244. end;
  245. create_ext(Aname,Atype,Ashtype,Ashflags,0,0,Aalign,Aentsize);
  246. end;
  247. constructor telf32section.create_ext(const Aname:string;Atype:TAsmSectionType;Ashtype,Ashflags,Ashlink,Ashinfo,Aalign,Aentsize:longint);
  248. var
  249. aoptions : TAsmSectionOptions;
  250. begin
  251. aoptions:=[];
  252. if (AshType=SHT_NOBITS) then
  253. include(aoptions,aso_alloconly);
  254. inherited create(Aname,Atype,Aalign,aoptions);
  255. secshidx:=0;
  256. shstridx:=0;
  257. shtype:=AshType;
  258. shflags:=AshFlags;
  259. shlink:=Ashlink;
  260. shinfo:=Ashinfo;
  261. entsize:=Aentsize;
  262. relocsect:=nil;
  263. end;
  264. destructor telf32section.destroy;
  265. begin
  266. if assigned(relocsect) then
  267. relocsect.free;
  268. inherited destroy;
  269. end;
  270. {****************************************************************************
  271. telf32objectdata
  272. ****************************************************************************}
  273. constructor telf32objectdata.create(const n:string);
  274. var
  275. s : string;
  276. begin
  277. inherited create(n);
  278. CAsmSection:=TElf32Section;
  279. { reset }
  280. Syms:=TDynamicArray.Create(symbolresize);
  281. { default sections }
  282. symtabsect:=telf32section.create_ext('.symtab',sec_custom,2,0,0,0,4,16);
  283. strtabsect:=telf32section.create_ext('.strtab',sec_custom,3,0,0,0,1,0);
  284. shstrtabsect:=telf32section.create_ext('.shstrtab',sec_custom,3,0,0,0,1,0);
  285. { insert the empty and filename as first in strtab }
  286. strtabsect.writestr(#0);
  287. strtabsect.writestr(SplitFileName(current_module.mainsource^)+#0);
  288. { we need at least the following sections }
  289. createsection(sec_code,'',0,[]);
  290. createsection(sec_data,'',0,[]);
  291. createsection(sec_bss,'',0,[]);
  292. {$ifdef segment_threadvars}
  293. createsection(sec_threadvar,'',0,[]);
  294. {$endif}
  295. { create stabs sections if debugging }
  296. if (cs_debuginfo in aktmoduleswitches) then
  297. begin
  298. stabssec:=createsection(sec_stab,'',0,[]);
  299. stabstrsec:=createsection(sec_stabstr,'',0,[]);
  300. end;
  301. end;
  302. destructor telf32objectdata.destroy;
  303. begin
  304. Syms.Free;
  305. symtabsect.free;
  306. strtabsect.free;
  307. shstrtabsect.free;
  308. inherited destroy;
  309. end;
  310. function telf32objectdata.sectionname(atype:tasmsectiontype;const aname:string):string;
  311. const
  312. secnames : array[tasmsectiontype] of string[12] = ('',
  313. {$ifdef userodata}
  314. '.text','.data','.rodata','.bss','.threadvar',
  315. {$else userodata}
  316. '.text','.data','.data','.bss','.threadvar',
  317. {$endif userodata}
  318. 'common',
  319. '.note',
  320. '.stab','.stabstr',
  321. '.idata$2','.idata$4','.idata$5','.idata$6','.idata$7','.edata',
  322. '.eh_frame',
  323. '.debug_frame',
  324. 'fpc.resptrs'
  325. );
  326. begin
  327. if use_smartlink_section and
  328. (aname<>'') then
  329. result:=secnames[atype]+'.'+aname
  330. else
  331. result:=secnames[atype];
  332. end;
  333. procedure telf32objectdata.writesymbol(p:tasmsymbol);
  334. begin
  335. if currsec=nil then
  336. internalerror(200403291);
  337. { already written ? }
  338. if p.indexnr<>-1 then
  339. exit;
  340. { calculate symbol index }
  341. if (p.currbind<>AB_LOCAL) then
  342. begin
  343. { insert the symbol in the local index, the indexarray
  344. will take care of the numbering }
  345. symbols.insert(p);
  346. end
  347. else
  348. p.indexnr:=-2; { local }
  349. end;
  350. procedure telf32objectdata.writereloc(data,len:aint;p:tasmsymbol;relative:TAsmRelocationType);
  351. var
  352. symaddr : longint;
  353. begin
  354. if currsec=nil then
  355. internalerror(200403292);
  356. {$ifdef userodata}
  357. if currsec.sectype in [sec_rodata,sec_bss,sec_threadvar] then
  358. internalerror(200408252);
  359. {$endif userodata}
  360. if assigned(p) then
  361. begin
  362. { real address of the symbol }
  363. symaddr:=p.address;
  364. { Local symbols can be resolved already or need a section reloc }
  365. if (p.currbind=AB_LOCAL) then
  366. begin
  367. { For a relative relocation in the same section the
  368. value can be calculated }
  369. if (p.section=currsec) and
  370. (relative=RELOC_RELATIVE) then
  371. inc(data,symaddr-len-currsec.datasize)
  372. else
  373. begin
  374. currsec.addsectionreloc(currsec.datasize,p.section,relative);
  375. inc(data,symaddr);
  376. end;
  377. end
  378. else
  379. begin
  380. writesymbol(p);
  381. currsec.addsymreloc(currsec.datasize,p,relative);
  382. if relative=RELOC_RELATIVE then
  383. dec(data,len);
  384. end;
  385. end;
  386. currsec.write(data,len);
  387. end;
  388. procedure telf32objectdata.writestabs(offset:aint;p:pchar;nidx,nother,line:longint;reloc : boolean);
  389. var
  390. stab : telf32stab;
  391. begin
  392. if reloc then
  393. begin
  394. if (offset=-1) then
  395. begin
  396. if currsec=nil then
  397. offset:=0
  398. else
  399. offset:=currsec.datasize;
  400. end;
  401. end;
  402. fillchar(stab,sizeof(telf32stab),0);
  403. if assigned(p) and (p[0]<>#0) then
  404. begin
  405. stab.strpos:=stabstrsec.datasize;
  406. stabstrsec.write(p^,strlen(p)+1);
  407. end;
  408. stab.ntype:=nidx;
  409. stab.ndesc:=line;
  410. stab.nother:=nother;
  411. stab.nvalue:=offset;
  412. stabssec.write(stab,sizeof(stab));
  413. { when the offset is not 0 then write a relocation, take also the
  414. hdrstab into account with the offset }
  415. if reloc then
  416. stabssec.addsectionreloc(stabssec.datasize-4,currsec,RELOC_ABSOLUTE);
  417. end;
  418. procedure telf32objectdata.writesymstabs(offset:aint;p:pchar;ps:tasmsymbol;nidx,nother,line:longint;reloc:boolean);
  419. var
  420. stab : telf32stab;
  421. begin
  422. fillchar(stab,sizeof(telf32stab),0);
  423. if assigned(p) and (p[0]<>#0) then
  424. begin
  425. stab.strpos:=stabstrsec.datasize;
  426. stabstrsec.write(p^,strlen(p)+1);
  427. end;
  428. stab.ntype:=nidx;
  429. stab.ndesc:=line;
  430. stab.nother:=nother;
  431. stab.nvalue:=0;
  432. stabssec.write(stab,sizeof(stab));
  433. { when the offset is not 0 then write a relocation, take also the
  434. hdrstab into account with the offset }
  435. if reloc then
  436. stabssec.addsymreloc(stabssec.datasize-4,ps,RELOC_ABSOLUTE);
  437. end;
  438. procedure telf32objectdata.beforealloc;
  439. begin
  440. { create stabs sections if debugging }
  441. if (cs_debuginfo in aktmoduleswitches) then
  442. begin
  443. StabsSec.Alloc(sizeof(telf32stab));
  444. StabStrSec.Alloc(length(SplitFileName(current_module.mainsource^))+2);
  445. end;
  446. end;
  447. procedure telf32objectdata.beforewrite;
  448. var
  449. s : string;
  450. begin
  451. { create stabs sections if debugging }
  452. if (cs_debuginfo in aktmoduleswitches) then
  453. begin
  454. writestabs(0,nil,0,0,0,false);
  455. { write zero pchar and name together (PM) }
  456. s:=#0+SplitFileName(current_module.mainsource^)+#0;
  457. stabstrsec.write(s[1],length(s));
  458. end;
  459. end;
  460. {****************************************************************************
  461. telf32objectoutput
  462. ****************************************************************************}
  463. function telf32objectoutput.newobjectdata(const n:string):TAsmObjectData;
  464. begin
  465. result:=telf32objectdata.create(n);
  466. end;
  467. procedure telf32objectoutput.createrelocsection(s:telf32section);
  468. var
  469. rel : telf32reloc;
  470. r : tasmrelocation;
  471. relsym,reltyp : longint;
  472. begin
  473. with elf32data do
  474. begin
  475. {$ifdef userodata}
  476. { rodata can't have relocations }
  477. if s.sectype=sec_rodata then
  478. begin
  479. if assigned(s.relocations.first) then
  480. internalerror(200408251);
  481. exit;
  482. end;
  483. {$endif userodata}
  484. { create the reloc section }
  485. s.relocsect:=telf32section.create_ext('.rel'+s.name,sec_custom,9,0,symtabsect.secshidx,s.secshidx,4,8);
  486. { add the relocations }
  487. r:=TasmRelocation(s.relocations.first);
  488. while assigned(r) do
  489. begin
  490. rel.address:=r.address;
  491. if assigned(r.symbol) then
  492. begin
  493. if (r.symbol.currbind=AB_LOCAL) then
  494. relsym:=r.symbol.section.secsymidx
  495. else
  496. begin
  497. if r.symbol.indexnr=-1 then
  498. internalerror(4321);
  499. { indexnr starts with 1, ELF starts with 0 }
  500. relsym:=r.symbol.indexnr+initsym-1;
  501. end;
  502. end
  503. else
  504. if r.section<>nil then
  505. relsym:=r.section.secsymidx
  506. else
  507. relsym:=SHN_UNDEF;
  508. case r.typ of
  509. RELOC_RELATIVE :
  510. reltyp:=R_386_PC32;
  511. RELOC_ABSOLUTE :
  512. reltyp:=R_386_32;
  513. end;
  514. rel.info:=(relsym shl 8) or reltyp;
  515. { write reloc }
  516. s.relocsect.write(rel,sizeof(rel));
  517. r:=TAsmRelocation(r.next);
  518. end;
  519. end;
  520. end;
  521. procedure telf32objectoutput.section_write_symbol(p:tnamedindexitem;arg:pointer);
  522. var
  523. elfsym : telf32symbol;
  524. begin
  525. fillchar(elfsym,sizeof(elfsym),0);
  526. elfsym.st_name:=telf32section(p).shstridx;
  527. elfsym.st_info:=STT_SECTION;
  528. elfsym.st_shndx:=telf32section(p).secshidx;
  529. elf32data.symtabsect.write(elfsym,sizeof(elfsym));
  530. { increase locals count }
  531. inc(plongint(arg)^);
  532. end;
  533. procedure telf32objectoutput.createsymtab;
  534. var
  535. elfsym : telf32symbol;
  536. locals : longint;
  537. sym : tasmsymbol;
  538. begin
  539. with elf32data do
  540. begin
  541. locals:=2;
  542. { empty entry }
  543. fillchar(elfsym,sizeof(elfsym),0);
  544. symtabsect.write(elfsym,sizeof(elfsym));
  545. { filename entry }
  546. elfsym.st_name:=1;
  547. elfsym.st_info:=STT_FILE;
  548. elfsym.st_shndx:=SHN_ABS;
  549. symtabsect.write(elfsym,sizeof(elfsym));
  550. { section }
  551. sects.foreach(@section_write_symbol,@locals);
  552. { symbols }
  553. sym:=Tasmsymbol(symbols.First);
  554. while assigned(sym) do
  555. begin
  556. fillchar(elfsym,sizeof(elfsym),0);
  557. { symbolname, write the #0 separate to overcome 255+1 char not possible }
  558. elfsym.st_name:=strtabsect.datasize;
  559. strtabsect.writestr(sym.name);
  560. strtabsect.writestr(#0);
  561. case sym.currbind of
  562. AB_LOCAL,
  563. AB_GLOBAL :
  564. elfsym.st_value:=sym.address;
  565. AB_COMMON :
  566. elfsym.st_value:=$10;
  567. end;
  568. elfsym.st_size:=sym.size;
  569. case sym.currbind of
  570. AB_LOCAL :
  571. begin
  572. elfsym.st_info:=STB_LOCAL shl 4;
  573. inc(locals);
  574. end;
  575. AB_COMMON,
  576. AB_EXTERNAL,
  577. AB_GLOBAL :
  578. elfsym.st_info:=STB_GLOBAL shl 4;
  579. end;
  580. if (sym.currbind<>AB_EXTERNAL) and
  581. not(assigned(sym.section) and
  582. (sym.section.sectype=sec_bss)) then
  583. begin
  584. case sym.typ of
  585. AT_FUNCTION :
  586. elfsym.st_info:=elfsym.st_info or STT_FUNC;
  587. AT_DATA :
  588. elfsym.st_info:=elfsym.st_info or STT_OBJECT;
  589. end;
  590. end;
  591. if sym.currbind=AB_COMMON then
  592. elfsym.st_shndx:=SHN_COMMON
  593. else
  594. if assigned(sym.section) then
  595. elfsym.st_shndx:=telf32section(sym.section).secshidx
  596. else
  597. elfsym.st_shndx:=SHN_UNDEF;
  598. symtabsect.write(elfsym,sizeof(elfsym));
  599. sym:=tasmsymbol(sym.indexnext);
  600. end;
  601. { update the .symtab section header }
  602. symtabsect.shlink:=strtabsect.secshidx;
  603. symtabsect.shinfo:=locals;
  604. end;
  605. end;
  606. procedure telf32objectoutput.section_write_sh_string(p:tnamedindexitem;arg:pointer);
  607. begin
  608. telf32section(p).shstridx:=elf32data.shstrtabsect.writestr(tasmsection(p).name+#0);
  609. if assigned(telf32section(p).relocsect) then
  610. telf32section(p).relocsect.shstridx:=elf32data.shstrtabsect.writestr(telf32section(p).relocsect.name+#0);
  611. end;
  612. procedure telf32objectoutput.createshstrtab;
  613. begin
  614. with elf32data do
  615. begin
  616. with shstrtabsect do
  617. begin
  618. writestr(#0);
  619. symtabsect.shstridx:=writestr('.symtab'#0);
  620. strtabsect.shstridx:=writestr('.strtab'#0);
  621. shstrtabsect.shstridx:=writestr('.shstrtab'#0);
  622. sects.foreach(@section_write_sh_string,nil);
  623. end;
  624. end;
  625. end;
  626. procedure telf32objectoutput.writesectionheader(s:telf32section);
  627. var
  628. sechdr : telf32sechdr;
  629. begin
  630. fillchar(sechdr,sizeof(sechdr),0);
  631. sechdr.sh_name:=s.shstridx;
  632. sechdr.sh_type:=s.shtype;
  633. sechdr.sh_flags:=s.shflags;
  634. sechdr.sh_offset:=s.datapos;
  635. sechdr.sh_size:=s.datasize;
  636. sechdr.sh_link:=s.shlink;
  637. sechdr.sh_info:=s.shinfo;
  638. sechdr.sh_addralign:=s.addralign;
  639. sechdr.sh_entsize:=s.entsize;
  640. writer.write(sechdr,sizeof(sechdr));
  641. end;
  642. procedure telf32objectoutput.writesectiondata(s:telf32section);
  643. var
  644. hp : pdynamicblock;
  645. begin
  646. FWriter.writezeros(s.dataalignbytes);
  647. s.alignsection;
  648. hp:=s.data.firstblock;
  649. while assigned(hp) do
  650. begin
  651. FWriter.write(hp^.data,hp^.used);
  652. hp:=hp^.next;
  653. end;
  654. end;
  655. procedure telf32objectoutput.section_number_symbol(p:tnamedindexitem;arg:pointer);
  656. begin
  657. tasmsection(p).secsymidx:=plongint(arg)^;
  658. inc(plongint(arg)^);
  659. end;
  660. procedure telf32objectoutput.section_count_sects(p:tnamedindexitem;arg:pointer);
  661. begin
  662. telf32section(p).secshidx:=plongint(arg)^;
  663. inc(plongint(arg)^);
  664. if telf32section(p).relocations.count>0 then
  665. inc(plongint(arg)^);
  666. end;
  667. procedure telf32objectoutput.section_create_relocsec(p:tnamedindexitem;arg:pointer);
  668. begin
  669. if (telf32section(p).relocations.count>0) then
  670. createrelocsection(telf32section(p));
  671. end;
  672. procedure telf32objectoutput.section_set_datapos(p:tnamedindexitem;arg:pointer);
  673. begin
  674. if (aso_alloconly in tasmsection(p).secoptions) then
  675. tasmsection(p).datapos:=paint(arg)^
  676. else
  677. tasmsection(p).setdatapos(paint(arg)^);
  678. end;
  679. procedure telf32objectoutput.section_relocsec_set_datapos(p:tnamedindexitem;arg:pointer);
  680. begin
  681. if assigned(telf32section(p).relocsect) then
  682. telf32section(p).relocsect.setdatapos(paint(arg)^);
  683. end;
  684. procedure telf32objectoutput.section_write_data(p:tnamedindexitem;arg:pointer);
  685. begin
  686. if (aso_alloconly in tasmsection(p).secoptions) then
  687. exit;
  688. if tasmsection(p).data=nil then
  689. internalerror(200403073);
  690. writesectiondata(telf32section(p));
  691. end;
  692. procedure telf32objectoutput.section_write_sechdr(p:tnamedindexitem;arg:pointer);
  693. begin
  694. writesectionheader(telf32section(p));
  695. if assigned(telf32section(p).relocsect) then
  696. writesectionheader(telf32section(p).relocsect);
  697. end;
  698. procedure telf32objectoutput.section_write_relocsec(p:tnamedindexitem;arg:pointer);
  699. begin
  700. if assigned(telf32section(p).relocsect) then
  701. writesectiondata(telf32section(p).relocsect);
  702. end;
  703. function telf32objectoutput.writedata(data:TAsmObjectData):boolean;
  704. var
  705. header : telf32header;
  706. datapos : aint;
  707. shoffset,
  708. nsects : longint;
  709. hstab : telf32stab;
  710. empty : array[0..63] of byte;
  711. begin
  712. result:=false;
  713. elf32data:=telf32objectdata(data);
  714. with elf32data do
  715. begin
  716. { calc amount of sections we have }
  717. initsym:=2;
  718. nsects:=1;
  719. fillchar(empty,sizeof(empty),0);
  720. { each section requires a symbol for relocation }
  721. sects.foreach(@section_number_symbol,@initsym);
  722. { also create the index in the section header table }
  723. sects.foreach(@section_count_sects,@nsects);
  724. { add default sections follows }
  725. shstrtabsect.secshidx:=nsects;
  726. inc(nsects);
  727. symtabsect.secshidx:=nsects;
  728. inc(nsects);
  729. strtabsect.secshidx:=nsects;
  730. inc(nsects);
  731. { For the stab section we need an HdrSym which can now be
  732. calculated more easily }
  733. if assigned(stabssec) then
  734. begin
  735. hstab.strpos:=1;
  736. hstab.ntype:=0;
  737. hstab.nother:=0;
  738. hstab.ndesc:=(stabssec.datasize div sizeof(telf32stab))-1{+1 according to gas output PM};
  739. hstab.nvalue:=stabstrsec.datasize;
  740. stabssec.Data.seek(0);
  741. stabssec.Data.write(hstab,sizeof(hstab));
  742. end;
  743. { Create the relocation sections }
  744. sects.foreach(@section_create_relocsec,nil);
  745. { create .symtab and .strtab }
  746. createsymtab;
  747. { create .shstrtab }
  748. createshstrtab;
  749. { Calculate the filepositions }
  750. datapos:=$40; { elfheader + alignment }
  751. { sections first }
  752. sects.foreach(@section_set_datapos,@datapos);
  753. { shstrtab }
  754. shstrtabsect.setdatapos(datapos);
  755. { section headers }
  756. shoffset:=datapos;
  757. inc(datapos,nsects*sizeof(telf32sechdr));
  758. { symtab }
  759. symtabsect.setdatapos(datapos);
  760. { strtab }
  761. strtabsect.setdatapos(datapos);
  762. { .rel sections }
  763. sects.foreach(@section_relocsec_set_datapos,@datapos);
  764. { Write ELF Header }
  765. fillchar(header,sizeof(header),0);
  766. header.magic0123:=$464c457f; { = #127'ELF' }
  767. header.file_class:=1;
  768. header.data_encoding:=1;
  769. header.file_version:=1;
  770. header.e_type:=1;
  771. header.e_machine:=3;
  772. header.e_version:=1;
  773. header.e_shoff:=shoffset;
  774. header.e_shstrndx:=shstrtabsect.secshidx;
  775. header.e_shnum:=nsects;
  776. header.e_ehsize:=sizeof(telf32header);
  777. header.e_shentsize:=sizeof(telf32sechdr);
  778. writer.write(header,sizeof(header));
  779. writer.write(empty,$40-sizeof(header)); { align }
  780. { Sections }
  781. sects.foreach(@section_write_data,nil);
  782. { .shstrtab }
  783. writesectiondata(shstrtabsect);
  784. { section headers, start with an empty header for sh_undef }
  785. writer.write(empty,sizeof(telf32sechdr));
  786. sects.foreach(@section_write_sechdr,nil);
  787. writesectionheader(shstrtabsect);
  788. writesectionheader(symtabsect);
  789. writesectionheader(strtabsect);
  790. { .symtab }
  791. writesectiondata(symtabsect);
  792. { .strtab }
  793. writesectiondata(strtabsect);
  794. { .rel sections }
  795. sects.foreach(@section_write_relocsec,nil);
  796. end;
  797. result:=true;
  798. end;
  799. {****************************************************************************
  800. TELFAssembler
  801. ****************************************************************************}
  802. constructor TELF32Assembler.Create(smart:boolean);
  803. begin
  804. inherited Create(smart);
  805. objectoutput:=telf32objectoutput.create(smart);
  806. end;
  807. {*****************************************************************************
  808. Initialize
  809. *****************************************************************************}
  810. const
  811. as_i386_elf32_info : tasminfo =
  812. (
  813. id : as_i386_elf32;
  814. idtxt : 'ELF';
  815. asmbin : '';
  816. asmcmd : '';
  817. supported_target : system_any; //target_i386_linux;
  818. flags : [af_outputbinary,af_smartlink_sections];
  819. labelprefix : '.L';
  820. comment : '';
  821. );
  822. initialization
  823. RegisterAssembler(as_i386_elf32_info,TElf32Assembler);
  824. end.