ldump.c 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342
  1. /*
  2. ** $Id: ldump.c,v 2.8.1.1 2007/12/27 13:02:25 roberto Exp $
  3. ** save precompiled Lua chunks
  4. ** See Copyright Notice in lua.h
  5. */
  6. #include <stddef.h>
  7. #include <string.h>
  8. #define ldump_c
  9. #define LUA_CORE
  10. #include "lua.h"
  11. #include "lobject.h"
  12. #include "lstate.h"
  13. #include "lundump.h"
  14. typedef struct
  15. {
  16. lua_State *L;
  17. lua_Writer writer;
  18. void *data;
  19. int strip;
  20. int status;
  21. DumpTargetInfo target;
  22. size_t wrote;
  23. } DumpState;
  24. #define DumpMem(b,n,size,D) DumpBlock(b,(n)*(size),D)
  25. #define DumpVar(x,D) DumpMem(&x,1,sizeof(x),D)
  26. static void DumpBlock(const void *b, size_t size, DumpState *D)
  27. {
  28. if (D->status == 0)
  29. {
  30. lua_unlock(D->L);
  31. D->status = (*D->writer)(D->L, b, size, D->data);
  32. D->wrote += size;
  33. lua_lock(D->L);
  34. }
  35. }
  36. static void DumpChar(int y, DumpState *D)
  37. {
  38. char x = (char)y;
  39. DumpVar(x, D);
  40. }
  41. static void Align4(DumpState *D)
  42. {
  43. while (D->wrote & 3)
  44. DumpChar(0, D);
  45. }
  46. static void MaybeByteSwap(char *number, size_t numbersize, DumpState *D)
  47. {
  48. int x = 1;
  49. int platform_little_endian = *(char *)&x;
  50. if (platform_little_endian != D->target.little_endian)
  51. {
  52. unsigned long i;
  53. for (i = 0; i < numbersize / 2; i++)
  54. {
  55. char temp = number[i];
  56. number[i] = number[numbersize - 1 - i];
  57. number[numbersize - 1 - i] = temp;
  58. }
  59. }
  60. }
  61. static void DumpIntWithSize(int x, int sizeof_int, DumpState *D)
  62. {
  63. /* dump signed integer */
  64. switch (sizeof_int)
  65. {
  66. case 1:
  67. {
  68. if (x > 0x7F || x < (-0x80)) D->status = LUA_ERR_CC_INTOVERFLOW;
  69. DumpChar(x, D);
  70. }
  71. break;
  72. case 2:
  73. {
  74. if (x > 0x7FFF || x < (-0x8000)) D->status = LUA_ERR_CC_INTOVERFLOW;
  75. int16_t y = (int16_t)x;
  76. MaybeByteSwap((char *)&y, 2, D);
  77. DumpVar(y, D);
  78. }
  79. break;
  80. case 4:
  81. {
  82. /* Need to reduce bounds by 1 to avoid messing 32-bit compilers up */
  83. if (x > 0x7FFFFFFE || x < (-0x7FFFFFFF)) D->status = LUA_ERR_CC_INTOVERFLOW;
  84. int32_t y = (int32_t)x;
  85. MaybeByteSwap((char *)&y, 4, D);
  86. DumpVar(y, D);
  87. }
  88. break;
  89. default:
  90. lua_assert(0);
  91. }
  92. }
  93. static void DumpInt(int x, DumpState *D)
  94. {
  95. DumpIntWithSize(x, D->target.sizeof_int, D);
  96. }
  97. static void DumpSize(uint32_t x, DumpState *D)
  98. {
  99. /* dump unsigned integer */
  100. switch (D->target.sizeof_strsize_t)
  101. {
  102. case 1:
  103. {
  104. if (x > 0xFF) D->status = LUA_ERR_CC_INTOVERFLOW;
  105. DumpChar(x, D);
  106. }
  107. break;
  108. case 2:
  109. {
  110. if (x > 0xFFFF) D->status = LUA_ERR_CC_INTOVERFLOW;
  111. uint16_t y = (uint16_t)x;
  112. MaybeByteSwap((char *)&y, 2, D);
  113. DumpVar(y, D);
  114. }
  115. break;
  116. case 4:
  117. {
  118. /* Reduce bounds to avoid messing 32-bit compilers up */
  119. if (x > 0xFFFFFFFE) D->status = LUA_ERR_CC_INTOVERFLOW;
  120. uint32_t y = x;
  121. MaybeByteSwap((char *)&y, 4, D);
  122. DumpVar(y, D);
  123. }
  124. break;
  125. default:
  126. lua_assert(0);
  127. }
  128. }
  129. static void DumpNumber(lua_Number x, DumpState *D)
  130. {
  131. #if defined( LUA_NUMBER_INTEGRAL ) && !defined( LUA_CROSS_COMPILER )
  132. DumpIntWithSize(x, D->target.sizeof_lua_Number, D);
  133. #else // #if defined( LUA_NUMBER_INTEGRAL ) && !defined( LUA_CROSS_COMPILER )
  134. if (D->target.lua_Number_integral)
  135. {
  136. if (((float)(int)x) != x) D->status = LUA_ERR_CC_NOTINTEGER;
  137. DumpIntWithSize(x, D->target.sizeof_lua_Number, D);
  138. }
  139. else
  140. {
  141. switch (D->target.sizeof_lua_Number)
  142. {
  143. /* do we need bounds checking? */
  144. case 4:
  145. {
  146. float y = x;
  147. MaybeByteSwap((char *)&y, 4, D);
  148. DumpVar(y, D);
  149. }
  150. break;
  151. case 8:
  152. {
  153. double y = x;
  154. // ARM FPA mode: keep endianness, but swap high and low parts of the
  155. // memory representation. This is the default compilation mode for ARM
  156. // targets with non-EABI gcc
  157. if (D->target.is_arm_fpa)
  158. {
  159. char *pnum = (char *)&y, temp[4];
  160. memcpy(temp, pnum, 4);
  161. memcpy(pnum, pnum + 4, 4);
  162. memcpy(pnum + 4, temp, 4);
  163. }
  164. MaybeByteSwap((char *)&y, 8, D);
  165. DumpVar(y, D);
  166. }
  167. break;
  168. default:
  169. lua_assert(0);
  170. }
  171. }
  172. #endif // #if defined( LUA_NUMBER_INTEGRAL ) && !defined( LUA_CROSS_COMPILER )
  173. }
  174. static void DumpCode(const Proto *f, DumpState *D)
  175. {
  176. DumpInt(f->sizecode, D);
  177. char buf[10];
  178. int i;
  179. Align4(D);
  180. for (i = 0; i < f->sizecode; i++)
  181. {
  182. memcpy(buf, &f->code[i], sizeof(Instruction));
  183. MaybeByteSwap(buf, sizeof(Instruction), D);
  184. DumpBlock(buf, sizeof(Instruction), D);
  185. }
  186. }
  187. static void DumpString(const TString *s, DumpState *D)
  188. {
  189. if (s == NULL || getstr(s) == NULL)
  190. {
  191. strsize_t size = 0;
  192. DumpSize(size, D);
  193. }
  194. else
  195. {
  196. strsize_t size = (strsize_t)s->tsv.len + 1; /* include trailing '\0' */
  197. DumpSize(size, D);
  198. DumpBlock(getstr(s), size, D);
  199. }
  200. }
  201. static void DumpFunction(const Proto *f, const TString *p, DumpState *D);
  202. static void DumpConstants(const Proto *f, DumpState *D)
  203. {
  204. int i, n = f->sizek;
  205. DumpInt(n, D);
  206. for (i = 0; i < n; i++)
  207. {
  208. const TValue *o = &f->k[i];
  209. DumpChar(ttype(o), D);
  210. switch (ttype(o))
  211. {
  212. case LUA_TNIL:
  213. break;
  214. case LUA_TBOOLEAN:
  215. DumpChar(bvalue(o), D);
  216. break;
  217. case LUA_TNUMBER:
  218. DumpNumber(nvalue(o), D);
  219. break;
  220. case LUA_TSTRING:
  221. DumpString(rawtsvalue(o), D);
  222. break;
  223. default:
  224. lua_assert(0); /* cannot happen */
  225. break;
  226. }
  227. }
  228. n = f->sizep;
  229. DumpInt(n, D);
  230. for (i = 0; i < n; i++) DumpFunction(f->p[i], f->source, D);
  231. }
  232. static void DumpDebug(const Proto *f, DumpState *D)
  233. {
  234. int i, n;
  235. n = (D->strip) ? 0 : f->sizelineinfo;
  236. DumpInt(n, D);
  237. Align4(D);
  238. for (i = 0; i < n; i++)
  239. {
  240. DumpInt(f->lineinfo[i], D);
  241. }
  242. n = (D->strip) ? 0 : f->sizelocvars;
  243. DumpInt(n, D);
  244. for (i = 0; i < n; i++)
  245. {
  246. DumpString(f->locvars[i].varname, D);
  247. DumpInt(f->locvars[i].startpc, D);
  248. DumpInt(f->locvars[i].endpc, D);
  249. }
  250. n = (D->strip) ? 0 : f->sizeupvalues;
  251. DumpInt(n, D);
  252. for (i = 0; i < n; i++) DumpString(f->upvalues[i], D);
  253. }
  254. static void DumpFunction(const Proto *f, const TString *p, DumpState *D)
  255. {
  256. DumpString((f->source == p || D->strip) ? NULL : f->source, D);
  257. DumpInt(f->linedefined, D);
  258. DumpInt(f->lastlinedefined, D);
  259. DumpChar(f->nups, D);
  260. DumpChar(f->numparams, D);
  261. DumpChar(f->is_vararg, D);
  262. DumpChar(f->maxstacksize, D);
  263. DumpCode(f, D);
  264. DumpConstants(f, D);
  265. DumpDebug(f, D);
  266. }
  267. static void DumpHeader(DumpState *D)
  268. {
  269. char buf[LUAC_HEADERSIZE];
  270. char *h = buf;
  271. /* This code must be kept in sync wiht luaU_header */
  272. memcpy(h, LUA_SIGNATURE, sizeof(LUA_SIGNATURE) - 1);
  273. h += sizeof(LUA_SIGNATURE) - 1;
  274. *h++ = (char)LUAC_VERSION;
  275. *h++ = (char)LUAC_FORMAT;
  276. *h++ = (char)D->target.little_endian;
  277. *h++ = (char)D->target.sizeof_int;
  278. *h++ = (char)D->target.sizeof_strsize_t;
  279. *h++ = (char)sizeof(Instruction);
  280. *h++ = (char)D->target.sizeof_lua_Number;
  281. *h++ = (char)D->target.lua_Number_integral;
  282. DumpBlock(buf, LUAC_HEADERSIZE, D);
  283. }
  284. /*
  285. ** dump Lua function as precompiled chunk with specified target
  286. */
  287. int luaU_dump_crosscompile(lua_State *L, const Proto *f, lua_Writer w, void *data, int strip, DumpTargetInfo target)
  288. {
  289. DumpState D;
  290. D.L = L;
  291. D.writer = w;
  292. D.data = data;
  293. D.strip = strip;
  294. D.status = 0;
  295. D.target = target;
  296. D.wrote = 0;
  297. DumpHeader(&D);
  298. DumpFunction(f, NULL, &D);
  299. return D.status;
  300. }
  301. /*
  302. ** dump Lua function as precompiled chunk with local machine as target
  303. */
  304. int luaU_dump(lua_State *L, const Proto *f, lua_Writer w, void *data, int strip)
  305. {
  306. DumpTargetInfo target;
  307. int test = 1;
  308. target.little_endian = *(char *)&test;
  309. target.sizeof_int = sizeof(int);
  310. target.sizeof_strsize_t = sizeof(strsize_t);
  311. target.sizeof_lua_Number = sizeof(lua_Number);
  312. target.lua_Number_integral = (((lua_Number)0.5) == 0);
  313. target.is_arm_fpa = 0;
  314. return luaU_dump_crosscompile(L, f, w, data, strip, target);
  315. }