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

This commit is contained in:
Nikolay Nikolov 2024-06-27 06:39:06 +03:00
parent 868d5f29c9
commit b28d49ced7
2 changed files with 110 additions and 4 deletions

View File

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

View File

@ -40,14 +40,19 @@ type
fDescription : string;
fRoot : TRootResTreeNode;
fResStringTable : TResStringTable;
fOppositeEndianess : boolean;
fDataAlignment : longword;
fDataCurOfs : longword;
FWasmSections: array [TWasmSectionID] of TMemoryStream;
FDataSegments: array [TWasmResourceDataSegment] of TMemoryStream;
function NextAligned(aBound, aValue : longword) : longword;
procedure PrescanResourceTree;
function PrescanNode(aNode : TResourceTreeNode; aNodeSize : longword) : longword;
procedure WriteResHeader(aResources : TResources);
procedure WriteWasmSection(aStream: TStream; wsid: TWasmSectionID);
procedure WriteWasmSectionIfNotEmpty(aStream: TStream; wsid: TWasmSectionID);
procedure WriteImportSection;
procedure WriteDataSegments;
protected
function GetExtensions : string; override;
function GetDescription : string; override;
@ -59,6 +64,22 @@ type
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);
var
b: byte;
@ -72,6 +93,13 @@ begin
until v=0;
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 }
function TWasmResourceWriter.NextAligned(aBound, aValue: longword): longword;
@ -125,6 +153,33 @@ begin
Result:=curofs;
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;
wsid: TWasmSectionID);
var
@ -143,6 +198,44 @@ begin
WriteWasmSection(aStream,wsid);
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;
begin
Result:=fExtensions;
@ -154,17 +247,17 @@ begin
end;
procedure TWasmResourceWriter.Write(aResources: TResources; aStream: TStream);
const
DataSegmentCount = 0;
begin
fRoot:=TRootResTreeNode(GetTree(aResources));
PrescanResourceTree;
WriteResHeader(aResources);
WriteUleb(FWasmSections[wsiData],DataSegmentCount);
WriteUleb(FWasmSections[wsiDataCount],DataSegmentCount);
WriteImportSection;
WriteDataSegments;
aStream.WriteBuffer(WasmModuleMagic,SizeOf(WasmModuleMagic));
aStream.WriteBuffer(WasmVersion,SizeOf(WasmVersion));
WriteWasmSection(aStream,wsiImport);
WriteWasmSection(aStream,wsiDataCount);
WriteWasmSection(aStream,wsiData);
end;
@ -172,20 +265,31 @@ end;
constructor TWasmResourceWriter.Create;
var
i: TWasmSectionID;
j: TWasmResourceDataSegment;
begin
fExtensions:='.o .or';
fDescription:='WebAssembly resource writer';
fResStringTable:=TResStringTable.Create;
fDataCurOfs:=0;
fDataAlignment:=4;
{$IFDEF FPC_BIG_ENDIAN}
fOppositeEndianess := True;
{$ELSE FPC_BIG_ENDIAN}
fOppositeEndianess := False;
{$ENDIF FPC_BIG_ENDIAN}
for i in TWasmSectionID do
FWasmSections[i] := TMemoryStream.Create;
for j in TWasmResourceDataSegment do
FDataSegments[j] := TMemoryStream.Create;
end;
destructor TWasmResourceWriter.Destroy;
var
i: TWasmSectionID;
j: TWasmResourceDataSegment;
begin
for j in TWasmResourceDataSegment do
FreeAndNil(FDataSegments[j]);
for i in TWasmSectionID do
FreeAndNil(FWasmSections[i]);
FreeAndNil(fResStringTable);