mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-04-08 01:08:07 +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/wasmld.lpi 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
|
||||
|
||||
uses
|
||||
SysUtils, Classes, wasmbin;
|
||||
SysUtils, Classes;
|
||||
|
||||
function ReadU(src: TStream): UInt64;
|
||||
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
|
||||
|
||||
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;
|
||||
var
|
||||
b : byte;
|
||||
@ -78,34 +44,4 @@ begin
|
||||
result := result or ( (not 0) shl sh);
|
||||
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.
|
||||
|
@ -5,7 +5,7 @@ unit wasmbin;
|
||||
interface
|
||||
|
||||
uses
|
||||
Classes, SysUtils;
|
||||
Classes, SysUtils, lebutils;
|
||||
|
||||
const
|
||||
valtype_i32 = $7f;
|
||||
@ -90,6 +90,20 @@ type
|
||||
function SectionIdToStr(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
|
||||
|
||||
function ValTypeToStr(id: integer): string;
|
||||
@ -127,5 +141,49 @@ begin
|
||||
|
||||
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.
|
||||
|
||||
|
@ -9,6 +9,9 @@ uses
|
||||
|
||||
procedure DumpTypes(sr: TStream);
|
||||
|
||||
procedure ReadFuncTypesArray(src: TStream; var arr: TFuncTypeArray);
|
||||
procedure ReadFuncType(src: TStream; var ft: TFuncType);
|
||||
|
||||
implementation
|
||||
|
||||
procedure DumpTypes(sr: TStream);
|
||||
@ -32,5 +35,34 @@ begin
|
||||
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.
|
||||
|
||||
|
@ -7,7 +7,7 @@ uses
|
||||
cthreads,
|
||||
{$ENDIF}{$ENDIF}
|
||||
{ you can add units after this }
|
||||
Classes, SysUtils, wasmbin, lebutils, wasmbindebug;
|
||||
Classes, SysUtils, wasmbin, lebutils, wasmbindebug, wasmlink;
|
||||
|
||||
function ReadStream(st: TStream): Boolean;
|
||||
var
|
||||
@ -15,6 +15,7 @@ var
|
||||
ofs : int64;
|
||||
sc : TSection;
|
||||
ps : int64;
|
||||
nm : string;
|
||||
begin
|
||||
dw := st.ReadDWord;
|
||||
Result := dw = WasmId_Int;
|
||||
@ -31,11 +32,17 @@ begin
|
||||
writeln(ofs,': id=', sc.id,'(', SectionIdToStr(sc.id),') sz=', 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
|
||||
begin
|
||||
writeln('adjust stream targ=',ps,' actual: ', st.position);
|
||||
//writeln('adjust stream targ=',ps,' actual: ', st.position);
|
||||
st.Position := ps;
|
||||
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