ogwasm.pas 50 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394
  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. TWasmObjSymbolExtraData = class;
  34. { TWasmObjSymbol }
  35. TWasmObjSymbol = class(TObjSymbol)
  36. ImportIndex: Integer;
  37. FuncIndex: Integer;
  38. SymbolIndex: Integer;
  39. AliasOf: string;
  40. ExtraData: TWasmObjSymbolExtraData;
  41. constructor create(AList:TFPHashObjectList;const AName:string);override;
  42. function ImportOrFuncIndex: Integer;
  43. function IsAlias: Boolean;
  44. end;
  45. { TWasmObjRelocation }
  46. TWasmObjRelocation = class(TObjRelocation)
  47. public
  48. TypeIndex: Integer;
  49. Addend: LongInt;
  50. constructor CreateTypeIndex(ADataOffset:TObjSectionOfs; ATypeIndex: Integer);
  51. end;
  52. { TWasmObjSymbolExtraData }
  53. TWasmObjSymbolExtraData = class(TFPHashObject)
  54. TypeIdx: Integer;
  55. ImportModule: string;
  56. ImportName: string;
  57. Locals: array of TWasmBasicType;
  58. constructor Create(HashObjectList: TFPHashObjectList; const s: TSymStr);
  59. procedure AddLocal(bastyp: TWasmBasicType);
  60. end;
  61. { TWasmObjSection }
  62. TWasmObjSection = class(TObjSection)
  63. public
  64. SegIdx: Integer;
  65. SegOfs: qword;
  66. FileSectionOfs: qword;
  67. function IsCode: Boolean;
  68. function IsData: Boolean;
  69. end;
  70. { TWasmObjData }
  71. TWasmObjData = class(TObjData)
  72. private
  73. FFuncTypes: array of TWasmFuncType;
  74. FObjSymbolsExtraDataList: TFPHashObjectList;
  75. FLastFuncName: string;
  76. function is_smart_section(atype:TAsmSectiontype):boolean;
  77. function sectionname_gas(atype:TAsmSectiontype;const aname:string;aorder:TAsmSectionOrder):string;
  78. public
  79. constructor create(const n:string);override;
  80. destructor destroy; override;
  81. function sectionname(atype:TAsmSectiontype;const aname:string;aorder:TAsmSectionOrder):string;override;
  82. procedure writeReloc(Data:TRelocDataInt;len:aword;p:TObjSymbol;Reloctype:TObjRelocationType);override;
  83. function AddOrCreateObjSymbolExtraData(const symname:TSymStr): TWasmObjSymbolExtraData;
  84. function AddFuncType(wft: TWasmFuncType): integer;
  85. procedure DeclareFuncType(ft: tai_functype);
  86. procedure DeclareImportModule(aim: tai_import_module);
  87. procedure DeclareImportName(ain: tai_import_name);
  88. procedure DeclareLocal(al: tai_local);
  89. procedure symbolpairdefine(akind: TSymbolPairKind;const asym, avalue: string);override;
  90. end;
  91. { TWasmObjOutput }
  92. TWasmObjOutput = class(tObjOutput)
  93. private
  94. FData: TWasmObjData;
  95. FWasmRelocationCodeTable: tdynamicarray;
  96. FWasmRelocationCodeTableEntriesCount: Integer;
  97. FWasmRelocationDataTable: tdynamicarray;
  98. FWasmRelocationDataTableEntriesCount: Integer;
  99. FWasmSymbolTable: tdynamicarray;
  100. FWasmSymbolTableEntriesCount: Integer;
  101. FWasmSections: array [TWasmSectionID] of tdynamicarray;
  102. FWasmCustomSections: array [TWasmCustomSectionType] of tdynamicarray;
  103. FWasmLinkingSubsections: array [low(TWasmLinkingSubsectionType)..high(TWasmLinkingSubsectionType)] of tdynamicarray;
  104. procedure WriteUleb(d: tdynamicarray; v: uint64);
  105. procedure WriteUleb(w: TObjectWriter; v: uint64);
  106. procedure WriteSleb(d: tdynamicarray; v: int64);
  107. procedure WriteByte(d: tdynamicarray; b: byte);
  108. procedure WriteName(d: tdynamicarray; const s: string);
  109. procedure WriteWasmSection(wsid: TWasmSectionID);
  110. procedure WriteWasmCustomSection(wcst: TWasmCustomSectionType);
  111. procedure CopyDynamicArray(src, dest: tdynamicarray; size: QWord);
  112. procedure WriteZeros(dest: tdynamicarray; size: QWord);
  113. procedure WriteWasmResultType(dest: tdynamicarray; wrt: TWasmResultType);
  114. procedure WriteWasmBasicType(dest: tdynamicarray; wbt: TWasmBasicType);
  115. function IsExternalFunction(sym: TObjSymbol): Boolean;
  116. procedure WriteFunctionLocals(dest: tdynamicarray; ed: TWasmObjSymbolExtraData);
  117. procedure WriteFunctionCode(dest: tdynamicarray; objsym: TObjSymbol);
  118. procedure WriteSymbolTable;
  119. procedure WriteRelocationCodeTable(CodeSectionIndex: Integer);
  120. procedure WriteRelocationDataTable(DataSectionIndex: Integer);
  121. procedure WriteLinkingSubsection(wlst: TWasmLinkingSubsectionType);
  122. procedure DoRelocations;
  123. procedure WriteRelocations;
  124. protected
  125. function writeData(Data:TObjData):boolean;override;
  126. public
  127. constructor create(AWriter:TObjectWriter);override;
  128. destructor destroy;override;
  129. end;
  130. { TWasmAssembler }
  131. TWasmAssembler = class(tinternalassembler)
  132. constructor create(info: pasminfo; smart:boolean);override;
  133. end;
  134. implementation
  135. uses
  136. verbose;
  137. procedure WriteUleb5(d: tdynamicarray; v: uint64);
  138. var
  139. b: byte;
  140. i: Integer;
  141. begin
  142. for i:=1 to 5 do
  143. begin
  144. b:=byte(v) and 127;
  145. v:=v shr 7;
  146. if i<>5 then
  147. b:=b or 128;
  148. d.write(b,1);
  149. end;
  150. end;
  151. procedure WriteUleb5(d: tobjsection; v: uint64);
  152. var
  153. b: byte;
  154. i: Integer;
  155. begin
  156. for i:=1 to 5 do
  157. begin
  158. b:=byte(v) and 127;
  159. v:=v shr 7;
  160. if i<>5 then
  161. b:=b or 128;
  162. d.write(b,1);
  163. end;
  164. end;
  165. procedure WriteSleb5(d: tdynamicarray; v: int64);
  166. var
  167. b: byte;
  168. i: Integer;
  169. begin
  170. for i:=1 to 5 do
  171. begin
  172. b:=byte(v) and 127;
  173. v:=SarInt64(v,7);
  174. if i<>5 then
  175. b:=b or 128;
  176. d.write(b,1);
  177. end;
  178. end;
  179. procedure WriteSleb5(d: tobjsection; v: int64);
  180. var
  181. b: byte;
  182. i: Integer;
  183. begin
  184. for i:=1 to 5 do
  185. begin
  186. b:=byte(v) and 127;
  187. v:=SarInt64(v,7);
  188. if i<>5 then
  189. b:=b or 128;
  190. d.write(b,1);
  191. end;
  192. end;
  193. function ReadUleb(d: tdynamicarray): uint64;
  194. var
  195. b: byte;
  196. shift:integer;
  197. begin
  198. b:=0;
  199. result:=0;
  200. shift:=0;
  201. repeat
  202. d.read(b,1);
  203. result:=result or (uint64(b and 127) shl shift);
  204. inc(shift,7);
  205. until (b and 128)=0;
  206. end;
  207. function ReadSleb(d: tdynamicarray): int64;
  208. var
  209. b: byte;
  210. shift:integer;
  211. begin
  212. b:=0;
  213. result:=0;
  214. shift:=0;
  215. repeat
  216. d.read(b,1);
  217. result:=result or (uint64(b and 127) shl shift);
  218. inc(shift,7);
  219. until (b and 128)=0;
  220. if (b and 64)<>0 then
  221. result:=result or (high(uint64) shl shift);
  222. end;
  223. procedure AddSleb5(d: tdynamicarray; v: int64);
  224. var
  225. q: Int64;
  226. p: LongWord;
  227. begin
  228. p:=d.Pos;
  229. q:=ReadSleb(d);
  230. q:=q+v;
  231. d.seek(p);
  232. WriteSleb5(d,q);
  233. end;
  234. procedure AddUleb5(d: tdynamicarray; v: int64);
  235. var
  236. q: UInt64;
  237. p: LongWord;
  238. begin
  239. p:=d.Pos;
  240. q:=ReadUleb(d);
  241. q:=q+v;
  242. d.seek(p);
  243. WriteUleb5(d,q);
  244. end;
  245. procedure AddInt32(d: tdynamicarray; v: int32);
  246. var
  247. q: int32;
  248. p: LongWord;
  249. begin
  250. p:=d.Pos;
  251. d.read(q,4);
  252. {$ifdef FPC_BIG_ENDIAN}
  253. q:=SwapEndian(q);
  254. {$endif FPC_BIG_ENDIAN}
  255. q:=q+v;
  256. {$ifdef FPC_BIG_ENDIAN}
  257. q:=SwapEndian(q);
  258. {$endif FPC_BIG_ENDIAN}
  259. d.seek(p);
  260. d.write(q,4);
  261. end;
  262. {****************************************************************************
  263. TWasmObjRelocation
  264. ****************************************************************************}
  265. constructor TWasmObjRelocation.CreateTypeIndex(ADataOffset: TObjSectionOfs; ATypeIndex: Integer);
  266. begin
  267. DataOffset:=ADataOffset;
  268. Symbol:=nil;
  269. OrgSize:=0;
  270. Group:=nil;
  271. ObjSection:=nil;
  272. ftype:=ord(RELOC_TYPE_INDEX_LEB);
  273. TypeIndex:=ATypeIndex;
  274. end;
  275. {****************************************************************************
  276. TWasmObjSymbol
  277. ****************************************************************************}
  278. constructor TWasmObjSymbol.create(AList: TFPHashObjectList; const AName: string);
  279. begin
  280. inherited create(AList,AName);
  281. ImportIndex:=-1;
  282. FuncIndex:=-1;
  283. SymbolIndex:=-1;
  284. AliasOf:='';
  285. ExtraData:=nil;
  286. end;
  287. function TWasmObjSymbol.ImportOrFuncIndex: Integer;
  288. begin
  289. if ImportIndex<>-1 then
  290. result:=ImportIndex
  291. else if FuncIndex<>-1 then
  292. result:=FuncIndex
  293. else
  294. internalerror(2021092601);
  295. end;
  296. function TWasmObjSymbol.IsAlias: Boolean;
  297. begin
  298. result:=AliasOf<>'';
  299. end;
  300. {****************************************************************************
  301. TWasmObjSymbolExtraData
  302. ****************************************************************************}
  303. constructor TWasmObjSymbolExtraData.Create(HashObjectList: TFPHashObjectList; const s: TSymStr);
  304. begin
  305. inherited Create(HashObjectList,s);
  306. TypeIdx:=-1;
  307. end;
  308. procedure TWasmObjSymbolExtraData.AddLocal(bastyp: TWasmBasicType);
  309. begin
  310. SetLength(Locals,Length(Locals)+1);
  311. Locals[High(Locals)]:=bastyp;
  312. end;
  313. {****************************************************************************
  314. TWasmObjSection
  315. ****************************************************************************}
  316. function TWasmObjSection.IsCode: Boolean;
  317. const
  318. CodePrefix = '.text';
  319. begin
  320. result:=(Length(Name)>=Length(CodePrefix)) and
  321. (Copy(Name,1,Length(CodePrefix))=CodePrefix);
  322. end;
  323. function TWasmObjSection.IsData: Boolean;
  324. begin
  325. result:=not IsCode;
  326. end;
  327. {****************************************************************************
  328. TWasmObjData
  329. ****************************************************************************}
  330. function TWasmObjData.is_smart_section(atype: TAsmSectiontype): boolean;
  331. begin
  332. { For bss we need to set some flags that are target dependent,
  333. it is easier to disable it for smartlinking. It doesn't take up
  334. filespace }
  335. result:=not(target_info.system in systems_darwin) and
  336. create_smartlink_sections and
  337. (atype<>sec_toc) and
  338. (atype<>sec_user) and
  339. { on embedded systems every byte counts, so smartlink bss too }
  340. ((atype<>sec_bss) or (target_info.system in (systems_embedded+systems_freertos)));
  341. end;
  342. function TWasmObjData.sectionname_gas(atype: TAsmSectiontype;
  343. const aname: string; aorder: TAsmSectionOrder): string;
  344. const
  345. secnames : array[TAsmSectiontype] of string[length('__DATA, __datacoal_nt,coalesced')] = ('','',
  346. '.text',
  347. '.data',
  348. { why doesn't .rodata work? (FK) }
  349. { sometimes we have to create a data.rel.ro instead of .rodata, e.g. for }
  350. { vtables (and anything else containing relocations), otherwise those are }
  351. { not relocated properly on e.g. linux/ppc64. g++ generates there for a }
  352. { vtable for a class called Window: }
  353. { .section .data.rel.ro._ZTV6Window,"awG",@progbits,_ZTV6Window,comdat }
  354. { TODO: .data.ro not yet working}
  355. {$if defined(arm) or defined(riscv64) or defined(powerpc)}
  356. '.rodata',
  357. {$else defined(arm) or defined(riscv64) or defined(powerpc)}
  358. '.data',
  359. {$endif defined(arm) or defined(riscv64) or defined(powerpc)}
  360. '.rodata',
  361. '.bss',
  362. '.threadvar',
  363. '.pdata',
  364. '', { stubs }
  365. '__DATA,__nl_symbol_ptr',
  366. '__DATA,__la_symbol_ptr',
  367. '__DATA,__mod_init_func',
  368. '__DATA,__mod_term_func',
  369. '.stab',
  370. '.stabstr',
  371. '.idata$2','.idata$4','.idata$5','.idata$6','.idata$7','.edata',
  372. '.eh_frame',
  373. '.debug_frame','.debug_info','.debug_line','.debug_abbrev','.debug_aranges','.debug_ranges',
  374. '.fpc',
  375. '.toc',
  376. '.init',
  377. '.fini',
  378. '.objc_class',
  379. '.objc_meta_class',
  380. '.objc_cat_cls_meth',
  381. '.objc_cat_inst_meth',
  382. '.objc_protocol',
  383. '.objc_string_object',
  384. '.objc_cls_meth',
  385. '.objc_inst_meth',
  386. '.objc_cls_refs',
  387. '.objc_message_refs',
  388. '.objc_symbols',
  389. '.objc_category',
  390. '.objc_class_vars',
  391. '.objc_instance_vars',
  392. '.objc_module_info',
  393. '.objc_class_names',
  394. '.objc_meth_var_types',
  395. '.objc_meth_var_names',
  396. '.objc_selector_strs',
  397. '.objc_protocol_ext',
  398. '.objc_class_ext',
  399. '.objc_property',
  400. '.objc_image_info',
  401. '.objc_cstring_object',
  402. '.objc_sel_fixup',
  403. '__DATA,__objc_data',
  404. '__DATA,__objc_const',
  405. '.objc_superrefs',
  406. '__DATA, __datacoal_nt,coalesced',
  407. '.objc_classlist',
  408. '.objc_nlclasslist',
  409. '.objc_catlist',
  410. '.obcj_nlcatlist',
  411. '.objc_protolist',
  412. '.stack',
  413. '.heap',
  414. '.gcc_except_table',
  415. '.ARM.attributes'
  416. );
  417. var
  418. sep : string[3];
  419. secname : string;
  420. begin
  421. secname:=secnames[atype];
  422. if (atype=sec_fpc) and (Copy(aname,1,3)='res') then
  423. begin
  424. result:=secname+'.'+aname;
  425. exit;
  426. end;
  427. if atype=sec_threadvar then
  428. begin
  429. if (target_info.system in (systems_windows+systems_wince)) then
  430. secname:='.tls'
  431. else if (target_info.system in systems_linux) then
  432. secname:='.tbss';
  433. end;
  434. { go32v2 stub only loads .text and .data sections, and allocates space for .bss.
  435. Thus, data which normally goes into .rodata and .rodata_norel sections must
  436. end up in .data section }
  437. if (atype in [sec_rodata,sec_rodata_norel]) and
  438. (target_info.system in [system_i386_go32v2,system_m68k_palmos]) then
  439. secname:='.data';
  440. { Windows correctly handles reallocations in readonly sections }
  441. if (atype=sec_rodata) and
  442. (target_info.system in systems_all_windows+systems_nativent-[system_i8086_win16]) then
  443. secname:='.rodata';
  444. { section type user gives the user full controll on the section name }
  445. if atype=sec_user then
  446. secname:=aname;
  447. if is_smart_section(atype) and (aname<>'') then
  448. begin
  449. case aorder of
  450. secorder_begin :
  451. sep:='.b_';
  452. secorder_end :
  453. sep:='.z_';
  454. else
  455. sep:='.n_';
  456. end;
  457. result:=secname+sep+aname
  458. end
  459. else
  460. result:=secname;
  461. end;
  462. constructor TWasmObjData.create(const n: string);
  463. begin
  464. inherited;
  465. CObjSection:=TWasmObjSection;
  466. CObjSymbol:=TWasmObjSymbol;
  467. FObjSymbolsExtraDataList:=TFPHashObjectList.Create;
  468. end;
  469. destructor TWasmObjData.destroy;
  470. var
  471. i: Integer;
  472. begin
  473. FObjSymbolsExtraDataList.Free;
  474. for i:=low(FFuncTypes) to high(FFuncTypes) do
  475. begin
  476. FFuncTypes[i].free;
  477. FFuncTypes[i]:=nil;
  478. end;
  479. inherited destroy;
  480. end;
  481. function TWasmObjData.sectionname(atype: TAsmSectiontype;
  482. const aname: string; aorder: TAsmSectionOrder): string;
  483. begin
  484. if (atype=sec_fpc) or (atype=sec_threadvar) then
  485. atype:=sec_data;
  486. Result:=sectionname_gas(atype, aname, aorder);
  487. end;
  488. procedure TWasmObjData.writeReloc(Data: TRelocDataInt; len: aword;
  489. p: TObjSymbol; Reloctype: TObjRelocationType);
  490. const
  491. leb_zero: array[0..4] of byte=($80,$80,$80,$80,$00);
  492. var
  493. objreloc: TWasmObjRelocation;
  494. begin
  495. if CurrObjSec=nil then
  496. internalerror(200403072);
  497. objreloc:=nil;
  498. case Reloctype of
  499. RELOC_FUNCTION_INDEX_LEB:
  500. begin
  501. if Data<>0 then
  502. internalerror(2021092502);
  503. if len<>5 then
  504. internalerror(2021092503);
  505. if not assigned(p) then
  506. internalerror(2021092504);
  507. objreloc:=TWasmObjRelocation.CreateSymbol(CurrObjSec.Size,p,Reloctype);
  508. CurrObjSec.ObjRelocations.Add(objreloc);
  509. writebytes(leb_zero,5);
  510. end;
  511. RELOC_MEMORY_ADDR_LEB,
  512. RELOC_MEMORY_ADDR_OR_TABLE_INDEX_SLEB:
  513. begin
  514. if (Reloctype=RELOC_MEMORY_ADDR_LEB) and (Data<0) then
  515. internalerror(2021092602);
  516. if len<>5 then
  517. internalerror(2021092503);
  518. if not assigned(p) then
  519. internalerror(2021092504);
  520. objreloc:=TWasmObjRelocation.CreateSymbol(CurrObjSec.Size,p,Reloctype);
  521. objreloc.Addend:=Data;
  522. CurrObjSec.ObjRelocations.Add(objreloc);
  523. if RelocType=RELOC_MEMORY_ADDR_LEB then
  524. WriteUleb5(CurrObjSec,Data)
  525. else
  526. WriteSleb5(CurrObjSec,Data);
  527. end;
  528. RELOC_ABSOLUTE:
  529. begin
  530. if len<>4 then
  531. internalerror(2021092607);
  532. if not assigned(p) then
  533. internalerror(2021092608);
  534. objreloc:=TWasmObjRelocation.CreateSymbol(CurrObjSec.Size,p,Reloctype);
  535. objreloc.Addend:=Data;
  536. CurrObjSec.ObjRelocations.Add(objreloc);
  537. Data:=NtoLE(Data);
  538. writebytes(Data,4);
  539. end;
  540. RELOC_TYPE_INDEX_LEB:
  541. begin
  542. if len<>5 then
  543. internalerror(2021092612);
  544. if assigned(p) then
  545. internalerror(2021092613);
  546. objreloc:=TWasmObjRelocation.CreateTypeIndex(CurrObjSec.Size,Data);
  547. CurrObjSec.ObjRelocations.Add(objreloc);
  548. WriteUleb5(CurrObjSec,Data);
  549. end;
  550. else
  551. internalerror(2021092501);
  552. end;
  553. end;
  554. function TWasmObjData.AddOrCreateObjSymbolExtraData(const symname: TSymStr): TWasmObjSymbolExtraData;
  555. begin
  556. result:=TWasmObjSymbolExtraData(FObjSymbolsExtraDataList.Find(symname));
  557. if not assigned(result) then
  558. result:=TWasmObjSymbolExtraData.Create(FObjSymbolsExtraDataList,symname);
  559. end;
  560. function TWasmObjData.AddFuncType(wft: TWasmFuncType): integer;
  561. var
  562. i: Integer;
  563. begin
  564. for i:=low(FFuncTypes) to high(FFuncTypes) do
  565. if wft.Equals(FFuncTypes[i]) then
  566. exit(i);
  567. result:=Length(FFuncTypes);
  568. SetLength(FFuncTypes,result+1);
  569. FFuncTypes[result]:=TWasmFuncType.Create(wft);
  570. end;
  571. procedure TWasmObjData.DeclareFuncType(ft: tai_functype);
  572. var
  573. i: Integer;
  574. ObjSymExtraData: TWasmObjSymbolExtraData;
  575. begin
  576. FLastFuncName:=ft.funcname;
  577. i:=AddFuncType(ft.functype);
  578. ObjSymExtraData:=AddOrCreateObjSymbolExtraData(ft.funcname);
  579. ObjSymExtraData.TypeIdx:=i;
  580. end;
  581. procedure TWasmObjData.DeclareImportModule(aim: tai_import_module);
  582. var
  583. ObjSymExtraData: TWasmObjSymbolExtraData;
  584. begin
  585. ObjSymExtraData:=AddOrCreateObjSymbolExtraData(aim.symname);
  586. ObjSymExtraData.ImportModule:=aim.importmodule;
  587. end;
  588. procedure TWasmObjData.DeclareImportName(ain: tai_import_name);
  589. var
  590. ObjSymExtraData: TWasmObjSymbolExtraData;
  591. begin
  592. ObjSymExtraData:=AddOrCreateObjSymbolExtraData(ain.symname);
  593. ObjSymExtraData.ImportName:=ain.importname;
  594. end;
  595. procedure TWasmObjData.DeclareLocal(al: tai_local);
  596. var
  597. ObjSymExtraData: TWasmObjSymbolExtraData;
  598. begin
  599. ObjSymExtraData:=TWasmObjSymbolExtraData(FObjSymbolsExtraDataList.Find(FLastFuncName));
  600. ObjSymExtraData.AddLocal(al.bastyp);
  601. end;
  602. procedure TWasmObjData.symbolpairdefine(akind: TSymbolPairKind; const asym, avalue: string);
  603. var
  604. valsym: TObjSymbol;
  605. aliassym: TWasmObjSymbol;
  606. begin
  607. valsym:=CreateSymbol(avalue);
  608. aliassym:=TWasmObjSymbol(symboldefine(asym,valsym.bind,valsym.typ));
  609. aliassym.AliasOf:=valsym.Name;
  610. end;
  611. {****************************************************************************
  612. TWasmObjOutput
  613. ****************************************************************************}
  614. procedure TWasmObjOutput.WriteUleb(d: tdynamicarray; v: uint64);
  615. var
  616. b: byte;
  617. begin
  618. repeat
  619. b:=byte(v) and 127;
  620. v:=v shr 7;
  621. if v<>0 then
  622. b:=b or 128;
  623. d.write(b,1);
  624. until v=0;
  625. end;
  626. procedure TWasmObjOutput.WriteUleb(w: TObjectWriter; v: uint64);
  627. var
  628. b: byte;
  629. begin
  630. repeat
  631. b:=byte(v) and 127;
  632. v:=v shr 7;
  633. if v<>0 then
  634. b:=b or 128;
  635. w.write(b,1);
  636. until v=0;
  637. end;
  638. procedure TWasmObjOutput.WriteSleb(d: tdynamicarray; v: int64);
  639. var
  640. b: byte;
  641. Done: Boolean=false;
  642. begin
  643. repeat
  644. b:=byte(v) and 127;
  645. v:=SarInt64(v,7);
  646. if ((v=0) and ((b and 64)=0)) or ((v=-1) and ((b and 64)<>0)) then
  647. Done:=true
  648. else
  649. b:=b or 128;
  650. d.write(b,1);
  651. until Done;
  652. end;
  653. procedure TWasmObjOutput.WriteByte(d: tdynamicarray; b: byte);
  654. begin
  655. d.write(b,1);
  656. end;
  657. procedure TWasmObjOutput.WriteName(d: tdynamicarray; const s: string);
  658. begin
  659. WriteUleb(d,Length(s));
  660. d.writestr(s);
  661. end;
  662. procedure TWasmObjOutput.WriteWasmSection(wsid: TWasmSectionID);
  663. var
  664. b: byte;
  665. begin
  666. b:=ord(wsid);
  667. Writer.write(b,1);
  668. WriteUleb(Writer,FWasmSections[wsid].size);
  669. Writer.writearray(FWasmSections[wsid]);
  670. end;
  671. procedure TWasmObjOutput.WriteWasmCustomSection(wcst: TWasmCustomSectionType);
  672. var
  673. b: byte;
  674. begin
  675. b:=0;
  676. Writer.write(b,1);
  677. WriteUleb(Writer,FWasmCustomSections[wcst].size);
  678. Writer.writearray(FWasmCustomSections[wcst]);
  679. end;
  680. procedure TWasmObjOutput.CopyDynamicArray(src, dest: tdynamicarray; size: QWord);
  681. var
  682. buf: array [0..4095] of byte;
  683. bs: Integer;
  684. begin
  685. while size>0 do
  686. begin
  687. if size<SizeOf(buf) then
  688. bs:=Integer(size)
  689. else
  690. bs:=SizeOf(buf);
  691. src.read(buf,bs);
  692. dest.write(buf,bs);
  693. dec(size,bs);
  694. end;
  695. end;
  696. procedure TWasmObjOutput.WriteZeros(dest: tdynamicarray; size: QWord);
  697. var
  698. buf : array[0..1023] of byte;
  699. bs: Integer;
  700. begin
  701. fillchar(buf,sizeof(buf),0);
  702. while size>0 do
  703. begin
  704. if size<SizeOf(buf) then
  705. bs:=Integer(size)
  706. else
  707. bs:=SizeOf(buf);
  708. dest.write(buf,bs);
  709. dec(size,bs);
  710. end;
  711. end;
  712. procedure TWasmObjOutput.WriteWasmResultType(dest: tdynamicarray; wrt: TWasmResultType);
  713. var
  714. i: Integer;
  715. begin
  716. WriteUleb(dest,Length(wrt));
  717. for i:=low(wrt) to high(wrt) do
  718. WriteWasmBasicType(dest,wrt[i]);
  719. end;
  720. procedure TWasmObjOutput.WriteWasmBasicType(dest: tdynamicarray; wbt: TWasmBasicType);
  721. begin
  722. WriteByte(dest,encode_wasm_basic_type(wbt));
  723. end;
  724. function TWasmObjOutput.IsExternalFunction(sym: TObjSymbol): Boolean;
  725. begin
  726. result:=(sym.bind=AB_EXTERNAL) and (TWasmObjData(sym.ObjData).FObjSymbolsExtraDataList.Find(sym.Name)<>nil);
  727. end;
  728. procedure TWasmObjOutput.WriteFunctionLocals(dest: tdynamicarray; ed: TWasmObjSymbolExtraData);
  729. var
  730. i,
  731. rle_entries,
  732. cnt: Integer;
  733. lasttype: TWasmBasicType;
  734. begin
  735. if Length(ed.Locals)=0 then
  736. begin
  737. WriteUleb(dest,0);
  738. exit;
  739. end;
  740. rle_entries:=1;
  741. for i:=low(ed.Locals)+1 to high(ed.Locals) do
  742. if ed.Locals[i]<>ed.Locals[i-1] then
  743. inc(rle_entries);
  744. WriteUleb(dest,rle_entries);
  745. lasttype:=ed.Locals[Low(ed.Locals)];
  746. cnt:=1;
  747. for i:=low(ed.Locals)+1 to high(ed.Locals) do
  748. if ed.Locals[i]=ed.Locals[i-1] then
  749. inc(cnt)
  750. else
  751. begin
  752. WriteUleb(dest,cnt);
  753. WriteWasmBasicType(dest,lasttype);
  754. lasttype:=ed.Locals[i];
  755. cnt:=1;
  756. end;
  757. WriteUleb(dest,cnt);
  758. WriteWasmBasicType(dest,lasttype);
  759. end;
  760. procedure TWasmObjOutput.WriteFunctionCode(dest: tdynamicarray; objsym: TObjSymbol);
  761. var
  762. encoded_locals: tdynamicarray;
  763. ObjSymExtraData: TWasmObjSymbolExtraData;
  764. codelen: LongWord;
  765. ObjSection: TWasmObjSection;
  766. codeexprlen: QWord;
  767. begin
  768. ObjSymExtraData:=TWasmObjSymbolExtraData(FData.FObjSymbolsExtraDataList.Find(objsym.Name));
  769. ObjSection:=TWasmObjSection(objsym.objsection);
  770. ObjSection.Data.seek(objsym.address);
  771. codeexprlen:=ObjSection.Size-objsym.address;
  772. encoded_locals:=tdynamicarray.Create(64);
  773. WriteFunctionLocals(encoded_locals,ObjSymExtraData);
  774. codelen:=encoded_locals.size+codeexprlen+1;
  775. WriteUleb(dest,codelen);
  776. encoded_locals.seek(0);
  777. CopyDynamicArray(encoded_locals,dest,encoded_locals.size);
  778. ObjSection.FileSectionOfs:=dest.size-objsym.offset;
  779. CopyDynamicArray(ObjSection.Data,dest,codeexprlen);
  780. WriteByte(dest,$0B);
  781. encoded_locals.Free;
  782. end;
  783. procedure TWasmObjOutput.WriteSymbolTable;
  784. begin
  785. WriteUleb(FWasmLinkingSubsections[WASM_SYMBOL_TABLE],FWasmSymbolTableEntriesCount);
  786. FWasmSymbolTable.seek(0);
  787. CopyDynamicArray(FWasmSymbolTable,FWasmLinkingSubsections[WASM_SYMBOL_TABLE],FWasmSymbolTable.size);
  788. end;
  789. procedure TWasmObjOutput.WriteRelocationCodeTable(CodeSectionIndex: Integer);
  790. begin
  791. WriteUleb(FWasmCustomSections[wcstRelocCode],CodeSectionIndex);
  792. WriteUleb(FWasmCustomSections[wcstRelocCode],FWasmRelocationCodeTableEntriesCount);
  793. FWasmRelocationCodeTable.seek(0);
  794. CopyDynamicArray(FWasmRelocationCodeTable,FWasmCustomSections[wcstRelocCode],FWasmRelocationCodeTable.size);
  795. end;
  796. procedure TWasmObjOutput.WriteRelocationDataTable(DataSectionIndex: Integer);
  797. begin
  798. WriteUleb(FWasmCustomSections[wcstRelocData],DataSectionIndex);
  799. WriteUleb(FWasmCustomSections[wcstRelocData],FWasmRelocationDataTableEntriesCount);
  800. FWasmRelocationDataTable.seek(0);
  801. CopyDynamicArray(FWasmRelocationDataTable,FWasmCustomSections[wcstRelocData],FWasmRelocationDataTable.size);
  802. end;
  803. procedure TWasmObjOutput.WriteLinkingSubsection(wlst: TWasmLinkingSubsectionType);
  804. begin
  805. if FWasmLinkingSubsections[wlst].size>0 then
  806. begin
  807. WriteByte(FWasmCustomSections[wcstLinking],Ord(wlst));
  808. WriteUleb(FWasmCustomSections[wcstLinking],FWasmLinkingSubsections[wlst].size);
  809. FWasmLinkingSubsections[wlst].seek(0);
  810. CopyDynamicArray(FWasmLinkingSubsections[wlst],FWasmCustomSections[wcstLinking],FWasmLinkingSubsections[wlst].size);
  811. end;
  812. end;
  813. procedure TWasmObjOutput.DoRelocations;
  814. var
  815. si, ri: Integer;
  816. objsec: TWasmObjSection;
  817. objrel: TWasmObjRelocation;
  818. begin
  819. for si:=0 to FData.ObjSectionList.Count-1 do
  820. begin
  821. objsec:=TWasmObjSection(FData.ObjSectionList[si]);
  822. for ri:=0 to objsec.ObjRelocations.Count-1 do
  823. begin
  824. objrel:=TWasmObjRelocation(objsec.ObjRelocations[ri]);
  825. case objrel.typ of
  826. RELOC_FUNCTION_INDEX_LEB:
  827. begin
  828. if not assigned(objrel.symbol) then
  829. internalerror(2021092509);
  830. objsec.Data.seek(objrel.DataOffset);
  831. WriteUleb5(objsec.Data,TWasmObjSymbol(objrel.symbol).ImportOrFuncIndex);
  832. end;
  833. RELOC_MEMORY_ADDR_OR_TABLE_INDEX_SLEB:
  834. begin
  835. if not assigned(objrel.symbol) then
  836. internalerror(2021092605);
  837. if not (IsExternalFunction(objrel.symbol) or (objrel.symbol.typ=AT_FUNCTION) or (objrel.symbol.bind=AB_EXTERNAL)) then
  838. begin
  839. Writeln('!!!', objrel.symbol.Name);
  840. Writeln(assigned(objrel.symbol.objsection));
  841. objsec.Data.seek(objrel.DataOffset);
  842. AddSleb5(objsec.Data,objrel.symbol.offset+TWasmObjSection(objrel.symbol.objsection).SegOfs);
  843. end;
  844. end;
  845. RELOC_MEMORY_ADDR_LEB:
  846. begin
  847. if not assigned(objrel.symbol) then
  848. internalerror(2021092606);
  849. if IsExternalFunction(objrel.symbol) or (objrel.symbol.typ=AT_FUNCTION) then
  850. internalerror(2021092628);
  851. if objrel.symbol.bind<>AB_EXTERNAL then
  852. begin
  853. objsec.Data.seek(objrel.DataOffset);
  854. AddUleb5(objsec.Data,objrel.symbol.offset+TWasmObjSection(objrel.symbol.objsection).SegOfs);
  855. end;
  856. end;
  857. RELOC_ABSOLUTE:
  858. begin
  859. if not (IsExternalFunction(objrel.symbol) or (objrel.symbol.typ=AT_FUNCTION) or (objrel.symbol.bind=AB_EXTERNAL)) then
  860. begin
  861. objsec.Data.seek(objrel.DataOffset);
  862. AddInt32(objsec.Data,objrel.symbol.offset+TWasmObjSection(objrel.symbol.objsection).SegOfs);
  863. end;
  864. end;
  865. RELOC_TYPE_INDEX_LEB:
  866. ;
  867. else
  868. internalerror(2021092510);
  869. end;
  870. end;
  871. end;
  872. end;
  873. procedure TWasmObjOutput.WriteRelocations;
  874. var
  875. si, ri: Integer;
  876. objsec: TWasmObjSection;
  877. objrel: TWasmObjRelocation;
  878. relout: tdynamicarray;
  879. relcount: PInteger;
  880. begin
  881. for si:=0 to FData.ObjSectionList.Count-1 do
  882. begin
  883. objsec:=TWasmObjSection(FData.ObjSectionList[si]);
  884. if objsec.IsCode then
  885. begin
  886. relout:=FWasmRelocationCodeTable;
  887. relcount:=@FWasmRelocationCodeTableEntriesCount;
  888. end
  889. else
  890. begin
  891. relout:=FWasmRelocationDataTable;
  892. relcount:=@FWasmRelocationDataTableEntriesCount;
  893. end;
  894. for ri:=0 to objsec.ObjRelocations.Count-1 do
  895. begin
  896. objrel:=TWasmObjRelocation(objsec.ObjRelocations[ri]);
  897. case objrel.typ of
  898. RELOC_FUNCTION_INDEX_LEB:
  899. begin
  900. if not assigned(objrel.symbol) then
  901. internalerror(2021092508);
  902. Inc(relcount^);
  903. WriteByte(relout,Ord(R_WASM_FUNCTION_INDEX_LEB));
  904. WriteUleb(relout,objrel.DataOffset+objsec.FileSectionOfs);
  905. WriteUleb(relout,TWasmObjSymbol(objrel.symbol).SymbolIndex);
  906. end;
  907. RELOC_MEMORY_ADDR_LEB:
  908. begin
  909. if not assigned(objrel.symbol) then
  910. internalerror(2021092603);
  911. Inc(relcount^);
  912. if IsExternalFunction(objrel.symbol) or (objrel.symbol.typ=AT_FUNCTION) then
  913. internalerror(2021092628);
  914. WriteByte(relout,Ord(R_WASM_MEMORY_ADDR_LEB));
  915. WriteUleb(relout,objrel.DataOffset+objsec.FileSectionOfs);
  916. WriteUleb(relout,TWasmObjSymbol(objrel.symbol).SymbolIndex);
  917. WriteSleb(relout,objrel.Addend); { addend to add to the address }
  918. end;
  919. RELOC_MEMORY_ADDR_OR_TABLE_INDEX_SLEB:
  920. begin
  921. if not assigned(objrel.symbol) then
  922. internalerror(2021092604);
  923. Inc(relcount^);
  924. if IsExternalFunction(objrel.symbol) or (objrel.symbol.typ=AT_FUNCTION) then
  925. begin
  926. WriteByte(relout,Ord(R_WASM_TABLE_INDEX_SLEB));
  927. WriteUleb(relout,objrel.DataOffset+objsec.FileSectionOfs);
  928. WriteUleb(relout,TWasmObjSymbol(objrel.symbol).SymbolIndex);
  929. end
  930. else
  931. begin
  932. WriteByte(relout,Ord(R_WASM_MEMORY_ADDR_SLEB));
  933. WriteUleb(relout,objrel.DataOffset+objsec.FileSectionOfs);
  934. WriteUleb(relout,TWasmObjSymbol(objrel.symbol).SymbolIndex);
  935. WriteSleb(relout,objrel.Addend); { addend to add to the address }
  936. end;
  937. end;
  938. RELOC_ABSOLUTE:
  939. begin
  940. if not assigned(objrel.symbol) then
  941. internalerror(2021092604);
  942. if IsExternalFunction(objrel.symbol) or (objrel.symbol.typ=AT_FUNCTION) then
  943. begin
  944. Inc(relcount^);
  945. WriteByte(relout,Ord(R_WASM_TABLE_INDEX_I32));
  946. WriteUleb(relout,objrel.DataOffset+objsec.FileSectionOfs);
  947. WriteUleb(relout,TWasmObjSymbol(objrel.symbol).SymbolIndex);
  948. end
  949. else
  950. begin
  951. Inc(relcount^);
  952. WriteByte(relout,Ord(R_WASM_MEMORY_ADDR_I32));
  953. WriteUleb(relout,objrel.DataOffset+objsec.FileSectionOfs);
  954. WriteUleb(relout,TWasmObjSymbol(objrel.symbol).SymbolIndex);
  955. WriteSleb(relout,objrel.Addend); { addend to add to the address }
  956. end;
  957. end;
  958. RELOC_TYPE_INDEX_LEB:
  959. begin
  960. Inc(relcount^);
  961. WriteByte(relout,Ord(R_WASM_TYPE_INDEX_LEB));
  962. WriteUleb(relout,objrel.DataOffset+objsec.FileSectionOfs);
  963. WriteUleb(relout,objrel.TypeIndex);
  964. end;
  965. else
  966. internalerror(2021092507);
  967. end;
  968. end;
  969. end;
  970. end;
  971. function TWasmObjOutput.writeData(Data:TObjData):boolean;
  972. var
  973. i: Integer;
  974. objsec: TWasmObjSection;
  975. segment_count: Integer = 0;
  976. cur_seg_ofs: qword = 0;
  977. types_count,
  978. imports_count, NextImportFunctionIndex, NextFunctionIndex: Integer;
  979. import_functions_count: Integer = 0;
  980. functions_count: Integer = 0;
  981. objsym, ObjSymAlias: TWasmObjSymbol;
  982. cust_sec: TWasmCustomSectionType;
  983. begin
  984. FData:=TWasmObjData(Data);
  985. { each custom sections starts with its name }
  986. for cust_sec in TWasmCustomSectionType do
  987. WriteName(FWasmCustomSections[cust_sec],WasmCustomSectionName[cust_sec]);
  988. WriteUleb(FWasmCustomSections[wcstLinking],2); { linking metadata version }
  989. for i:=0 to Data.ObjSymbolList.Count-1 do
  990. begin
  991. objsym:=TWasmObjSymbol(Data.ObjSymbolList[i]);
  992. if IsExternalFunction(objsym) then
  993. Inc(import_functions_count);
  994. if (objsym.typ=AT_FUNCTION) and not objsym.IsAlias then
  995. Inc(functions_count);
  996. end;
  997. types_count:=Length(FData.FFuncTypes);
  998. WriteUleb(FWasmSections[wsiType],types_count);
  999. for i:=0 to types_count-1 do
  1000. with FData.FFuncTypes[i] do
  1001. begin
  1002. WriteByte(FWasmSections[wsiType],$60);
  1003. WriteWasmResultType(FWasmSections[wsiType],params);
  1004. WriteWasmResultType(FWasmSections[wsiType],results);
  1005. end;
  1006. for i:=0 to Data.ObjSectionList.Count-1 do
  1007. begin
  1008. objsec:=TWasmObjSection(Data.ObjSectionList[i]);
  1009. if objsec.IsCode then
  1010. objsec.SegIdx:=-1
  1011. else
  1012. begin
  1013. objsec.SegIdx:=segment_count;
  1014. objsec.SegOfs:=cur_seg_ofs;
  1015. Inc(segment_count);
  1016. Inc(cur_seg_ofs,objsec.Size);
  1017. end;
  1018. end;
  1019. WriteUleb(FWasmSections[wsiData],segment_count);
  1020. WriteUleb(FWasmSections[wsiDataCount],segment_count);
  1021. WriteUleb(FWasmLinkingSubsections[WASM_SEGMENT_INFO],segment_count);
  1022. for i:=0 to Data.ObjSectionList.Count-1 do
  1023. begin
  1024. objsec:=TWasmObjSection(Data.ObjSectionList[i]);
  1025. if objsec.IsData then
  1026. begin
  1027. WriteName(FWasmLinkingSubsections[WASM_SEGMENT_INFO],objsec.Name);
  1028. WriteUleb(FWasmLinkingSubsections[WASM_SEGMENT_INFO],BsrQWord(objsec.SecAlign));
  1029. WriteUleb(FWasmLinkingSubsections[WASM_SEGMENT_INFO],0); { flags }
  1030. WriteByte(FWasmSections[wsiData],0);
  1031. WriteByte(FWasmSections[wsiData],$41);
  1032. WriteSleb(FWasmSections[wsiData],objsec.SegOfs);
  1033. WriteByte(FWasmSections[wsiData],$0b);
  1034. WriteUleb(FWasmSections[wsiData],objsec.Size);
  1035. objsec.FileSectionOfs:=FWasmSections[wsiData].size;
  1036. if oso_Data in objsec.SecOptions then
  1037. begin
  1038. objsec.Data.seek(0);
  1039. CopyDynamicArray(objsec.Data,FWasmSections[wsiData],objsec.Size);
  1040. end
  1041. else
  1042. begin
  1043. WriteZeros(FWasmSections[wsiData],objsec.Size);
  1044. end;
  1045. end;
  1046. end;
  1047. imports_count:=3+import_functions_count;
  1048. WriteUleb(FWasmSections[wsiImport],imports_count);
  1049. { import[0] }
  1050. WriteName(FWasmSections[wsiImport],'env');
  1051. WriteName(FWasmSections[wsiImport],'__linear_memory');
  1052. WriteByte(FWasmSections[wsiImport],$02); { mem }
  1053. WriteByte(FWasmSections[wsiImport],$00); { min }
  1054. WriteUleb(FWasmSections[wsiImport],1); { 1 page }
  1055. { import[1] }
  1056. WriteName(FWasmSections[wsiImport],'env');
  1057. WriteName(FWasmSections[wsiImport],'__stack_pointer');
  1058. WriteByte(FWasmSections[wsiImport],$03); { global }
  1059. WriteByte(FWasmSections[wsiImport],$7F); { i32 }
  1060. WriteByte(FWasmSections[wsiImport],$01); { var }
  1061. { import[2]..import[imports_count-2] }
  1062. NextImportFunctionIndex:=0;
  1063. for i:=0 to Data.ObjSymbolList.Count-1 do
  1064. begin
  1065. objsym:=TWasmObjSymbol(Data.ObjSymbolList[i]);
  1066. if IsExternalFunction(objsym) then
  1067. begin
  1068. objsym.ImportIndex:=NextImportFunctionIndex;
  1069. Inc(NextImportFunctionIndex);
  1070. objsym.ExtraData:=TWasmObjSymbolExtraData(FData.FObjSymbolsExtraDataList.Find(objsym.Name));
  1071. if objsym.ExtraData.ImportModule<>'' then
  1072. WriteName(FWasmSections[wsiImport],objsym.ExtraData.ImportModule)
  1073. else
  1074. WriteName(FWasmSections[wsiImport],'env');
  1075. WriteName(FWasmSections[wsiImport],objsym.Name);
  1076. WriteByte(FWasmSections[wsiImport],$00); { func }
  1077. WriteUleb(FWasmSections[wsiImport],TWasmObjSymbolExtraData(FData.FObjSymbolsExtraDataList.Find(objsym.Name)).TypeIdx);
  1078. end;
  1079. end;
  1080. { import[imports_count-1] }
  1081. WriteName(FWasmSections[wsiImport],'env');
  1082. WriteName(FWasmSections[wsiImport],'__indirect_function_table');
  1083. WriteByte(FWasmSections[wsiImport],$01); { table }
  1084. WriteByte(FWasmSections[wsiImport],$70); { funcref }
  1085. WriteByte(FWasmSections[wsiImport],$00); { min }
  1086. WriteUleb(FWasmSections[wsiImport],1); { 1 }
  1087. WriteUleb(FWasmSections[wsiFunction],functions_count);
  1088. NextFunctionIndex:=NextImportFunctionIndex;
  1089. for i:=0 to Data.ObjSymbolList.Count-1 do
  1090. begin
  1091. objsym:=TWasmObjSymbol(Data.ObjSymbolList[i]);
  1092. if (objsym.typ=AT_FUNCTION) and not objsym.IsAlias then
  1093. begin
  1094. objsym.FuncIndex:=NextFunctionIndex;
  1095. Inc(NextFunctionIndex);
  1096. WriteUleb(FWasmSections[wsiFunction],TWasmObjSymbolExtraData(FData.FObjSymbolsExtraDataList.Find(objsym.Name)).TypeIdx);
  1097. end;
  1098. end;
  1099. for i:=0 to Data.ObjSymbolList.Count-1 do
  1100. begin
  1101. objsym:=TWasmObjSymbol(Data.ObjSymbolList[i]);
  1102. if IsExternalFunction(objsym) then
  1103. begin
  1104. objsym.SymbolIndex:=FWasmSymbolTableEntriesCount;
  1105. Inc(FWasmSymbolTableEntriesCount);
  1106. WriteByte(FWasmSymbolTable,Ord(SYMTAB_FUNCTION));
  1107. if objsym.ExtraData.ImportModule<>'' then
  1108. begin
  1109. WriteUleb(FWasmSymbolTable,WASM_SYM_UNDEFINED or WASM_SYM_EXPLICIT_NAME);
  1110. WriteUleb(FWasmSymbolTable,objsym.ImportIndex);
  1111. WriteName(FWasmSymbolTable,objsym.Name);
  1112. end
  1113. else
  1114. begin
  1115. WriteUleb(FWasmSymbolTable,WASM_SYM_UNDEFINED);
  1116. WriteUleb(FWasmSymbolTable,objsym.ImportIndex);
  1117. end;
  1118. end
  1119. else if objsym.typ=AT_FUNCTION then
  1120. begin
  1121. objsym.SymbolIndex:=FWasmSymbolTableEntriesCount;
  1122. Inc(FWasmSymbolTableEntriesCount);
  1123. WriteByte(FWasmSymbolTable,Ord(SYMTAB_FUNCTION));
  1124. if objsym.IsAlias then
  1125. begin
  1126. ObjSymAlias:=TWasmObjSymbol(Data.ObjSymbolList.Find(objsym.AliasOf));
  1127. ObjSym.FuncIndex:=ObjSymAlias.FuncIndex;
  1128. WriteUleb(FWasmSymbolTable,WASM_SYM_EXPLICIT_NAME or WASM_SYM_NO_STRIP);
  1129. WriteUleb(FWasmSymbolTable,ObjSymAlias.FuncIndex);
  1130. end
  1131. else
  1132. begin
  1133. WriteUleb(FWasmSymbolTable,0);
  1134. WriteUleb(FWasmSymbolTable,objsym.FuncIndex);
  1135. end;
  1136. WriteName(FWasmSymbolTable,objsym.Name);
  1137. end
  1138. else if (objsym.typ in [AT_DATA,AT_TLS]) or ((objsym.typ=AT_NONE) and (objsym.bind=AB_EXTERNAL)) then
  1139. begin
  1140. objsym.SymbolIndex:=FWasmSymbolTableEntriesCount;
  1141. Inc(FWasmSymbolTableEntriesCount);
  1142. WriteByte(FWasmSymbolTable,Ord(SYMTAB_DATA));
  1143. if objsym.bind=AB_GLOBAL then
  1144. WriteUleb(FWasmSymbolTable,0)
  1145. else if objsym.bind=AB_LOCAL then
  1146. WriteUleb(FWasmSymbolTable,WASM_SYM_BINDING_LOCAL)
  1147. else if objsym.bind=AB_EXTERNAL then
  1148. WriteUleb(FWasmSymbolTable,WASM_SYM_UNDEFINED)
  1149. else
  1150. internalerror(2021092506);
  1151. WriteName(FWasmSymbolTable,objsym.Name);
  1152. if objsym.bind<>AB_EXTERNAL then
  1153. begin
  1154. WriteUleb(FWasmSymbolTable,TWasmObjSection(objsym.objsection).SegIdx);
  1155. WriteUleb(FWasmSymbolTable,objsym.offset);
  1156. WriteUleb(FWasmSymbolTable,objsym.size);
  1157. end;
  1158. end;
  1159. end;
  1160. DoRelocations;
  1161. WriteUleb(FWasmSections[wsiCode],functions_count);
  1162. for i:=0 to Data.ObjSymbolList.Count-1 do
  1163. begin
  1164. objsym:=TWasmObjSymbol(Data.ObjSymbolList[i]);
  1165. if (objsym.typ=AT_FUNCTION) and not objsym.IsAlias then
  1166. WriteFunctionCode(FWasmSections[wsiCode],objsym);
  1167. end;
  1168. WriteRelocations;
  1169. WriteSymbolTable;
  1170. WriteLinkingSubsection(WASM_SYMBOL_TABLE);
  1171. WriteLinkingSubsection(WASM_SEGMENT_INFO);
  1172. WriteRelocationCodeTable(4); { code section is section #4 }
  1173. WriteRelocationDataTable(5); { code section is section #5 }
  1174. Writer.write(WasmModuleMagic,SizeOf(WasmModuleMagic));
  1175. Writer.write(WasmVersion,SizeOf(WasmVersion));
  1176. WriteWasmSection(wsiType); { section #0 }
  1177. WriteWasmSection(wsiImport); { section #1 }
  1178. WriteWasmSection(wsiFunction); { section #2 }
  1179. WriteWasmSection(wsiDataCount); { section #3 }
  1180. WriteWasmSection(wsiCode); { section #4 }
  1181. WriteWasmSection(wsiData); { section #5 }
  1182. WriteWasmCustomSection(wcstLinking); { section #6 }
  1183. WriteWasmCustomSection(wcstRelocCode); { section #7 }
  1184. WriteWasmCustomSection(wcstRelocData); { section #8 }
  1185. Writeln('ObjSymbolList:');
  1186. for i:=0 to Data.ObjSymbolList.Count-1 do
  1187. begin
  1188. objsym:=TWasmObjSymbol(Data.ObjSymbolList[i]);
  1189. Write(objsym.Name, ' bind=', objsym.Bind, ' typ=', objsym.typ, ' address=', objsym.address, ' objsection=');
  1190. if assigned(objsym.objsection) then
  1191. Write(objsym.objsection.Name)
  1192. else
  1193. Write('nil');
  1194. Writeln;
  1195. end;
  1196. Writeln('ObjSectionList:');
  1197. for i:=0 to Data.ObjSectionList.Count-1 do
  1198. begin
  1199. objsec:=TWasmObjSection(Data.ObjSectionList[i]);
  1200. Writeln(objsec.Name, ' IsCode=', objsec.IsCode, ' IsData=', objsec.IsData, ' Size=', objsec.Size, ' MemPos=', objsec.MemPos, ' DataPos=', objsec.DataPos, ' SegIdx=', objsec.SegIdx);
  1201. end;
  1202. result:=true;
  1203. end;
  1204. constructor TWasmObjOutput.create(AWriter: TObjectWriter);
  1205. var
  1206. i: TWasmSectionID;
  1207. j: TWasmCustomSectionType;
  1208. k: TWasmLinkingSubsectionType;
  1209. begin
  1210. inherited;
  1211. cobjdata:=TWasmObjData;
  1212. for i in TWasmSectionID do
  1213. FWasmSections[i] := tdynamicarray.create(SectionDataMaxGrow);
  1214. for j in TWasmCustomSectionType do
  1215. FWasmCustomSections[j] := tdynamicarray.create(SectionDataMaxGrow);
  1216. for k:=low(TWasmLinkingSubsectionType) to high(TWasmLinkingSubsectionType) do
  1217. FWasmLinkingSubsections[k] := tdynamicarray.create(SectionDataMaxGrow);
  1218. FWasmSymbolTable:=tdynamicarray.create(SectionDataMaxGrow);
  1219. FWasmSymbolTableEntriesCount:=0;
  1220. FWasmRelocationCodeTable:=tdynamicarray.create(SectionDataMaxGrow);
  1221. FWasmRelocationCodeTableEntriesCount:=0;
  1222. FWasmRelocationDataTable:=tdynamicarray.create(SectionDataMaxGrow);
  1223. FWasmRelocationDataTableEntriesCount:=0;
  1224. end;
  1225. destructor TWasmObjOutput.destroy;
  1226. var
  1227. i: TWasmSectionID;
  1228. j: TWasmCustomSectionType;
  1229. k: TWasmLinkingSubsectionType;
  1230. begin
  1231. for i in TWasmSectionID do
  1232. FWasmSections[i].Free;
  1233. for j in TWasmCustomSectionType do
  1234. FWasmCustomSections[j].Free;
  1235. for k:=low(TWasmLinkingSubsectionType) to high(TWasmLinkingSubsectionType) do
  1236. FWasmLinkingSubsections[k].Free;
  1237. FWasmSymbolTable.Free;
  1238. FWasmRelocationCodeTable.Free;
  1239. FWasmRelocationDataTable.Free;
  1240. inherited destroy;
  1241. end;
  1242. {****************************************************************************
  1243. TWasmAssembler
  1244. ****************************************************************************}
  1245. constructor TWasmAssembler.Create(info: pasminfo; smart:boolean);
  1246. begin
  1247. inherited;
  1248. CObjOutput:=TWasmObjOutput;
  1249. end;
  1250. {*****************************************************************************
  1251. Initialize
  1252. *****************************************************************************}
  1253. {$ifdef wasm32}
  1254. const
  1255. as_wasm32_wasm_info : tasminfo =
  1256. (
  1257. id : as_wasm32_wasm;
  1258. idtxt : 'OMF';
  1259. asmbin : '';
  1260. asmcmd : '';
  1261. supported_targets : [system_wasm32_embedded,system_wasm32_wasi];
  1262. flags : [af_outputbinary,af_smartlink_sections];
  1263. labelprefix : '..@';
  1264. labelmaxlen : -1;
  1265. comment : '; ';
  1266. dollarsign: '$';
  1267. );
  1268. {$endif wasm32}
  1269. initialization
  1270. {$ifdef wasm32}
  1271. RegisterAssembler(as_wasm32_wasm_info,TWasmAssembler);
  1272. {$endif wasm32}
  1273. end.