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

+ 101 - 64
compiler/ogwasm.pas

@@ -119,8 +119,10 @@ interface
         GlobalType: TWasmBasicType;
         GlobalType: TWasmBasicType;
         GlobalIsImmutable: Boolean;
         GlobalIsImmutable: Boolean;
         Locals: array of TWasmBasicType;
         Locals: array of TWasmBasicType;
+        EncodedLocals: tdynamicarray;
         constructor Create(HashObjectList: TFPHashObjectList; const s: TSymStr);
         constructor Create(HashObjectList: TFPHashObjectList; const s: TSymStr);
-        procedure AddLocal(bastyp: TWasmBasicType);
+        destructor Destroy; override;
+        procedure AddLocals(alocals: TWasmLocalsDynArray);
       end;
       end;
 
 
       { TWasmObjSection }
       { TWasmObjSection }
@@ -131,7 +133,6 @@ interface
         SegSymIdx: Integer;
         SegSymIdx: Integer;
         SegOfs: qword;
         SegOfs: qword;
         FileSectionOfs: qword;
         FileSectionOfs: qword;
-        EncodedLocalsSize: qword;
         MainFuncSymbol: TWasmObjSymbol;
         MainFuncSymbol: TWasmObjSymbol;
         CustomSectionIdx: Integer;
         CustomSectionIdx: Integer;
         constructor create(AList:TFPHashObjectList;const Aname:string;Aalign:longint;Aoptions:TObjSectionOptions);override;
         constructor create(AList:TFPHashObjectList;const Aname:string;Aalign:longint;Aoptions:TObjSectionOptions);override;
@@ -175,12 +176,16 @@ interface
         function globalref(asmsym:TAsmSymbol):TObjSymbol;
         function globalref(asmsym:TAsmSymbol):TObjSymbol;
         function ExceptionTagRef(asmsym:TAsmSymbol):TObjSymbol;
         function ExceptionTagRef(asmsym:TAsmSymbol):TObjSymbol;
         procedure DeclareGlobalType(gt: tai_globaltype);
         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 DeclareTagType(tt: tai_tagtype);
         procedure DeclareExportName(en: tai_export_name);
         procedure DeclareExportName(en: tai_export_name);
         procedure DeclareImportModule(aim: tai_import_module);
         procedure DeclareImportModule(aim: tai_import_module);
         procedure DeclareImportName(ain: tai_import_name);
         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;
         procedure symbolpairdefine(akind: TSymbolPairKind;const asym, avalue: string);override;
         property FuncTypes: TWasmFuncTypeTable read FFuncTypes;
         property FuncTypes: TWasmFuncTypeTable read FFuncTypes;
       end;
       end;
@@ -217,7 +222,6 @@ interface
         procedure WriteWasmCustomSection(wcst: TWasmCustomSectionType);
         procedure WriteWasmCustomSection(wcst: TWasmCustomSectionType);
         function IsExternalFunction(sym: TObjSymbol): Boolean;
         function IsExternalFunction(sym: TObjSymbol): Boolean;
         function IsExportedFunction(sym: TWasmObjSymbol): Boolean;
         function IsExportedFunction(sym: TWasmObjSymbol): Boolean;
-        procedure WriteFunctionLocals(dest: tdynamicarray; ed: TWasmObjSymbolExtraData);
         procedure WriteFunctionCode(dest: tdynamicarray; objsym: TObjSymbol);
         procedure WriteFunctionCode(dest: tdynamicarray; objsym: TObjSymbol);
         procedure WriteSymbolTable;
         procedure WriteSymbolTable;
         procedure WriteRelocationCodeTable(CodeSectionIndex: Integer);
         procedure WriteRelocationCodeTable(CodeSectionIndex: Integer);
@@ -735,15 +739,55 @@ implementation
 
 
     constructor TWasmObjSymbolExtraData.Create(HashObjectList: TFPHashObjectList; const s: TSymStr);
     constructor TWasmObjSymbolExtraData.Create(HashObjectList: TFPHashObjectList; const s: TSymStr);
       begin
       begin
+        EncodedLocals:=nil;
         inherited Create(HashObjectList,s);
         inherited Create(HashObjectList,s);
         TypeIdx:=-1;
         TypeIdx:=-1;
         ExceptionTagTypeIdx:=-1;
         ExceptionTagTypeIdx:=-1;
       end;
       end;
 
 
-    procedure TWasmObjSymbolExtraData.AddLocal(bastyp: TWasmBasicType);
+    destructor TWasmObjSymbolExtraData.Destroy;
       begin
       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;
       end;
 
 
 {****************************************************************************
 {****************************************************************************
@@ -1155,7 +1199,7 @@ implementation
         ObjSymExtraData.GlobalIsImmutable:=gt.immutable;
         ObjSymExtraData.GlobalIsImmutable:=gt.immutable;
       end;
       end;
 
 
-    procedure TWasmObjData.DeclareFuncType(ft: tai_functype);
+    procedure TWasmObjData.DeclareFuncType_Pass0(ft: tai_functype);
       var
       var
         i: Integer;
         i: Integer;
         ObjSymExtraData: TWasmObjSymbolExtraData;
         ObjSymExtraData: TWasmObjSymbolExtraData;
@@ -1166,6 +1210,16 @@ implementation
         ObjSymExtraData.TypeIdx:=i;
         ObjSymExtraData.TypeIdx:=i;
       end;
       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);
     procedure TWasmObjData.DeclareTagType(tt: tai_tagtype);
       var
       var
         ObjSymExtraData: TWasmObjSymbolExtraData;
         ObjSymExtraData: TWasmObjSymbolExtraData;
@@ -1203,14 +1257,44 @@ implementation
         ObjSymExtraData.ImportName:=ain.importname;
         ObjSymExtraData.ImportName:=ain.importname;
       end;
       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
       var
         ObjSymExtraData: TWasmObjSymbolExtraData;
         ObjSymExtraData: TWasmObjSymbolExtraData;
-        t: TWasmBasicType;
       begin
       begin
         ObjSymExtraData:=TWasmObjSymbolExtraData(FObjSymbolsExtraDataList.Find(FLastFuncName));
         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;
       end;
 
 
     procedure TWasmObjData.symbolpairdefine(akind: TSymbolPairKind; const asym, avalue: string);
     procedure TWasmObjData.symbolpairdefine(akind: TSymbolPairKind; const asym, avalue: string);
@@ -1274,64 +1358,20 @@ implementation
           result:=false;
           result:=false;
       end;
       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);
     procedure TWasmObjOutput.WriteFunctionCode(dest: tdynamicarray; objsym: TObjSymbol);
       var
       var
-        encoded_locals: tdynamicarray;
         ObjSymExtraData: TWasmObjSymbolExtraData;
         ObjSymExtraData: TWasmObjSymbolExtraData;
-        codelen: LongWord;
         ObjSection: TWasmObjSection;
         ObjSection: TWasmObjSection;
-        codeexprlen: QWord;
+        codelen: QWord;
       begin
       begin
         ObjSymExtraData:=TWasmObjSymbolExtraData(FData.FObjSymbolsExtraDataList.Find(objsym.Name));
         ObjSymExtraData:=TWasmObjSymbolExtraData(FData.FObjSymbolsExtraDataList.Find(objsym.Name));
         ObjSection:=TWasmObjSection(objsym.objsection);
         ObjSection:=TWasmObjSection(objsym.objsection);
         ObjSection.Data.seek(objsym.address);
         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);
         WriteUleb(dest,codelen);
-        encoded_locals.seek(0);
-        CopyDynamicArray(encoded_locals,dest,encoded_locals.size);
         ObjSection.FileSectionOfs:=dest.size-objsym.offset;
         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;
       end;
 
 
     procedure TWasmObjOutput.WriteSymbolTable;
     procedure TWasmObjOutput.WriteSymbolTable;
@@ -1610,10 +1650,7 @@ implementation
                             message1(asmw_e_illegal_unset_index,FuncSym.Name)
                             message1(asmw_e_illegal_unset_index,FuncSym.Name)
                           else
                           else
                             WriteUleb(relout,FuncSym.SymbolIndex);
                             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
                         end
                       else if assigned(objrel.symbol) and (objrel.symbol.typ=AT_WASM_GLOBAL) then
                       else if assigned(objrel.symbol) and (objrel.symbol.typ=AT_WASM_GLOBAL) then
                         begin
                         begin