lundump.c 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642
  1. /*---
  2. ** $Id: lundump.c,v 2.44.1.1 2017/04/19 17:20:42 roberto Exp $
  3. ** load precompiled Lua chunks
  4. ** See Copyright Notice in lua.h
  5. */
  6. #define lundump_c
  7. #define LUA_CORE
  8. #include "lprefix.h"
  9. #include <string.h>
  10. #include "lua.h"
  11. #include "ldebug.h"
  12. #include "ldo.h"
  13. #include "lfunc.h"
  14. #include "llex.h"
  15. #include "lmem.h"
  16. #include "lnodemcu.h"
  17. #include "lobject.h"
  18. #include "lstring.h"
  19. #include "lundump.h"
  20. #include "lzio.h"
  21. /*
  22. ** Unlike the standard Lua version of lundump.c, this NodeMCU version must be
  23. ** able to store the dumped Protos into one of two targets:
  24. **
  25. ** (A) RAM-based heap. This in the same way as standard Lua, where the
  26. ** Proto data structures can be created by direct in memory addressing,
  27. ** with any references complying with Lua GC assumptions, so that all
  28. ** storage can be collected in the case of a thrown error.
  29. **
  30. ** (B) Flash programmable ROM memory. This can only be written to serially,
  31. ** using a write API, it can be subsequently but accessed and directly
  32. ** addressable through a memory-mapped address window after cache flush.
  33. **
  34. ** Mode (B) also know as LFS (Lua FLash Store) enables running Lua apps
  35. ** on small-memory IoT devices which support programmable flash storage such
  36. ** as the ESP8266 SoC. In the case of this chip, the usable RAM heap is
  37. ** roughly 45Kb, so the ability to store an extra 128Kb, say, of program into
  38. ** LFS can materially increase the size of application that can be executed
  39. ** and leave most of the heap for true R/W application data.
  40. **
  41. ** The changes to this source file enable the addition of LFS mode. In mode B,
  42. ** the resources aren't allocated in RAM but are written to Flash using the
  43. ** write API which returns the corresponding Flash read address is returned;
  44. ** also data can't be immediately read back using these addresses because of
  45. ** cache staleness.
  46. **
  47. ** Handling the Proto record has been reordered to avoid interleaved resource
  48. ** writes in mode (B), with the f->k being cached in RAM and the Proto
  49. ** hierarchies walked bottom-up in a way that still maintains GC compliance
  50. ** conformance for mode (A). This no-interleave constraint also complicates
  51. ** the writing of TString resources into flash, so the flashing process
  52. ** circumvents this issue for LFS loads by header by taking two passes to dump
  53. ** the hierarchy. The first dumps all strings that needed to load the Protos,
  54. ** with the subsequent Proto loads use an index to any TString references.
  55. ** This enables all strings to be loaded into an LFS-based ROstrt before
  56. ** starting to load the Protos.
  57. **
  58. ** Note that this module and ldump.c are compiled into both the ESP firmware
  59. ** and a host-based luac cross compiler. LFS dump is currently only supported
  60. ** in the compiler, but both the LFS and standard loads are supported in both
  61. ** the target (lua.c) and the host (luac.cross -e)environments. Both
  62. ** environments are built with the same integer and float formats (e.g. 32 bit,
  63. ** 32-bit IEEE).
  64. **
  65. ** Dumps can either be loaded into RAM or LFS depending on the load format. An
  66. ** extra complication is that luac.cross supports two LFS modes, with the
  67. ** first loading into an host process address space and using host 32 or 64
  68. ** bit address references. The second uses shadow ESP 32 bit addresses to
  69. ** create an absolute binary image for direct provisioning of ESP images.
  70. */
  71. #define MODE_RAM 0 /* Loading into RAM */
  72. #define MODE_LFS 1 /* Loading into a locally executable LFS */
  73. #define MODE_LFSA 2 /* (Host only) Loading into a shadow ESP image */
  74. typedef struct {
  75. lua_State *L; /* cache L to drop parameter list */
  76. ZIO *Z; /* ZIO context */
  77. const char *name; /* Filename of the LFS image being loaded */
  78. LFSHeader *fh; /* LFS flash header block */
  79. void *startLFS; /* Start address of LFS region */
  80. TString **TS; /* List of TStrings being used in the image */
  81. lu_int32 TSlen; /* Length of the same */
  82. lu_int32 TSndx; /* Index into the same */
  83. lu_int32 TSnFixed; /* Number of "fixed" TS */
  84. char *buff; /* Working buffer for assembling a TString */
  85. lu_int32 buffLen; /* Maximum length of TS used in the image */
  86. TString **list; /* TS list used to index the ROstrt */
  87. lu_int32 listLen; /* Length of the same */
  88. Proto **pv; /* List of Protos in LFS */
  89. lu_int32 pvLen; /* Length of the same */
  90. GCObject *protogc; /* LFS proto linked list */
  91. lu_byte useStrRefs; /* Flag if set then TStings are a index into TS */
  92. lu_byte mode; /* Either LFS or RAM */
  93. } LoadState;
  94. static l_noret error(LoadState *S, const char *why) {
  95. luaO_pushfstring(S->L, "%s: %s precompiled chunk", S->name, why);
  96. luaD_throw(S->L, LUA_ERRSYNTAX);
  97. }
  98. #define wordptr(p) cast(lu_int32 *, p)
  99. #define byteptr(p) cast(lu_byte *, p)
  100. #define wordoffset(p,q) (wordptr(p) - wordptr(q))
  101. #define FHaddr(S,t,f) cast(t, wordptr(S->startLFS) + (f))
  102. #define FHoffset(S,o) wordoffset((o), S->startLFS)
  103. #define NewVector(S, n, t) cast(t *,NewVector_(S, n, sizeof(t)))
  104. #define StoreGetPos(S) luaN_writeFlash((S)->Z->data, NULL, 0)
  105. static void *NewVector_(LoadState *S, int n, size_t s) {
  106. void *v;
  107. if (S->mode == MODE_RAM) {
  108. v = luaM_reallocv(S->L, NULL, 0, n, s);
  109. memset (v, 0, n*s);
  110. } else {
  111. v = StoreGetPos(S);
  112. }
  113. return v;
  114. }
  115. static void *Store_(LoadState *S, void *a, int ndx, const void *e, size_t s
  116. #ifdef LUA_USE_HOST
  117. , const char *format
  118. #endif
  119. ) {
  120. if (S->mode == MODE_RAM) {
  121. lu_byte *p = byteptr(a) + ndx*s;
  122. if (p != byteptr(e))
  123. memcpy(p, e, s);
  124. return p;
  125. }
  126. #ifdef LUA_USE_HOST
  127. else if (S->mode == MODE_LFSA && format) { /* do a repack move */
  128. void *p = StoreGetPos(S);
  129. const char *f = format;
  130. int o;
  131. for (o = 0; *f; o++, f++ ) {
  132. luaN_writeFlash(S->Z->data, wordptr(e)+o, sizeof(lu_int32));
  133. if (*f == 'A' || *f == 'W') /* Addr or word followed by alignment fill */
  134. o++;
  135. }
  136. lua_assert(o*sizeof(lu_int32) == s);
  137. return p;
  138. }
  139. #endif
  140. /* mode == LFS or 32bit build */
  141. return luaN_writeFlash(S->Z->data, e, s);
  142. }
  143. #ifdef LUA_USE_HOST
  144. #include <stdio.h>
  145. /* These compression maps must match the definitions in lobject.h etc. */
  146. # define OFFSET_TSTRING (2*(sizeof(lu_int32)-sizeof(size_t)))
  147. # define FMT_TSTRING "AwwA"
  148. #if defined(CONFIG_LUA_NUMBER_INT64) || defined(CONFIG_LUA_NUMBER_DOUBLE) || defined(LUA_NUMBER_64BITS)
  149. # define FMT_TVALUE "www"
  150. #else
  151. # define FMT_TVALUE "AW"
  152. #endif
  153. # define FMT_PROTO "AwwwwwwwwwwAAAAAAAA"
  154. # define FMT_UPVALUE "AW"
  155. # define FMT_LOCVAR "Aww"
  156. # define FMT_ROTENTRY "A" FMT_TVALUE
  157. # define FMT_ROTABLE "AWAA"
  158. # define StoreR(S,a, i, v, f) Store_(S, (a), i, &(v), sizeof(v), f)
  159. # define Store(S, a, i, v) StoreR(S, (a), i, v, NULL)
  160. # define StoreN(S, v, n) Store_(S, NULL, 0, (v), (n)*sizeof(*(v)), NULL)
  161. static void *StoreAV (LoadState *S, void *a, int n) {
  162. void **av = cast(void**, a);
  163. if (S->mode == MODE_LFSA) {
  164. void *p = StoreGetPos(S);
  165. int i; for (i = 0; i < n; i ++)
  166. luaN_writeFlash(S->Z->data, wordptr(av++), sizeof(lu_int32));
  167. return p;
  168. } else {
  169. return Store_(S, NULL, 0, av, n*sizeof(*av), NULL);
  170. }
  171. }
  172. #else // LUA_USE_ESP
  173. # define OFFSET_TSTRING (0)
  174. # define Store(S, a, i, v) Store_(S, (a), i, &(v), sizeof(v))
  175. # define StoreN(S, v, n) Store_(S, NULL, 0, (v), (n)*sizeof(*(v)))
  176. # define StoreR(S, a, i, v, f) Store(S, a, i, v)
  177. # define StoreAV(S, p, n) StoreN(S, p, n)
  178. # define OPT_FMT
  179. #endif
  180. #define StoreFlush(S) luaN_flushFlash((S)->Z->data);
  181. #define LoadVector(S,b,n) LoadBlock(S,b,(n)*sizeof((b)[0]))
  182. static void LoadBlock (LoadState *S, void *b, size_t size) {
  183. lu_int32 left = luaZ_read(S->Z, b, size);
  184. if ( left != 0)
  185. error(S, "truncated");
  186. }
  187. #define LoadVar(S,x) LoadVector(S,&x,1)
  188. static lu_byte LoadByte (LoadState *S) {
  189. lu_byte x;
  190. LoadVar(S, x);
  191. return x;
  192. }
  193. static lua_Integer LoadInt (LoadState *S) {
  194. lu_byte b;
  195. lua_Integer x = 0;
  196. do { b = LoadByte(S); x = (x<<7) + (b & 0x7f); } while (b & 0x80);
  197. return x;
  198. }
  199. static lua_Number LoadNumber (LoadState *S) {
  200. lua_Number x;
  201. LoadVar(S, x);
  202. return x;
  203. }
  204. static lua_Integer LoadInteger (LoadState *S, lu_byte tt_data) {
  205. lu_byte b;
  206. lua_Integer x = tt_data & LUAU_DMASK;
  207. if (tt_data & 0x80) {
  208. do { b = LoadByte(S); x = (x<<7) + (b & 0x7f); } while (b & 0x80);
  209. }
  210. return (tt_data & LUAU_TMASK) == LUAU_TNUMNINT ? -x-1 : x;
  211. }
  212. static TString *LoadString_ (LoadState *S, int prelen) {
  213. TString *ts;
  214. char buff[LUAI_MAXSHORTLEN];
  215. int n = LoadInteger(S, (prelen < 0 ? LoadByte(S) : prelen)) - 1;
  216. if (n < 0)
  217. return NULL;
  218. if (S->useStrRefs)
  219. ts = S->TS[n];
  220. else if (n <= LUAI_MAXSHORTLEN) { /* short string? */
  221. LoadVector(S, buff, n);
  222. ts = luaS_newlstr(S->L, buff, n);
  223. } else { /* long string */
  224. ts = luaS_createlngstrobj(S->L, n);
  225. LoadVector(S, getstr(ts), n); /* load directly in final place */
  226. }
  227. return ts;
  228. }
  229. #define LoadString(S) LoadString_(S,-1)
  230. #define LoadString2(S,pl) LoadString_(S,(pl))
  231. static void LoadCode (LoadState *S, Proto *f) {
  232. Instruction *p;
  233. f->sizecode = LoadInt(S);
  234. f->code = luaM_newvector(S->L, f->sizecode, Instruction);
  235. LoadVector(S, f->code, f->sizecode);
  236. if (S->mode != MODE_RAM) {
  237. p = StoreN(S, f->code, f->sizecode);
  238. luaM_freearray(S->L, f->code, f->sizecode);
  239. f->code = p;
  240. }
  241. }
  242. static void *LoadFunction(LoadState *S, Proto *f, TString *psource);
  243. static void LoadConstants (LoadState *S, Proto *f) {
  244. int i;
  245. f->sizek = LoadInt(S);
  246. f->k = NewVector(S, f->sizek, TValue);
  247. for (i = 0; i < f->sizek; i++) {
  248. TValue o;
  249. /*
  250. * tt is formatted 0bFTTTDDDD where TTT is the type; the F and the DDDD
  251. * fields are used by the integer decoder as this often saves a byte in
  252. * the endcoding.
  253. */
  254. lu_byte tt = LoadByte(S);
  255. switch (tt & LUAU_TMASK) {
  256. case LUAU_TNIL:
  257. setnilvalue(&o);
  258. break;
  259. case LUAU_TBOOLEAN:
  260. setbvalue(&o, !(tt == LUAU_TBOOLEAN));
  261. break;
  262. case LUAU_TNUMFLT:
  263. setfltvalue(&o, LoadNumber(S));
  264. break;
  265. case LUAU_TNUMPINT:
  266. case LUAU_TNUMNINT:
  267. setivalue(&o, LoadInteger(S, tt));
  268. break;
  269. case LUAU_TSSTRING:
  270. o.value_.gc = cast(GCObject *, LoadString2(S, tt));
  271. o.tt_ = ctb(LUA_TSHRSTR);
  272. break;
  273. case LUAU_TLSTRING:
  274. o.value_.gc = cast(GCObject *, LoadString2(S, tt));
  275. o.tt_ = ctb(LUA_TLNGSTR);
  276. break;
  277. default:
  278. lua_assert(0);
  279. }
  280. StoreR(S, f->k, i, o, FMT_TVALUE);
  281. }
  282. }
  283. /*
  284. ** The handling of Protos has support both modes, and in the case of flash
  285. ** mode, this requires some care as any writes to a Proto f must be deferred
  286. ** until after all of the writes to its sub Protos have been completed; so
  287. ** the Proto record and its p vector must be retained in RAM until stored to
  288. ** flash.
  289. **
  290. ** Recovery of dead resources on error handled by the Lua GC as standard in
  291. ** the case of RAM loading. In the case of loading an LFS image into flash,
  292. ** the error recovery could be done through the S->protogc list, but given
  293. ** that the immediate action is to restart the CPU, there is little point
  294. ** in adding the extra functionality to recover these dangling resources.
  295. */
  296. static void LoadProtos (LoadState *S, Proto *f) {
  297. int i, n = LoadInt(S);
  298. Proto **p = luaM_newvector(S->L, n, Proto *);
  299. f->p = p;
  300. f->sizep = n;
  301. memset (p, 0, n * sizeof(*p));
  302. for (i = 0; i < n; i++)
  303. p[i] = LoadFunction(S, luaF_newproto(S->L), f->source);
  304. if (S->mode != MODE_RAM) {
  305. f->p = StoreAV(S, cast(void **, p), n);
  306. luaM_freearray(S->L, p, n);
  307. }
  308. }
  309. static void LoadUpvalues (LoadState *S, Proto *f) {
  310. int i, nostripnames = LoadByte(S);
  311. f->sizeupvalues = LoadInt(S);
  312. if (f->sizeupvalues) {
  313. f->upvalues = NewVector(S, f->sizeupvalues, Upvaldesc);
  314. for (i = 0; i < f->sizeupvalues ; i++) {
  315. TString *name = nostripnames ? LoadString(S) : NULL;
  316. Upvaldesc uv = {name, LoadByte(S), LoadByte(S)};
  317. StoreR(S, f->upvalues, i, uv, FMT_UPVALUE);
  318. }
  319. }
  320. }
  321. static void LoadDebug (LoadState *S, Proto *f) {
  322. int i;
  323. f->sizelineinfo = LoadInt(S);
  324. if (f->sizelineinfo) {
  325. lu_byte *li = luaM_newvector(S->L, f->sizelineinfo, lu_byte);
  326. LoadVector(S, li, f->sizelineinfo);
  327. if (S->mode == MODE_RAM) {
  328. f->lineinfo = li;
  329. } else {
  330. f->lineinfo = StoreN(S, li, f->sizelineinfo);
  331. luaM_freearray(S->L, li, f->sizelineinfo);
  332. }
  333. }
  334. f->sizelocvars = LoadInt(S);
  335. f->locvars = NewVector(S, f->sizelocvars, LocVar);
  336. for (i = 0; i < f->sizelocvars; i++) {
  337. LocVar lv = {LoadString(S), LoadInt(S), LoadInt(S)};
  338. StoreR(S, f->locvars, i, lv, FMT_LOCVAR);
  339. }
  340. }
  341. static void *LoadFunction (LoadState *S, Proto *f, TString *psource) {
  342. /*
  343. * Main protos have f->source naming the file used to create the hierarchy;
  344. * subordinate protos set f->source != NULL to inherit this name from the
  345. * parent. In LFS mode, the Protos are moved from the GC to a local list
  346. * in S, but no error GC is attempted as discussed in LoadProtos.
  347. */
  348. Proto *p;
  349. global_State *g = G(S->L);
  350. if (S->mode != MODE_RAM) {
  351. lua_assert(g->allgc == obj2gco(f));
  352. g->allgc = f->next; /* remove object from 'allgc' list */
  353. f->next = S->protogc; /* push f into the head of the protogc list */
  354. S->protogc = obj2gco(f);
  355. }
  356. f->source = LoadString(S);
  357. if (f->source == NULL) /* no source in dump? */
  358. f->source = psource; /* reuse parent's source */
  359. f->linedefined = LoadInt(S);
  360. f->lastlinedefined = LoadInt(S);
  361. f->numparams = LoadByte(S);
  362. f->is_vararg = LoadByte(S);
  363. f->maxstacksize = LoadByte(S);
  364. LoadProtos(S, f);
  365. LoadCode(S, f);
  366. LoadConstants(S, f);
  367. LoadUpvalues(S, f);
  368. LoadDebug(S, f);
  369. if (S->mode != MODE_RAM) {
  370. GCObject *save = f->next;
  371. if (f->source != NULL) {
  372. setLFSbit(f);
  373. /* cache the RAM next and set up the next for the LFS proto chain */
  374. f->next = FHaddr(S, GCObject *, S->fh->protoHead);
  375. p = StoreR(S, NULL, 0, *f, FMT_PROTO);
  376. S->fh->protoHead = FHoffset(S, p);
  377. } else {
  378. p = StoreR(S, NULL, 0, *f, FMT_PROTO);
  379. }
  380. S->protogc = save; /* pop f from the head of the protogc list */
  381. luaM_free(S->L, f); /* and collect the dead resource */
  382. f = p;
  383. }
  384. return f;
  385. }
  386. static void checkliteral (LoadState *S, const char *s, const char *msg) {
  387. char buff[sizeof(LUA_SIGNATURE) + sizeof(LUAC_DATA)]; /* larger than both */
  388. size_t len = strlen(s);
  389. LoadVector(S, buff, len);
  390. if (memcmp(s, buff, len) != 0)
  391. error(S, msg);
  392. }
  393. static void fchecksize (LoadState *S, size_t size, const char *tname) {
  394. if (LoadByte(S) != size)
  395. error(S, luaO_pushfstring(S->L, "%s size mismatch in", tname));
  396. }
  397. #define checksize(S,t) fchecksize(S,sizeof(t),#t)
  398. static void checkHeader (LoadState *S, int format) {
  399. checkliteral(S, LUA_SIGNATURE + 1, "not a"); /* 1st char already checked */
  400. if (LoadByte(S) != LUAC_VERSION)
  401. error(S, "version mismatch in");
  402. if (LoadByte(S) != format)
  403. error(S, "format mismatch in");
  404. checkliteral(S, LUAC_DATA, "corrupted");
  405. checksize(S, int);
  406. /*
  407. * The standard Lua VM does a check on the sizeof size_t and endian check on
  408. * integer; both are dropped as the former prevents dump files being shared
  409. * across 32 and 64 bit machines, and we use multi-byte coding of ints.
  410. */
  411. checksize(S, Instruction);
  412. checksize(S, lua_Integer);
  413. checksize(S, lua_Number);
  414. LoadByte(S); /* skip number tt field */
  415. if (LoadNumber(S) != LUAC_NUM)
  416. error(S, "float format mismatch in");
  417. }
  418. /*
  419. ** Load precompiled chunk to support standard LUA_API load functions. The
  420. ** extra LFS functionality is effectively NO-OPed out on this MODE_RAM path.
  421. */
  422. LClosure *luaU_undump(lua_State *L, ZIO *Z, const char *name) {
  423. LoadState S = {0};
  424. LClosure *cl;
  425. if (*name == '@' || *name == '=')
  426. S.name = name + 1;
  427. else if (*name == LUA_SIGNATURE[0])
  428. S.name = "binary string";
  429. else
  430. S.name = name;
  431. S.L = L;
  432. S.Z = Z;
  433. S.mode = MODE_RAM;
  434. S.fh = NULL;
  435. S.useStrRefs = 0;
  436. checkHeader(&S, LUAC_FORMAT);
  437. cl = luaF_newLclosure(L, LoadByte(&S));
  438. setclLvalue(L, L->top, cl);
  439. luaD_inctop(L);
  440. cl->p = luaF_newproto(L);
  441. LoadFunction(&S, cl->p, NULL);
  442. lua_assert(cl->nupvalues == cl->p->sizeupvalues);
  443. return cl;
  444. }
  445. /*============================================================================**
  446. ** NodeMCU extensions for LFS support and Loading. Note that this funtionality
  447. ** is called from a hook in the lua startup within a lua_lock() (as with
  448. ** LuaU_undump), so luaU_undumpLFS() cannot use the external Lua API. It does
  449. ** uses the Lua stack, but staying within LUA_MINSTACK limits.
  450. **
  451. ** The in-RAM Protos used to assemble proto content prior to writing to LFS
  452. ** need special treatment since these hold LFS references rather than RAM ones
  453. ** and will cause the Lua GC to error if swept. Rather than adding complexity
  454. ** to lgc.c for this one-off process, these Protos are removed from the allgc
  455. ** list and fixed in a local one, and collected inline.
  456. **============================================================================*/
  457. /*
  458. ** Write a TString to the LFS. This parallels the lstring.c algo but writes
  459. ** directly to the LFS buffer and also append the LFS address in S->TS. Seeding
  460. ** is based on the seed defined in the LFS image, rather than g->seed.
  461. */
  462. static void addTS(LoadState *S, int l, int extra) {
  463. LFSHeader *fh = S->fh;
  464. TString *ts = cast(TString *, S->buff);
  465. char *s = getstr(ts);
  466. lua_assert (sizelstring(l) <= S->buffLen);
  467. s[l] = '\0';
  468. /* The collectable and LFS bits must be set; all others inc the whitebits clear */
  469. ts->marked = bitmask(LFSBIT) | BIT_ISCOLLECTABLE;
  470. ts->extra = extra;
  471. if (l <= LUAI_MAXSHORTLEN) { /* short string */
  472. TString **p;
  473. ts->tt = LUA_TSHRSTR;
  474. ts->shrlen = cast_byte(l);
  475. ts->hash = luaS_hash(s, l, fh->seed);
  476. p = S->list + lmod(ts->hash, S->listLen);
  477. ts->u.hnext = *p;
  478. ts->next = FHaddr(S, GCObject *, fh->shortTShead);
  479. S->TS[S->TSndx] = *p = StoreR(S, NULL, 0, *ts, FMT_TSTRING);
  480. fh->shortTShead = FHoffset(S, *p);
  481. } else { /* long string */
  482. TString *p;
  483. ts->tt = LUA_TLNGSTR;
  484. ts->shrlen = 0;
  485. ts->u.lnglen = l;
  486. ts->hash = fh->seed;
  487. luaS_hashlongstr(ts); /* sets hash and extra fields */
  488. ts->next = FHaddr(S, GCObject *, fh->longTShead);
  489. S->TS[S->TSndx] = p = StoreR(S, NULL, 0, *ts, FMT_TSTRING);
  490. fh->longTShead = FHoffset(S, p);
  491. }
  492. // printf("%04u(%u): %s\n", S->TSndx, l, S->buff + sizeof(union UTString));
  493. StoreN(S,S->buff + sizeof(union UTString), l+1);
  494. S->TSndx++;
  495. }
  496. /*
  497. ** The runtime (in ltm.c and llex.c) declares ~100 fixed strings and so these
  498. ** are moved into LFS to free up an extra ~2Kb RAM. Extra get token access
  499. ** functions have been added to these modules. These tokens aren't unique as
  500. ** ("nil" and "function" are both tokens and typenames), hardwiring this
  501. ** duplication debounce as a wrapper around addTS() is the simplest way of
  502. ** voiding the need for extra lookup resources.
  503. */
  504. static void addTSnodup(LoadState *S, const char *s, int extra) {
  505. int i, l = strlen(s);
  506. static struct {const char *k; int found; } t[] = {{"nil", 0},{"function", 0}};
  507. for (i = 0; i < sizeof(t)/sizeof(*t); i++) {
  508. if (!strcmp(t[i].k, s)) {
  509. if (t[i].found) return; /* ignore the duplicate copy */
  510. t[i].found = 1; /* flag that this constant is already loaded */
  511. break;
  512. }
  513. }
  514. memcpy(getstr(cast(TString *, S->buff)), s, l);
  515. addTS(S, l, extra);
  516. }
  517. /*
  518. ** Load TStrings in dump format. ALl TStrings used in an LFS image excepting
  519. ** any fixed strings are dumped as a unique collated set. Any strings in the
  520. ** following Proto streams use an index reference into this list rather than an
  521. ** inline copy. This function loads and stores them into LFS, constructing the
  522. ** ROstrt for the shorter interned strings.
  523. */
  524. static void LoadAllStrings (LoadState *S) {
  525. lua_State *L = S->L;
  526. global_State *g = G(L);
  527. int nb = sizelstring(LoadInt(S));
  528. int ns = LoadInt(S);
  529. int nl = LoadInt(S);
  530. int nstrings = LoadInt(S);
  531. int n = ns + nl;
  532. int nlist = 1<<luaO_ceillog2(ns);
  533. int i, extra;
  534. const char *p;
  535. /* allocate dynamic resources and save in S for error path collection */
  536. S->TS = luaM_newvector(L, n+1, TString *);
  537. S->TSlen = n+1;
  538. S->buff = luaM_newvector(L, nb, char);
  539. S->buffLen = nb;
  540. S->list = luaM_newvector(L, nlist, TString *);
  541. S->listLen = nlist;
  542. memset (S->list, 0, nlist*sizeof(TString *));
  543. /* add the strings in the image file to LFS */
  544. for (i = 1; i <= nstrings; i++) {
  545. int tt = LoadByte(S);
  546. lua_assert((tt&LUAU_TMASK)==LUAU_TSSTRING || (tt&LUAU_TMASK)==LUAU_TLSTRING);
  547. int l = LoadInteger(S, tt) - 1; /* No NULL entry in list of TSs */
  548. LoadVector(S, getstr(cast(TString *, S->buff)), l);
  549. addTS(S, l, 0);
  550. }
  551. /* add the fixed strings to LFS */
  552. for (i = 0; (p = luaX_getstr(i, &extra))!=NULL; i++) {
  553. addTSnodup(S, p, extra);
  554. }
  555. addTSnodup(S, getstr(g->memerrmsg), 0);
  556. addTSnodup(S, LUA_ENV, 0);
  557. for (i = 0; (p = luaT_getstr(i))!=NULL; i++) {
  558. addTSnodup(S, p, 0);
  559. }
  560. /* check that the actual size is the same as the predicted */
  561. lua_assert(n == S->TSndx-1);
  562. S->fh->oROhash = FHoffset(S, StoreAV(S, S->list, nlist));
  563. S->fh->nROuse = ns;
  564. S->fh->nROsize = nlist;
  565. StoreFlush(S);
  566. S->buff = luaM_freearray(L, S->buff, nb);
  567. S->buffLen = 0;
  568. S->list = luaM_freearray(L, S->list, nlist);
  569. S->listLen = 0;
  570. }
  571. static void LoadAllProtos (LoadState *S) {
  572. lua_State *L = S->L;
  573. ROTable_entry eol = {NULL, LRO_NILVAL};
  574. int i, n = LoadInt(S);
  575. S->pv = luaM_newvector(L, n, Proto *);
  576. S->pvLen = n;
  577. /* Load Protos and store addresses in the Proto vector */
  578. for (i = 0; i < n; i++) {
  579. S->pv[i] = LoadFunction(S, luaF_newproto(L), NULL);
  580. }
  581. /* generate the ROTable entries from first N constants; the last is a timestamp */
  582. int nk = LoadInt(S);
  583. lua_assert(n+1 == nk);
  584. ROTable_entry *entry_list = cast(ROTable_entry *, StoreGetPos(S));
  585. for (i = 0; i < nk - 1; i++) { // -1 to ignore timestamp
  586. lu_byte tt_data = LoadByte(S);
  587. TString *Tname = LoadString2(S, tt_data);
  588. const char *name = getstr(Tname) + OFFSET_TSTRING;
  589. lua_assert((tt_data & LUAU_TMASK) == LUAU_TSSTRING);
  590. ROTable_entry me = {name, LRO_LUDATA(S->pv[i])};
  591. StoreR(S, NULL, 0, me, FMT_ROTENTRY);
  592. }
  593. StoreR(S, NULL, 0, eol, FMT_ROTENTRY);
  594. /* terminate the ROTable entry list and store the ROTable header */
  595. ROTable ev = { (GCObject *)1, LUA_TTBLROF, LROT_MARKED,
  596. (lu_byte) ~0, n, NULL, entry_list};
  597. S->fh->protoROTable = FHoffset(S, StoreR(S, NULL, 0, ev, FMT_ROTABLE));
  598. /* last const is timestamp */
  599. S->fh->timestamp = LoadInteger(S, LoadByte(S));
  600. }
  601. static void undumpLFS(lua_State *L, void *ud) {
  602. LoadState *S = cast(LoadState *, ud);
  603. void *F = S->Z->data;
  604. S->startLFS = StoreGetPos(S);
  605. luaN_setFlash(F, sizeof(LFSHeader));
  606. S->fh->flash_sig = FLASH_SIG;
  607. if (LoadByte(S) != LUA_SIGNATURE[0])
  608. error(S, "invalid header in");
  609. checkHeader(S, LUAC_LFS_IMAGE_FORMAT);
  610. S->fh->seed = LoadInteger(S, LoadByte(S));
  611. checkliteral(S, LUA_STRING_SIG,"no string vector");
  612. LoadAllStrings (S);
  613. checkliteral(S, LUA_PROTO_SIG,"no Proto vector");
  614. LoadAllProtos(S);
  615. S->fh->flash_size = byteptr(StoreGetPos(S)) - byteptr(S->startLFS);
  616. luaN_setFlash(F, 0);
  617. StoreN(S, S->fh, 1);
  618. luaN_setFlash(F, 0);
  619. S->TS = luaM_freearray(L, S->TS, S->TSlen);
  620. }
  621. /*
  622. ** Load precompiled LFS image. This is called from a hook in the firmware
  623. ** startup if LFS reload is required.
  624. */
  625. LUAI_FUNC int luaU_undumpLFS(lua_State *L, ZIO *Z, int isabs) {
  626. LFSHeader fh = {0};
  627. LoadState S = {0};
  628. int status;
  629. S.L = L;
  630. S.Z = Z;
  631. S.mode = isabs && sizeof(size_t) != sizeof(lu_int32) ? MODE_LFSA : MODE_LFS;
  632. S.useStrRefs = 1;
  633. S.fh = &fh;
  634. L->nny++; /* do not yield during undump LFS */
  635. status = luaD_pcall(L, undumpLFS, &S, savestack(L, L->top), L->errfunc);
  636. luaM_freearray(L, S.TS, S.TSlen);
  637. luaM_freearray(L, S.buff, S.buffLen);
  638. luaM_freearray(L, S.list, S.listLen);
  639. luaM_freearray(L, S.pv, S.pvLen);
  640. L->nny--;
  641. return status;
  642. }