Browse Source

[PATCH 185/188] changing relocation to use actual wasmmodule objects,
instead of indexes. As the actual symbol index is only known when after
linking section was written

From 32f96b6a7da19db001b62481e860df5757f0867c Mon Sep 17 00:00:00 2001
From: Dmitry Boyarintsev <[email protected]>
Date: Mon, 13 Apr 2020 09:32:18 -0400

git-svn-id: branches/wasm@46181 -

nickysn 5 years ago
parent
commit
9d235d92bf
3 changed files with 145 additions and 22 deletions
  1. 84 14
      utils/wasmbin/wasmbinwriter.pas
  2. 47 4
      utils/wasmbin/wasmmodule.pas
  3. 14 4
      utils/wasmbin/wasmnormalize.pas

+ 84 - 14
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<p2 then Result:=-1
+  else if p1=p2 then Result:=0
+  else Result:=1;
+end;
+
+function CompareSymObjs(Item1, Item2: Pointer): Integer;
+var
+  s1, s2: TSymbolObject;
+begin
+  s1:=TSymbolObject(Item1);
+  s2:=TSymbolObject(Item2);
+  Result:=ComparePtrUInt(PtrUInt(s1.wasmObj), PtrUInt(s2.wasmObj));
+end;
+
+function CompareWasmToSymObj(Item1, Item2: Pointer): Integer;
+var
+  s2: TSymbolObject;
+begin
+  s2:=TSymbolObject(Item2);
+  Result:=ComparePtrUInt(PtrUInt(Item1), PtrUInt(s2.wasmObj));
+end;
+
 procedure WriteLimit(dst: TStream; amin, amax: LongWord);
 begin
   if not Assigned(dst) then Exit;
@@ -161,19 +189,47 @@ end;
 
 { TBinWriter }
 
-function TBinWriter.AddSymbolObject: TSymbolObject;
+function GetLinkName(const linkInfo: TLinkInfo; const id: string): string;
+begin
+  if linkInfo.Name<>'' 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.

+ 47 - 4
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

+ 14 - 4
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;