wasmlink.pas 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562
  1. { This file is part of wasmbin - a collection of WebAssembly binary utils.
  2. Copyright (C) 2019, 2020 Dmitry Boyarintsev <[email protected]>
  3. Copyright (C) 2020 by the Free Pascal development team
  4. This source is free software; you can redistribute it and/or modify it under
  5. the terms of the GNU General Public License as published by the Free
  6. Software Foundation; either version 2 of the License, or (at your option)
  7. any later version.
  8. This code is distributed in the hope that it will be useful, but WITHOUT ANY
  9. WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  10. FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
  11. details.
  12. A copy of the GNU General Public License is available on the World Wide Web
  13. at <http://www.gnu.org/copyleft/gpl.html>. You can also obtain it by writing
  14. to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
  15. Boston, MA 02110-1335, USA.
  16. }
  17. unit wasmlink;
  18. // The unit covers the WebAssembly static linking convention
  19. // as described at https://github.com/WebAssembly/tool-conventions/blob/master/Linking.md
  20. {$mode objfpc}{$H+}
  21. interface
  22. uses
  23. Classes, SysUtils, lebutils, wasmbin, wasmbincode;
  24. const
  25. SectionName_Linking = 'linking';
  26. SectionNamePfx_Reloc = 'reloc.';
  27. type
  28. TRelocationSection = record
  29. section : UInt32; // the index of the target section
  30. count : Uint32; // count of entries to follow
  31. end;
  32. TRelocationEntry = record
  33. sec : Uint8; // section to be relocated at
  34. reltype : UInt8; // the relocation type (see R_WASM constants)
  35. offset : UInt32; // offset of the value to rewrite
  36. index : Uint32; // the index of the symbol used (or, for R_WASM_TYPE_INDEX_LEB relocations, the index of the type)
  37. end;
  38. TRelocationEntryEx = record
  39. entry : TRelocationEntry;
  40. addend : UInt32;
  41. end;
  42. const
  43. // A relocation type can be one of the following:
  44. R_WASM_FUNCTION_INDEX_LEB = 0; // a function index encoded as a 5-byte varuint32. Used for the immediate argument of a call instruction.
  45. 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.
  46. 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.
  47. 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.
  48. 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.
  49. 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.
  50. 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.
  51. R_WASM_GLOBAL_INDEX_LEB = 7; // a global index encoded as a 5-byte varuint32, e.g. the index immediate in a get_global.
  52. 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.
  53. R_WASM_SECTION_OFFSET_I32 = 9; // an byte offset from start of the specified section encoded as a uint32.
  54. 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.
  55. 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.
  56. type
  57. TLinkingMetadata = record
  58. version : UInt32; // the version of linking metadata contained in this section. Currently: 2
  59. end;
  60. TLinkingSubSection = record
  61. sectype : UInt8; // code identifying type of subsection
  62. length : UInt32; // size of this subsection in bytes
  63. end;
  64. const
  65. LINKING_VERSION = 2;
  66. // The current list of valid TLinkinSubSection.sectype codes are:
  67. WASM_SEGMENT_INFO = 5; // Extra metadata about the data segments.
  68. WASM_INIT_FUNCS = 6; // Specifies a list of constructor functions to be called at startup.
  69. // These constructors will be called in priority order after memory
  70. // has been initialized.
  71. WASM_COMDAT_INFO = 7; // Specifies the COMDAT groups of associated linking objects,
  72. // which are linked only once and all together.
  73. WASM_SYMBOL_TABLE = 8; // Specifies extra information about the symbols present in the module
  74. type
  75. TSymInfo = record
  76. kind : UInt8;
  77. flags : UInt32;
  78. hasSymIndex : Boolean; // always true for Kind non Data
  79. // for Data it's true for defined symbols (see flags);
  80. symindex : UInt32; // either symbol or data symbol offset
  81. hasSymName : Boolean;
  82. symname : string;
  83. dataofs : integer; // only if Kind is Data and hasSymIndex = true;
  84. datasize : integer;
  85. end;
  86. // The symbol type. One of:
  87. const
  88. SYMTAB_FUNCTION = 0;
  89. SYMTAB_DATA = 1;
  90. SYMTAB_GLOBAL = 2;
  91. SYMTAB_SECTION = 3;
  92. SYMTAB_EVENT = 4;
  93. SYMTAB_TABLE = 5;
  94. // The current set of valid flags for symbols are:
  95. const
  96. // Indicating that this is a weak symbol. When linking multiple modules
  97. // defining the same symbol, all weak definitions are discarded if
  98. // any strong definitions exist; then if multiple weak definitions
  99. // exist all but one (unspecified) are discarded; and finally it is an error
  100. // if more than one definition remains.
  101. WASM_SYM_BINDING_WEAK = $01;
  102. // Indicating that this is a local symbol (this is exclusive
  103. // with WASM_SYM_BINDING_WEAK). Local symbols are not to be exported,
  104. // or linked to other modules/sections. The names of all non-local
  105. // symbols must be unique, but the names of local symbols are
  106. // not considered for uniqueness. A local function or global
  107. // symbol cannot reference an import.
  108. WASM_SYM_BINDING_LOCAL = $02;
  109. // Indicating that this is a hidden symbol. Hidden symbols are not to be
  110. // exported when performing the final link, but may be linked to other modules.
  111. WASM_SYM_VISIBILITY_HIDDEN = $04;
  112. // Indicating that this symbol is not defined. For non-data symbols,
  113. // this must match whether the symbol is an import or is defined;
  114. // for data symbols, determines whether a segment is specified.
  115. WASM_SYM_UNDEFINED = $10;
  116. WASM_SYM_IMPORTED = WASM_SYM_UNDEFINED;
  117. // The symbol is intended to be exported from the wasm module to the host
  118. // environment. This differs from the visibility flags in that it effects
  119. // the static linker.
  120. WASM_SYM_EXPORTED = $20;
  121. // The symbol uses an explicit symbol name, rather than reusing the name
  122. // from a wasm import. This allows it to remap imports from foreign WebAssembly
  123. // modules into local symbols with different names.
  124. WASM_SYM_EXPLICIT_NAME = $40;
  125. // The symbol is intended to be included in the linker output,
  126. // regardless of whether it is used by the program.
  127. WASM_SYM_NO_STRIP = $80;
  128. function ReadMetaData(st: TStream; out m:TLinkingMetadata): Boolean;
  129. function ReadLinkSubSect(st: TStream; out m: TLinkingSubSection): Boolean;
  130. function ReadSymInfo(st: TStream; out m: TSymInfo): Boolean;
  131. procedure WriteSymInfo(st: TStream; const m: TSymInfo);
  132. // dumps linking information. Note: that the name of the "Linking" section
  133. // must have already been read
  134. procedure DumpLinking(st: TStream; secsize: integer);
  135. function SubSecTypeToStr(b: Byte): string;
  136. function SymKindToStr(b: Byte): string;
  137. type
  138. TLinkingSection = record
  139. metadata: TLinkingMetadata;
  140. symbols : array of TSymInfo;
  141. end;
  142. // the stream should be set at the beggining of the section
  143. // after name and size values
  144. procedure ReadLinkingSection(st: TStream; size: integer; var sc: TLinkingSection);
  145. procedure WriteLinkingSection(st: TStream; const sc: TLinkingSection);
  146. type
  147. TInstRelocFlag = record
  148. doReloc: Boolean;
  149. relocType: byte;
  150. end;
  151. const
  152. INST_RELOC_FLAGS : array [MIN_INST..MAX_INST] of TInstRelocFlag = (
  153. (doReloc: false; relocType: $FF) // 00 trap (unreachable)
  154. ,(doReloc: false; relocType: $FF) // 01 nop
  155. ,(doReloc: false; relocType: $FF) // 02 block
  156. ,(doReloc: false; relocType: $FF) // 03 lock
  157. ,(doReloc: false; relocType: $FF) // 04 if
  158. ,(doReloc: false; relocType: $FF) // 05
  159. ,(doReloc: false; relocType: $FF) // 06
  160. ,(doReloc: false; relocType: $FF) // 07
  161. ,(doReloc: false; relocType: $FF) // 08
  162. ,(doReloc: false; relocType: $FF) // 09
  163. ,(doReloc: false; relocType: $FF) // 0A
  164. ,(doReloc: false; relocType: $FF) // 0B end
  165. ,(doReloc: false; relocType: $FF) // 0C br
  166. ,(doReloc: false; relocType: $FF) // 0D br_if
  167. ,(doReloc: false; relocType: $FF) // 0E br_table
  168. ,(doReloc: false; relocType: $FF) // 0F return
  169. ,(doReloc: true; relocType: R_WASM_FUNCTION_INDEX_LEB) // 10 call
  170. ,(doReloc: true; relocType: R_WASM_TYPE_INDEX_LEB) // 11 call_indirect
  171. ,(doReloc: false; relocType: $FF) // 12
  172. ,(doReloc: false; relocType: $FF) // 13
  173. ,(doReloc: false; relocType: $FF) // 14
  174. ,(doReloc: false; relocType: $FF) // 15
  175. ,(doReloc: false; relocType: $FF) // 16
  176. ,(doReloc: false; relocType: $FF) // 17
  177. ,(doReloc: false; relocType: $FF) // 18
  178. ,(doReloc: false; relocType: $FF) // 19
  179. ,(doReloc: false; relocType: $FF) // 1A drop
  180. ,(doReloc: false; relocType: $FF) // 1B select
  181. ,(doReloc: false; relocType: $FF) // 1C
  182. ,(doReloc: false; relocType: $FF) // 1D
  183. ,(doReloc: false; relocType: $FF) // 1E
  184. ,(doReloc: false; relocType: $FF) // 1F
  185. ,(doReloc: false; relocType: $FF) // 20 local.get
  186. ,(doReloc: false; relocType: $FF) // 21 local.set
  187. ,(doReloc: false; relocType: $FF) // 22 local.tee
  188. ,(doReloc: true; relocType: R_WASM_GLOBAL_INDEX_LEB) // 23 global.get
  189. ,(doReloc: true; relocType: R_WASM_GLOBAL_INDEX_LEB) // 24 global.set
  190. ,(doReloc: false; relocType: $FF) // 25
  191. ,(doReloc: false; relocType: $FF) // 26
  192. ,(doReloc: false; relocType: $FF) // 27
  193. ,(doReloc: true; relocType: R_WASM_MEMORY_ADDR_LEB) // 28 i32.load
  194. ,(doReloc: true; relocType: R_WASM_MEMORY_ADDR_LEB) // 29 i64_load
  195. ,(doReloc: true; relocType: R_WASM_MEMORY_ADDR_LEB) // 2A f32_load
  196. ,(doReloc: true; relocType: R_WASM_MEMORY_ADDR_LEB) // 2B f64_load
  197. ,(doReloc: true; relocType: R_WASM_MEMORY_ADDR_LEB) // 2C i32_load8_s
  198. ,(doReloc: true; relocType: R_WASM_MEMORY_ADDR_LEB) // 2D i32_load8_u
  199. ,(doReloc: true; relocType: R_WASM_MEMORY_ADDR_LEB) // 2E i32_load16_s
  200. ,(doReloc: true; relocType: R_WASM_MEMORY_ADDR_LEB) // 2F i32_load16_u
  201. ,(doReloc: true; relocType: R_WASM_MEMORY_ADDR_LEB) // 30 i64_load8_s
  202. ,(doReloc: true; relocType: R_WASM_MEMORY_ADDR_LEB) // 31 i64_load8_u
  203. ,(doReloc: true; relocType: R_WASM_MEMORY_ADDR_LEB) // 32 i64_load16_s
  204. ,(doReloc: true; relocType: R_WASM_MEMORY_ADDR_LEB) // 33 i64_load16_u
  205. ,(doReloc: true; relocType: R_WASM_MEMORY_ADDR_LEB) // 34 i64.load32_s
  206. ,(doReloc: true; relocType: R_WASM_MEMORY_ADDR_LEB) // 35 i64.load32_u
  207. ,(doReloc: true; relocType: R_WASM_MEMORY_ADDR_LEB) // 36 i32_store
  208. ,(doReloc: true; relocType: R_WASM_MEMORY_ADDR_LEB) // 37 i64_store
  209. ,(doReloc: true; relocType: R_WASM_MEMORY_ADDR_LEB) // 38 f32_store
  210. ,(doReloc: true; relocType: R_WASM_MEMORY_ADDR_LEB) // 39 f64_store
  211. ,(doReloc: true; relocType: R_WASM_MEMORY_ADDR_LEB) // 3A i32_store8
  212. ,(doReloc: true; relocType: R_WASM_MEMORY_ADDR_LEB) // 3B i32_store16
  213. ,(doReloc: true; relocType: R_WASM_MEMORY_ADDR_LEB) // 3C i64_store8
  214. ,(doReloc: true; relocType: R_WASM_MEMORY_ADDR_LEB) // 3D i64_store16
  215. ,(doReloc: true; relocType: R_WASM_MEMORY_ADDR_LEB) // 3E i64_store32
  216. ,(doReloc: false; relocType: $FF) // 3F memory_size
  217. ,(doReloc: false; relocType: $FF) // 40 memory_grow
  218. ,(doReloc: true; relocType: R_WASM_TABLE_INDEX_SLEB) // 41 i32_const // TODO: special case for function address
  219. ,(doReloc: false; relocType: $FF) // 42 i64_const
  220. ,(doReloc: false; relocType: $FF) // 43 f32_const
  221. ,(doReloc: false; relocType: $FF) // 44 f64_const
  222. ,(doReloc: false; relocType: $FF) // 45 i32_eqz
  223. ,(doReloc: false; relocType: $FF) // 46 i32_eq
  224. ,(doReloc: false; relocType: $FF) // 47 i32_ne
  225. ,(doReloc: false; relocType: $FF) // 48 i32_lt_s
  226. ,(doReloc: false; relocType: $FF) // 49 i32_lt_u
  227. ,(doReloc: false; relocType: $FF) // 4A i32_gt_s
  228. ,(doReloc: false; relocType: $FF) // 4B i32_gt_u
  229. ,(doReloc: false; relocType: $FF) // 4C i32_le_s
  230. ,(doReloc: false; relocType: $FF) // 4D i32_le_u
  231. ,(doReloc: false; relocType: $FF) // 4E i32_ge_s
  232. ,(doReloc: false; relocType: $FF) // 4F i32_ge_u
  233. ,(doReloc: false; relocType: $FF) // 50 i64_eqz
  234. ,(doReloc: false; relocType: $FF) // 51 i64_eq
  235. ,(doReloc: false; relocType: $FF) // 52 i64_ne
  236. ,(doReloc: false; relocType: $FF) // 53 i64_lt_s
  237. ,(doReloc: false; relocType: $FF) // 54 i64_lt_u
  238. ,(doReloc: false; relocType: $FF) // 55 i64_gt_s
  239. ,(doReloc: false; relocType: $FF) // 56 i64_gt_u
  240. ,(doReloc: false; relocType: $FF) // 57 i64_le_s
  241. ,(doReloc: false; relocType: $FF) // 58 i64_le_u
  242. ,(doReloc: false; relocType: $FF) // 59 i64_ge_s
  243. ,(doReloc: false; relocType: $FF) // 5A i64_ge_u
  244. ,(doReloc: false; relocType: $FF) // 5B f32_eq
  245. ,(doReloc: false; relocType: $FF) // 5C f32_ne
  246. ,(doReloc: false; relocType: $FF) // 5D f32_lt
  247. ,(doReloc: false; relocType: $FF) // 5E f32_gt
  248. ,(doReloc: false; relocType: $FF) // 5F f32_le
  249. ,(doReloc: false; relocType: $FF) // 60 f32_ge
  250. ,(doReloc: false; relocType: $FF) // 61 f64_eq
  251. ,(doReloc: false; relocType: $FF) // 62 f64_ne
  252. ,(doReloc: false; relocType: $FF) // 63 f64_lt
  253. ,(doReloc: false; relocType: $FF) // 64 f64_gt
  254. ,(doReloc: false; relocType: $FF) // 65 f64_le
  255. ,(doReloc: false; relocType: $FF) // 66 f64_ge
  256. ,(doReloc: false; relocType: $FF) // 67 i32_clz
  257. ,(doReloc: false; relocType: $FF) // 68 i32_ctz
  258. ,(doReloc: false; relocType: $FF) // 69 i32_popcnt
  259. ,(doReloc: false; relocType: $FF) // 6A i32_add
  260. ,(doReloc: false; relocType: $FF) // 6B i32_sub
  261. ,(doReloc: false; relocType: $FF) // 6C i32_mul
  262. ,(doReloc: false; relocType: $FF) // 6D i32_div_s
  263. ,(doReloc: false; relocType: $FF) // 6E i32_div_u
  264. ,(doReloc: false; relocType: $FF) // 6F i32_rem_s
  265. ,(doReloc: false; relocType: $FF) // 70 i32_rem_u
  266. ,(doReloc: false; relocType: $FF) // 71 i32_and
  267. ,(doReloc: false; relocType: $FF) // 72 i32_or
  268. ,(doReloc: false; relocType: $FF) // 73 i32_xor
  269. ,(doReloc: false; relocType: $FF) // 74 i32_shl
  270. ,(doReloc: false; relocType: $FF) // 75 i32_shr_s
  271. ,(doReloc: false; relocType: $FF) // 76 i32_shr_u
  272. ,(doReloc: false; relocType: $FF) // 77 i32_rotl
  273. ,(doReloc: false; relocType: $FF) // 78 i32_rotr
  274. ,(doReloc: false; relocType: $FF) // 79 i64_clz
  275. ,(doReloc: false; relocType: $FF) // 7A i64_ctz
  276. ,(doReloc: false; relocType: $FF) // 7B i64_popcnt
  277. ,(doReloc: false; relocType: $FF) // 7C i64_add
  278. ,(doReloc: false; relocType: $FF) // 7D i64_sub
  279. ,(doReloc: false; relocType: $FF) // 7E i64_mul
  280. ,(doReloc: false; relocType: $FF) // 7F i64_div_s
  281. ,(doReloc: false; relocType: $FF) // 80 i64_div_u
  282. ,(doReloc: false; relocType: $FF) // 81 i64_rem_s
  283. ,(doReloc: false; relocType: $FF) // 82 i64_rem_u
  284. ,(doReloc: false; relocType: $FF) // 83 i64_and
  285. ,(doReloc: false; relocType: $FF) // 84 i64_or
  286. ,(doReloc: false; relocType: $FF) // 85 i64_xor
  287. ,(doReloc: false; relocType: $FF) // 86 i64_shl
  288. ,(doReloc: false; relocType: $FF) // 87 i64_shr_s
  289. ,(doReloc: false; relocType: $FF) // 88 i64_shr_u
  290. ,(doReloc: false; relocType: $FF) // 89 i64_rotl
  291. ,(doReloc: false; relocType: $FF) // 8A i64_rotr
  292. ,(doReloc: false; relocType: $FF) // 8B f32_abs
  293. ,(doReloc: false; relocType: $FF) // 8C f32_neg
  294. ,(doReloc: false; relocType: $FF) // 8D f32_ceil
  295. ,(doReloc: false; relocType: $FF) // 8E f32_floor
  296. ,(doReloc: false; relocType: $FF) // 8F f32_trunc
  297. ,(doReloc: false; relocType: $FF) // 90 f32_nearest
  298. ,(doReloc: false; relocType: $FF) // 91 f32_sqrt
  299. ,(doReloc: false; relocType: $FF) // 92 f32_add
  300. ,(doReloc: false; relocType: $FF) // 93 f32_sub
  301. ,(doReloc: false; relocType: $FF) // 94 f32_mul
  302. ,(doReloc: false; relocType: $FF) // 95 f32_div
  303. ,(doReloc: false; relocType: $FF) // 96 f32_min
  304. ,(doReloc: false; relocType: $FF) // 97 f32_max
  305. ,(doReloc: false; relocType: $FF) // 98 f32_copysign
  306. ,(doReloc: false; relocType: $FF) // 99 f64_abs
  307. ,(doReloc: false; relocType: $FF) // 9A f64_neg
  308. ,(doReloc: false; relocType: $FF) // 9B f64_ceil
  309. ,(doReloc: false; relocType: $FF) // 9C f64_floor
  310. ,(doReloc: false; relocType: $FF) // 9D f64_trunc
  311. ,(doReloc: false; relocType: $FF) // 9E f64_nearest
  312. ,(doReloc: false; relocType: $FF) // 9F f64_sqrt
  313. ,(doReloc: false; relocType: $FF) // A0 f64_add
  314. ,(doReloc: false; relocType: $FF) // A1 f64_sub
  315. ,(doReloc: false; relocType: $FF) // A2 f64_mul
  316. ,(doReloc: false; relocType: $FF) // A3 f64_div
  317. ,(doReloc: false; relocType: $FF) // A4 f64_min
  318. ,(doReloc: false; relocType: $FF) // A5 f64_max
  319. ,(doReloc: false; relocType: $FF) // A6 f64_copysign
  320. ,(doReloc: false; relocType: $FF) // A7 i32_wrap_i64
  321. ,(doReloc: false; relocType: $FF) // A8 i32_trunc_f32_s
  322. ,(doReloc: false; relocType: $FF) // A9 i32_trunc_f32_u
  323. ,(doReloc: false; relocType: $FF) // AA i32_trunc_f64_s
  324. ,(doReloc: false; relocType: $FF) // AB i32_trunc_f64_u
  325. ,(doReloc: false; relocType: $FF) // AC i64_extend_i32_s
  326. ,(doReloc: false; relocType: $FF) // AD i64_extend_i32_u
  327. ,(doReloc: false; relocType: $FF) // AE i64_trunc_f32_s
  328. ,(doReloc: false; relocType: $FF) // AF i64_trunc_f32_u
  329. ,(doReloc: false; relocType: $FF) // B0 i64_trunc_f64_s
  330. ,(doReloc: false; relocType: $FF) // B1 i64_trunc_f64_u
  331. ,(doReloc: false; relocType: $FF) // B2 f32_convert_i32_s
  332. ,(doReloc: false; relocType: $FF) // B3 f32_convert_i32_u
  333. ,(doReloc: false; relocType: $FF) // B4 f32_convert_i64_s
  334. ,(doReloc: false; relocType: $FF) // B5 f32_convert_i64_u
  335. ,(doReloc: false; relocType: $FF) // B6 f32_demote_f64
  336. ,(doReloc: false; relocType: $FF) // B7 f64_convert_i32_s
  337. ,(doReloc: false; relocType: $FF) // B8 f64_convert_i32_u
  338. ,(doReloc: false; relocType: $FF) // B9 f64_convert_i64_s
  339. ,(doReloc: false; relocType: $FF) // BA f64_convert_i64_u
  340. ,(doReloc: false; relocType: $FF) // BB f64_promote_f32
  341. ,(doReloc: false; relocType: $FF) // BC i32_reinterpret_f32
  342. ,(doReloc: false; relocType: $FF) // BD i64_reinterpret_f64
  343. ,(doReloc: false; relocType: $FF) // BE f32_reinterpret_i32
  344. ,(doReloc: false; relocType: $FF) // BF f64_reinterpret_i64
  345. );
  346. implementation
  347. function ReadMetaData(st: TStream; out m:TLinkingMetadata): Boolean;
  348. begin
  349. FillChar(m, sizeof(m), 0);
  350. m.version := st.ReadByte;
  351. Result:=true;
  352. end;
  353. function ReadLinkSubSect(st: TStream; out m: TLinkingSubSection): Boolean;
  354. begin
  355. FillChar(m, sizeof(m), 0);
  356. m.sectype := st.ReadByte; //ReadU(st);
  357. m.length := ReadU(st);
  358. Result := true;
  359. end;
  360. function ReadSymInfo(st: TStream; out m: TSymInfo): Boolean;
  361. begin
  362. FillChar(m, sizeof(m), 0);
  363. m.kind := st.ReadByte;
  364. m.flags := ReadU(st);
  365. if m.kind = SYMTAB_DATA then begin
  366. m.hasSymName := true; // always exist
  367. m.symname := ReadName(st);
  368. m.hasSymIndex := (m.flags and WASM_SYM_UNDEFINED)=0;
  369. if m.hasSymIndex then begin
  370. m.symindex := ReadU(st);
  371. m.dataofs := ReadU(st);
  372. m.datasize := ReadU(st);
  373. end;
  374. end else begin
  375. m.hasSymIndex := true; // always exists
  376. m.symindex := ReadU(st);
  377. m.hasSymName := ((m.flags and WASM_SYM_IMPORTED) = 0) or ((m.flags and WASM_SYM_EXPLICIT_NAME) > 0); // imported
  378. if m.hasSymName then
  379. m.symname:=ReadName(st);
  380. end;
  381. Result := true;
  382. end;
  383. procedure WriteSymInfo(st: TStream; const m: TSymInfo);
  384. begin
  385. st.WriteByte(m.kind);
  386. WriteU32(st, m.flags);
  387. if m.kind = SYMTAB_DATA then begin
  388. WriteName(st, m.symname);
  389. if (m.flags and WASM_SYM_UNDEFINED)=0 then begin
  390. WriteU32(st, m.symindex);
  391. WriteU32(st, m.dataofs);
  392. WriteU32(st, m.datasize);
  393. end;
  394. end else begin
  395. WriteU32(st, m.symindex);
  396. if ((m.flags and WASM_SYM_IMPORTED) = 0) or ((m.flags and WASM_SYM_EXPLICIT_NAME) > 0) then
  397. WriteName(st, m.symname);
  398. end;
  399. end;
  400. procedure DumpLinking(st: TStream; secsize: integer);
  401. var
  402. mt : TLinkingMetadata;
  403. en : Int64;
  404. sub : TLinkingSubSection;
  405. cnt : LongWord;
  406. nx : Int64;
  407. i : integer;
  408. si : TSymInfo;
  409. begin
  410. en := st.Position+secsize;
  411. ReadMetadata(st, mt);
  412. writeln('version: ', mt.version);
  413. while st.Position<en do begin
  414. ReadLinkSubSect(st, sub);
  415. nx := st.Position+sub.length;
  416. writeln('subsec=',SubSecTypeToStr(sub.sectype),' ',sub.sectype);
  417. cnt := ReadU(st);
  418. writeln('- symbol table [count=', cnt,']');
  419. for i:=0 to cnt-1 do begin
  420. write(' - ',i,' ');
  421. ReadSymInfo(st, si);
  422. write(SymKindToStr(si.kind),' ',IntToHex(si.flags,8));
  423. if si.hasSymName then write(' ',si.symname);
  424. writeln;
  425. //writeln(si.symname);
  426. end;
  427. st.Position:=nx;
  428. end;
  429. end;
  430. function SubSecTypeToStr(b: Byte): string;
  431. begin
  432. case b of
  433. WASM_SEGMENT_INFO: Result := 'WASM_SEGMENT_INFO';
  434. WASM_INIT_FUNCS: Result := 'WASM_INIT_FUNCS';
  435. WASM_COMDAT_INFO: Result := 'WASM_COMDAT_INFO';
  436. WASM_SYMBOL_TABLE: Result := 'WASM_SYMBOL_TABLE';
  437. else
  438. Result := Format('UNKNOWN %d',[b]);
  439. end;
  440. end;
  441. function SymKindToStr(b: Byte): string;
  442. begin
  443. case b of
  444. SYMTAB_FUNCTION: Result := 'F';
  445. SYMTAB_DATA: Result := 'D';
  446. SYMTAB_GLOBAL: Result := 'G';
  447. SYMTAB_SECTION: Result := 'S';
  448. SYMTAB_EVENT: Result := 'E';
  449. SYMTAB_TABLE: Result := 'T';
  450. else
  451. Result := 'U'+IntToStR(b);
  452. end;
  453. end;
  454. procedure ReadLinkingSection(st: TStream; size: integer; var sc: TLinkingSection);
  455. var
  456. eofs : int64;
  457. sub : TLinkingSubSection;
  458. cnt : integer;
  459. i : integer;
  460. nx : int64;
  461. begin
  462. eofs := st.Position+size;
  463. ReadMetadata(st, sc.metadata);
  464. while st.Position < eofs do begin
  465. ReadLinkSubSect(st, sub);
  466. nx := st.Position+sub.length;
  467. case sub.sectype of
  468. //todo: others!
  469. WASM_SYMBOL_TABLE: begin
  470. cnt := ReadU(st);
  471. SetLength(sc.symbols, cnt);
  472. for i:=0 to cnt-1 do
  473. ReadSymInfo(st, sc.symbols[i]);
  474. end;
  475. end;
  476. st.Position:=nx;
  477. end;
  478. end;
  479. procedure WriteLinkingSection(st: TStream; const sc: TLinkingSection);
  480. var
  481. mem : TMemoryStream;
  482. i : integer;
  483. begin
  484. st.WriteByte(sc.metadata.version);
  485. mem:=TMemoryStream.Create;
  486. try
  487. WriteU32(mem, length(sc.symbols));
  488. for i:=0 to length(sc.symbols)-1 do
  489. WriteSymInfo(mem, sc.symbols[i]);
  490. st.WriteByte(WASM_SYMBOL_TABLE);
  491. WriteU32(st, mem.Size);
  492. mem.Position:=0;
  493. st.CopyFrom(mem, mem.Size);
  494. finally
  495. mem.Free;
  496. end;
  497. // todo: other sub setions are possible
  498. end;
  499. end.