Skip to content
Permalink
Browse files
added cross-compile support
  • Loading branch information
bogdanm committed Sep 19, 2008
1 parent 4793225 commit 810b787
Show file tree
Hide file tree
Showing 5 changed files with 245 additions and 17 deletions.
@@ -0,0 +1,23 @@
import os, sys

output = 'luac'
cdefs = '-DLUA_CROSS_COMPILER'

# Lua source files and include path
lua_files = """lapi.c lcode.c ldebug.c ldo.c ldump.c lfunc.c lgc.c llex.c lmem.c lobject.c lopcodes.c
lparser.c lstate.c lstring.c ltable.c ltm.c lundump.c lvm.c lzio.c lauxlib.c lbaselib.c
ldblib.c liolib.c lmathlib.c loslib.c ltablib.c lstrlib.c loadlib.c linit.c luac.c print.c"""
lua_full_files = " " + " ".join( [ "src/lua/%s" % name for name in lua_files.split() ] )
local_include = "-Isrc/lua"

# Compiler/linker options
cccom = "gcc -O3 %s -Wall %s -c $SOURCE -o $TARGET" % ( local_include, cdefs )
linkcom = "gcc -o $TARGET $SOURCES -lm"

# Env for building the program
comp = Environment( CCCOM = cccom,
LINKCOM = linkcom,
ENV = os.environ )
comp.TargetSignatures( 'content' )
comp.SourceSignatures( 'MD5' )
Default( comp.Program( output, Split( lua_full_files ) ) )
@@ -5,6 +5,8 @@
*/

#include <stddef.h>
#include <sys/types.h>
#include <string.h>

#define ldump_c
#define LUA_CORE
@@ -21,6 +23,7 @@ typedef struct {
void* data;
int strip;
int status;
DumpTargetInfo target;
} DumpState;

#define DumpMem(b,n,size,D) DumpBlock(b,(n)*(size),D)
@@ -42,39 +45,142 @@ static void DumpChar(int y, DumpState* D)
DumpVar(x,D);
}

static void MaybeByteSwap(char *number, size_t numbersize, DumpState *D)
{
int x=1;
int platform_little_endian = *(char*)&x;
if (platform_little_endian != D->target.little_endian)
{
int i;
for (i=0; i<numbersize/2; i++)
{
char temp = number[i];
number[i] = number[numbersize-1-i];
number[numbersize-1-i] = temp;
}
}
}

static void DumpIntWithSize(int x, int sizeof_int, DumpState* D)
{
/* dump signed integer */
switch(sizeof_int) {
case 1: {
if (x>0x7F || x<(-0x80)) D->status=LUA_ERR_CC_INTOVERFLOW;
DumpChar(x,D);
} break;
case 2: {
if (x>0x7FFF || x<(-0x8000)) D->status=LUA_ERR_CC_INTOVERFLOW;
int16_t y=x;
MaybeByteSwap((char*)&y,2,D);
DumpVar(y,D);
} break;
case 4: {
/* Need to reduce bounds by 1 to avoid messing 32-bit compilers up */
if (x>0x7FFFFFFE || x<(-0x7FFFFFFF)) D->status=LUA_ERR_CC_INTOVERFLOW;
int32_t y=x;
MaybeByteSwap((char*)&y,4,D);
DumpVar(y,D);
} break;
default: lua_assert(0);
}
}

static void DumpInt(int x, DumpState* D)
{
DumpVar(x,D);
DumpIntWithSize(x,D->target.sizeof_int,D);
}

static void DumpSize(size_t x, DumpState* D)
{
/* dump unsigned integer */
switch(D->target.sizeof_size_t) {
case 1: {
if (x>0xFF) D->status=LUA_ERR_CC_INTOVERFLOW;
DumpChar(x,D);
} break;
case 2: {
if (x>0xFFFF) D->status=LUA_ERR_CC_INTOVERFLOW;
unsigned short y=x;
MaybeByteSwap((char*)&y,2,D);
DumpVar(y,D);
} break;
case 4: {
/* Reduce bounds to avoid messing 32-bit compilers up */
if (x>0xFFFFFFFE) D->status=LUA_ERR_CC_INTOVERFLOW;
unsigned long y=x;
MaybeByteSwap((char*)&y,4,D);
DumpVar(y,D);
} break;
default: lua_assert(0);
}
}

static void DumpNumber(lua_Number x, DumpState* D)
{
DumpVar(x,D);
if (D->target.lua_Number_integral)
{
if (((float)(int)x)!=x) D->status=LUA_ERR_CC_NOTINTEGER;
DumpIntWithSize(x,D->target.sizeof_lua_Number,D);
}
else
{
switch(D->target.sizeof_lua_Number)
{
/* do we need bounds checking? */
case 4: {
float y=x;
MaybeByteSwap((char*)&y,4,D);
DumpVar(y,D);
} break;
case 8: {
double y=x;
// ARM FPA mode: keep endianness, but swap high and low parts of the
// memory representation. This is the default compilation mode for ARM
// targets (at least with GCC)
if(D->target.is_arm_fpa)
{
char *pnum=(char*)&y, temp[4];
memcpy(temp,pnum,4);
memcpy(pnum,pnum+4,4);
memcpy(pnum+4,temp,4);
}
MaybeByteSwap((char*)&y,8,D);
DumpVar(y,D);
} break;
default: lua_assert(0);
}
}
}

static void DumpVector(const void* b, int n, size_t size, DumpState* D)
static void DumpCode(const Proto *f, DumpState* D)
{
DumpInt(n,D);
DumpMem(b,n,size,D);
DumpInt(f->sizecode,D);
char buf[10];
int i;
for (i=0; i<f->sizecode; i++)
{
memcpy(buf,&f->code[i],sizeof(Instruction));
MaybeByteSwap(buf,sizeof(Instruction),D);
DumpBlock(buf,sizeof(Instruction),D);
}
}

static void DumpString(const TString* s, DumpState* D)
{
if (s==NULL || getstr(s)==NULL)
{
size_t size=0;
DumpVar(size,D);
DumpSize(size,D);
}
else
{
size_t size=s->tsv.len+1; /* include trailing '\0' */
DumpVar(size,D);
DumpSize(size,D);
DumpBlock(getstr(s),size,D);
}
}

#define DumpCode(f,D) DumpVector(f->code,f->sizecode,sizeof(Instruction),D)

static void DumpFunction(const Proto* f, const TString* p, DumpState* D);

static void DumpConstants(const Proto* f, DumpState* D)
@@ -112,7 +218,12 @@ static void DumpDebug(const Proto* f, DumpState* D)
{
int i,n;
n= (D->strip) ? 0 : f->sizelineinfo;
DumpVector(f->lineinfo,n,sizeof(int),D);
DumpInt(n,D);
for (i=0; i<n; i++)
{
DumpInt(f->lineinfo[i],D);
}

n= (D->strip) ? 0 : f->sizelocvars;
DumpInt(n,D);
for (i=0; i<n; i++)
@@ -121,6 +232,7 @@ static void DumpDebug(const Proto* f, DumpState* D)
DumpInt(f->locvars[i].startpc,D);
DumpInt(f->locvars[i].endpc,D);
}

n= (D->strip) ? 0 : f->sizeupvalues;
DumpInt(n,D);
for (i=0; i<n; i++) DumpString(f->upvalues[i],D);
@@ -142,23 +254,53 @@ static void DumpFunction(const Proto* f, const TString* p, DumpState* D)

static void DumpHeader(DumpState* D)
{
char h[LUAC_HEADERSIZE];
luaU_header(h);
DumpBlock(h,LUAC_HEADERSIZE,D);
char buf[LUAC_HEADERSIZE];
char *h=buf;

/* This code must be kept in sync wiht luaU_header */
memcpy(h,LUA_SIGNATURE,sizeof(LUA_SIGNATURE)-1);
h+=sizeof(LUA_SIGNATURE)-1;
*h++=(char)LUAC_VERSION;
*h++=(char)LUAC_FORMAT;
*h++=(char)D->target.little_endian;
*h++=(char)D->target.sizeof_int;
*h++=(char)D->target.sizeof_size_t;
*h++=(char)sizeof(Instruction);
*h++=(char)D->target.sizeof_lua_Number;
*h++=(char)D->target.lua_Number_integral;

DumpBlock(buf,LUAC_HEADERSIZE,D);
}

/*
** dump Lua function as precompiled chunk
** dump Lua function as precompiled chunk with specified target
*/
int luaU_dump (lua_State* L, const Proto* f, lua_Writer w, void* data, int strip)
int luaU_dump_crosscompile (lua_State* L, const Proto* f, lua_Writer w, void* data, int strip, DumpTargetInfo target)
{
DumpState D;
D.L=L;
D.writer=w;
D.data=data;
D.strip=strip;
D.status=0;
D.target=target;
DumpHeader(&D);
DumpFunction(f,NULL,&D);
return D.status;
}

/*
** dump Lua function as precompiled chunk with local machine as target
*/
int luaU_dump (lua_State* L, const Proto* f, lua_Writer w, void* data, int strip)
{
DumpTargetInfo target;
int test=1;
target.little_endian=*(char*)&test;
target.sizeof_int=sizeof(int);
target.sizeof_size_t=sizeof(size_t);
target.sizeof_lua_Number=sizeof(lua_Number);
target.lua_Number_integral=(((lua_Number)0.5)==0);
target.is_arm_fpa=0;
return luaU_dump_crosscompile(L,f,w,data,strip,target);
}
@@ -4,7 +4,6 @@
** See Copyright Notice in lua.h
*/


#define linit_c
#define LUA_LIB

@@ -13,7 +12,9 @@
#include "lualib.h"
#include "lauxlib.h"

#ifndef LUA_CROSS_COMPILER
#include "platform_libs.h"
#endif

static const luaL_Reg lualibs[] = {
{"", luaopen_base},
@@ -32,6 +32,7 @@ static int stripping=0; /* strip debug information? */
static char Output[]={ OUTPUT }; /* default output file name */
static const char* output=Output; /* actual output file name */
static const char* progname=PROGNAME; /* actual program name */
static DumpTargetInfo target;

static void fatal(const char* message)
{
@@ -60,6 +61,9 @@ static void usage(const char* message)
" -p parse only\n"
" -s strip debug information\n"
" -v show version information\n"
" -cci bits cross-compile with given integer size\n"
" -ccn type bits cross-compile with given lua_Number type and size\n"
" -cce endian cross-compile with given endianness ('big' or 'little')\n"
" -- stop handling options\n",
progname,Output);
exit(EXIT_FAILURE);
@@ -98,6 +102,33 @@ static int doargs(int argc, char* argv[])
stripping=1;
else if (IS("-v")) /* show version */
++version;
else if (IS("-cci")) /* target integer size */
{
int s = target.sizeof_int = target.sizeof_size_t = atoi(argv[++i])/8;
if (!(s==1 || s==2 || s==4)) fatal(LUA_QL("-cci") " must be 8, 16 or 32");
}
else if (IS("-ccn")) /* target lua_Number type and size */
{
const char *type=argv[++i];
if (strcmp(type,"int")==0) target.lua_Number_integral=1;
else if (strcmp(type,"float")==0) target.lua_Number_integral=0;
else if (strcmp(type,"float_arm")==0)
{
target.lua_Number_integral=0;
target.is_arm_fpa=1;
}
else fatal(LUA_QL("-ccn") " type must be " LUA_QL("int") " or " LUA_QL("float") " or " LUA_QL("float_arm"));
int s = target.sizeof_lua_Number = atoi(argv[++i])/8;
if (target.lua_Number_integral && !(s==1 || s==2 || s==4)) fatal(LUA_QL("-ccn") " size must be 8, 16, or 32 for int");
if (!target.lua_Number_integral && !(s==4 || s==8)) fatal(LUA_QL("-ccn") " size must be 32 or 64 for float");
}
else if (IS("-cce")) /* target endianness */
{
const char *val=argv[++i];
if (strcmp(val,"big")==0) target.little_endian=0;
else if (strcmp(val,"little")==0) target.little_endian=1;
else fatal(LUA_QL("-cce") " must be " LUA_QL("big") " or " LUA_QL("little"));
}
else /* unknown option */
usage(argv[i]);
}
@@ -175,8 +206,10 @@ static int pmain(lua_State* L)
FILE* D= (output==NULL) ? stdout : fopen(output,"wb");
if (D==NULL) cannot("open");
lua_lock(L);
luaU_dump(L,f,writer,D,stripping);
int result=luaU_dump_crosscompile(L,f,writer,D,stripping,target);
lua_unlock(L);
if (result==LUA_ERR_CC_INTOVERFLOW) fatal("value too big or small for target integer type");
if (result==LUA_ERR_CC_NOTINTEGER) fatal("target lua_Number is integral but fractional value found");
if (ferror(D)) cannot("write");
if (fclose(D)) cannot("close");
}
@@ -187,6 +220,15 @@ int main(int argc, char* argv[])
{
lua_State* L;
struct Smain s;

int test=1;
target.little_endian=*(char*)&test;
target.sizeof_int=sizeof(int);
target.sizeof_size_t=sizeof(size_t);
target.sizeof_lua_Number=sizeof(lua_Number);
target.lua_Number_integral=(((lua_Number)0.5)==0);
target.is_arm_fpa=0;

int i=doargs(argc,argv);
argc-=i; argv+=i;
if (argc<=0) usage("no input files given");

0 comments on commit 810b787

Please sign in to comment.