wasmtoolutils.pas 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335
  1. unit wasmtoolutils;
  2. interface
  3. uses
  4. Classes,SysUtils, wasmbin, lebutils,
  5. //wasmbindebug,
  6. wasmlink, wasmlinkchange;
  7. function ChangeSymbolFlagStream(st: TStream; syms: TStrings): Boolean;
  8. procedure ChangeSymbolFlag(const fn, symfn: string);
  9. procedure MatchExportNameToSymName(const x: TExportSection; const l: TLinkingSection; dst: TStrings);
  10. function ExportRenameSym(var x: TExportSection; syms: TStrings): Integer;
  11. function ExportRenameProcess(st, dst: TStream; syms: TStrings; doVerbose: Boolean): Boolean;
  12. function ExportNameGather(const wasmfile: string; syms: TStrings; doVerbose: Boolean = false): Boolean;
  13. procedure ExportRename(const fn, symfn: string; doVerbose: Boolean);
  14. implementation
  15. function ChangeSymbolFlagStream(st: TStream; syms: TStrings): Boolean;
  16. var
  17. dw : LongWord;
  18. ofs : int64;
  19. sc : TSection;
  20. ps : int64;
  21. nm : string;
  22. begin
  23. dw := st.ReadDWord;
  24. Result := dw = WasmId_Int;
  25. if not Result then Exit;
  26. dw := st.ReadDWord;
  27. while st.Position<st.Size do begin
  28. ofs := st.Position;
  29. sc.id := st.ReadByte;
  30. sc.Size := ReadU(st);
  31. ps := st.Position+sc.size;
  32. if sc.id=0 then begin
  33. nm := GetName(st);
  34. if nm = SectionName_Linking then begin
  35. ProcessLinkingSection(st, syms);
  36. break;
  37. end;
  38. //DumpLinking(st, sc.size - (st.Position - ofs));
  39. end;
  40. //if sc.id= 1 then DumpTypes(st);
  41. if st.Position <> ps then
  42. begin
  43. //writeln('adjust stream targ=',ps,' actual: ', st.position);
  44. st.Position := ps;
  45. end;
  46. end;
  47. end;
  48. // Assumption is made, there's only 1 table in the file!
  49. // if a function is a stub function (the only code is "unreachable"), the status given
  50. // "weak" (it's a reference function elsewhere)
  51. // if a function is located in the function table, then the status given is
  52. // "hidden" (do not add to the final linked executable)
  53. // if a function is not located in the function table, the status given is:
  54. // "hidden"+"local" (local means the function can be used only in this object file)
  55. procedure MatchExportNameToSymFlag(
  56. x: TExportSection;
  57. l: TLinkingSection;
  58. e: TElementSection;
  59. syms : TStrings)
  60. begin
  61. end;
  62. function PredictSymbolsFromLink(const wasmfn: string; syms: TStrings; doVerbose: Boolean = false): Boolean;
  63. var
  64. st : TFileStream;
  65. dw : LongWord;
  66. foundExport : Boolean;
  67. foundElement : Boolean;
  68. foundLink : Boolean;
  69. ofs : Int64;
  70. ps : Int64;
  71. sc : TSection;
  72. x : TExportSection;
  73. l : TLinkingSection;
  74. e : TElementSection;
  75. cnt : Integer;
  76. nm : string;
  77. begin
  78. st := TFileStream.Create(wasmfn, fmOpenRead or fmShareDenyNone);
  79. try
  80. dw := st.ReadDWord;
  81. Result := dw = WasmId_Int;
  82. if not Result then begin
  83. Exit;
  84. end;
  85. dw := st.ReadDWord;
  86. foundElement:=false;
  87. foundExport:=false;
  88. foundLink:=false;
  89. while st.Position<st.Size do begin
  90. ofs := st.Position;
  91. sc.id := st.ReadByte;
  92. sc.Size := ReadU(st);
  93. ps := st.Position+sc.size;
  94. if sc.id = SECT_EXPORT then begin
  95. if doVerbose then writeln(' export section found');
  96. ReadExport(st, x);
  97. cnt := ExportRenameSym(x, syms);
  98. foundExport:=true;
  99. end else if sc.id = SECT_CUSTOM then begin
  100. nm := ReadName(st);
  101. if nm = SectionName_Linking then begin
  102. foundLink := true;
  103. ReadLinkingSection(st, sc.size, l);
  104. end;
  105. end;
  106. if st.Position <> ps then
  107. st.Position := ps;
  108. end;
  109. Result := foundLink and foundExport;
  110. if Result then
  111. MatchExportNameToSymFlag(x, l, syms);
  112. finally
  113. st.Free;
  114. end;
  115. end;
  116. procedure ChangeSymbolFlag(const fn, symfn: string);
  117. var
  118. fs :TFileStream;
  119. syms: TStringList;
  120. begin
  121. syms:=TStringList.Create;
  122. fs := TFileStream.Create(fn, fmOpenReadWrite or fmShareDenyNone);
  123. try
  124. if (symfn<>'') then begin
  125. if not isWasmFile(symfn) then
  126. ReadSymbolsConf(symfn, syms)
  127. else begin
  128. PredictSymbolsFromLink(symfn, syms);
  129. end;
  130. end;
  131. ChangeSymbolFlagStream(fs, syms);
  132. finally
  133. fs.Free;
  134. syms.Free;
  135. end;
  136. end;
  137. function ExportRenameSym(var x: TExportSection; syms: TStrings): integer;
  138. var
  139. i : integer;
  140. v : string;
  141. begin
  142. Result := 0;
  143. for i:=0 to length(x.entries)-1 do begin
  144. v := syms.Values[x.entries[i].name];
  145. if v <> '' then begin
  146. x.entries[i].name := v;
  147. inc(Result);
  148. end;
  149. end;
  150. end;
  151. function ExportRenameProcess(st, dst: TStream; syms: TStrings; doVerbose: Boolean): Boolean;
  152. var
  153. dw : LongWord;
  154. ofs : int64;
  155. sc : TSection;
  156. ps : int64;
  157. x : TExportSection;
  158. mem : TMemoryStream;
  159. cnt : integer;
  160. begin
  161. dw := st.ReadDWord;
  162. Result := dw = WasmId_Int;
  163. if not Result then begin
  164. Exit;
  165. end;
  166. dw := st.ReadDWord;
  167. while st.Position<st.Size do begin
  168. ofs := st.Position;
  169. sc.id := st.ReadByte;
  170. sc.Size := ReadU(st);
  171. ps := st.Position+sc.size;
  172. if sc.id = SECT_EXPORT then begin
  173. if doVerbose then writeln(' export section found');
  174. ReadExport(st, x);
  175. cnt := ExportRenameSym(x, syms);
  176. writeln(' renamings: ', cnt);
  177. st.Position:=0;
  178. dst.CopyFrom(st, ofs);
  179. st.Position:=ps;
  180. mem := TMemoryStream.Create;
  181. WriteExport(x, mem);
  182. mem.Position:=0;
  183. dst.WriteByte(SECT_EXPORT);
  184. WriteU32(dst, mem.Size);
  185. dst.CopyFrom(mem, mem.Size);
  186. dst.CopyFrom(st, st.Size-st.Position);
  187. break;
  188. end;
  189. if st.Position <> ps then
  190. st.Position := ps;
  191. end;
  192. end;
  193. // match between exported function names and symbol names
  194. procedure MatchExportNameToSymName(const x: TExportSection; const l: TLinkingSection; dst: TStrings);
  195. var
  196. expname : string;
  197. i,j : integer;
  198. begin
  199. for i:=0 to length(x.entries)-1 do begin
  200. // gathering only function names for now
  201. if x.entries[i].desc <> EXPDESC_FUNC then continue;
  202. expname := x.entries[i].name;
  203. for j:=0 to length(l.symbols)-1 do begin
  204. if (l.symbols[j].kind = SYMTAB_FUNCTION)
  205. and (l.symbols[j].symindex = x.entries[i].index)
  206. and (l.symbols[j].hasSymName)
  207. then
  208. dst.Values[ l.symbols[j].symname ] := expname;
  209. end;
  210. end;
  211. end;
  212. function ExportNameGather(const wasmfile: string; syms: TStrings; doVerbose: Boolean = false): Boolean;
  213. var
  214. dw : LongWord;
  215. ofs : int64;
  216. sc : TSection;
  217. ps : int64;
  218. mem : TMemoryStream;
  219. cnt : integer;
  220. st : TFileStream;
  221. nm : string;
  222. x : TExportSection;
  223. foundExport: Boolean;
  224. l : TLinkingSection;
  225. foundLink: Boolean;
  226. begin
  227. st := TFileStream.Create(wasmfile, fmOpenRead or fmShareDenyNone);
  228. try
  229. dw := st.ReadDWord;
  230. Result := dw = WasmId_Int;
  231. if not Result then begin
  232. Exit;
  233. end;
  234. dw := st.ReadDWord;
  235. foundExport:=false;
  236. foundLink:=false;
  237. while st.Position<st.Size do begin
  238. ofs := st.Position;
  239. sc.id := st.ReadByte;
  240. sc.Size := ReadU(st);
  241. ps := st.Position+sc.size;
  242. if sc.id = SECT_EXPORT then begin
  243. if doVerbose then writeln(' export section found');
  244. ReadExport(st, x);
  245. cnt := ExportRenameSym(x, syms);
  246. foundExport:=true;
  247. end else if sc.id = SECT_CUSTOM then begin
  248. nm := ReadName(st);
  249. if nm = SectionName_Linking then begin
  250. foundLink := true;
  251. ReadLinkingSection(st, sc.size, l);
  252. end;
  253. end;
  254. if st.Position <> ps then
  255. st.Position := ps;
  256. end;
  257. Result := foundLink and foundExport;
  258. if Result then
  259. MatchExportNameToSymName(x, l, syms);
  260. finally
  261. st.Free;
  262. end;
  263. end;
  264. procedure ExportRename(const fn, symfn: string; doVerbose: Boolean);
  265. var
  266. fs : TFileStream;
  267. syms : TStringList;
  268. dst : TMemoryStream;
  269. begin
  270. if doVerbose then writeln('Export symbols renaming');
  271. syms:=TStringList.Create;
  272. fs := TFileStream.Create(fn, fmOpenReadWrite or fmShareDenyNone);
  273. dst := TMemoryStream.Create;
  274. try
  275. if (symfn <> '') and fileExists(symfn) then
  276. begin
  277. if doVerbose then writeln('reading symbols: ', symfn);
  278. if isWasmFile(symfn) then
  279. ExportNameGather(symfn, syms, doVerbose)
  280. else
  281. syms.LoadFromFile(symfn);
  282. if doVerbose then write(syms.Text);
  283. end;
  284. ExportRenameProcess(fs, dst, syms, doVerbose);
  285. fs.Position:=0;
  286. dst.Position:=0;
  287. fs.CopyFrom(dst, dst.Size);
  288. fs.Size:=dst.Size;
  289. finally
  290. dst.Free;
  291. fs.Free;
  292. syms.Free;
  293. end;
  294. end;
  295. end.