Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- local lbc={};
- local function readByte(s)
- local b=s.inf[s.count];
- s.count=s.count+1;
- return b;
- end
- local function skipByte(s,w)
- if s.dbg and w then
- print("byte:"..w.."="..s.inf[s.count]);
- end
- s.count=s.count+1;
- end
- local function readInt(s)
- --[[if intSize==4 then
- count=count+4;
- if bigEndian then return inf[count-4]*2^24+inf[count-3]*2^16+inf[count-2]*2^8+inf[count-1];
- else return inf[count-1]*2^24+inf[count-2]*2^16+inf[count-3]*2^8+inf[count-4]; end
- else]]
- local num=0;
- for i=0,s.intSize-1 do
- if s.bigEndian then
- num=num+s.inf[s.count+s.intSize-i-1]*2^(i*8);
- else
- num=num+s.inf[s.count+i]*2^(i*8);
- end
- end
- s.count=s.count+s.intSize;
- return num;
- --end
- end
- local function skipInt(s,w)
- if s.dbg and w then
- print("int:"..w.."="..readInt(s));
- else s.count=s.count+s.intSize; end
- end
- local function readSizet(s)
- --[[if sizetSize==4 then
- count=count+4;
- if bigEndian then return inf[count-4]*2^24+inf[count-3]*2^16+inf[count-2]*2^8+inf[count-1];
- else return inf[count-1]*2^24+inf[count-2]*2^16+inf[count-3]*2^8+inf[count-4]; end
- else]]
- local num=0;
- for i=0,s.sizetSize-1 do
- if s.bigEndian then
- num=num+s.inf[s.count+s.sizetSize-i-1]*2^(i*8);
- else
- num=num+s.inf[s.count+i]*2^(i*8);
- end
- end
- s.count=s.count+s.sizetSize;
- return num;
- --end
- end
- local function skipSizet(s,w)
- if s.dbg and w then
- print("size_t:"..w.."="..readSizet(s));
- else s.count=s.count+s.sizetSize; end
- end
- local function readString(s)
- local ln=readSizet(s); --Skip null terminator
- if ln==0 then return false; end
- s.count=s.count-1;
- local b={};
- for i=1,ln-1 do
- b[i]=s.inf[s.count+i];
- end
- s.count=s.count+1+ln;
- return string.char(unpack(b));
- end
- local function skipString(s,w)
- if s.dbg and w then
- local str=readString(s);
- print("string:"..w.."="..(str and ("\""..str.."\"") or "no value"));
- else
- local ln=readSizet(s);
- s.count=s.count+ln;
- end
- end
- local function readDouble(s)
- --Maybe replace this with chunkspy's readdouble?
- local dump={string.dump(function()return 0;end):byte(1,-1)};
- if dump[5]~=0x51 or dump[6]~=0 or dump[10]~=4 or dump[11]~=8 or dump[12]~=0 then
- error("Incompatible lua platform for number decoding");
- end
- local tmps={
- inf=dump,
- bigEndian=dump[7]==0,
- intSize=dump[8],
- sizetSize=dump[9],
- count=13,
- }
- skipString(tmps); --Skip sourceName
- skipInt(tmps); --Skip firstLine
- skipInt(tmps); --Skip lastLine
- skipByte(tmps); --Skip upvalueCount
- skipByte(tmps); --Skip paramCount
- skipByte(tmps); --Skip varargFlags
- skipByte(tmps); --Skip stackSize
- --Skip instructions
- local cs=readInt(tmps);
- for i=1,cs do
- tmps.count=tmps.count+4;
- end
- skipInt(tmps); --Skip constant list size
- skipByte(tmps); --Skip constant type
- --Got to constant spot, copy double
- if tmps.bigEndian==s.bigEndian then
- for i=0,7 do
- dump[tmps.count+i]=s.inf[s.count+i];
- end
- else
- for i=0,7 do
- dump[tmps.count+i]=s.inf[s.count+7-i];
- end
- end
- local f=loadstring(string.char(unpack(dump)));
- if not f then error("Error decoding number"); end
- s.count=s.count+8;
- return f();
- end
- local function skipDouble(s,w)
- if s.dbg and w then
- print("number:"..w.."="..tostring(readDouble(s)));
- else s.count=s.count+8; end
- end
- local opMeta;
- do
- local opAlias={"a","b","c",type1="typeA",type2="typeB",type3="typeC"};
- opMeta={
- __index=function(t,k)
- local rk=opAlias[k];
- if rk==nil then
- return rawget(t,k);
- else
- return rawget(t,rk);
- end
- end,
- __newindex=function(t,k,v)
- local rk=opAlias[k];
- if rk==nil then
- return rawset(t,k,v);
- else
- return rawset(t,rk,v);
- end
- end,
- };
- end
- lbc.codes={
- --Numeric to name
- [0]="move","loadk","loadbool","loadnil","getupval","getglobal","gettable",
- "setglobal","setupval","settable","newtable","self","add","sub","mul","div",
- "mod","pow","unm","not","len","concat","jmp","eq","lt","le","test","testset",
- "call","tailcall","return","forloop","forprep","tforloop","setlist","close",
- "closure","vararg",
- --Name to numeric
- move=0,loadk=1,loadbool=2,loadnil=3,getupval=4,getglobal=5,gettable=6,
- setglobal=7,setupval=8,settable=9,newtable=10,self=11,add=12,sub=13,mul=14,div=15,
- mod=16,pow=17,unm=18,_not=19,["not"]=19,len=20,concat=21,jmp=22,eq=23,lt=24,le=25,
- test=26,testset=27,call=28,tailcall=29,_return=30,["return"]=30,forloop=31,
- forprep=32,tforloop=33,setlist=34,close=35,closure=36,vararg=37,
- };
- lbc.types={
- ABC=1,ABx=2,AsBx=3,
- [0]=1, --move A B c
- 2, --loadk A Bx
- 1, --loadbool A B C
- 1, --loadnil A B c
- 1, --getupval A B c
- 2, --getglobal A Bx
- 1, --gettable A B C
- 2, --setglobal A Bx
- 1, --setupval A B c
- 1, --settable A B C
- 1, --newtable A B C
- 1, --self A B C
- 1, --add A B C
- 1, --sub A B C
- 1, --mul A B C
- 1, --div A B C
- 1, --mod A B C
- 1, --pow A B C
- 1, --unm A B c
- 1, --not A B c
- 1, --len A B c
- 1, --concat A B C
- 3, --jmp a sBx
- 1, --eq A B C
- 1, --lt A B C
- 1, --le A B C
- 1, --test A b C
- 1, --testset A B C
- 1, --call A B C
- 1, --tailcall A B C
- 1, --return A B c
- 3, --forloop A sBx
- 3, --forprep A sBx
- 1, --tforloop A b C
- 1, --setlist A B C
- 1, --close A b c
- 2, --closure A Bx
- 1, --vararg A B c
- };
- lbc.insertOp=function(bm,i,iop)
- if iop==nil then
- iop=i;
- i=iop.i;
- else
- iop.i=i;
- end
- for j,jop in ipairs(bm.code) do
- local a,b=lbc.getTargets(jop);
- if b=="code" then --If op is a jump, update jump
- b=j+1+jop.b;
- if b<i and j>=i then jop.b=jop.b-1;
- elseif b>=i and j<i then jop.b=jop.b+1;
- end
- end
- if j>=i then --Push ops upwards
- jop.i=jop.i+1;
- end
- end
- table.insert(bm.code,i,iop);
- end
- lbc.insertMany=function(bm,i,iops)
- local code=bm.code;
- local ioplen=#iops;
- for j=1,#code do
- local jop=code[j];
- local a,b=lbc.getTargets(jop);
- if b=="code" then --If op is a jump, update jump
- b=j+1+jop.b;
- if b<i and j>=i then jop.b=jop.b-ioplen;
- elseif b>=i and j<i then jop.b=jop.b+ioplen;
- end
- end
- if j>=i then --Push ops upwards
- jop.i=j+ioplen;
- end
- end
- --Actually insert ops
- for j=1,ioplen do
- table.insert(code,i+j-1,iops[j]);
- end
- end
- lbc.asm=function(asm)
- for i=1,#asm do
- local args=asm[i];
- local op=setmetatable({name=args[1]},opMeta);
- local stacks={lbc.getTargets(op)};
- local mode=false;
- local num=1;
- for j=2,#args do
- while not stacks[num] do num=num+1; end
- if num>3 then
- error("op "..i..": too many args",2);
- end
- local fakearg=args[j];
- if mode=="p" or mode=="k" or mode=="pk" then
- op.marked=true;
- op[10+num]=mode;
- op[20+num]=fakearg;
- num=num+1;
- mode=false;
- else
- if fakearg=="k" or fakearg=="pk" or fakearg=="p" then
- mode=fakearg;
- elseif fakearg=="knil" then
- op.marked=true;
- op[10+num]="k";
- op[20+num]=nil;
- num=num+1;
- elseif type(fakearg)=="number" then
- op[num]=fakearg;
- num=num+1;
- elseif type(fakearg)=="string" and fakearg:sub(1,1)=="t" then
- op["type"..num]=fakearg:sub(2);
- else error("op "..i..": invalid arg "..tostring(fakearg)..", only numbers, 'k', 'p' or 'pk'",2); end
- end
- end
- if mode then error("op "..i..": '"..mode.."' missing constant value",2); end
- asm[i]=op;
- end
- return asm;
- end
- lbc.insertAsm=function(bm,i,asm,ph)
- if asm.stackSize and asm.stackSize>bm.header.stackSize then bm.header.stackSize=asm.stackSize; end
- local code={};
- for j=1,#asm do
- local op=asm[j];
- local newop=op;
- local stacks={lbc.getTargets(op)};
- if op.marked then --Marked ops need to be "deep-copied"
- newop=setmetatable({name=op.name},opMeta);
- end
- for k=1,3 do
- local special=op[10+k];
- if stacks[k]==nil then
- elseif special then
- local val=op[20+k];
- if special=="p" or special=="pk" then val=ph[val]; end
- if special=="k" or special=="pk" then
- val=bm:k(val);
- if stacks[k]=="mixed" then val=val+256; end
- end
- newop[k]=val;
- newop["type"..k]=op["type"..k];
- elseif op.marked then
- newop[k]=op[k];
- newop["type"..k]=op["type"..k];
- end
- end
- code[j]=newop;
- end
- return lbc.insertMany(bm,i,code);
- end
- local function getRK(p,t)
- p=lbc.typeToRaw(t,p);
- if not p then return "mixed"; end
- return (p/2^8)%2<1 and "registers" or "constants";
- end
- lbc.getTargets=function(op)
- local name=op.name;
- if name=="move" or name=="loadnil" or name=="unm" or name=="not" or name=="len" then
- return "registers","registers";
- elseif name=="loadk" or name=="getglobal" or name=="setglobal" then
- return "registers","constants";
- elseif name=="loadbool" or name=="call" or name=="newtable" or name=="setlist" then
- return "registers","staticValues","staticValues";
- elseif name=="getupval" or name=="setupval" then
- return "registers","upvalues";
- elseif name=="gettable" or name=="self" then
- return "registers","registers",getRK(op.c,op.typeC);
- elseif name=="settable" or name=="add" or name=="sub" or name=="mul" or name=="div" or name=="mod" or name=="pow" then
- return "registers",getRK(op.b,op.typeB),getRK(op.c,op.typeC);
- elseif name=="concat" then
- return "registers","registers","registers";
- elseif name=="jmp" then
- return nil,"code";
- elseif name=="return" or name=="tailcall" or name=="vararg" then
- return "registers","staticValues";
- elseif name=="eq" or name=="lt" or name=="le" then
- return "staticValues",getRK(op.b,op.typeB),getRK(op.c,op.typeC);
- elseif name=="test" then
- return "registers",nil,"staticValues";
- elseif name=="testset" then
- return "registers","registers","staticValues";
- elseif name=="forprep" or name=="forloop" then
- return "registers","code";
- elseif name=="tforloop" then
- return "registers",nil,"staticValues";
- elseif name=="closure" then
- return "registers","functions";
- elseif name=="close" then
- return "registers";
- elseif name=="setlist_c" then
- return nil,nil,"staticValues";
- else
- error("Invalid opcode "..tostring(name),2);
- end
- end
- lbc.new=function(name,a,b,c)
- return setmetatable({name=name,a=a,b=b,c=c},opMeta);
- end
- lbc.addConstant=function(bm,val)
- local ks=bm.constants;
- for i,kval in ipairs(ks) do
- if val==kval then
- return i-1; --Constant list starts at 0, not 1
- end
- end
- ks.size=ks.size+1;
- ks[ks.size]=val;
- return ks.size-1; --Constant list starts at 0, not 1
- end
- do
- local frexp=math.frexp; --Upvalues are ALOTFASTER than getglobal+gettable
- lbc.toBytefloat=function(num)
- if num>=8 then
- local _,n=frexp(num);
- n=n-4; --This lines get the number of bits to shift to the right, such that the leftmost 1 is the 4th bit
- num=num/2^n; --Shift n bits to the right
- local mn=num%1; --Save the decimal part
- num=(num-mn)%8; --First floor the number and then BAND the rightmost 3 bits
- num=num+(n+1)*2^3; --BOR the exponent+1 shifted to the left by 3
- if mn~=0 then --If the number should be rounded up
- num=num+1; --Add one to the mantissa. If it overflows it will overflow into the exponent (which is what we want)
- end
- end
- return num;
- end
- end
- lbc.fromBytefloat=function(bf)
- local e;
- e=bf/(2^3); --Shift 3 to the right
- e=e-(e%1); --math.floor without function calls
- local m=bf%(8); --BAND the rightmost 3 bits
- if e==0 then
- return m;
- else
- return (m+8)*(2^(e-1)); --Add the bit #4 to the mantissa, and shift the bits by the amount indicated by the exponent
- end
- end
- local function readInstruction(s)
- local code;
- s.count=s.count+4;
- if s.bigEndian then code=s.inf[s.count-4]*2^24+s.inf[s.count-3]*2^16+s.inf[s.count-2]*2^8+s.inf[s.count-1];
- else code=s.inf[s.count-1]*2^24+s.inf[s.count-2]*2^16+s.inf[s.count-3]*2^8+s.inf[s.count-4]; end
- local name,a,b,c;
- local opcode=bit32.band(code,0x0000003F); --6 bits
- name=lbc.codes[opcode];
- local optype=lbc.types[opcode];
- a=bit32.rshift(bit32.band(code,0x00003FC0),6); --8 bits
- if optype==lbc.types.ABC then
- c=bit32.rshift(bit32.band(code,0x007FC000),14); --9 bits
- b=bit32.rshift(bit32.band(code,0xFF800000),23); --9 bits
- else
- b=bit32.rshift(bit32.band(code,0xFFFFC000),14); --18 bits
- if optype==lbc.types.ABx then
- elseif optype==lbc.types.AsBx then
- b=b-0x1FFFF; --Signed in bias format
- else error("Invalid opcode "..tostring(opcode)); end
- end
- return lbc.new(name,a,b,c);
- end
- local function skipInstruction(s,w)
- if s.dbg and w then
- local op=readInstruction(s);
- print(op.name,op.a,op.b,op.c);
- else s.count=s.count+4; end
- end
- local funcMeta={k=lbc.addConstant};
- funcMeta.__index=funcMeta;
- local function readFunc(s)
- local bm=setmetatable({},funcMeta);
- --Read function header
- if s.skipHeader then
- skipString(s,"sourceName");
- skipInt(s,"firstLine");
- skipInt(s,"lastLine");
- skipByte(s,"upvalueCount");
- skipByte(s,"paramCount");
- skipByte(s,"varargFlags");
- skipByte(s,"stackSize");
- else
- bm.header={};
- bm.header.sourceName=readString(s);
- bm.header.firstLine=readInt(s);
- bm.header.lastLine=readInt(s);
- bm.header.upvalueCount=readByte(s);
- bm.header.paramCount=readByte(s);
- local flags=readByte(s);
- bm.header.varargFlags={hasArg=bit32.band(flags,1)~=0,isVararg=bit32.band(flags,2)~=0,needsArg=bit32.band(flags,4)~=0};
- bm.header.stackSize=readByte(s);
- end
- --Read instructions
- local codeSize=readInt(s);
- local op;
- if s.skipCode then
- for i=1,codeSize do
- skipInstruction(s,"instruction");
- end
- else
- local prevOp;
- bm.code={};
- for i=1,codeSize do
- if prevOp and prevOp.name=="setlist" and prevOp.c==0 then
- --SETLIST's 3rd arg is encoded in this instruction
- s.count=s.count+4;
- local c;
- if s.bigEndian then c=s.inf[s.count-4]*2^24+s.inf[s.count-3]*2^16+s.inf[s.count-2]*2^8+s.inf[s.count-1];
- else c=s.inf[s.count-1]*2^24+s.inf[s.count-2]*2^16+s.inf[s.count-3]*2^8+s.inf[s.count-4]; end
- prevOp=lbc.new("setlist_c",nil,nil,c);
- else
- prevOp=readInstruction(s);
- end
- prevOp.i=i;
- bm.code[i]=prevOp;
- end
- end
- --Read constants
- local kSize=readInt(s);
- local kType;
- if s.skipK then
- for i=1,kSize do
- kType=readByte(s);
- if kType==0 then
- elseif kType==1 then
- skipByte(s,"boolK");
- elseif kType==3 then
- skipDouble(s,"numberK");
- elseif kType==4 then
- skipString(s,"stringK");
- else error("Invalid constant type "..kType); end
- end
- else
- bm.constants=setmetatable({size=kSize},{
- __index=function(t,k)
- if type(k)=="number" then
- --Allow for constants to be fetched with MSB notation
- if k>=257 then --Starts at 1, not 0, so 256 refers to register 256, while 257 refers to constant 1
- return rawget(t,k-256);
- end
- end
- return rawget(t,k);
- end,
- __newindex=function(t,k,v)
- if type(k)=="number" then
- if k>=257 then
- return rawset(t,k-256,v);
- end
- end
- return rawset(t,k,v);
- end,
- });
- for i=1,kSize do
- kType=readByte(s);
- if kType==0 then
- elseif kType==1 then
- bm.constants[i]=readByte(s)~=0;
- elseif kType==3 then
- bm.constants[i]=readDouble(s);
- elseif kType==4 then
- bm.constants[i]=readString(s);
- else error("Invalid constant type "..kType); end
- end
- end
- --Read function prototypes (unskippable)
- local pSize=readInt(s);
- bm.functions={};
- for i=1,pSize do
- bm.functions[i]=readFunc(s);
- end
- --Read source lines
- local lineInfoSize=readInt(s);
- if s.skipSourceLines then
- for i=1,lineInfoSize do
- skipInt(s,"sourceLine");
- end
- else
- bm.sourceLines={};
- for i=1,lineInfoSize do
- bm.sourceLines[i]=readInt(s);
- end
- end
- --Read local vars
- local locVarSize=readInt(s);
- if s.skipLocalVars then
- for i=1,locVarSize do
- skipString(s,"localVarName");
- skipInt(s,"localVarStartpc");
- skipInt(s,"localVarEndpc");
- end
- else
- bm.localVars={};
- for i=1,locVarSize do
- bm.localVars[i]={
- name=readString(s),
- startScope=readInt(s),
- endScope=readInt(s),
- };
- end
- end
- --Read upvalue list
- local upValueSize=readInt(s);
- if s.skipUpvalues then
- for i=1,upValueSize do
- skipString(s,"upvalueName");
- end
- else
- bm.upvalues={};
- for i=1,upValueSize do
- bm.upvalues[i]=readString(s);
- end
- end
- return bm;
- end
- --Converts a binary chunk (or function) to a bytemap
- lbc.chunkToBytemap=function(chunk,s)
- s=s or {};
- if type(chunk)=="function" then chunk=string.dump(chunk); end
- if type(chunk)=="string" then chunk={chunk:byte(1,-1)}; end
- s.inf=chunk;
- if s.inf[5]~=0x51 then
- print("Bytecode version: "..bit32.rshift(s.inf[5],4).."."..bit32.band(s.inf[5],0x0F));
- error("Parser only works on Lua 5.1 bytecode",0);
- elseif s.inf[6]~=0 then
- print("Bytecode format: "..s.inf[6]);
- error("Parser only works on official bytecode format (format 0)",0);
- elseif s.inf[10]~=4 then
- print("Instruction size: "..(s.inf[10]*8).."-bit");
- error("Parser only works on 32-bit instructions",0);
- elseif s.inf[11]~=8 or s.inf[12]~=0 then
- print("Numbers: "..(s.inf[11]*8).."-bit "..(s.inf[12]==0 and "floating point" or "integral"));
- error("Parser only works on 64-bit floating point numbers",0);
- end
- s.count=1;
- s.bigEndian=s.inf[7]==0;
- s.intSize=s.inf[8];
- s.sizetSize=s.inf[9];
- --print((s.bigEndian and "Big endian, " or "Little endian, ")..(s.intSize*8).."-bit integer, "..(s.sizetSize*8).."-bit size_t");
- s.count=s.count+12;
- local bm=readFunc(s);
- if s.count~=#s.inf+1 then error("Extra bytes in file"); end
- bm.chunkHeader={
- luaVersion=bit32.rshift(s.inf[5],4).."."..bit32.band(s.inf[5],0x0F),
- luaVersionCode=s.inf[5],
- format=s.inf[6]==0 and "official" or "unknown",
- formatNumber=s.inf[6],
- instructionSize=s.inf[10],
- numberSize=s.inf[11],
- numberType=s.inf[12]==0 and "floating_point" or "integer",
- endianness=s.bigEndian and "big" or "little",
- bigEndian=s.bigEndian,
- littleEndian=not s.bigEndian,
- intSize=s.intSize,
- sizetSize=s.sizetSize,
- parserVersion=1,
- };
- return bm;
- end
- lbc.stringToBytemap=function(str,s)
- if str:sub(1,4)=="\27Lua" then
- local f,err=loadstring(str);
- if f then
- str=string.dump(f);
- else
- return nil,err;
- end
- end
- return lbc.chunkToBytemap(str,s);
- end
- lbc.emptyBytemap=function()
- return lbc.chunkToBytemap(function()end);
- end
- --Chunk writer
- local function writeByte(s,b)
- s.out[s.count]=b;
- s.count=s.count+1;
- end
- local function writeInt(s,i)
- if s.bigEndian then
- for j=0,s.intSize-1 do
- s.out[s.count+j]=bit32.band(bit32.rshift(i,(s.intSize-j-1)*8),0xFF);
- end
- else
- for j=0,s.intSize-1 do
- s.out[s.count+j]=bit32.band(bit32.rshift(i,j*8),0xFF);
- end
- end
- s.count=s.count+s.intSize;
- end
- local function writeSizet(s,i)
- if s.bigEndian then
- for j=0,s.sizetSize-1 do
- s.out[s.count+j]=bit32.band(bit32.rshift(i,(s.sizetSize-j-1)*8),0xFF);
- end
- else
- for j=0,s.sizetSize-1 do
- s.out[s.count+j]=bit32.band(bit32.rshift(i,j*8),0xFF);
- end
- end
- s.count=s.count+s.sizetSize;
- end
- local function writeString(s,str)
- if str then writeSizet(s,#str+1); --Write string length
- else return writeSizet(s,0); end --Write 0 (a nonexistent string)
- local sb={str:byte(1,-1)};
- sb[#sb+1]=0; --Add null terminator
- for i=0,#str do
- s.out[s.count+i]=sb[i+1];
- end
- s.count=s.count+#sb;
- end
- local function writeDouble(s,x) --DOESN'T SUPPORT DENORMALIZED
- local bytes={};
- if x~=x then bytes[1]=0x7F;bytes[2]=0xFF;bytes[3]=0xFF;bytes[4]=0xFF;bytes[5]=0xFF;bytes[6]=0xFF;bytes[7]=0xFF;bytes[8]=0xFF;
- elseif x==math.huge then bytes[1]=0x7F;bytes[2]=0xF0;bytes[3]=0x00;bytes[4]=0x00;bytes[5]=0x00;bytes[6]=0x00;bytes[7]=0x00;bytes[8]=0x00;
- elseif x==-math.huge then bytes[1]=0xFF;bytes[2]=0xF0;bytes[3]=0x00;bytes[4]=0x00;bytes[5]=0x00;bytes[6]=0x00;bytes[7]=0x00;bytes[8]=0x00;
- else
- --Double encoder taken from ChunkSpy's convert_to["double"] and modified
- --ChunkSpy Copyright (c) 2004-2006 Kein-Hong Man <[email protected]>
- --http://luaforge.net/projects/chunkspy/
- --http://www.geocities.com/keinhong/chunkspy.html
- --Takes a normalized number and outputs an 8-byte little-endian IEEE 754 binary64 byte list
- local function grab_byte(v)
- return math.floor(v / 256), math.floor(v) % 256
- end
- local sign = 0
- if x < 0 then sign = 1; x = -x end
- local mantissa, exponent = math.frexp(x)
- if x == 0 then -- zero
- mantissa, exponent = 0, 0
- else
- mantissa = (mantissa * 2 - 1) * math.ldexp(0.5, 53)
- exponent = exponent + 1022
- end
- local byte -- convert to bytes
- x = mantissa
- for i = 1,6 do
- x, byte = grab_byte(x); bytes[i] = byte -- 47:0
- end
- x, byte = grab_byte(exponent * 16 + x); bytes[7]=byte -- 55:48
- x, byte = grab_byte(sign * 128 + x); bytes[8]=byte -- 63:56
- end
- if s.bigEndian then
- for i=0,7 do
- s.out[s.count+i]=bytes[8-i];
- end
- else
- for i=0,7 do
- s.out[s.count+i]=bytes[i+1];
- end
- end
- s.count=s.count+8;
- end
- lbc.typeToRaw=function(vtype,val)
- if vtype==nil or val==nil then return val; end
- if vtype=="table" then
- return val[1];
- elseif vtype=="bytefloat" then
- return lbc.fromBytefloat(val);
- elseif vtype=="argamount" then
- if val=="varargs" then return 0;
- else return val-1; end
- elseif vtype=="boolean" then
- if val then return 1;
- else return 0; end
- end
- end
- local function writeInstruction(s,op)
- local name=op.name;
- local a=lbc.typeToRaw(op.typeA,op.a) or 0;
- local b=lbc.typeToRaw(op.typeB,op.b) or 0;
- local c=lbc.typeToRaw(op.typeC,op.c) or 0;
- local code;
- if name=="setlist_c" then
- code=c;
- else
- local opcode=lbc.codes[name];
- code=opcode;
- code=code+a*2^6; --Shift 6 to the left
- local optype=lbc.types[opcode];
- if optype==lbc.types.ABC then
- code=code+c*2^14; --Shift 14 to the left
- code=code+b*2^23; --Shift 23 to the left
- else
- if optype==lbc.types.AsBx then b=b+0x1FFFF; --Apply bias
- elseif optype~=lbc.types.ABx then
- error("Invalid opcode "..tostring(name));
- end
- code=code+b*2^14; --Shift 14 to the left
- end
- end
- if s.bigEndian then
- for j=0,3 do
- local tmp=(code/2^((3-j)*8))%0x100; --rshift code by (3-j)*8 bits and band by 0xFF
- s.out[s.count+j]=tmp-(tmp%1); --Floor result and assign
- end
- else
- for j=0,3 do
- local tmp=(code/2^(j*8))%0x100; --rshift code by j*8 bits and band by 0xFF
- s.out[s.count+j]=tmp-(tmp%1); --Floor result and assign
- end
- end
- s.count=s.count+4;
- end
- local function writeFunc(s,bm)
- --Write function header
- writeString(s,bm.header.sourceName);
- writeInt(s,bm.header.firstLine);
- writeInt(s,bm.header.lastLine);
- writeByte(s,bm.header.upvalueCount);
- writeByte(s,bm.header.paramCount);
- local flags=bm.header.varargFlags;
- writeByte(s,(flags.hasArg and 1 or 0)+(flags.isVararg and 2 or 0)+(flags.needsArg and 4 or 0));
- writeByte(s,bm.header.stackSize);
- --Write instructions
- writeInt(s,#bm.code);
- for i,ins in ipairs(bm.code) do
- writeInstruction(s,ins);
- end
- --Write constants
- local kSize=bm.constants.size;
- writeInt(s,kSize);
- local k;
- local kType;
- for i=1,kSize do
- k=bm.constants[i];
- kType=type(k);
- if kType=="nil" then
- writeByte(s,0);
- elseif kType=="boolean" then
- writeByte(s,1);
- writeByte(s,k and 1 or 0);
- elseif kType=="number" then
- writeByte(s,3);
- writeDouble(s,k);
- elseif kType=="string" then
- writeByte(s,4);
- writeString(s,k);
- end
- end
- --Write functions
- writeInt(s,#bm.functions);
- for i=1,#bm.functions do
- writeFunc(s,bm.functions[i]);
- end
- --Write source lines
- writeInt(s,#bm.sourceLines);
- for i=1,#bm.sourceLines do
- writeInt(s,bm.sourceLines[i]);
- end
- --Write local variables
- writeInt(s,#bm.localVars);
- for i=1,#bm.localVars do
- local lv=bm.localVars[i];
- writeString(s,lv.name);
- writeInt(s,lv.startScope);
- writeInt(s,lv.endScope);
- end
- --Write upvalues
- writeInt(s,#bm.upvalues);
- for i=1,#bm.upvalues do
- writeString(s,bm.upvalues[i]);
- end
- end
- lbc.bytemapToChunk=function(bm,s)
- s=s or {};
- do
- --Compute endianness
- local be=s.bigEndian~=nil;
- local le=s.littleEndian~=nil;
- local e=s.endianness~=nil;
- if (be and le) or (be and e) or (le and e) then error("Multiple endianness specifiers"); end
- if le then s.bigEndian=not s.littleEndian;
- elseif e then
- if s.endianness=="big" then s.bigEndian=true;
- elseif s.endianness=="little" then s.bigEndian=false;
- else error("Invalid endianness. Must be 'big' or 'little'"); end
- end
- end
- if s.bigEndian==nil or s.intSize==nil or s.sizetSize==nil then
- local dump=string.dump(function()end); --Get platform parameters
- if s.bigEndian==nil then s.bigEndian=dump:sub(7,7)=="\0"; end
- if s.intSize==nil then s.intSize=dump:sub(8,8):byte(); end
- if s.sizetSize==nil then s.sizetSize=dump:sub(9,9):byte(); end
- end
- s.out=s.out or {};
- s.count=s.count or #s.out+1;
- if bm.chunkHeader.luaVersionCode~=0x51 then error("Only Lua 5.1 bytemaps are supported");
- elseif bm.chunkHeader.parserVersion~=1 then error("Only parser version 1 bytemaps are supported");
- elseif bm.chunkHeader.format~="official" then error("Only official bytemaps are supported");
- --elseif bm.chunkHeader.instructionSize~=4 then error("Only 32-bit instruction size is supported"); --Bytemap format doesn't care, only chunks care
- --elseif bm.chunkHeader.numberSize~=8 or bm.chunkHeader.numberType~="floating_point" then error("Only 64-bit double numbers are supported"); --Bytemap doesn't care, only chunks care
- end
- --Write chunk header
- s.out[s.count]=0x1B;
- s.out[s.count+1]=0x4C;
- s.out[s.count+2]=0x75;
- s.out[s.count+3]=0x61;
- s.out[s.count+4]=bm.chunkHeader.luaVersionCode;
- s.out[s.count+5]=bm.chunkHeader.formatNumber;
- s.out[s.count+6]=s.bigEndian and 0 or 1;
- s.out[s.count+7]=s.intSize;
- s.out[s.count+8]=s.sizetSize;
- s.out[s.count+9]=4;
- s.out[s.count+10]=8;
- s.out[s.count+11]=0;
- s.count=s.count+12;
- --Write main function
- writeFunc(s,bm);
- return s.out;
- end
- lbc.bytemapToFunction=function(bm,s)
- return loadstring(string.char(unpack(lbc.bytemapToChunk(bm,s))),bm.header.sourceName or nil);
- end
- lbc.runBytemap=function(bm,...)
- local f,err=lbc.bytemapToFunction(bm);
- if f then
- return f(...);
- else
- return error(err);
- end
- end
- if fs then
- --CC Helper functions
- lbc.fileToBytemap=function(path,s)
- local h=fs.open(path,"rb");
- path=fs.getName(path);
- if h==nil then error("Error opening file '"..path.."'",2); end
- local bytes={};
- while true do
- local b=h.read();
- if b==nil then break; end
- bytes[#bytes+1]=b;
- end
- h.close();
- local chunk;
- if bytes[1]==0x1B and bytes[2]==0x4C and bytes[3]==0x75 and bytes[4]==0x61 then
- chunk=bytes;
- else
- --Compile and error-check
- local f,err=loadstring(string.char(unpack(bytes)),path);
- if not f then
- --Try to remove "lbc_parse:??:"
- local c1=err:find(":");
- if c1 then
- local c2=err:find(":",c1+1);
- if c2 then
- err=err:sub(c2+2);
- end
- end
- error(err,0);
- end
- --Convert into bytestring
- chunk=string.dump(f);
- end
- return lbc.chunkToBytemap(chunk,s);
- end
- lbc.bytemapToFile=function(path,bm,s)
- local bytes=lbc.bytemapToChunk(bm,s);
- local h=fs.open(path,"wb");
- path=fs.getName(path);
- if h==nil then error("Could not open file "..path); end
- for i=1,#bytes do
- h.write(bytes[i]);
- end
- h.close();
- end
- end
- return lbc;
Advertisement
Add Comment
Please, Sign In to add comment