Browse Source

+ wasm resource writer: start writing the data segments, also the import section

Nikolay Nikolov 1 year ago
parent
commit
b28d49ced7
2 changed files with 110 additions and 4 deletions
  1. 2 0
      packages/fcl-res/src/wasmtypes.pp
  2. 108 4
      packages/fcl-res/src/wasmwriter.pp

+ 2 - 0
packages/fcl-res/src/wasmtypes.pp

@@ -97,6 +97,8 @@ type
     SYMTAB_EVENT    = 4,
     SYMTAB_EVENT    = 4,
     SYMTAB_TABLE    = 5);
     SYMTAB_TABLE    = 5);
 
 
+  TWasmResourceDataSegment = (wrdsResources, wrdsResHandles);
+
 implementation
 implementation
 
 
 end.
 end.

+ 108 - 4
packages/fcl-res/src/wasmwriter.pp

@@ -40,14 +40,19 @@ type
     fDescription : string;
     fDescription : string;
     fRoot : TRootResTreeNode;
     fRoot : TRootResTreeNode;
     fResStringTable : TResStringTable;
     fResStringTable : TResStringTable;
+    fOppositeEndianess : boolean;
     fDataAlignment : longword;
     fDataAlignment : longword;
     fDataCurOfs : longword;
     fDataCurOfs : longword;
     FWasmSections: array [TWasmSectionID] of TMemoryStream;
     FWasmSections: array [TWasmSectionID] of TMemoryStream;
+    FDataSegments: array [TWasmResourceDataSegment] of TMemoryStream;
     function NextAligned(aBound, aValue : longword) : longword;
     function NextAligned(aBound, aValue : longword) : longword;
     procedure PrescanResourceTree;
     procedure PrescanResourceTree;
     function PrescanNode(aNode : TResourceTreeNode; aNodeSize : longword) : longword;
     function PrescanNode(aNode : TResourceTreeNode; aNodeSize : longword) : longword;
+    procedure WriteResHeader(aResources : TResources);
     procedure WriteWasmSection(aStream: TStream; wsid: TWasmSectionID);
     procedure WriteWasmSection(aStream: TStream; wsid: TWasmSectionID);
     procedure WriteWasmSectionIfNotEmpty(aStream: TStream; wsid: TWasmSectionID);
     procedure WriteWasmSectionIfNotEmpty(aStream: TStream; wsid: TWasmSectionID);
+    procedure WriteImportSection;
+    procedure WriteDataSegments;
   protected
   protected
     function GetExtensions : string; override;
     function GetExtensions : string; override;
     function GetDescription : string; override;
     function GetDescription : string; override;
@@ -59,6 +64,22 @@ type
 
 
 implementation
 implementation
 
 
+procedure WriteSleb(aStream: TStream; v: int64);
+var
+  b: byte;
+  Done: Boolean=false;
+begin
+  repeat
+    b:=byte(v) and 127;
+    v:=SarInt64(v,7);
+    if ((v=0) and ((b and 64)=0)) or ((v=-1) and ((b and 64)<>0)) then
+      Done:=true
+    else
+      b:=b or 128;
+    aStream.WriteByte(b);
+  until Done;
+end;
+
 procedure WriteUleb(aStream: TStream; v: uint64);
 procedure WriteUleb(aStream: TStream; v: uint64);
 var
 var
   b: byte;
   b: byte;
@@ -72,6 +93,13 @@ begin
   until v=0;
   until v=0;
 end;
 end;
 
 
+procedure WriteName(aStream: TStream; const s: string);
+begin
+  WriteUleb(aStream,Length(s));
+  if Length(s)>0 then
+    aStream.WriteBuffer(s[1],Length(s));
+end;
+
 { TWasmResourceWriter }
 { TWasmResourceWriter }
 
 
 function TWasmResourceWriter.NextAligned(aBound, aValue: longword): longword;
 function TWasmResourceWriter.NextAligned(aBound, aValue: longword): longword;
@@ -125,6 +153,33 @@ begin
   Result:=curofs;
   Result:=curofs;
 end;
 end;
 
 
+procedure TWasmResourceWriter.WriteResHeader(aResources: TResources);
+var hdr : TResHdr32;
+begin
+  hdr.count:=aResources.Count;
+  hdr.usedhandles:=0;
+  hdr.handles:=0;
+
+  //fSymbolTable.AddSection(RSRCSECT_IDX);
+  //fSymbolTable.AddSection(HANDLESECT_IDX);
+  //case fRelocInfo.SectionType of
+  //  SHT_REL  : hdr.rootptr:=sizeof(hdr);
+  //  SHT_RELA : hdr.rootptr:=0;
+  //end;
+
+  //fRelocTable.Add(0,sizeof(hdr),RSRCSECT_IDX);
+  //fRelocTable.Add(sizeof(hdr.rootptr)+sizeof(hdr.count)+sizeof(hdr.usedhandles),0,HANDLESECT_IDX);
+  if fOppositeEndianess then
+  begin
+    hdr.rootptr:=SwapEndian(hdr.rootptr);
+    hdr.count:=SwapEndian(hdr.count);
+    //handles must be fixed later
+//    hdr.usedhandles:=SwapEndian(hdr.usedhandles);
+//    hdr.handles:=SwapEndian(hdr.handles);
+  end;
+  FDataSegments[wrdsResources].WriteBuffer(hdr,sizeof(hdr));
+end;
+
 procedure TWasmResourceWriter.WriteWasmSection(aStream: TStream;
 procedure TWasmResourceWriter.WriteWasmSection(aStream: TStream;
   wsid: TWasmSectionID);
   wsid: TWasmSectionID);
 var
 var
@@ -143,6 +198,44 @@ begin
     WriteWasmSection(aStream,wsid);
     WriteWasmSection(aStream,wsid);
 end;
 end;
 
 
+procedure TWasmResourceWriter.WriteImportSection;
+const
+  ImportsCount = 1;
+begin
+  WriteUleb(FWasmSections[wsiImport],ImportsCount);
+  { import memories }
+  WriteName(FWasmSections[wsiImport],'env');
+  WriteName(FWasmSections[wsiImport],'__linear_memory');
+  FWasmSections[wsiImport].WriteByte($02);  { mem }
+  FWasmSections[wsiImport].WriteByte($00);  { min }
+  WriteUleb(FWasmSections[wsiImport],1);    { 1 page }
+end;
+
+procedure TWasmResourceWriter.WriteDataSegments;
+const
+  DataSegmentCount = 2;
+var
+  ds: TMemoryStream;
+  ofs: int64;
+begin
+  WriteUleb(FWasmSections[wsiData],DataSegmentCount);
+  WriteUleb(FWasmSections[wsiDataCount],DataSegmentCount);
+  ofs:=0;
+  for ds in FDataSegments do
+  begin
+    FWasmSections[wsiData].WriteByte(0);
+    FWasmSections[wsiData].WriteByte($41);
+    WriteSleb(FWasmSections[wsiData],ofs);
+    FWasmSections[wsiData].WriteByte($0b);
+    WriteUleb(FWasmSections[wsiData],ds.Size);
+    if ds.Size>0 then
+    begin
+      FWasmSections[wsiData].CopyFrom(ds, 0);
+      Inc(ofs,ds.Size);
+    end;
+  end;
+end;
+
 function TWasmResourceWriter.GetExtensions: string;
 function TWasmResourceWriter.GetExtensions: string;
 begin
 begin
   Result:=fExtensions;
   Result:=fExtensions;
@@ -154,17 +247,17 @@ begin
 end;
 end;
 
 
 procedure TWasmResourceWriter.Write(aResources: TResources; aStream: TStream);
 procedure TWasmResourceWriter.Write(aResources: TResources; aStream: TStream);
-const
-  DataSegmentCount = 0;
 begin
 begin
   fRoot:=TRootResTreeNode(GetTree(aResources));
   fRoot:=TRootResTreeNode(GetTree(aResources));
   PrescanResourceTree;
   PrescanResourceTree;
+  WriteResHeader(aResources);
 
 
-  WriteUleb(FWasmSections[wsiData],DataSegmentCount);
-  WriteUleb(FWasmSections[wsiDataCount],DataSegmentCount);
+  WriteImportSection;
+  WriteDataSegments;
 
 
   aStream.WriteBuffer(WasmModuleMagic,SizeOf(WasmModuleMagic));
   aStream.WriteBuffer(WasmModuleMagic,SizeOf(WasmModuleMagic));
   aStream.WriteBuffer(WasmVersion,SizeOf(WasmVersion));
   aStream.WriteBuffer(WasmVersion,SizeOf(WasmVersion));
+  WriteWasmSection(aStream,wsiImport);
   WriteWasmSection(aStream,wsiDataCount);
   WriteWasmSection(aStream,wsiDataCount);
   WriteWasmSection(aStream,wsiData);
   WriteWasmSection(aStream,wsiData);
 end;
 end;
@@ -172,20 +265,31 @@ end;
 constructor TWasmResourceWriter.Create;
 constructor TWasmResourceWriter.Create;
 var
 var
   i: TWasmSectionID;
   i: TWasmSectionID;
+  j: TWasmResourceDataSegment;
 begin
 begin
   fExtensions:='.o .or';
   fExtensions:='.o .or';
   fDescription:='WebAssembly resource writer';
   fDescription:='WebAssembly resource writer';
   fResStringTable:=TResStringTable.Create;
   fResStringTable:=TResStringTable.Create;
   fDataCurOfs:=0;
   fDataCurOfs:=0;
   fDataAlignment:=4;
   fDataAlignment:=4;
+{$IFDEF FPC_BIG_ENDIAN}
+  fOppositeEndianess := True;
+{$ELSE FPC_BIG_ENDIAN}
+  fOppositeEndianess := False;
+{$ENDIF FPC_BIG_ENDIAN}
   for i in TWasmSectionID do
   for i in TWasmSectionID do
     FWasmSections[i] := TMemoryStream.Create;
     FWasmSections[i] := TMemoryStream.Create;
+  for j in TWasmResourceDataSegment do
+    FDataSegments[j] := TMemoryStream.Create;
 end;
 end;
 
 
 destructor TWasmResourceWriter.Destroy;
 destructor TWasmResourceWriter.Destroy;
 var
 var
   i: TWasmSectionID;
   i: TWasmSectionID;
+  j: TWasmResourceDataSegment;
 begin
 begin
+  for j in TWasmResourceDataSegment do
+    FreeAndNil(FDataSegments[j]);
   for i in TWasmSectionID do
   for i in TWasmSectionID do
     FreeAndNil(FWasmSections[i]);
     FreeAndNil(FWasmSections[i]);
   FreeAndNil(fResStringTable);
   FreeAndNil(fResStringTable);