mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-08-29 13:21:35 +02:00
[PATCH 003/188] starting on linking utils
From 533bcbb688ca6868da515bff3d266377e1b88eff Mon Sep 17 00:00:00 2001 From: Dmitry Boyarintsev <skalogryz.lists@gmail.com> Date: Tue, 24 Sep 2019 12:34:37 -0400 git-svn-id: branches/wasm@45999 -
This commit is contained in:
parent
93d6993296
commit
64027a4527
1
.gitattributes
vendored
1
.gitattributes
vendored
@ -18981,3 +18981,4 @@ utils/wasmbin/wasmbin.pas svneol=native#text/plain
|
|||||||
utils/wasmbin/wasmbindebug.pas svneol=native#text/plain
|
utils/wasmbin/wasmbindebug.pas svneol=native#text/plain
|
||||||
utils/wasmbin/wasmld.lpi svneol=native#text/plain
|
utils/wasmbin/wasmld.lpi svneol=native#text/plain
|
||||||
utils/wasmbin/wasmld.lpr svneol=native#text/plain
|
utils/wasmbin/wasmld.lpr svneol=native#text/plain
|
||||||
|
utils/wasmbin/wasmlink.pas svneol=native#text/plain
|
||||||
|
@ -3,47 +3,13 @@ unit lebutils;
|
|||||||
interface
|
interface
|
||||||
|
|
||||||
uses
|
uses
|
||||||
SysUtils, Classes, wasmbin;
|
SysUtils, Classes;
|
||||||
|
|
||||||
function ReadU(src: TStream): UInt64;
|
function ReadU(src: TStream): UInt64;
|
||||||
function ReadS(src: TStream; bits: Integer): Int64;
|
function ReadS(src: TStream; bits: Integer): Int64;
|
||||||
|
|
||||||
procedure ReadFuncTypesArray(src: TStream; var arr: TFuncTypeArray);
|
|
||||||
procedure ReadFuncType(src: TStream; var ft: TFuncType);
|
|
||||||
|
|
||||||
procedure ReadCodeEntry(src: TStream; var en: TCodeEntry);
|
|
||||||
procedure ReadCodeSection(src: TStream; var sc: TCodeSection);
|
|
||||||
|
|
||||||
implementation
|
implementation
|
||||||
|
|
||||||
procedure ReadFuncType(src: TStream; var ft: TFuncType);
|
|
||||||
var
|
|
||||||
c: integer;
|
|
||||||
begin
|
|
||||||
// vector of t1
|
|
||||||
c:=ReadU(src);
|
|
||||||
SetLength(ft.param, c);
|
|
||||||
src.Read(ft.param[0], c);
|
|
||||||
|
|
||||||
// vector of t2
|
|
||||||
c:=ReadU(src);
|
|
||||||
SetLength(ft.result, c);
|
|
||||||
src.Read(ft.result[0], c);
|
|
||||||
end;
|
|
||||||
|
|
||||||
procedure ReadFuncTypesArray(src: TStream; var arr: TFuncTypeArray);
|
|
||||||
var
|
|
||||||
cnt : integer;
|
|
||||||
i : Integer;
|
|
||||||
begin
|
|
||||||
cnt := ReadU(src);
|
|
||||||
SetLength(arr.funTypes, cnt);
|
|
||||||
for i:=0 to cnt-1 do begin
|
|
||||||
if src.ReadByte = func_type then
|
|
||||||
ReadFuncType(src, arr.funTypes[i]);
|
|
||||||
end;
|
|
||||||
end;
|
|
||||||
|
|
||||||
function ReadU(src: TStream): UInt64;
|
function ReadU(src: TStream): UInt64;
|
||||||
var
|
var
|
||||||
b : byte;
|
b : byte;
|
||||||
@ -78,34 +44,4 @@ begin
|
|||||||
result := result or ( (not 0) shl sh);
|
result := result or ( (not 0) shl sh);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure ReadCodeEntry(src: TStream; var en: TCodeEntry);
|
|
||||||
var
|
|
||||||
sz : integer; // size in bytes
|
|
||||||
//pos : int64;
|
|
||||||
cnt : Integer;
|
|
||||||
i : integer;
|
|
||||||
begin
|
|
||||||
sz := ReadU(src);
|
|
||||||
|
|
||||||
cnt := ReadU(src);
|
|
||||||
SetLength(en.locals, cnt);
|
|
||||||
for i:=0 to cnt-1 do begin
|
|
||||||
en.locals[i].count := ReadU(src);
|
|
||||||
en.locals[i].valtyp := src.ReadByte;
|
|
||||||
end;
|
|
||||||
|
|
||||||
|
|
||||||
end;
|
|
||||||
|
|
||||||
procedure ReadCodeSection(src: TStream; var sc: TCodeSection);
|
|
||||||
var
|
|
||||||
cnt : integer;
|
|
||||||
i : integer;
|
|
||||||
begin
|
|
||||||
cnt := ReadU(src);
|
|
||||||
SetLength(sc.entries, cnt);
|
|
||||||
for i:= 0 to cnt-1 do
|
|
||||||
ReadCodeEntry(src, sc.entries[i]);
|
|
||||||
end;
|
|
||||||
|
|
||||||
end.
|
end.
|
||||||
|
@ -5,7 +5,7 @@ unit wasmbin;
|
|||||||
interface
|
interface
|
||||||
|
|
||||||
uses
|
uses
|
||||||
Classes, SysUtils;
|
Classes, SysUtils, lebutils;
|
||||||
|
|
||||||
const
|
const
|
||||||
valtype_i32 = $7f;
|
valtype_i32 = $7f;
|
||||||
@ -90,6 +90,20 @@ type
|
|||||||
function SectionIdToStr(id: integer): string;
|
function SectionIdToStr(id: integer): string;
|
||||||
function ValTypeToStr(id: integer): string;
|
function ValTypeToStr(id: integer): string;
|
||||||
|
|
||||||
|
// reads the name from the input stream
|
||||||
|
// the name consists of
|
||||||
|
// size - in butes Leb128
|
||||||
|
// bytes - in utf8 format
|
||||||
|
function GetName(sr: TStream): string;
|
||||||
|
|
||||||
|
// reads
|
||||||
|
function GetU32(sr: TStream): UInt32;
|
||||||
|
|
||||||
|
// reads the code entry into TCodeEntry structure
|
||||||
|
procedure ReadCodeEntry(src: TStream; var en: TCodeEntry);
|
||||||
|
// reads the code entry into TCodeEntry structure
|
||||||
|
procedure ReadCodeSection(src: TStream; var sc: TCodeSection);
|
||||||
|
|
||||||
implementation
|
implementation
|
||||||
|
|
||||||
function ValTypeToStr(id: integer): string;
|
function ValTypeToStr(id: integer): string;
|
||||||
@ -127,5 +141,49 @@ begin
|
|||||||
|
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function GetName(sr: TStream): string;
|
||||||
|
var
|
||||||
|
ln : LongWord;
|
||||||
|
begin
|
||||||
|
ln := ReadU(sr);
|
||||||
|
SetLength(result, ln);
|
||||||
|
if ln>0 then sr.Read(result[1], ln);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function GetU32(sr: TStream): UInt32;
|
||||||
|
begin
|
||||||
|
Result := UInt32(ReadU(sr));
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure ReadCodeEntry(src: TStream; var en: TCodeEntry);
|
||||||
|
var
|
||||||
|
sz : integer; // size in bytes
|
||||||
|
//pos : int64;
|
||||||
|
cnt : Integer;
|
||||||
|
i : integer;
|
||||||
|
begin
|
||||||
|
sz := ReadU(src);
|
||||||
|
|
||||||
|
cnt := ReadU(src);
|
||||||
|
SetLength(en.locals, cnt);
|
||||||
|
for i:=0 to cnt-1 do begin
|
||||||
|
en.locals[i].count := ReadU(src);
|
||||||
|
en.locals[i].valtyp := src.ReadByte;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure ReadCodeSection(src: TStream; var sc: TCodeSection);
|
||||||
|
var
|
||||||
|
cnt : integer;
|
||||||
|
i : integer;
|
||||||
|
begin
|
||||||
|
cnt := ReadU(src);
|
||||||
|
SetLength(sc.entries, cnt);
|
||||||
|
for i:= 0 to cnt-1 do
|
||||||
|
ReadCodeEntry(src, sc.entries[i]);
|
||||||
|
end;
|
||||||
|
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
@ -9,6 +9,9 @@ uses
|
|||||||
|
|
||||||
procedure DumpTypes(sr: TStream);
|
procedure DumpTypes(sr: TStream);
|
||||||
|
|
||||||
|
procedure ReadFuncTypesArray(src: TStream; var arr: TFuncTypeArray);
|
||||||
|
procedure ReadFuncType(src: TStream; var ft: TFuncType);
|
||||||
|
|
||||||
implementation
|
implementation
|
||||||
|
|
||||||
procedure DumpTypes(sr: TStream);
|
procedure DumpTypes(sr: TStream);
|
||||||
@ -32,5 +35,34 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure ReadFuncType(src: TStream; var ft: TFuncType);
|
||||||
|
var
|
||||||
|
c: integer;
|
||||||
|
begin
|
||||||
|
// vector of t1
|
||||||
|
c:=ReadU(src);
|
||||||
|
SetLength(ft.param, c);
|
||||||
|
src.Read(ft.param[0], c);
|
||||||
|
|
||||||
|
// vector of t2
|
||||||
|
c:=ReadU(src);
|
||||||
|
SetLength(ft.result, c);
|
||||||
|
src.Read(ft.result[0], c);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure ReadFuncTypesArray(src: TStream; var arr: TFuncTypeArray);
|
||||||
|
var
|
||||||
|
cnt : integer;
|
||||||
|
i : Integer;
|
||||||
|
begin
|
||||||
|
cnt := ReadU(src);
|
||||||
|
SetLength(arr.funTypes, cnt);
|
||||||
|
for i:=0 to cnt-1 do begin
|
||||||
|
if src.ReadByte = func_type then
|
||||||
|
ReadFuncType(src, arr.funTypes[i]);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@ uses
|
|||||||
cthreads,
|
cthreads,
|
||||||
{$ENDIF}{$ENDIF}
|
{$ENDIF}{$ENDIF}
|
||||||
{ you can add units after this }
|
{ you can add units after this }
|
||||||
Classes, SysUtils, wasmbin, lebutils, wasmbindebug;
|
Classes, SysUtils, wasmbin, lebutils, wasmbindebug, wasmlink;
|
||||||
|
|
||||||
function ReadStream(st: TStream): Boolean;
|
function ReadStream(st: TStream): Boolean;
|
||||||
var
|
var
|
||||||
@ -15,6 +15,7 @@ var
|
|||||||
ofs : int64;
|
ofs : int64;
|
||||||
sc : TSection;
|
sc : TSection;
|
||||||
ps : int64;
|
ps : int64;
|
||||||
|
nm : string;
|
||||||
begin
|
begin
|
||||||
dw := st.ReadDWord;
|
dw := st.ReadDWord;
|
||||||
Result := dw = WasmId_Int;
|
Result := dw = WasmId_Int;
|
||||||
@ -31,11 +32,17 @@ begin
|
|||||||
writeln(ofs,': id=', sc.id,'(', SectionIdToStr(sc.id),') sz=', sc.size);
|
writeln(ofs,': id=', sc.id,'(', SectionIdToStr(sc.id),') sz=', sc.size);
|
||||||
|
|
||||||
ps := st.Position+sc.size;
|
ps := st.Position+sc.size;
|
||||||
if sc.id= 1 then DumpTypes(st);
|
if sc.id=0 then begin
|
||||||
|
nm := GetName(st);
|
||||||
|
writeln(nm);
|
||||||
|
if nm = SectionName_Linking then
|
||||||
|
DumpLinking(st, sc.size - (st.Position - ofs));
|
||||||
|
end;
|
||||||
|
//if sc.id= 1 then DumpTypes(st);
|
||||||
|
|
||||||
if st.Position <> ps then
|
if st.Position <> ps then
|
||||||
begin
|
begin
|
||||||
writeln('adjust stream targ=',ps,' actual: ', st.position);
|
//writeln('adjust stream targ=',ps,' actual: ', st.position);
|
||||||
st.Position := ps;
|
st.Position := ps;
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
155
utils/wasmbin/wasmlink.pas
Normal file
155
utils/wasmbin/wasmlink.pas
Normal file
@ -0,0 +1,155 @@
|
|||||||
|
unit wasmlink;
|
||||||
|
// The unit covers the WebAssembly static linking convention
|
||||||
|
// as described at https://github.com/WebAssembly/tool-conventions/blob/master/Linking.md
|
||||||
|
|
||||||
|
interface
|
||||||
|
|
||||||
|
uses
|
||||||
|
Classes, SysUtils, lebutils;
|
||||||
|
|
||||||
|
const
|
||||||
|
SectionName_Linking = 'linking';
|
||||||
|
SectionNamePfx_Reloc = 'reloc.';
|
||||||
|
|
||||||
|
type
|
||||||
|
TRelocationSection = record
|
||||||
|
section : UInt32; // the index of the target section
|
||||||
|
count : Uint32; // count of entries to follow
|
||||||
|
end;
|
||||||
|
|
||||||
|
TRelocationEntry = record
|
||||||
|
reltype : UInt8; // the relocation type (see R_WASM constants)
|
||||||
|
offset : UInt32; // offset of the value to rewrite
|
||||||
|
index : Uint32; // the index of the symbol used (or, for R_WASM_TYPE_INDEX_LEB relocations, the index of the type)
|
||||||
|
end;
|
||||||
|
TRelocationEntryEx = record
|
||||||
|
entry : TRelocationEntry;
|
||||||
|
addend : UInt32;
|
||||||
|
end;
|
||||||
|
|
||||||
|
const
|
||||||
|
// A relocation type can be one of the following:
|
||||||
|
R_WASM_FUNCTION_INDEX_LEB = 0; // a function index encoded as a 5-byte varuint32. Used for the immediate argument of a call instruction.
|
||||||
|
R_WASM_TABLE_INDEX_SLEB = 1; // a function table index encoded as a 5-byte varint32. Used to refer to the immediate argument of a i32.const instruction, e.g. taking the address of a function.
|
||||||
|
R_WASM_TABLE_INDEX_I32 = 2; // a function table index encoded as a uint32, e.g. taking the address of a function in a static data initializer.
|
||||||
|
R_WASM_MEMORY_ADDR_LEB = 3; // a linear memory index encoded as a 5-byte varuint32. Used for the immediate argument of a load or store instruction, e.g. directly loading from or storing to a C++ global.
|
||||||
|
R_WASM_MEMORY_ADDR_SLEB = 4; // a linear memory index encoded as a 5-byte varint32. Used for the immediate argument of a i32.const instruction, e.g. taking the address of a C++ global.
|
||||||
|
R_WASM_MEMORY_ADDR_I32 = 5; // a linear memory index encoded as a uint32, e.g. taking the address of a C++ global in a static data initializer.
|
||||||
|
R_WASM_TYPE_INDEX_LEB = 6; // a type table index encoded as a 5-byte varuint32, e.g. the type immediate in a call_indirect.
|
||||||
|
R_WASM_GLOBAL_INDEX_LEB = 7; // a global index encoded as a 5-byte varuint32, e.g. the index immediate in a get_global.
|
||||||
|
R_WASM_FUNCTION_OFFSET_I32 = 8; // a byte offset within code section for the specic function encoded as a uint32. The offsets start at the actual function code excluding its size field.
|
||||||
|
R_WASM_SECTION_OFFSET_I32 = 9; // an byte offset from start of the specified section encoded as a uint32.
|
||||||
|
R_WASM_EVENT_INDEX_LEB = 10; // an event index encoded as a 5-byte varuint32. Used for the immediate argument of a throw and if_except instruction.
|
||||||
|
R_WASM_TABLE_NUMBER_LEB = 13; // a table number encoded as a 5-byte varuint32. Used for the table immediate argument in the table.* instructions.
|
||||||
|
|
||||||
|
type
|
||||||
|
TLinkingMetadata = record
|
||||||
|
version : UInt32; // the version of linking metadata contained in this section. Currently: 2
|
||||||
|
end;
|
||||||
|
|
||||||
|
TLinkinSubSection = record
|
||||||
|
sectype : UInt8; // code identifying type of subsection
|
||||||
|
length : UInt32; // size of this subsection in bytes
|
||||||
|
end;
|
||||||
|
|
||||||
|
const
|
||||||
|
LINKING_VERSION = 2;
|
||||||
|
|
||||||
|
// The current list of valid TLinkinSubSection.sectype codes are:
|
||||||
|
WASM_SEGMENT_INFO = 5; // Extra metadata about the data segments.
|
||||||
|
WASM_INIT_FUNCS = 6; // Specifies a list of constructor functions to be called at startup.
|
||||||
|
// These constructors will be called in priority order after memory
|
||||||
|
// has been initialized.
|
||||||
|
WASM_COMDAT_INFO = 7; // Specifies the COMDAT groups of associated linking objects,
|
||||||
|
// which are linked only once and all together.
|
||||||
|
WASM_SYMBOL_TABLE = 8; // Specifies extra information about the symbols present in the module
|
||||||
|
|
||||||
|
|
||||||
|
type
|
||||||
|
TSymInfo = record
|
||||||
|
symkind : UInt8;
|
||||||
|
flags : UInt32;
|
||||||
|
end;
|
||||||
|
|
||||||
|
// The current set of valid flags for symbols are:
|
||||||
|
const
|
||||||
|
// Indicating that this is a weak symbol. When linking multiple modules
|
||||||
|
// defining the same symbol, all weak definitions are discarded if
|
||||||
|
// any strong definitions exist; then if multiple weak definitions
|
||||||
|
// exist all but one (unspecified) are discarded; and finally it is an error
|
||||||
|
// if more than one definition remains.
|
||||||
|
WASM_SYM_BINDING_WEAK = $01;
|
||||||
|
|
||||||
|
// Indicating that this is a local symbol (this is exclusive
|
||||||
|
// with WASM_SYM_BINDING_WEAK). Local symbols are not to be exported,
|
||||||
|
// or linked to other modules/sections. The names of all non-local
|
||||||
|
// symbols must be unique, but the names of local symbols are
|
||||||
|
// not considered for uniqueness. A local function or global
|
||||||
|
// symbol cannot reference an import.
|
||||||
|
WASM_SYM_BINDING_LOCAL = $02;
|
||||||
|
|
||||||
|
// Indicating that this is a hidden symbol. Hidden symbols are not to be
|
||||||
|
// exported when performing the final link, but may be linked to other modules.
|
||||||
|
WASM_SYM_VISIBILITY_HIDDEN = $04;
|
||||||
|
|
||||||
|
// Indicating that this symbol is not defined. For non-data symbols,
|
||||||
|
// this must match whether the symbol is an import or is defined;
|
||||||
|
// for data symbols, determines whether a segment is specified.
|
||||||
|
WASM_SYM_UNDEFINED = $10;
|
||||||
|
|
||||||
|
// The symbol is intended to be exported from the wasm module to the host
|
||||||
|
// environment. This differs from the visibility flags in that it effects
|
||||||
|
// the static linker.
|
||||||
|
WASM_SYM_EXPORTED = $20;
|
||||||
|
|
||||||
|
// The symbol uses an explicit symbol name, rather than reusing the name
|
||||||
|
// from a wasm import. This allows it to remap imports from foreign WebAssembly
|
||||||
|
// modules into local symbols with different names.
|
||||||
|
WASM_SYM_EXPLICIT_NAME = $40;
|
||||||
|
|
||||||
|
// The symbol is intended to be included in the linker output,
|
||||||
|
// regardless of whether it is used by the program.
|
||||||
|
WASM_SYM_NO_STRIP = $80;
|
||||||
|
|
||||||
|
function ReadMetaData(st: TStream; out m:TLinkingMetadata): Boolean;
|
||||||
|
function ReadLinkSubSect(st: TStream; out m: TLinkinSubSection): Boolean;
|
||||||
|
|
||||||
|
// dumps linking information. Note: that the name of the "Linking" section
|
||||||
|
// must have already been read
|
||||||
|
procedure DumpLinking(st: TStream; secsize: integer);
|
||||||
|
|
||||||
|
implementation
|
||||||
|
|
||||||
|
function ReadMetaData(st: TStream; out m:TLinkingMetadata): Boolean;
|
||||||
|
begin
|
||||||
|
FillChar(m, sizeof(m), 0);
|
||||||
|
m.version := ReadU(st);
|
||||||
|
Result:=true;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function ReadLinkSubSect(st: TStream; out m: TLinkinSubSection): Boolean;
|
||||||
|
begin
|
||||||
|
FillChar(m, sizeof(m), 0);
|
||||||
|
m.sectype := ReadU(st);
|
||||||
|
m.length := ReadU(st);
|
||||||
|
Result:=true;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure DumpLinking(st: TStream; secsize: integer);
|
||||||
|
var
|
||||||
|
mt : TLinkingMetadata;
|
||||||
|
en : Int64;
|
||||||
|
sub : TLinkinSubSection;
|
||||||
|
begin
|
||||||
|
en := st.Position+secsize;
|
||||||
|
ReadMetadata(st, mt);
|
||||||
|
writeln('version: ', mt.version);
|
||||||
|
while st.Position<en do begin
|
||||||
|
ReadLinkSubSect(st, sub);
|
||||||
|
writeln(sub.sectype);
|
||||||
|
st.Position:=st.Position+sub.length;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
end.
|
Loading…
Reference in New Issue
Block a user