ogwasm.pas 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336
  1. {
  2. Copyright (c) 2021 by Nikolay Nikolov
  3. Contains the WebAssembly binary module format reader and writer
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program; if not, write to the Free Software
  14. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  15. ****************************************************************************
  16. }
  17. unit ogwasm;
  18. {$i fpcdefs.inc}
  19. interface
  20. uses
  21. { common }
  22. globtype,
  23. { target }
  24. systems,
  25. { assembler }
  26. aasmbase,assemble,
  27. { WebAssembly module format definitions }
  28. wasmbase,
  29. { output }
  30. ogbase,
  31. owbase;
  32. type
  33. { TWasmObjSection }
  34. TWasmObjSection = class(TObjSection)
  35. public
  36. SegIdx: Integer;
  37. function IsCode: Boolean;
  38. function IsData: Boolean;
  39. end;
  40. { TWasmObjData }
  41. TWasmObjData = class(TObjData)
  42. private
  43. function is_smart_section(atype:TAsmSectiontype):boolean;
  44. function sectionname_gas(atype:TAsmSectiontype;const aname:string;aorder:TAsmSectionOrder):string;
  45. public
  46. constructor create(const n:string);override;
  47. function sectionname(atype:TAsmSectiontype;const aname:string;aorder:TAsmSectionOrder):string;override;
  48. procedure writeReloc(Data:TRelocDataInt;len:aword;p:TObjSymbol;Reloctype:TObjRelocationType);override;
  49. end;
  50. { TWasmObjOutput }
  51. TWasmObjOutput = class(tObjOutput)
  52. protected
  53. function writeData(Data:TObjData):boolean;override;
  54. public
  55. constructor create(AWriter:TObjectWriter);override;
  56. end;
  57. { TWasmAssembler }
  58. TWasmAssembler = class(tinternalassembler)
  59. constructor create(info: pasminfo; smart:boolean);override;
  60. end;
  61. implementation
  62. {****************************************************************************
  63. TWasmObjSection
  64. ****************************************************************************}
  65. function TWasmObjSection.IsCode: Boolean;
  66. const
  67. CodePrefix = '.text';
  68. begin
  69. result:=(Length(Name)>=Length(CodePrefix)) and
  70. (Copy(Name,1,Length(CodePrefix))=CodePrefix);
  71. end;
  72. function TWasmObjSection.IsData: Boolean;
  73. begin
  74. result:=not IsCode;
  75. end;
  76. {****************************************************************************
  77. TWasmObjData
  78. ****************************************************************************}
  79. function TWasmObjData.is_smart_section(atype: TAsmSectiontype): boolean;
  80. begin
  81. { For bss we need to set some flags that are target dependent,
  82. it is easier to disable it for smartlinking. It doesn't take up
  83. filespace }
  84. result:=not(target_info.system in systems_darwin) and
  85. create_smartlink_sections and
  86. (atype<>sec_toc) and
  87. (atype<>sec_user) and
  88. { on embedded systems every byte counts, so smartlink bss too }
  89. ((atype<>sec_bss) or (target_info.system in (systems_embedded+systems_freertos)));
  90. end;
  91. function TWasmObjData.sectionname_gas(atype: TAsmSectiontype;
  92. const aname: string; aorder: TAsmSectionOrder): string;
  93. const
  94. secnames : array[TAsmSectiontype] of string[length('__DATA, __datacoal_nt,coalesced')] = ('','',
  95. '.text',
  96. '.data',
  97. { why doesn't .rodata work? (FK) }
  98. { sometimes we have to create a data.rel.ro instead of .rodata, e.g. for }
  99. { vtables (and anything else containing relocations), otherwise those are }
  100. { not relocated properly on e.g. linux/ppc64. g++ generates there for a }
  101. { vtable for a class called Window: }
  102. { .section .data.rel.ro._ZTV6Window,"awG",@progbits,_ZTV6Window,comdat }
  103. { TODO: .data.ro not yet working}
  104. {$if defined(arm) or defined(riscv64) or defined(powerpc)}
  105. '.rodata',
  106. {$else defined(arm) or defined(riscv64) or defined(powerpc)}
  107. '.data',
  108. {$endif defined(arm) or defined(riscv64) or defined(powerpc)}
  109. '.rodata',
  110. '.bss',
  111. '.threadvar',
  112. '.pdata',
  113. '', { stubs }
  114. '__DATA,__nl_symbol_ptr',
  115. '__DATA,__la_symbol_ptr',
  116. '__DATA,__mod_init_func',
  117. '__DATA,__mod_term_func',
  118. '.stab',
  119. '.stabstr',
  120. '.idata$2','.idata$4','.idata$5','.idata$6','.idata$7','.edata',
  121. '.eh_frame',
  122. '.debug_frame','.debug_info','.debug_line','.debug_abbrev','.debug_aranges','.debug_ranges',
  123. '.fpc',
  124. '.toc',
  125. '.init',
  126. '.fini',
  127. '.objc_class',
  128. '.objc_meta_class',
  129. '.objc_cat_cls_meth',
  130. '.objc_cat_inst_meth',
  131. '.objc_protocol',
  132. '.objc_string_object',
  133. '.objc_cls_meth',
  134. '.objc_inst_meth',
  135. '.objc_cls_refs',
  136. '.objc_message_refs',
  137. '.objc_symbols',
  138. '.objc_category',
  139. '.objc_class_vars',
  140. '.objc_instance_vars',
  141. '.objc_module_info',
  142. '.objc_class_names',
  143. '.objc_meth_var_types',
  144. '.objc_meth_var_names',
  145. '.objc_selector_strs',
  146. '.objc_protocol_ext',
  147. '.objc_class_ext',
  148. '.objc_property',
  149. '.objc_image_info',
  150. '.objc_cstring_object',
  151. '.objc_sel_fixup',
  152. '__DATA,__objc_data',
  153. '__DATA,__objc_const',
  154. '.objc_superrefs',
  155. '__DATA, __datacoal_nt,coalesced',
  156. '.objc_classlist',
  157. '.objc_nlclasslist',
  158. '.objc_catlist',
  159. '.obcj_nlcatlist',
  160. '.objc_protolist',
  161. '.stack',
  162. '.heap',
  163. '.gcc_except_table',
  164. '.ARM.attributes'
  165. );
  166. var
  167. sep : string[3];
  168. secname : string;
  169. begin
  170. secname:=secnames[atype];
  171. if (atype=sec_fpc) and (Copy(aname,1,3)='res') then
  172. begin
  173. result:=secname+'.'+aname;
  174. exit;
  175. end;
  176. if atype=sec_threadvar then
  177. begin
  178. if (target_info.system in (systems_windows+systems_wince)) then
  179. secname:='.tls'
  180. else if (target_info.system in systems_linux) then
  181. secname:='.tbss';
  182. end;
  183. { go32v2 stub only loads .text and .data sections, and allocates space for .bss.
  184. Thus, data which normally goes into .rodata and .rodata_norel sections must
  185. end up in .data section }
  186. if (atype in [sec_rodata,sec_rodata_norel]) and
  187. (target_info.system in [system_i386_go32v2,system_m68k_palmos]) then
  188. secname:='.data';
  189. { Windows correctly handles reallocations in readonly sections }
  190. if (atype=sec_rodata) and
  191. (target_info.system in systems_all_windows+systems_nativent-[system_i8086_win16]) then
  192. secname:='.rodata';
  193. { section type user gives the user full controll on the section name }
  194. if atype=sec_user then
  195. secname:=aname;
  196. if is_smart_section(atype) and (aname<>'') then
  197. begin
  198. case aorder of
  199. secorder_begin :
  200. sep:='.b_';
  201. secorder_end :
  202. sep:='.z_';
  203. else
  204. sep:='.n_';
  205. end;
  206. result:=secname+sep+aname
  207. end
  208. else
  209. result:=secname;
  210. end;
  211. constructor TWasmObjData.create(const n: string);
  212. begin
  213. inherited;
  214. CObjSection:=TWasmObjSection;
  215. end;
  216. function TWasmObjData.sectionname(atype: TAsmSectiontype;
  217. const aname: string; aorder: TAsmSectionOrder): string;
  218. begin
  219. if (atype=sec_fpc) or (atype=sec_threadvar) then
  220. atype:=sec_data;
  221. Result:=sectionname_gas(atype, aname, aorder);
  222. end;
  223. procedure TWasmObjData.writeReloc(Data: TRelocDataInt; len: aword;
  224. p: TObjSymbol; Reloctype: TObjRelocationType);
  225. begin
  226. end;
  227. {****************************************************************************
  228. TWasmObjOutput
  229. ****************************************************************************}
  230. function TWasmObjOutput.writeData(Data:TObjData):boolean;
  231. var
  232. i: Integer;
  233. objsec: TWasmObjSection;
  234. segment_count: Integer = 0;
  235. begin
  236. for i:=0 to Data.ObjSectionList.Count-1 do
  237. begin
  238. objsec:=TWasmObjSection(Data.ObjSectionList[i]);
  239. if objsec.IsCode then
  240. objsec.SegIdx:=-1
  241. else
  242. begin
  243. objsec.SegIdx:=segment_count;
  244. Inc(segment_count);
  245. end;
  246. end;
  247. Writer.write(WasmModuleMagic,SizeOf(WasmModuleMagic));
  248. Writer.write(WasmVersion,SizeOf(WasmVersion));
  249. Writeln('ObjSectionList:');
  250. for i:=0 to Data.ObjSectionList.Count-1 do
  251. begin
  252. objsec:=TWasmObjSection(Data.ObjSectionList[i]);
  253. Writeln(objsec.Name, ' IsCode=', objsec.IsCode, ' IsData=', objsec.IsData, ' Size=', objsec.Size, ' MemPos=', objsec.MemPos, ' Data.Size=', objsec.Data.size, ' DataPos=', objsec.DataPos, ' SegIdx=', objsec.SegIdx);
  254. end;
  255. result:=true;
  256. end;
  257. constructor TWasmObjOutput.create(AWriter: TObjectWriter);
  258. begin
  259. inherited;
  260. cobjdata:=TWasmObjData;
  261. end;
  262. {****************************************************************************
  263. TWasmAssembler
  264. ****************************************************************************}
  265. constructor TWasmAssembler.Create(info: pasminfo; smart:boolean);
  266. begin
  267. inherited;
  268. CObjOutput:=TWasmObjOutput;
  269. end;
  270. {*****************************************************************************
  271. Initialize
  272. *****************************************************************************}
  273. {$ifdef wasm32}
  274. const
  275. as_wasm32_wasm_info : tasminfo =
  276. (
  277. id : as_wasm32_wasm;
  278. idtxt : 'OMF';
  279. asmbin : '';
  280. asmcmd : '';
  281. supported_targets : [system_wasm32_embedded,system_wasm32_wasi];
  282. flags : [af_outputbinary,af_smartlink_sections];
  283. labelprefix : '..@';
  284. labelmaxlen : -1;
  285. comment : '; ';
  286. dollarsign: '$';
  287. );
  288. {$endif wasm32}
  289. initialization
  290. {$ifdef wasm32}
  291. RegisterAssembler(as_wasm32_wasm_info,TWasmAssembler);
  292. {$endif wasm32}
  293. end.