diff --git a/utils/wasmbin/wasmbinwriter.pas b/utils/wasmbin/wasmbinwriter.pas index b98b404260..d39e3f1ec2 100644 --- a/utils/wasmbin/wasmbinwriter.pas +++ b/utils/wasmbin/wasmbinwriter.pas @@ -5,7 +5,7 @@ unit wasmbinwriter; interface uses - Classes, SysUtils, + Classes, SysUtils, AVL_Tree, wasmmodule, wasmbin, lebutils, wasmbincode ,wasmlink; @@ -18,8 +18,10 @@ type end; TSymbolObject = class(TObject) + idx : Integer; syminfo : TSymInfo; next : TSymbolObject; + wasmObj : TObject; end; { TBinWriter } @@ -39,9 +41,11 @@ type symHead : TSymbolObject; symTail : TSymbolObject; + syms : TAVLTree; symCount : Integer; - function AddSymbolObject: TSymbolObject; - procedure AddReloc(relocType: byte; ofs: int64; index: UInt32); + function AddSymbolObject(obj: TObject): TSymbolObject; + procedure AddRelocWithIndex(relocType: byte; secOfs: int64; index: UInt32); + procedure AddRelocToObj(relocType: byte; secOfs: int64; wasmObj: TObject); procedure WriteRelocU32(u: longword); procedure WriteString(const s: string); @@ -60,13 +64,12 @@ type procedure WriteCodeSect; procedure WriteElemSect; + procedure PrepareLinkSym(m: TWasmModule); procedure WriteLinkingSect; procedure WriteRelocSect; procedure pushStream(st: TStream); function popStream: TStream; - - procedure PrepareLinkSym(m: TWasmModule); public keepLeb128 : Boolean; // keep leb128 at 4 offset relocatable writeReloc : Boolean; // writting relocation (linking) information @@ -93,6 +96,31 @@ procedure WriteLimit(dst: TStream; amin, amax: LongWord); implementation + +function ComparePtrUInt(p1,p2: PtrUInt): Integer; inline; +begin + if p1'' then Result:=linkInfo.Name + else Result:=id; +end; + +function TBinWriter.AddSymbolObject(obj: TObject): TSymbolObject; var so : TSymbolObject; + t : TAVLTreeNode; begin + t := syms.FindKey(obj, @CompareWasmToSymObj); + if Assigned(t) then begin + Result:=TSymbolObject(t.Data); + Exit; + end; so := TSymbolObject.Create; if not Assigned(symHead) then symHead:=so; if Assigned(symTail) then symTail.Next:=so; + so.idx:=symCount; + so.wasmObj:=obj; symTail:=so; inc(symCount); Result:=so; + + if (obj is TWasmFunc) then begin + so.syminfo.kind:=SYMTAB_FUNCTION; + so.syminfo.symindex:=TWasmFunc(obj).idNum; + end else if (obj is TWasmGlobal) then begin + so.syminfo.kind:=SYMTAB_GLOBAL; + so.syminfo.symindex:=TWasmGlobal(obj).id.idNum; + so.syminfo.symname:=GetLinkName(TWasmGlobal(obj).LinkInfo, TWasmGlobal(obj).id.id); //todo: use symbolic name + end else if (obj is TWasmTable) then begin + so.syminfo.kind:=SYMTAB_TABLE; + so.syminfo.symindex:=TWasmTable(obj).id.idNum; + end; + + syms.Add(so); end; -procedure TBinWriter.AddReloc(relocType: byte; ofs: int64; index: UInt32); +procedure TBinWriter.AddRelocWithIndex(relocType: byte; secOfs: int64; index: UInt32); var i : integer; f : TWasmFunc; @@ -186,7 +242,7 @@ begin i:=relocCount; reloc[i].sec:=writeSec; reloc[i].reltype:=relocType; - reloc[i].offset:=ofs; + reloc[i].offset:=secOfs; reloc[i].index:=index; inc(relocCount); @@ -202,6 +258,16 @@ begin end; end; +procedure TBinWriter.AddRelocToObj(relocType: byte; secOfs: int64; wasmObj: TObject); +var + idx : integer; +begin + if not Assigned(wasmObj) then Exit; + + idx:=AddSymbolObject(wasmObj).idx; + AddRelocWithIndex(relocType, secOfs, idx); +end; + procedure TBinWriter.WriteRelocU32(u: longword); begin WriteU(dst, u, sizeof(u)*8, keepLeb128); @@ -520,7 +586,8 @@ begin if writeReloc then begin for j:=0 to el.funcCount-1 do begin - AddReloc(R_WASM_FUNCTION_INDEX_LEB, dst.Position - sc.datapos, el.funcs[j].idNum); + AddRelocToObj(R_WASM_FUNCTION_INDEX_LEB, dst.Position - sc.datapos, + GetFuncByNum(module, el.funcs[j].idNum)); WriteRelocU32(el.funcs[j].idNum); end; end else @@ -620,9 +687,8 @@ begin dst.WriteByte(ci.code); if ci.hasRelocIdx then begin - idx := ci.relocIdx; rt := ci.relocType; - AddReloc(rt, dst.Position+ofsAddition, LongWord(idx)); + AddRelocToObj(rt, dst.Position+ofsAddition, ci.relocObj); end; case INST_FLAGS[ci.code].Param of @@ -745,10 +811,12 @@ constructor TBinWriter.Create; begin inherited Create; strm:=TList.Create; + syms:=TAVLTree.Create(@CompareSymObjs); end; destructor TBinWriter.Destroy; begin + syms.Free; strm.Free; inherited Destroy; end; @@ -761,7 +829,7 @@ begin or l.NoStrip; end; -procedure LinkInfoToBin(const src: TLinkInfo; var dst: TSymInfo; ASymTab: byte; aofs: longword); +procedure LinkInfoToBin(const src: TLinkInfo; var dst: TSymInfo; ASymTab: byte; objFnIdx: longword); begin dst.kind := ASymTab; dst.flags := 0; @@ -773,7 +841,7 @@ begin if src.isHidden then dst.flags := dst.flags or WASM_SYM_VISIBILITY_HIDDEN; if src.isUndefined then dst.flags := dst.flags or WASM_SYM_UNDEFINED; if src.NoStrip then dst.flags := dst.flags or WASM_SYM_NO_STRIP; - dst.symindex := aofs; + dst.symindex := objFnIdx; dst.hasSymIndex := ASymTab<>SYMTAB_DATA; dst.hasSymName := src.Name<>''; if (dst.hasSymName) then begin @@ -788,14 +856,16 @@ var f : TWasmFunc; so : TSymbolObject; begin + writeln('preparing symlinks'); for i:=0 to m.FuncCount-1 do begin f := m.GetFunc(i); if isFuncLinkSym(f.LinkInfo) or (f.codeRefCount>0) then begin if f.LinkInfo.Name ='' then f.LinkInfo.Name := f.id; - so:=AddSymbolObject; + so:=AddSymbolObject(f); LinkInfoToBin(f.linkInfo, so.syminfo, SYMTAB_FUNCTION, f.idNum); end; end; + writeln('done'); end; end. diff --git a/utils/wasmbin/wasmmodule.pas b/utils/wasmbin/wasmmodule.pas index bb014cdbb8..18558c7edc 100644 --- a/utils/wasmbin/wasmmodule.pas +++ b/utils/wasmbin/wasmmodule.pas @@ -106,8 +106,9 @@ type jumplabel : string; // the label is used only for "loop", "block" and "if" hasRelocIdx : Boolean; - relocIdx : integer; + //relocIdx : integer; relocType : Byte; + relocObj : TObject; // vecTableCount : Integer; vecTable : array of TWasmId; @@ -115,7 +116,7 @@ type function addInstType: TWasmFuncType; constructor Create; destructor Destroy; override; - procedure SetReloc(ARelocType: byte; ARelocIndex: Integer); + procedure SetReloc(ARelocType: byte; ARelocObj: TObject); property offsetText : TWasmInstrOperand read operand1 write operand1; property alignText : TWasmInstrOperand read operand2 write operand2; @@ -326,6 +327,12 @@ procedure OperandSetType(var op: TWasmInstrOperand; tp: TWasmInstrOperandType); procedure OperandSetInt32(var op: TWasmInstrOperand; i32: Int32); inline; procedure OperandSetText(var op: TWasmInstrOperand; const txt: string); inline; +// should be used after normalization +// todo: what about imported functions? +function GetFuncByNum(m: TWasmModule; const idNum: Integer): TWasmFunc; +function GetGlobalByNum(m: TWasmModule; const idNum: Integer): TWasmGlobal; +function GetMemByNum(m: TWasmModule; const idNum: Integer): TWasmMemory; + implementation procedure OperandSetType(var op: TWasmInstrOperand; tp: TWasmInstrOperandType); inline; @@ -567,11 +574,11 @@ begin inherited Destroy; end; -procedure TWasmInstr.SetReloc(ARelocType: byte; ARelocIndex: Integer); +procedure TWasmInstr.SetReloc(ARelocType: byte; ARelocObj: TObject); begin hasRelocIdx := true; relocType := ARelocType; - relocIdx := ARelocIndex; + relocObj := ARelocObj; end; { TWasmInstrList } @@ -1027,6 +1034,42 @@ begin end; end; +function GetFuncByNum(m: TWasmMOdule; const idNum: Integer): TWasmFunc; +var + i : integer; +begin + for i:=0 to m.FuncCount-1 do begin + Result := m.GetFunc(i); + if Assigned(Result) and (Result.idNum = idNum) then + Exit; + end; + Result:=nil; +end; + +function GetGlobalByNum(m: TWasmModule; const idNum: Integer): TWasmGlobal; +var + i : integer; +begin + for i:=0 to m.GlobalCount-1 do begin + Result := m.GetGlobal(i); + if Assigned(Result) and (Result.id.idNum = idNum) then + Exit; + end; + Result:=nil; +end; + +function GetMemByNum(m: TWasmModule; const idNum: Integer): TWasmMemory; +var + i : integer; +begin + for i:=0 to m.MemoryCount-1 do begin + Result := m.GetMemory(i); + if Assigned(Result) and (Result.id.idNum = idNum) then + Exit; + end; + Result:=nil; +end; + // only looking up for the by the type index name function FindFuncType(m: TWasmModule; const typeIdx: string): integer; var diff --git a/utils/wasmbin/wasmnormalize.pas b/utils/wasmbin/wasmnormalize.pas index a96d23e8f5..7145eaa191 100644 --- a/utils/wasmbin/wasmnormalize.pas +++ b/utils/wasmbin/wasmnormalize.pas @@ -13,25 +13,35 @@ implementation procedure PopulateRelocData(module: TWasmModule; ci: TWasmInstr); var idx : integer; + obj : TObject; begin case INST_FLAGS[ci.code].Param of ipi32OrFunc: if (ci.operand1.textVal<>'') and (ci.operand1.textVal[1]='$') then begin //if not ci.hasRelocIdx then - idx := RegisterfuncInElem(module, ci.operand1.textVal); + idx := RegisterFuncInElem(module, ci.operand1.textVal); + obj := GetFuncByNum(module, idx); //AddReloc(rt, dst.Position+ofsAddition, idx); ci.operandNum := idx; - ci.SetReloc(INST_RELOC_FLAGS[ci.code].relocType, idx); + ci.SetReloc(INST_RELOC_FLAGS[ci.code].relocType, obj); end; ipLeb: if (INST_RELOC_FLAGS[ci.code].doReloc) then begin - ci.SetReloc(INST_RELOC_FLAGS[ci.code].relocType, ci.operandNum); + case INST_RELOC_FLAGS[ci.code].relocType of + R_WASM_GLOBAL_INDEX_LEB: + ci.SetReloc(INST_RELOC_FLAGS[ci.code].relocType, GetGlobalByNum(module, ci.operandNum)); + + R_WASM_MEMORY_ADDR_LEB : + ci.SetReloc(INST_RELOC_FLAGS[ci.code].relocType, GetMemByNum(module, ci.operandNum)); + end; end; ipCallType: if Assigned(ci.insttype) then - ci.SetReloc(INST_RELOC_FLAGS[ci.code].relocType, ci.insttype.typeNum); + begin + ci.SetReloc(INST_RELOC_FLAGS[ci.code].relocType, ci.insttype); + end; end; end;