Browse Source

* WebAssembly internal assembler writer: generate the function locals header
when assembling the tai_local directive, instead of injecting them manually in
TWasmObjOutput.WriteFunctionCode. This makes function code offsets correct
and avoids the need to manually adjust relocation fixups by adding the locals
header size. It also fixes relative relocations, used in DWARF debug line
info.

Nikolay Nikolov 10 months ago
parent
commit
562ca0ad80
2 changed files with 115 additions and 66 deletions
  1. 14 2
      compiler/assemble.pas
  2. 101 64
      compiler/ogwasm.pas

+ 14 - 2
compiler/assemble.pas

@@ -1942,7 +1942,7 @@ Implementation
              ait_globaltype:
                TWasmObjData(ObjData).DeclareGlobalType(tai_globaltype(hp));
              ait_functype:
-               TWasmObjData(ObjData).DeclareFuncType(tai_functype(hp));
+               TWasmObjData(ObjData).DeclareFuncType_Pass0(tai_functype(hp));
              ait_tagtype:
                TWasmObjData(ObjData).DeclareTagType(tai_tagtype(hp));
              ait_export_name:
@@ -1952,7 +1952,7 @@ Implementation
              ait_import_name:
                TWasmObjData(ObjData).DeclareImportName(tai_import_name(hp));
              ait_local:
-               TWasmObjData(ObjData).DeclareLocals(tai_local(hp));
+               TWasmObjData(ObjData).DeclareLocals_Pass0(tai_local(hp));
 {$endif WASM}
              else
                ;
@@ -2145,6 +2145,12 @@ Implementation
                      Internalerror(2019100703);
                  end;
                end;
+{$ifdef WASM}
+             ait_functype:
+               TWasmObjData(ObjData).DeclareFuncType_Pass1(tai_functype(hp));
+             ait_local:
+               TWasmObjData(ObjData).DeclareLocals_Pass1(tai_local(hp));
+{$endif WASM}
              else
                ;
            end;
@@ -2602,6 +2608,12 @@ Implementation
                  eabi_section.Data.write(ddword,4);
                  eabi_section.Data.Seek(TmpDataPos);
                end;
+{$ifdef WASM}
+             ait_functype:
+               TWasmObjData(ObjData).DeclareFuncType_Pass2(tai_functype(hp));
+             ait_local:
+               TWasmObjData(ObjData).WriteLocals_Pass2(tai_local(hp));
+{$endif WASM}
              else
                ;
            end;

+ 101 - 64
compiler/ogwasm.pas

@@ -119,8 +119,10 @@ interface
         GlobalType: TWasmBasicType;
         GlobalIsImmutable: Boolean;
         Locals: array of TWasmBasicType;
+        EncodedLocals: tdynamicarray;
         constructor Create(HashObjectList: TFPHashObjectList; const s: TSymStr);
-        procedure AddLocal(bastyp: TWasmBasicType);
+        destructor Destroy; override;
+        procedure AddLocals(alocals: TWasmLocalsDynArray);
       end;
 
       { TWasmObjSection }
@@ -131,7 +133,6 @@ interface
         SegSymIdx: Integer;
         SegOfs: qword;
         FileSectionOfs: qword;
-        EncodedLocalsSize: qword;
         MainFuncSymbol: TWasmObjSymbol;
         CustomSectionIdx: Integer;
         constructor create(AList:TFPHashObjectList;const Aname:string;Aalign:longint;Aoptions:TObjSectionOptions);override;
@@ -175,12 +176,16 @@ interface
         function globalref(asmsym:TAsmSymbol):TObjSymbol;
         function ExceptionTagRef(asmsym:TAsmSymbol):TObjSymbol;
         procedure DeclareGlobalType(gt: tai_globaltype);
-        procedure DeclareFuncType(ft: tai_functype);
+        procedure DeclareFuncType_Pass0(ft: tai_functype);
+        procedure DeclareFuncType_Pass1(ft: tai_functype);
+        procedure DeclareFuncType_Pass2(ft: tai_functype);
         procedure DeclareTagType(tt: tai_tagtype);
         procedure DeclareExportName(en: tai_export_name);
         procedure DeclareImportModule(aim: tai_import_module);
         procedure DeclareImportName(ain: tai_import_name);
-        procedure DeclareLocals(al: tai_local);
+        procedure DeclareLocals_Pass0(al: tai_local);
+        procedure DeclareLocals_Pass1(al: tai_local);
+        procedure WriteLocals_Pass2(al: tai_local);
         procedure symbolpairdefine(akind: TSymbolPairKind;const asym, avalue: string);override;
         property FuncTypes: TWasmFuncTypeTable read FFuncTypes;
       end;
@@ -217,7 +222,6 @@ interface
         procedure WriteWasmCustomSection(wcst: TWasmCustomSectionType);
         function IsExternalFunction(sym: TObjSymbol): Boolean;
         function IsExportedFunction(sym: TWasmObjSymbol): Boolean;
-        procedure WriteFunctionLocals(dest: tdynamicarray; ed: TWasmObjSymbolExtraData);
         procedure WriteFunctionCode(dest: tdynamicarray; objsym: TObjSymbol);
         procedure WriteSymbolTable;
         procedure WriteRelocationCodeTable(CodeSectionIndex: Integer);
@@ -735,15 +739,55 @@ implementation
 
     constructor TWasmObjSymbolExtraData.Create(HashObjectList: TFPHashObjectList; const s: TSymStr);
       begin
+        EncodedLocals:=nil;
         inherited Create(HashObjectList,s);
         TypeIdx:=-1;
         ExceptionTagTypeIdx:=-1;
       end;
 
-    procedure TWasmObjSymbolExtraData.AddLocal(bastyp: TWasmBasicType);
+    destructor TWasmObjSymbolExtraData.Destroy;
       begin
-        SetLength(Locals,Length(Locals)+1);
-        Locals[High(Locals)]:=bastyp;
+        EncodedLocals.Free;
+        inherited Destroy;
+      end;
+
+    procedure TWasmObjSymbolExtraData.AddLocals(alocals: TWasmLocalsDynArray);
+      var
+        i,
+        rle_entries,
+        cnt: Integer;
+        lasttype: TWasmBasicType;
+      begin
+        Locals:=alocals;
+        if Assigned(EncodedLocals) then
+          internalerror(2024081502);
+        EncodedLocals:=tdynamicarray.Create(64);
+        if Length(Locals)=0 then
+          begin
+            WriteUleb(EncodedLocals,0);
+            exit;
+          end;
+
+        rle_entries:=1;
+        for i:=low(Locals)+1 to high(Locals) do
+          if Locals[i]<>Locals[i-1] then
+            inc(rle_entries);
+
+        WriteUleb(EncodedLocals,rle_entries);
+        lasttype:=Locals[Low(Locals)];
+        cnt:=1;
+        for i:=low(Locals)+1 to high(Locals) do
+          if Locals[i]=Locals[i-1] then
+            inc(cnt)
+          else
+            begin
+              WriteUleb(EncodedLocals,cnt);
+              WriteWasmBasicType(EncodedLocals,lasttype);
+              lasttype:=Locals[i];
+              cnt:=1;
+            end;
+        WriteUleb(EncodedLocals,cnt);
+        WriteWasmBasicType(EncodedLocals,lasttype);
       end;
 
 {****************************************************************************
@@ -1155,7 +1199,7 @@ implementation
         ObjSymExtraData.GlobalIsImmutable:=gt.immutable;
       end;
 
-    procedure TWasmObjData.DeclareFuncType(ft: tai_functype);
+    procedure TWasmObjData.DeclareFuncType_Pass0(ft: tai_functype);
       var
         i: Integer;
         ObjSymExtraData: TWasmObjSymbolExtraData;
@@ -1166,6 +1210,16 @@ implementation
         ObjSymExtraData.TypeIdx:=i;
       end;
 
+    procedure TWasmObjData.DeclareFuncType_Pass1(ft: tai_functype);
+      begin
+        FLastFuncName:=ft.funcname;
+      end;
+
+    procedure TWasmObjData.DeclareFuncType_Pass2(ft: tai_functype);
+      begin
+        FLastFuncName:=ft.funcname;
+      end;
+
     procedure TWasmObjData.DeclareTagType(tt: tai_tagtype);
       var
         ObjSymExtraData: TWasmObjSymbolExtraData;
@@ -1203,14 +1257,44 @@ implementation
         ObjSymExtraData.ImportName:=ain.importname;
       end;
 
-    procedure TWasmObjData.DeclareLocals(al: tai_local);
+    procedure TWasmObjData.DeclareLocals_Pass0(al: tai_local);
+      var
+        ObjSymExtraData: TWasmObjSymbolExtraData;
+      begin
+        ObjSymExtraData:=TWasmObjSymbolExtraData(FObjSymbolsExtraDataList.Find(FLastFuncName));
+        ObjSymExtraData.AddLocals(al.locals);
+        alloc(ObjSymExtraData.EncodedLocals.size);
+      end;
+
+    procedure TWasmObjData.DeclareLocals_Pass1(al: tai_local);
       var
         ObjSymExtraData: TWasmObjSymbolExtraData;
-        t: TWasmBasicType;
       begin
         ObjSymExtraData:=TWasmObjSymbolExtraData(FObjSymbolsExtraDataList.Find(FLastFuncName));
-        for t in al.locals do
-          ObjSymExtraData.AddLocal(t);
+        alloc(ObjSymExtraData.EncodedLocals.size);
+      end;
+
+    procedure TWasmObjData.WriteLocals_Pass2(al: tai_local);
+      var
+        ObjSymExtraData: TWasmObjSymbolExtraData;
+        d: tdynamicarray;
+        buf: array [0..4095] of byte;
+        bs,size: Integer;
+      begin
+        ObjSymExtraData:=TWasmObjSymbolExtraData(FObjSymbolsExtraDataList.Find(FLastFuncName));
+        d:=ObjSymExtraData.EncodedLocals;
+        d.seek(0);
+        size:=d.size;
+        while size>0 do
+          begin
+            if size<SizeOf(buf) then
+              bs:=Integer(size)
+            else
+              bs:=SizeOf(buf);
+            d.read(buf,bs);
+            writebytes(buf,bs);
+            dec(size,bs);
+          end;
       end;
 
     procedure TWasmObjData.symbolpairdefine(akind: TSymbolPairKind; const asym, avalue: string);
@@ -1274,64 +1358,20 @@ implementation
           result:=false;
       end;
 
-    procedure TWasmObjOutput.WriteFunctionLocals(dest: tdynamicarray; ed: TWasmObjSymbolExtraData);
-      var
-        i,
-        rle_entries,
-        cnt: Integer;
-        lasttype: TWasmBasicType;
-      begin
-        if Length(ed.Locals)=0 then
-          begin
-            WriteUleb(dest,0);
-            exit;
-          end;
-
-        rle_entries:=1;
-        for i:=low(ed.Locals)+1 to high(ed.Locals) do
-          if ed.Locals[i]<>ed.Locals[i-1] then
-            inc(rle_entries);
-
-        WriteUleb(dest,rle_entries);
-        lasttype:=ed.Locals[Low(ed.Locals)];
-        cnt:=1;
-        for i:=low(ed.Locals)+1 to high(ed.Locals) do
-          if ed.Locals[i]=ed.Locals[i-1] then
-            inc(cnt)
-          else
-            begin
-              WriteUleb(dest,cnt);
-              WriteWasmBasicType(dest,lasttype);
-              lasttype:=ed.Locals[i];
-              cnt:=1;
-            end;
-        WriteUleb(dest,cnt);
-        WriteWasmBasicType(dest,lasttype);
-      end;
-
     procedure TWasmObjOutput.WriteFunctionCode(dest: tdynamicarray; objsym: TObjSymbol);
       var
-        encoded_locals: tdynamicarray;
         ObjSymExtraData: TWasmObjSymbolExtraData;
-        codelen: LongWord;
         ObjSection: TWasmObjSection;
-        codeexprlen: QWord;
+        codelen: QWord;
       begin
         ObjSymExtraData:=TWasmObjSymbolExtraData(FData.FObjSymbolsExtraDataList.Find(objsym.Name));
         ObjSection:=TWasmObjSection(objsym.objsection);
         ObjSection.Data.seek(objsym.address);
-        codeexprlen:=objsym.size;
+        codelen:=objsym.size;
 
-        encoded_locals:=tdynamicarray.Create(64);
-        WriteFunctionLocals(encoded_locals,ObjSymExtraData);
-        codelen:=encoded_locals.size+codeexprlen;
         WriteUleb(dest,codelen);
-        encoded_locals.seek(0);
-        CopyDynamicArray(encoded_locals,dest,encoded_locals.size);
         ObjSection.FileSectionOfs:=dest.size-objsym.offset;
-        ObjSection.EncodedLocalsSize:=encoded_locals.size;
-        CopyDynamicArray(ObjSection.Data,dest,codeexprlen);
-        encoded_locals.Free;
+        CopyDynamicArray(ObjSection.Data,dest,codelen);
       end;
 
     procedure TWasmObjOutput.WriteSymbolTable;
@@ -1610,10 +1650,7 @@ implementation
                             message1(asmw_e_illegal_unset_index,FuncSym.Name)
                           else
                             WriteUleb(relout,FuncSym.SymbolIndex);
-                          if (objrel.Addend+objrel.symbol.address)=0 then
-                            WriteSleb(relout,objrel.Addend+objrel.symbol.address)  { addend to add to the address }
-                          else
-                            WriteSleb(relout,objrel.Addend+objrel.symbol.address+TWasmObjSection(objrel.symbol.objsection).EncodedLocalsSize);  { addend to add to the address }
+                          WriteSleb(relout,objrel.Addend+objrel.symbol.address)  { addend to add to the address }
                         end
                       else if assigned(objrel.symbol) and (objrel.symbol.typ=AT_WASM_GLOBAL) then
                         begin