ogwasm.pas 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979
  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. cclasses,globtype,
  23. { target }
  24. systems,cpubase,
  25. { assembler }
  26. aasmbase,assemble,aasmcpu,
  27. { WebAssembly module format definitions }
  28. wasmbase,
  29. { output }
  30. ogbase,
  31. owbase;
  32. type
  33. { TWasmObjSymbol }
  34. TWasmObjSymbol = class(TObjSymbol)
  35. ImportIndex: Integer;
  36. FuncIndex: Integer;
  37. constructor create(AList:TFPHashObjectList;const AName:string);
  38. end;
  39. { TWasmObjRelocation }
  40. TWasmObjRelocation = class(TObjRelocation)
  41. end;
  42. { TWasmObjSymbolExtraData }
  43. TWasmObjSymbolExtraData = class(TFPHashObject)
  44. TypeIdx: Integer;
  45. ImportModule: string;
  46. ImportName: string;
  47. Locals: array of TWasmBasicType;
  48. constructor Create(HashObjectList: TFPHashObjectList; const s: TSymStr);
  49. procedure AddLocal(bastyp: TWasmBasicType);
  50. end;
  51. { TWasmObjSection }
  52. TWasmObjSection = class(TObjSection)
  53. public
  54. SegIdx: Integer;
  55. SegOfs: qword;
  56. function IsCode: Boolean;
  57. function IsData: Boolean;
  58. end;
  59. { TWasmObjData }
  60. TWasmObjData = class(TObjData)
  61. private
  62. FFuncTypes: array of TWasmFuncType;
  63. FObjSymbolsExtraDataList: TFPHashObjectList;
  64. FLastFuncName: string;
  65. function is_smart_section(atype:TAsmSectiontype):boolean;
  66. function sectionname_gas(atype:TAsmSectiontype;const aname:string;aorder:TAsmSectionOrder):string;
  67. public
  68. constructor create(const n:string);override;
  69. destructor destroy; override;
  70. function sectionname(atype:TAsmSectiontype;const aname:string;aorder:TAsmSectionOrder):string;override;
  71. procedure writeReloc(Data:TRelocDataInt;len:aword;p:TObjSymbol;Reloctype:TObjRelocationType);override;
  72. function AddOrCreateObjSymbolExtraData(const symname:TSymStr): TWasmObjSymbolExtraData;
  73. function AddFuncType(wft: TWasmFuncType): integer;
  74. procedure DeclareFuncType(ft: tai_functype);
  75. procedure DeclareImportModule(aim: tai_import_module);
  76. procedure DeclareImportName(ain: tai_import_name);
  77. procedure DeclareLocal(al: tai_local);
  78. end;
  79. { TWasmObjOutput }
  80. TWasmObjOutput = class(tObjOutput)
  81. private
  82. FData: TWasmObjData;
  83. FWasmRelocationCodeTable: tdynamicarray;
  84. FWasmRelocationCodeTableEntriesCount: Integer;
  85. FWasmRelocationDataTable: tdynamicarray;
  86. FWasmRelocationDataTableEntriesCount: Integer;
  87. FWasmSymbolTable: tdynamicarray;
  88. FWasmSymbolTableEntriesCount: Integer;
  89. FWasmSections: array [TWasmSectionID] of tdynamicarray;
  90. FWasmCustomSections: array [TWasmCustomSectionType] of tdynamicarray;
  91. FWasmLinkingSubsections: array [low(TWasmLinkingSubsectionType)..high(TWasmLinkingSubsectionType)] of tdynamicarray;
  92. procedure WriteUleb(d: tdynamicarray; v: uint64);
  93. procedure WriteUleb(w: TObjectWriter; v: uint64);
  94. procedure WriteSleb(d: tdynamicarray; v: int64);
  95. procedure WriteByte(d: tdynamicarray; b: byte);
  96. procedure WriteName(d: tdynamicarray; const s: string);
  97. procedure WriteWasmSection(wsid: TWasmSectionID);
  98. procedure WriteWasmCustomSection(wcst: TWasmCustomSectionType);
  99. procedure CopyDynamicArray(src, dest: tdynamicarray; size: QWord);
  100. procedure WriteZeros(dest: tdynamicarray; size: QWord);
  101. procedure WriteWasmResultType(dest: tdynamicarray; wrt: TWasmResultType);
  102. procedure WriteWasmBasicType(dest: tdynamicarray; wbt: TWasmBasicType);
  103. function IsExternalFunction(sym: TObjSymbol): Boolean;
  104. procedure WriteFunctionLocals(dest: tdynamicarray; ed: TWasmObjSymbolExtraData);
  105. procedure WriteFunctionCode(dest: tdynamicarray; objsym: TObjSymbol);
  106. procedure WriteSymbolTable;
  107. procedure WriteRelocationCodeTable(CodeSectionIndex: Integer);
  108. procedure WriteRelocationDataTable(DataSectionIndex: Integer);
  109. procedure WriteLinkingSubsection(wlst: TWasmLinkingSubsectionType);
  110. protected
  111. function writeData(Data:TObjData):boolean;override;
  112. public
  113. constructor create(AWriter:TObjectWriter);override;
  114. destructor destroy;override;
  115. end;
  116. { TWasmAssembler }
  117. TWasmAssembler = class(tinternalassembler)
  118. constructor create(info: pasminfo; smart:boolean);override;
  119. end;
  120. implementation
  121. uses
  122. verbose;
  123. {****************************************************************************
  124. TWasmObjSymbol
  125. ****************************************************************************}
  126. constructor TWasmObjSymbol.create(AList: TFPHashObjectList; const AName: string);
  127. begin
  128. inherited create(AList,AName);
  129. ImportIndex:=-1;
  130. FuncIndex:=-1;
  131. end;
  132. {****************************************************************************
  133. TWasmObjSymbolExtraData
  134. ****************************************************************************}
  135. constructor TWasmObjSymbolExtraData.Create(HashObjectList: TFPHashObjectList; const s: TSymStr);
  136. begin
  137. inherited Create(HashObjectList,s);
  138. TypeIdx:=-1;
  139. end;
  140. procedure TWasmObjSymbolExtraData.AddLocal(bastyp: TWasmBasicType);
  141. begin
  142. SetLength(Locals,Length(Locals)+1);
  143. Locals[High(Locals)]:=bastyp;
  144. end;
  145. {****************************************************************************
  146. TWasmObjSection
  147. ****************************************************************************}
  148. function TWasmObjSection.IsCode: Boolean;
  149. const
  150. CodePrefix = '.text';
  151. begin
  152. result:=(Length(Name)>=Length(CodePrefix)) and
  153. (Copy(Name,1,Length(CodePrefix))=CodePrefix);
  154. end;
  155. function TWasmObjSection.IsData: Boolean;
  156. begin
  157. result:=not IsCode;
  158. end;
  159. {****************************************************************************
  160. TWasmObjData
  161. ****************************************************************************}
  162. function TWasmObjData.is_smart_section(atype: TAsmSectiontype): boolean;
  163. begin
  164. { For bss we need to set some flags that are target dependent,
  165. it is easier to disable it for smartlinking. It doesn't take up
  166. filespace }
  167. result:=not(target_info.system in systems_darwin) and
  168. create_smartlink_sections and
  169. (atype<>sec_toc) and
  170. (atype<>sec_user) and
  171. { on embedded systems every byte counts, so smartlink bss too }
  172. ((atype<>sec_bss) or (target_info.system in (systems_embedded+systems_freertos)));
  173. end;
  174. function TWasmObjData.sectionname_gas(atype: TAsmSectiontype;
  175. const aname: string; aorder: TAsmSectionOrder): string;
  176. const
  177. secnames : array[TAsmSectiontype] of string[length('__DATA, __datacoal_nt,coalesced')] = ('','',
  178. '.text',
  179. '.data',
  180. { why doesn't .rodata work? (FK) }
  181. { sometimes we have to create a data.rel.ro instead of .rodata, e.g. for }
  182. { vtables (and anything else containing relocations), otherwise those are }
  183. { not relocated properly on e.g. linux/ppc64. g++ generates there for a }
  184. { vtable for a class called Window: }
  185. { .section .data.rel.ro._ZTV6Window,"awG",@progbits,_ZTV6Window,comdat }
  186. { TODO: .data.ro not yet working}
  187. {$if defined(arm) or defined(riscv64) or defined(powerpc)}
  188. '.rodata',
  189. {$else defined(arm) or defined(riscv64) or defined(powerpc)}
  190. '.data',
  191. {$endif defined(arm) or defined(riscv64) or defined(powerpc)}
  192. '.rodata',
  193. '.bss',
  194. '.threadvar',
  195. '.pdata',
  196. '', { stubs }
  197. '__DATA,__nl_symbol_ptr',
  198. '__DATA,__la_symbol_ptr',
  199. '__DATA,__mod_init_func',
  200. '__DATA,__mod_term_func',
  201. '.stab',
  202. '.stabstr',
  203. '.idata$2','.idata$4','.idata$5','.idata$6','.idata$7','.edata',
  204. '.eh_frame',
  205. '.debug_frame','.debug_info','.debug_line','.debug_abbrev','.debug_aranges','.debug_ranges',
  206. '.fpc',
  207. '.toc',
  208. '.init',
  209. '.fini',
  210. '.objc_class',
  211. '.objc_meta_class',
  212. '.objc_cat_cls_meth',
  213. '.objc_cat_inst_meth',
  214. '.objc_protocol',
  215. '.objc_string_object',
  216. '.objc_cls_meth',
  217. '.objc_inst_meth',
  218. '.objc_cls_refs',
  219. '.objc_message_refs',
  220. '.objc_symbols',
  221. '.objc_category',
  222. '.objc_class_vars',
  223. '.objc_instance_vars',
  224. '.objc_module_info',
  225. '.objc_class_names',
  226. '.objc_meth_var_types',
  227. '.objc_meth_var_names',
  228. '.objc_selector_strs',
  229. '.objc_protocol_ext',
  230. '.objc_class_ext',
  231. '.objc_property',
  232. '.objc_image_info',
  233. '.objc_cstring_object',
  234. '.objc_sel_fixup',
  235. '__DATA,__objc_data',
  236. '__DATA,__objc_const',
  237. '.objc_superrefs',
  238. '__DATA, __datacoal_nt,coalesced',
  239. '.objc_classlist',
  240. '.objc_nlclasslist',
  241. '.objc_catlist',
  242. '.obcj_nlcatlist',
  243. '.objc_protolist',
  244. '.stack',
  245. '.heap',
  246. '.gcc_except_table',
  247. '.ARM.attributes'
  248. );
  249. var
  250. sep : string[3];
  251. secname : string;
  252. begin
  253. secname:=secnames[atype];
  254. if (atype=sec_fpc) and (Copy(aname,1,3)='res') then
  255. begin
  256. result:=secname+'.'+aname;
  257. exit;
  258. end;
  259. if atype=sec_threadvar then
  260. begin
  261. if (target_info.system in (systems_windows+systems_wince)) then
  262. secname:='.tls'
  263. else if (target_info.system in systems_linux) then
  264. secname:='.tbss';
  265. end;
  266. { go32v2 stub only loads .text and .data sections, and allocates space for .bss.
  267. Thus, data which normally goes into .rodata and .rodata_norel sections must
  268. end up in .data section }
  269. if (atype in [sec_rodata,sec_rodata_norel]) and
  270. (target_info.system in [system_i386_go32v2,system_m68k_palmos]) then
  271. secname:='.data';
  272. { Windows correctly handles reallocations in readonly sections }
  273. if (atype=sec_rodata) and
  274. (target_info.system in systems_all_windows+systems_nativent-[system_i8086_win16]) then
  275. secname:='.rodata';
  276. { section type user gives the user full controll on the section name }
  277. if atype=sec_user then
  278. secname:=aname;
  279. if is_smart_section(atype) and (aname<>'') then
  280. begin
  281. case aorder of
  282. secorder_begin :
  283. sep:='.b_';
  284. secorder_end :
  285. sep:='.z_';
  286. else
  287. sep:='.n_';
  288. end;
  289. result:=secname+sep+aname
  290. end
  291. else
  292. result:=secname;
  293. end;
  294. constructor TWasmObjData.create(const n: string);
  295. begin
  296. inherited;
  297. CObjSection:=TWasmObjSection;
  298. CObjSymbol:=TWasmObjSymbol;
  299. FObjSymbolsExtraDataList:=TFPHashObjectList.Create;
  300. end;
  301. destructor TWasmObjData.destroy;
  302. var
  303. i: Integer;
  304. begin
  305. FObjSymbolsExtraDataList.Free;
  306. for i:=low(FFuncTypes) to high(FFuncTypes) do
  307. begin
  308. FFuncTypes[i].free;
  309. FFuncTypes[i]:=nil;
  310. end;
  311. inherited destroy;
  312. end;
  313. function TWasmObjData.sectionname(atype: TAsmSectiontype;
  314. const aname: string; aorder: TAsmSectionOrder): string;
  315. begin
  316. if (atype=sec_fpc) or (atype=sec_threadvar) then
  317. atype:=sec_data;
  318. Result:=sectionname_gas(atype, aname, aorder);
  319. end;
  320. procedure TWasmObjData.writeReloc(Data: TRelocDataInt; len: aword;
  321. p: TObjSymbol; Reloctype: TObjRelocationType);
  322. const
  323. leb_zero: array[0..4] of byte=($80,$80,$80,$80,$00);
  324. var
  325. objreloc: TWasmObjRelocation;
  326. begin
  327. if CurrObjSec=nil then
  328. internalerror(200403072);
  329. objreloc:=nil;
  330. case Reloctype of
  331. RELOC_FUNCTION_INDEX_LEB:
  332. begin
  333. if Data<>0 then
  334. internalerror(2021092502);
  335. if len<>5 then
  336. internalerror(2021092503);
  337. if not assigned(p) then
  338. internalerror(2021092504);
  339. if p.bind<>AB_EXTERNAL then
  340. internalerror(2021092505);
  341. objreloc:=TWasmObjRelocation.CreateSymbol(CurrObjSec.Size,p,Reloctype);
  342. CurrObjSec.ObjRelocations.Add(objreloc);
  343. writebytes(leb_zero,5);
  344. end;
  345. RELOC_ABSOLUTE:
  346. begin
  347. { todo... }
  348. end;
  349. else
  350. internalerror(2021092501);
  351. end;
  352. end;
  353. function TWasmObjData.AddOrCreateObjSymbolExtraData(const symname: TSymStr): TWasmObjSymbolExtraData;
  354. begin
  355. result:=TWasmObjSymbolExtraData(FObjSymbolsExtraDataList.Find(symname));
  356. if not assigned(result) then
  357. result:=TWasmObjSymbolExtraData.Create(FObjSymbolsExtraDataList,symname);
  358. end;
  359. function TWasmObjData.AddFuncType(wft: TWasmFuncType): integer;
  360. var
  361. i: Integer;
  362. begin
  363. for i:=low(FFuncTypes) to high(FFuncTypes) do
  364. if wft.Equals(FFuncTypes[i]) then
  365. exit(i);
  366. result:=Length(FFuncTypes);
  367. SetLength(FFuncTypes,result+1);
  368. FFuncTypes[result]:=TWasmFuncType.Create(wft);
  369. end;
  370. procedure TWasmObjData.DeclareFuncType(ft: tai_functype);
  371. var
  372. i: Integer;
  373. ObjSymExtraData: TWasmObjSymbolExtraData;
  374. begin
  375. FLastFuncName:=ft.funcname;
  376. i:=AddFuncType(ft.functype);
  377. ObjSymExtraData:=AddOrCreateObjSymbolExtraData(ft.funcname);
  378. ObjSymExtraData.TypeIdx:=i;
  379. end;
  380. procedure TWasmObjData.DeclareImportModule(aim: tai_import_module);
  381. var
  382. ObjSymExtraData: TWasmObjSymbolExtraData;
  383. begin
  384. ObjSymExtraData:=AddOrCreateObjSymbolExtraData(aim.symname);
  385. ObjSymExtraData.ImportModule:=aim.importmodule;
  386. end;
  387. procedure TWasmObjData.DeclareImportName(ain: tai_import_name);
  388. var
  389. ObjSymExtraData: TWasmObjSymbolExtraData;
  390. begin
  391. ObjSymExtraData:=AddOrCreateObjSymbolExtraData(ain.symname);
  392. ObjSymExtraData.ImportName:=ain.importname;
  393. end;
  394. procedure TWasmObjData.DeclareLocal(al: tai_local);
  395. var
  396. ObjSymExtraData: TWasmObjSymbolExtraData;
  397. begin
  398. ObjSymExtraData:=TWasmObjSymbolExtraData(FObjSymbolsExtraDataList.Find(FLastFuncName));
  399. ObjSymExtraData.AddLocal(al.bastyp);
  400. end;
  401. {****************************************************************************
  402. TWasmObjOutput
  403. ****************************************************************************}
  404. procedure TWasmObjOutput.WriteUleb(d: tdynamicarray; v: uint64);
  405. var
  406. b: byte;
  407. begin
  408. repeat
  409. b:=byte(v) and 127;
  410. v:=v shr 7;
  411. if v<>0 then
  412. b:=b or 128;
  413. d.write(b,1);
  414. until v=0;
  415. end;
  416. procedure TWasmObjOutput.WriteUleb(w: TObjectWriter; v: uint64);
  417. var
  418. b: byte;
  419. begin
  420. repeat
  421. b:=byte(v) and 127;
  422. v:=v shr 7;
  423. if v<>0 then
  424. b:=b or 128;
  425. w.write(b,1);
  426. until v=0;
  427. end;
  428. procedure TWasmObjOutput.WriteSleb(d: tdynamicarray; v: int64);
  429. var
  430. b: byte;
  431. Done: Boolean=false;
  432. begin
  433. repeat
  434. b:=byte(v) and 127;
  435. v:=SarInt64(v,7);
  436. if ((v=0) and ((b and 64)=0)) or ((v=-1) and ((b and 64)<>0)) then
  437. Done:=true
  438. else
  439. b:=b or 128;
  440. d.write(b,1);
  441. until Done;
  442. end;
  443. procedure TWasmObjOutput.WriteByte(d: tdynamicarray; b: byte);
  444. begin
  445. d.write(b,1);
  446. end;
  447. procedure TWasmObjOutput.WriteName(d: tdynamicarray; const s: string);
  448. begin
  449. WriteUleb(d,Length(s));
  450. d.writestr(s);
  451. end;
  452. procedure TWasmObjOutput.WriteWasmSection(wsid: TWasmSectionID);
  453. var
  454. b: byte;
  455. begin
  456. b:=ord(wsid);
  457. Writer.write(b,1);
  458. WriteUleb(Writer,FWasmSections[wsid].size);
  459. Writer.writearray(FWasmSections[wsid]);
  460. end;
  461. procedure TWasmObjOutput.WriteWasmCustomSection(wcst: TWasmCustomSectionType);
  462. var
  463. b: byte;
  464. begin
  465. b:=0;
  466. Writer.write(b,1);
  467. WriteUleb(Writer,FWasmCustomSections[wcst].size);
  468. Writer.writearray(FWasmCustomSections[wcst]);
  469. end;
  470. procedure TWasmObjOutput.CopyDynamicArray(src, dest: tdynamicarray; size: QWord);
  471. var
  472. buf: array [0..4095] of byte;
  473. bs: Integer;
  474. begin
  475. while size>0 do
  476. begin
  477. if size<SizeOf(buf) then
  478. bs:=Integer(size)
  479. else
  480. bs:=SizeOf(buf);
  481. src.read(buf,bs);
  482. dest.write(buf,bs);
  483. dec(size,bs);
  484. end;
  485. end;
  486. procedure TWasmObjOutput.WriteZeros(dest: tdynamicarray; size: QWord);
  487. var
  488. buf : array[0..1023] of byte;
  489. bs: Integer;
  490. begin
  491. fillchar(buf,sizeof(buf),0);
  492. while size>0 do
  493. begin
  494. if size<SizeOf(buf) then
  495. bs:=Integer(size)
  496. else
  497. bs:=SizeOf(buf);
  498. dest.write(buf,bs);
  499. dec(size,bs);
  500. end;
  501. end;
  502. procedure TWasmObjOutput.WriteWasmResultType(dest: tdynamicarray; wrt: TWasmResultType);
  503. var
  504. i: Integer;
  505. begin
  506. WriteUleb(dest,Length(wrt));
  507. for i:=low(wrt) to high(wrt) do
  508. WriteWasmBasicType(dest,wrt[i]);
  509. end;
  510. procedure TWasmObjOutput.WriteWasmBasicType(dest: tdynamicarray; wbt: TWasmBasicType);
  511. begin
  512. case wbt of
  513. wbt_i32:
  514. WriteByte(dest,$7F);
  515. wbt_i64:
  516. WriteByte(dest,$7E);
  517. wbt_f32:
  518. WriteByte(dest,$7D);
  519. wbt_f64:
  520. WriteByte(dest,$7C);
  521. end;
  522. end;
  523. function TWasmObjOutput.IsExternalFunction(sym: TObjSymbol): Boolean;
  524. begin
  525. result:=(sym.bind=AB_EXTERNAL) and (TWasmObjData(sym.ObjData).FObjSymbolsExtraDataList.Find(sym.Name)<>nil);
  526. end;
  527. procedure TWasmObjOutput.WriteFunctionLocals(dest: tdynamicarray; ed: TWasmObjSymbolExtraData);
  528. var
  529. i,
  530. rle_entries,
  531. cnt: Integer;
  532. lasttype: TWasmBasicType;
  533. begin
  534. if Length(ed.Locals)=0 then
  535. begin
  536. WriteUleb(dest,0);
  537. exit;
  538. end;
  539. rle_entries:=1;
  540. for i:=low(ed.Locals)+1 to high(ed.Locals) do
  541. if ed.Locals[i]<>ed.Locals[i-1] then
  542. inc(rle_entries);
  543. WriteUleb(dest,rle_entries);
  544. lasttype:=ed.Locals[Low(ed.Locals)];
  545. cnt:=1;
  546. for i:=low(ed.Locals)+1 to high(ed.Locals) do
  547. if ed.Locals[i]=ed.Locals[i-1] then
  548. inc(cnt)
  549. else
  550. begin
  551. WriteUleb(dest,cnt);
  552. WriteWasmBasicType(dest,lasttype);
  553. lasttype:=ed.Locals[i];
  554. cnt:=1;
  555. end;
  556. WriteUleb(dest,cnt);
  557. WriteWasmBasicType(dest,lasttype);
  558. end;
  559. procedure TWasmObjOutput.WriteFunctionCode(dest: tdynamicarray; objsym: TObjSymbol);
  560. var
  561. encoded_locals: tdynamicarray;
  562. ObjSymExtraData: TWasmObjSymbolExtraData;
  563. codelen: LongWord;
  564. ObjSection: TObjSection;
  565. codeexprlen: QWord;
  566. begin
  567. ObjSymExtraData:=TWasmObjSymbolExtraData(FData.FObjSymbolsExtraDataList.Find(objsym.Name));
  568. ObjSection:=objsym.objsection;
  569. ObjSection.Data.seek(objsym.address);
  570. codeexprlen:=ObjSection.Size-objsym.address;
  571. encoded_locals:=tdynamicarray.Create(64);
  572. WriteFunctionLocals(encoded_locals,ObjSymExtraData);
  573. codelen:=encoded_locals.size+codeexprlen+1;
  574. WriteUleb(dest,codelen);
  575. encoded_locals.seek(0);
  576. CopyDynamicArray(encoded_locals,dest,encoded_locals.size);
  577. CopyDynamicArray(ObjSection.Data,dest,codeexprlen);
  578. WriteByte(dest,$0B);
  579. encoded_locals.Free;
  580. end;
  581. procedure TWasmObjOutput.WriteSymbolTable;
  582. begin
  583. WriteUleb(FWasmLinkingSubsections[WASM_SYMBOL_TABLE],FWasmSymbolTableEntriesCount);
  584. FWasmSymbolTable.seek(0);
  585. CopyDynamicArray(FWasmSymbolTable,FWasmLinkingSubsections[WASM_SYMBOL_TABLE],FWasmSymbolTable.size);
  586. end;
  587. procedure TWasmObjOutput.WriteRelocationCodeTable(CodeSectionIndex: Integer);
  588. begin
  589. WriteUleb(FWasmCustomSections[wcstRelocCode],CodeSectionIndex);
  590. WriteUleb(FWasmCustomSections[wcstRelocCode],FWasmRelocationCodeTableEntriesCount);
  591. FWasmRelocationCodeTable.seek(0);
  592. CopyDynamicArray(FWasmRelocationCodeTable,FWasmCustomSections[wcstRelocCode],FWasmRelocationCodeTable.size);
  593. end;
  594. procedure TWasmObjOutput.WriteRelocationDataTable(DataSectionIndex: Integer);
  595. begin
  596. WriteUleb(FWasmCustomSections[wcstRelocData],DataSectionIndex);
  597. WriteUleb(FWasmCustomSections[wcstRelocData],FWasmRelocationDataTableEntriesCount);
  598. FWasmRelocationDataTable.seek(0);
  599. CopyDynamicArray(FWasmRelocationDataTable,FWasmCustomSections[wcstRelocData],FWasmRelocationDataTable.size);
  600. end;
  601. procedure TWasmObjOutput.WriteLinkingSubsection(wlst: TWasmLinkingSubsectionType);
  602. begin
  603. if FWasmLinkingSubsections[wlst].size>0 then
  604. begin
  605. WriteByte(FWasmCustomSections[wcstLinking],Ord(wlst));
  606. WriteUleb(FWasmCustomSections[wcstLinking],FWasmLinkingSubsections[wlst].size);
  607. FWasmLinkingSubsections[wlst].seek(0);
  608. CopyDynamicArray(FWasmLinkingSubsections[wlst],FWasmCustomSections[wcstLinking],FWasmLinkingSubsections[wlst].size);
  609. end;
  610. end;
  611. function TWasmObjOutput.writeData(Data:TObjData):boolean;
  612. var
  613. i: Integer;
  614. objsec: TWasmObjSection;
  615. segment_count: Integer = 0;
  616. cur_seg_ofs: qword = 0;
  617. types_count,
  618. imports_count, NextImportFunctionIndex, NextFunctionIndex: Integer;
  619. import_functions_count: Integer = 0;
  620. functions_count: Integer = 0;
  621. objsym: TWasmObjSymbol;
  622. cust_sec: TWasmCustomSectionType;
  623. begin
  624. FData:=TWasmObjData(Data);
  625. { each custom sections starts with its name }
  626. for cust_sec in TWasmCustomSectionType do
  627. WriteName(FWasmCustomSections[cust_sec],WasmCustomSectionName[cust_sec]);
  628. WriteUleb(FWasmCustomSections[wcstLinking],2); { linking metadata version }
  629. for i:=0 to Data.ObjSymbolList.Count-1 do
  630. begin
  631. objsym:=TWasmObjSymbol(Data.ObjSymbolList[i]);
  632. if IsExternalFunction(objsym) then
  633. Inc(import_functions_count);
  634. if objsym.typ=AT_FUNCTION then
  635. Inc(functions_count);
  636. end;
  637. types_count:=Length(FData.FFuncTypes);
  638. WriteUleb(FWasmSections[wsiType],types_count);
  639. for i:=0 to types_count-1 do
  640. with FData.FFuncTypes[i] do
  641. begin
  642. WriteByte(FWasmSections[wsiType],$60);
  643. WriteWasmResultType(FWasmSections[wsiType],params);
  644. WriteWasmResultType(FWasmSections[wsiType],results);
  645. end;
  646. for i:=0 to Data.ObjSectionList.Count-1 do
  647. begin
  648. objsec:=TWasmObjSection(Data.ObjSectionList[i]);
  649. if objsec.IsCode then
  650. objsec.SegIdx:=-1
  651. else
  652. begin
  653. objsec.SegIdx:=segment_count;
  654. objsec.SegOfs:=cur_seg_ofs;
  655. Inc(segment_count);
  656. Inc(cur_seg_ofs,objsec.Size);
  657. end;
  658. end;
  659. WriteUleb(FWasmSections[wsiData],segment_count);
  660. WriteUleb(FWasmSections[wsiDataCount],segment_count);
  661. WriteUleb(FWasmLinkingSubsections[WASM_SEGMENT_INFO],segment_count);
  662. for i:=0 to Data.ObjSectionList.Count-1 do
  663. begin
  664. objsec:=TWasmObjSection(Data.ObjSectionList[i]);
  665. if objsec.IsData then
  666. begin
  667. WriteName(FWasmLinkingSubsections[WASM_SEGMENT_INFO],objsec.Name);
  668. WriteUleb(FWasmLinkingSubsections[WASM_SEGMENT_INFO],BsrQWord(objsec.SecAlign));
  669. WriteUleb(FWasmLinkingSubsections[WASM_SEGMENT_INFO],0); { flags }
  670. WriteByte(FWasmSections[wsiData],0);
  671. WriteByte(FWasmSections[wsiData],$41);
  672. WriteSleb(FWasmSections[wsiData],objsec.SegOfs);
  673. WriteByte(FWasmSections[wsiData],$0b);
  674. WriteUleb(FWasmSections[wsiData],objsec.Size);
  675. if oso_Data in objsec.SecOptions then
  676. begin
  677. objsec.Data.seek(0);
  678. CopyDynamicArray(objsec.Data,FWasmSections[wsiData],objsec.Size);
  679. end
  680. else
  681. begin
  682. WriteZeros(FWasmSections[wsiData],objsec.Size);
  683. end;
  684. end;
  685. end;
  686. imports_count:=3+import_functions_count;
  687. WriteUleb(FWasmSections[wsiImport],imports_count);
  688. { import[0] }
  689. WriteName(FWasmSections[wsiImport],'env');
  690. WriteName(FWasmSections[wsiImport],'__linear_memory');
  691. WriteByte(FWasmSections[wsiImport],$02); { mem }
  692. WriteByte(FWasmSections[wsiImport],$00); { min }
  693. WriteUleb(FWasmSections[wsiImport],1); { 1 page }
  694. { import[1] }
  695. WriteName(FWasmSections[wsiImport],'env');
  696. WriteName(FWasmSections[wsiImport],'__stack_pointer');
  697. WriteByte(FWasmSections[wsiImport],$03); { global }
  698. WriteByte(FWasmSections[wsiImport],$7F); { i32 }
  699. WriteByte(FWasmSections[wsiImport],$01); { var }
  700. { import[2]..import[imports_count-2] }
  701. NextImportFunctionIndex:=0;
  702. for i:=0 to Data.ObjSymbolList.Count-1 do
  703. begin
  704. objsym:=TWasmObjSymbol(Data.ObjSymbolList[i]);
  705. if IsExternalFunction(objsym) then
  706. begin
  707. objsym.ImportIndex:=NextImportFunctionIndex;
  708. Inc(NextImportFunctionIndex);
  709. WriteName(FWasmSections[wsiImport],'env');
  710. WriteName(FWasmSections[wsiImport],objsym.Name);
  711. WriteByte(FWasmSections[wsiImport],$00); { func }
  712. WriteUleb(FWasmSections[wsiImport],TWasmObjSymbolExtraData(FData.FObjSymbolsExtraDataList.Find(objsym.Name)).TypeIdx);
  713. end;
  714. end;
  715. { import[imports_count-1] }
  716. WriteName(FWasmSections[wsiImport],'env');
  717. WriteName(FWasmSections[wsiImport],'__indirect_function_table');
  718. WriteByte(FWasmSections[wsiImport],$01); { table }
  719. WriteByte(FWasmSections[wsiImport],$70); { funcref }
  720. WriteByte(FWasmSections[wsiImport],$00); { min }
  721. WriteUleb(FWasmSections[wsiImport],1); { 1 }
  722. WriteUleb(FWasmSections[wsiFunction],functions_count);
  723. WriteUleb(FWasmSections[wsiCode],functions_count);
  724. NextFunctionIndex:=NextImportFunctionIndex;
  725. for i:=0 to Data.ObjSymbolList.Count-1 do
  726. begin
  727. objsym:=TWasmObjSymbol(Data.ObjSymbolList[i]);
  728. if objsym.typ=AT_FUNCTION then
  729. begin
  730. objsym.FuncIndex:=NextFunctionIndex;
  731. Inc(NextFunctionIndex);
  732. WriteUleb(FWasmSections[wsiFunction],TWasmObjSymbolExtraData(FData.FObjSymbolsExtraDataList.Find(objsym.Name)).TypeIdx);
  733. WriteFunctionCode(FWasmSections[wsiCode],objsym);
  734. end;
  735. end;
  736. for i:=0 to Data.ObjSymbolList.Count-1 do
  737. begin
  738. objsym:=TWasmObjSymbol(Data.ObjSymbolList[i]);
  739. if IsExternalFunction(objsym) then
  740. begin
  741. Inc(FWasmSymbolTableEntriesCount);
  742. WriteByte(FWasmSymbolTable,Ord(SYMTAB_FUNCTION));
  743. WriteUleb(FWasmSymbolTable,WASM_SYM_UNDEFINED);
  744. WriteUleb(FWasmSymbolTable,objsym.ImportIndex);
  745. end
  746. else if objsym.typ=AT_FUNCTION then
  747. begin
  748. Inc(FWasmSymbolTableEntriesCount);
  749. WriteByte(FWasmSymbolTable,Ord(SYMTAB_FUNCTION));
  750. WriteUleb(FWasmSymbolTable,0);
  751. WriteUleb(FWasmSymbolTable,objsym.FuncIndex);
  752. WriteName(FWasmSymbolTable,objsym.Name);
  753. end
  754. else if objsym.typ=AT_DATA then
  755. begin
  756. Inc(FWasmSymbolTableEntriesCount);
  757. WriteByte(FWasmSymbolTable,Ord(SYMTAB_DATA));
  758. if objsym.bind=AB_GLOBAL then
  759. WriteUleb(FWasmSymbolTable,0)
  760. else if objsym.bind=AB_LOCAL then
  761. WriteUleb(FWasmSymbolTable,WASM_SYM_BINDING_LOCAL)
  762. else if objsym.bind=AB_EXTERNAL then
  763. WriteUleb(FWasmSymbolTable,WASM_SYM_UNDEFINED)
  764. else
  765. internalerror(2021092506);
  766. WriteName(FWasmSymbolTable,objsym.Name);
  767. if objsym.bind<>AB_EXTERNAL then
  768. begin
  769. WriteUleb(FWasmSymbolTable,TWasmObjSection(objsym.objsection).SegIdx);
  770. WriteUleb(FWasmSymbolTable,objsym.offset);
  771. WriteUleb(FWasmSymbolTable,objsym.size);
  772. end;
  773. end;
  774. end;
  775. WriteSymbolTable;
  776. WriteLinkingSubsection(WASM_SYMBOL_TABLE);
  777. WriteLinkingSubsection(WASM_SEGMENT_INFO);
  778. WriteRelocationCodeTable(4); { code section is section #4 }
  779. WriteRelocationDataTable(5); { code section is section #5 }
  780. Writer.write(WasmModuleMagic,SizeOf(WasmModuleMagic));
  781. Writer.write(WasmVersion,SizeOf(WasmVersion));
  782. WriteWasmSection(wsiType); { section #0 }
  783. WriteWasmSection(wsiImport); { section #1 }
  784. WriteWasmSection(wsiFunction); { section #2 }
  785. WriteWasmSection(wsiDataCount); { section #3 }
  786. WriteWasmSection(wsiCode); { section #4 }
  787. WriteWasmSection(wsiData); { section #5 }
  788. WriteWasmCustomSection(wcstLinking); { section #6 }
  789. WriteWasmCustomSection(wcstRelocCode); { section #7 }
  790. WriteWasmCustomSection(wcstRelocData); { section #8 }
  791. Writeln('ObjSymbolList:');
  792. for i:=0 to Data.ObjSymbolList.Count-1 do
  793. begin
  794. objsym:=TWasmObjSymbol(Data.ObjSymbolList[i]);
  795. Write(objsym.Name, ' bind=', objsym.Bind, ' typ=', objsym.typ, ' address=', objsym.address, ' objsection=');
  796. if assigned(objsym.objsection) then
  797. Write(objsym.objsection.Name)
  798. else
  799. Write('nil');
  800. Writeln;
  801. end;
  802. Writeln('ObjSectionList:');
  803. for i:=0 to Data.ObjSectionList.Count-1 do
  804. begin
  805. objsec:=TWasmObjSection(Data.ObjSectionList[i]);
  806. Writeln(objsec.Name, ' IsCode=', objsec.IsCode, ' IsData=', objsec.IsData, ' Size=', objsec.Size, ' MemPos=', objsec.MemPos, ' DataPos=', objsec.DataPos, ' SegIdx=', objsec.SegIdx);
  807. end;
  808. result:=true;
  809. end;
  810. constructor TWasmObjOutput.create(AWriter: TObjectWriter);
  811. var
  812. i: TWasmSectionID;
  813. j: TWasmCustomSectionType;
  814. k: TWasmLinkingSubsectionType;
  815. begin
  816. inherited;
  817. cobjdata:=TWasmObjData;
  818. for i in TWasmSectionID do
  819. FWasmSections[i] := tdynamicarray.create(SectionDataMaxGrow);
  820. for j in TWasmCustomSectionType do
  821. FWasmCustomSections[j] := tdynamicarray.create(SectionDataMaxGrow);
  822. for k:=low(TWasmLinkingSubsectionType) to high(TWasmLinkingSubsectionType) do
  823. FWasmLinkingSubsections[k] := tdynamicarray.create(SectionDataMaxGrow);
  824. FWasmSymbolTable:=tdynamicarray.create(SectionDataMaxGrow);
  825. FWasmSymbolTableEntriesCount:=0;
  826. FWasmRelocationCodeTable:=tdynamicarray.create(SectionDataMaxGrow);
  827. FWasmRelocationCodeTableEntriesCount:=0;
  828. FWasmRelocationDataTable:=tdynamicarray.create(SectionDataMaxGrow);
  829. FWasmRelocationDataTableEntriesCount:=0;
  830. end;
  831. destructor TWasmObjOutput.destroy;
  832. var
  833. i: TWasmSectionID;
  834. j: TWasmCustomSectionType;
  835. k: TWasmLinkingSubsectionType;
  836. begin
  837. for i in TWasmSectionID do
  838. FWasmSections[i].Free;
  839. for j in TWasmCustomSectionType do
  840. FWasmCustomSections[j].Free;
  841. for k:=low(TWasmLinkingSubsectionType) to high(TWasmLinkingSubsectionType) do
  842. FWasmLinkingSubsections[k].Free;
  843. FWasmSymbolTable.Free;
  844. FWasmRelocationCodeTable.Free;
  845. FWasmRelocationDataTable.Free;
  846. inherited destroy;
  847. end;
  848. {****************************************************************************
  849. TWasmAssembler
  850. ****************************************************************************}
  851. constructor TWasmAssembler.Create(info: pasminfo; smart:boolean);
  852. begin
  853. inherited;
  854. CObjOutput:=TWasmObjOutput;
  855. end;
  856. {*****************************************************************************
  857. Initialize
  858. *****************************************************************************}
  859. {$ifdef wasm32}
  860. const
  861. as_wasm32_wasm_info : tasminfo =
  862. (
  863. id : as_wasm32_wasm;
  864. idtxt : 'OMF';
  865. asmbin : '';
  866. asmcmd : '';
  867. supported_targets : [system_wasm32_embedded,system_wasm32_wasi];
  868. flags : [af_outputbinary,af_smartlink_sections];
  869. labelprefix : '..@';
  870. labelmaxlen : -1;
  871. comment : '; ';
  872. dollarsign: '$';
  873. );
  874. {$endif wasm32}
  875. initialization
  876. {$ifdef wasm32}
  877. RegisterAssembler(as_wasm32_wasm_info,TWasmAssembler);
  878. {$endif wasm32}
  879. end.